1/* 2 * Copyright (C) 2010 Apple Inc. All rights reserved. 3 * Portions Copyright (c) 2010 Motorola Mobility, Inc. All rights reserved. 4 * Copyright (C) 2011 Igalia S.L. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' 16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 17 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 18 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS 19 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 24 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 25 * THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28#include "config.h" 29#include "WebEventFactory.h" 30 31#include "PlatformKeyboardEvent.h" 32#include "Scrollbar.h" 33#include "WindowsKeyboardCodes.h" 34#include <WebCore/GtkVersioning.h> 35#include <gdk/gdk.h> 36#include <gdk/gdkkeysyms.h> 37#include <gtk/gtk.h> 38#include <wtf/ASCIICType.h> 39 40using namespace WebCore; 41 42namespace WebKit { 43 44static inline bool isGdkKeyCodeFromKeyPad(unsigned keyval) 45{ 46 return keyval >= GDK_KP_Space && keyval <= GDK_KP_9; 47} 48 49static inline WebEvent::Modifiers modifiersForEvent(const GdkEvent* event) 50{ 51 unsigned modifiers = 0; 52 GdkModifierType state; 53 54 // Check for a valid state in GdkEvent. 55 if (!gdk_event_get_state(event, &state)) 56 return static_cast<WebEvent::Modifiers>(0); 57 58 if (state & GDK_CONTROL_MASK) 59 modifiers |= WebEvent::ControlKey; 60 if (state & GDK_SHIFT_MASK) 61 modifiers |= WebEvent::ShiftKey; 62 if (state & GDK_MOD1_MASK) 63 modifiers |= WebEvent::AltKey; 64 if (state & GDK_META_MASK) 65 modifiers |= WebEvent::MetaKey; 66 67 return static_cast<WebEvent::Modifiers>(modifiers); 68} 69 70static inline WebMouseEvent::Button buttonForEvent(const GdkEvent* event) 71{ 72 unsigned button = 0; 73 74 switch (event->type) { 75 case GDK_MOTION_NOTIFY: 76 button = WebMouseEvent::NoButton; 77 if (event->motion.state & GDK_BUTTON1_MASK) 78 button = WebMouseEvent::LeftButton; 79 else if (event->motion.state & GDK_BUTTON2_MASK) 80 button = WebMouseEvent::MiddleButton; 81 else if (event->motion.state & GDK_BUTTON3_MASK) 82 button = WebMouseEvent::RightButton; 83 break; 84 case GDK_BUTTON_PRESS: 85 case GDK_2BUTTON_PRESS: 86 case GDK_3BUTTON_PRESS: 87 case GDK_BUTTON_RELEASE: 88 if (event->button.button == 1) 89 button = WebMouseEvent::LeftButton; 90 else if (event->button.button == 2) 91 button = WebMouseEvent::MiddleButton; 92 else if (event->button.button == 3) 93 button = WebMouseEvent::RightButton; 94 break; 95 default: 96 ASSERT_NOT_REACHED(); 97 } 98 99 return static_cast<WebMouseEvent::Button>(button); 100} 101 102WebMouseEvent WebEventFactory::createWebMouseEvent(const GdkEvent* event, int currentClickCount) 103{ 104 double x, y, xRoot, yRoot; 105 gdk_event_get_coords(event, &x, &y); 106 gdk_event_get_root_coords(event, &xRoot, &yRoot); 107 108 WebEvent::Type type = static_cast<WebEvent::Type>(0); 109 switch (event->type) { 110 case GDK_MOTION_NOTIFY: 111 type = WebEvent::MouseMove; 112 break; 113 case GDK_BUTTON_PRESS: 114 case GDK_2BUTTON_PRESS: 115 case GDK_3BUTTON_PRESS: 116 type = WebEvent::MouseDown; 117 break; 118 case GDK_BUTTON_RELEASE: 119 type = WebEvent::MouseUp; 120 break; 121 default : 122 ASSERT_NOT_REACHED(); 123 } 124 125 return WebMouseEvent(type, 126 buttonForEvent(event), 127 IntPoint(x, y), 128 IntPoint(xRoot, yRoot), 129 0 /* deltaX */, 130 0 /* deltaY */, 131 0 /* deltaZ */, 132 currentClickCount, 133 modifiersForEvent(event), 134 gdk_event_get_time(event)); 135} 136 137WebWheelEvent WebEventFactory::createWebWheelEvent(const GdkEvent* event) 138{ 139 double x, y, xRoot, yRoot; 140 gdk_event_get_coords(event, &x, &y); 141 gdk_event_get_root_coords(event, &xRoot, &yRoot); 142 143 FloatSize wheelTicks; 144 switch (event->scroll.direction) { 145 case GDK_SCROLL_UP: 146 wheelTicks = FloatSize(0, 1); 147 break; 148 case GDK_SCROLL_DOWN: 149 wheelTicks = FloatSize(0, -1); 150 break; 151 case GDK_SCROLL_LEFT: 152 wheelTicks = FloatSize(1, 0); 153 break; 154 case GDK_SCROLL_RIGHT: 155 wheelTicks = FloatSize(-1, 0); 156 break; 157#if GTK_CHECK_VERSION(3, 3, 18) 158 case GDK_SCROLL_SMOOTH: { 159 double deltaX, deltaY; 160 gdk_event_get_scroll_deltas(event, &deltaX, &deltaY); 161 wheelTicks = FloatSize(-deltaX, -deltaY); 162 } 163 break; 164#endif 165 default: 166 ASSERT_NOT_REACHED(); 167 } 168 169 // FIXME: [GTK] Add a setting to change the pixels per line used for scrolling 170 // https://bugs.webkit.org/show_bug.cgi?id=54826 171 float step = static_cast<float>(Scrollbar::pixelsPerLineStep()); 172 FloatSize delta(wheelTicks.width() * step, wheelTicks.height() * step); 173 174 return WebWheelEvent(WebEvent::Wheel, 175 IntPoint(x, y), 176 IntPoint(xRoot, yRoot), 177 delta, 178 wheelTicks, 179 WebWheelEvent::ScrollByPixelWheelEvent, 180 modifiersForEvent(event), 181 gdk_event_get_time(event)); 182} 183 184WebKeyboardEvent WebEventFactory::createWebKeyboardEvent(const GdkEvent* event, const WebCore::CompositionResults& compositionResults) 185{ 186 unsigned int keyValue = event->key.keyval; 187 String text = compositionResults.simpleString.length() ? 188 compositionResults.simpleString : PlatformKeyboardEvent::singleCharacterString(keyValue); 189 190 int windowsVirtualKeyCode = compositionResults.compositionUpdated() ? 191 VK_PROCESSKEY : PlatformKeyboardEvent::windowsKeyCodeForGdkKeyCode(event->key.keyval); 192 193 return WebKeyboardEvent((event->type == GDK_KEY_RELEASE) ? WebEvent::KeyUp : WebEvent::KeyDown, 194 text, 195 text, 196 PlatformKeyboardEvent::keyIdentifierForGdkKeyCode(keyValue), 197 windowsVirtualKeyCode, 198 static_cast<int>(keyValue), 199 0 /* macCharCode */, 200 false /* isAutoRepeat */, 201 isGdkKeyCodeFromKeyPad(keyValue), 202 false /* isSystemKey */, 203 modifiersForEvent(event), 204 gdk_event_get_time(event)); 205} 206 207#ifndef GTK_API_VERSION_2 208static WebPlatformTouchPoint::TouchPointState touchPhaseFromEvents(const GdkEvent* current, const GdkEvent* event) 209{ 210 if (gdk_event_get_event_sequence(current) != gdk_event_get_event_sequence(event)) 211 return WebPlatformTouchPoint::TouchStationary; 212 213 switch (current->type) { 214 case GDK_TOUCH_UPDATE: 215 return WebPlatformTouchPoint::TouchMoved; 216 case GDK_TOUCH_BEGIN: 217 return WebPlatformTouchPoint::TouchPressed; 218 case GDK_TOUCH_END: 219 return WebPlatformTouchPoint::TouchReleased; 220 default: 221 return WebPlatformTouchPoint::TouchStationary; 222 } 223} 224 225static void appendTouchEvent(Vector<WebPlatformTouchPoint>& touchPointList, const GdkEvent* event, WebPlatformTouchPoint::TouchPointState state) 226{ 227 uint32_t identifier = GPOINTER_TO_UINT(gdk_event_get_event_sequence(event)); 228 229 gdouble x, y; 230 gdk_event_get_coords(event, &x, &y); 231 232 gdouble xRoot, yRoot; 233 gdk_event_get_root_coords(event, &xRoot, &yRoot); 234 235 WebPlatformTouchPoint touchPoint(identifier, state, IntPoint(xRoot, yRoot), IntPoint(x, y)); 236 touchPointList.uncheckedAppend(touchPoint); 237} 238#endif // GTK_API_VERSION_2 239 240WebTouchEvent WebEventFactory::createWebTouchEvent(const GdkEvent* event, const WebCore::GtkTouchContextHelper& touchContext) 241{ 242#ifndef GTK_API_VERSION_2 243 WebEvent::Type type = WebEvent::NoType; 244 const auto& touchEvents = touchContext.touchEvents(); 245 int numEvents = touchEvents.size(); 246 247 switch (event->type) { 248 case GDK_TOUCH_BEGIN: 249 type = WebEvent::TouchStart; 250 break; 251 case GDK_TOUCH_UPDATE: 252 type = WebEvent::TouchMove; 253 break; 254 case GDK_TOUCH_END: 255 type = WebEvent::TouchEnd; 256 ++numEvents; 257 break; 258 default: 259 ASSERT_NOT_REACHED(); 260 } 261 262 Vector<WebPlatformTouchPoint> touchPointList; 263 touchPointList.reserveInitialCapacity(numEvents); 264 265 for (auto it = touchEvents.begin(); it != touchEvents.end(); ++it) 266 appendTouchEvent(touchPointList, it->value.get(), touchPhaseFromEvents(it->value.get(), event)); 267 268 // Touch was already removed from the GtkTouchContextHelper, add it here. 269 if (event->type == GDK_TOUCH_END) 270 appendTouchEvent(touchPointList, event, WebPlatformTouchPoint::TouchReleased); 271 272 return WebTouchEvent(type, touchPointList, modifiersForEvent(event), gdk_event_get_time(event)); 273#else 274 return WebTouchEvent(); 275#endif // GTK_API_VERSION_2 276} 277 278} // namespace WebKit 279