8be918b0d7aca4be64811cde02b7e1e16872feee
[WebKit-https.git] / Source / WebKit / Shared / gtk / WebEventFactory.cpp
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/GtkUtilities.h>
35 #include <WebCore/GtkVersioning.h>
36 #include <gdk/gdk.h>
37 #include <gdk/gdkkeysyms.h>
38 #include <gtk/gtk.h>
39 #include <wtf/ASCIICType.h>
40
41 namespace WebKit {
42 using namespace WebCore;
43
44 static inline bool isGdkKeyCodeFromKeyPad(unsigned keyval)
45 {
46     return keyval >= GDK_KP_Space && keyval <= GDK_KP_9;
47 }
48
49 static 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     if (PlatformKeyboardEvent::modifiersContainCapsLock(state))
67         modifiers |= WebEvent::CapsLockKey;
68
69     return static_cast<WebEvent::Modifiers>(modifiers);
70 }
71
72 static inline WebMouseEvent::Button buttonForEvent(const GdkEvent* event)
73 {
74     unsigned button = 0;
75
76     switch (event->type) {
77     case GDK_ENTER_NOTIFY:
78     case GDK_LEAVE_NOTIFY:
79     case GDK_MOTION_NOTIFY: {
80         button = WebMouseEvent::NoButton;
81         GdkModifierType state;
82         gdk_event_get_state(event, &state);
83         if (state & GDK_BUTTON1_MASK)
84             button = WebMouseEvent::LeftButton;
85         else if (state & GDK_BUTTON2_MASK)
86             button = WebMouseEvent::MiddleButton;
87         else if (state & GDK_BUTTON3_MASK)
88             button = WebMouseEvent::RightButton;
89         break;
90     }
91     case GDK_BUTTON_PRESS:
92     case GDK_2BUTTON_PRESS:
93     case GDK_3BUTTON_PRESS:
94     case GDK_BUTTON_RELEASE:
95         if (event->button.button == 1)
96             button = WebMouseEvent::LeftButton;
97         else if (event->button.button == 2)
98             button = WebMouseEvent::MiddleButton;
99         else if (event->button.button == 3)
100             button = WebMouseEvent::RightButton;
101         break;
102     default:
103         ASSERT_NOT_REACHED();
104     }
105
106     return static_cast<WebMouseEvent::Button>(button);
107 }
108
109 WebMouseEvent WebEventFactory::createWebMouseEvent(const GdkEvent* event, int currentClickCount)
110 {
111     double x, y, xRoot, yRoot;
112     gdk_event_get_coords(event, &x, &y);
113     gdk_event_get_root_coords(event, &xRoot, &yRoot);
114
115     WebEvent::Type type = static_cast<WebEvent::Type>(0);
116     switch (event->type) {
117     case GDK_MOTION_NOTIFY:
118     case GDK_ENTER_NOTIFY:
119     case GDK_LEAVE_NOTIFY:
120         type = WebEvent::MouseMove;
121         break;
122     case GDK_BUTTON_PRESS:
123     case GDK_2BUTTON_PRESS:
124     case GDK_3BUTTON_PRESS:
125         type = WebEvent::MouseDown;
126         break;
127     case GDK_BUTTON_RELEASE:
128         type = WebEvent::MouseUp;
129         break;
130     default :
131         ASSERT_NOT_REACHED();
132     }
133
134     return WebMouseEvent(type,
135         buttonForEvent(event),
136         0,
137         IntPoint(x, y),
138         IntPoint(xRoot, yRoot),
139         0 /* deltaX */,
140         0 /* deltaY */,
141         0 /* deltaZ */,
142         currentClickCount,
143         modifiersForEvent(event),
144         wallTimeForEvent(event));
145 }
146
147 WebWheelEvent WebEventFactory::createWebWheelEvent(const GdkEvent* event)
148 {
149 #ifndef GTK_API_VERSION_2
150 #if GTK_CHECK_VERSION(3, 20, 0)
151     WebWheelEvent::Phase phase = gdk_event_is_scroll_stop_event(event) ?
152         WebWheelEvent::Phase::PhaseEnded :
153         WebWheelEvent::Phase::PhaseChanged;
154 #else
155     double deltaX, deltaY;
156     gdk_event_get_scroll_deltas(event, &deltaX, &deltaY);
157     WebWheelEvent::Phase phase = event->scroll.direction == GDK_SCROLL_SMOOTH && !deltaX && !deltaY ?
158         WebWheelEvent::Phase::PhaseEnded :
159         WebWheelEvent::Phase::PhaseChanged;
160 #endif
161 #else
162     WebWheelEvent::Phase phase = WebWheelEvent::Phase::PhaseChanged;
163 #endif // GTK_API_VERSION_2
164
165     return createWebWheelEvent(event, phase, WebWheelEvent::Phase::PhaseNone);
166 }
167
168 WebWheelEvent WebEventFactory::createWebWheelEvent(const GdkEvent* event, WebWheelEvent::Phase phase, WebWheelEvent::Phase momentumPhase)
169 {
170     double x, y, xRoot, yRoot;
171     gdk_event_get_coords(event, &x, &y);
172     gdk_event_get_root_coords(event, &xRoot, &yRoot);
173
174     FloatSize wheelTicks;
175     switch (event->scroll.direction) {
176     case GDK_SCROLL_UP:
177         wheelTicks = FloatSize(0, 1);
178         break;
179     case GDK_SCROLL_DOWN:
180         wheelTicks = FloatSize(0, -1);
181         break;
182     case GDK_SCROLL_LEFT:
183         wheelTicks = FloatSize(1, 0);
184         break;
185     case GDK_SCROLL_RIGHT:
186         wheelTicks = FloatSize(-1, 0);
187         break;
188 #if GTK_CHECK_VERSION(3, 3, 18)
189     case GDK_SCROLL_SMOOTH: {
190             double deltaX, deltaY;
191             gdk_event_get_scroll_deltas(event, &deltaX, &deltaY);
192             wheelTicks = FloatSize(-deltaX, -deltaY);
193         }
194         break;
195 #endif
196     default:
197         ASSERT_NOT_REACHED();
198     }
199
200     // FIXME: [GTK] Add a setting to change the pixels per line used for scrolling
201     // https://bugs.webkit.org/show_bug.cgi?id=54826
202     float step = static_cast<float>(Scrollbar::pixelsPerLineStep());
203     FloatSize delta(wheelTicks.width() * step, wheelTicks.height() * step);
204
205     return WebWheelEvent(WebEvent::Wheel,
206         IntPoint(x, y),
207         IntPoint(xRoot, yRoot),
208         delta,
209         wheelTicks,
210         phase,
211         momentumPhase,
212         WebWheelEvent::ScrollByPixelWheelEvent,
213         modifiersForEvent(event),
214         wallTimeForEvent(event));
215 }
216
217 WebKeyboardEvent WebEventFactory::createWebKeyboardEvent(const GdkEvent* event, const WebCore::CompositionResults& compositionResults, Vector<String>&& commands)
218 {
219     return WebKeyboardEvent(
220         event->type == GDK_KEY_RELEASE ? WebEvent::KeyUp : WebEvent::KeyDown,
221         compositionResults.simpleString.length() ? compositionResults.simpleString : PlatformKeyboardEvent::singleCharacterString(event->key.keyval),
222         PlatformKeyboardEvent::keyValueForGdkKeyCode(event->key.keyval),
223         PlatformKeyboardEvent::keyCodeForHardwareKeyCode(event->key.hardware_keycode),
224         PlatformKeyboardEvent::keyIdentifierForGdkKeyCode(event->key.keyval),
225         PlatformKeyboardEvent::windowsKeyCodeForGdkKeyCode(event->key.keyval),
226         static_cast<int>(event->key.keyval),
227         compositionResults.compositionUpdated(),
228         WTFMove(commands),
229         isGdkKeyCodeFromKeyPad(event->key.keyval),
230         modifiersForEvent(event),
231         wallTimeForEvent(event));
232 }
233
234 #if ENABLE(TOUCH_EVENTS)
235 WebTouchEvent WebEventFactory::createWebTouchEvent(const GdkEvent* event, Vector<WebPlatformTouchPoint>&& touchPoints)
236 {
237 #ifndef GTK_API_VERSION_2
238     WebEvent::Type type = WebEvent::NoType;
239     switch (event->type) {
240     case GDK_TOUCH_BEGIN:
241         type = WebEvent::TouchStart;
242         break;
243     case GDK_TOUCH_UPDATE:
244         type = WebEvent::TouchMove;
245         break;
246     case GDK_TOUCH_END:
247         type = WebEvent::TouchEnd;
248         break;
249     case GDK_TOUCH_CANCEL:
250         type = WebEvent::TouchCancel;
251         break;
252     default:
253         ASSERT_NOT_REACHED();
254     }
255
256     return WebTouchEvent(type, WTFMove(touchPoints), modifiersForEvent(event), wallTimeForEvent(event));
257 #else
258     return WebTouchEvent();
259 #endif // GTK_API_VERSION_2
260 }
261 #endif
262
263 } // namespace WebKit