Upstream version 7.35.144.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / web / WebInputEventFactoryGtk.cpp
1 /*
2  * Copyright (C) 2006-2009 Google Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
8  *     * Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  *     * Redistributions in binary form must reproduce the above
11  * copyright notice, this list of conditions and the following disclaimer
12  * in the documentation and/or other materials provided with the
13  * distribution.
14  *     * Neither the name of Google Inc. nor the names of its
15  * contributors may be used to endorse or promote products derived from
16  * this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30
31 #include "config.h"
32 #include "WebInputEventFactory.h"
33
34 #include "platform/KeyCodeConversion.h"
35 #include "platform/KeyboardCodes.h"
36
37 #include "WebInputEvent.h"
38
39 #include <gdk/gdk.h>
40 #include <gdk/gdkkeysyms.h>
41 #include <gtk/gtk.h>
42 #include <stdlib.h>
43
44 #include "wtf/Assertions.h"
45
46 namespace {
47
48 // For click count tracking.
49 static int gNumClicks = 0;
50 static GdkWindow* gLastClickEventWindow = 0;
51 static gint gLastClickTime = 0;
52 static gint gLastClickX = 0;
53 static gint gLastClickY = 0;
54 static blink::WebMouseEvent::Button gLastClickButton = blink::WebMouseEvent::ButtonNone;
55
56 bool shouldForgetPreviousClick(GdkWindow* window, gint time, gint x, gint y)
57 {
58     static GtkSettings* settings = gtk_settings_get_default();
59
60     if (window != gLastClickEventWindow)
61       return true;
62
63     gint doubleClickTime = 250;
64     gint doubleClickDistance = 5;
65     g_object_get(G_OBJECT(settings),
66                  "gtk-double-click-time", &doubleClickTime,
67                  "gtk-double-click-distance", &doubleClickDistance, NULL);
68     return (time - gLastClickTime) > doubleClickTime
69            || abs(x - gLastClickX) > doubleClickDistance
70            || abs(y - gLastClickY) > doubleClickDistance;
71 }
72
73 void resetClickCountState()
74 {
75     gNumClicks = 0;
76     gLastClickEventWindow = 0;
77     gLastClickTime = 0;
78     gLastClickX = 0;
79     gLastClickY = 0;
80     gLastClickButton = blink::WebMouseEvent::ButtonNone;
81 }
82
83 bool isKeyPadKeyval(guint keyval)
84 {
85     // Keypad keyvals all fall into one range.
86     return keyval >= GDK_KP_Space && keyval <= GDK_KP_9;
87 }
88
89 }  // namespace
90
91 namespace blink {
92
93 static double gdkEventTimeToWebEventTime(guint32 time)
94 {
95     // Convert from time in ms to time in sec.
96     return time / 1000.0;
97 }
98
99 static int gdkStateToWebEventModifiers(guint state)
100 {
101     int modifiers = 0;
102     if (state & GDK_SHIFT_MASK)
103         modifiers |= WebInputEvent::ShiftKey;
104     if (state & GDK_CONTROL_MASK)
105         modifiers |= WebInputEvent::ControlKey;
106     if (state & GDK_MOD1_MASK)
107         modifiers |= WebInputEvent::AltKey;
108     if (state & GDK_META_MASK)
109         modifiers |= WebInputEvent::MetaKey;
110     if (state & GDK_BUTTON1_MASK)
111         modifiers |= WebInputEvent::LeftButtonDown;
112     if (state & GDK_BUTTON2_MASK)
113         modifiers |= WebInputEvent::MiddleButtonDown;
114     if (state & GDK_BUTTON3_MASK)
115         modifiers |= WebInputEvent::RightButtonDown;
116     if (state & GDK_LOCK_MASK)
117         modifiers |= WebInputEvent::CapsLockOn;
118     if (state & GDK_MOD2_MASK)
119         modifiers |= WebInputEvent::NumLockOn;
120     return modifiers;
121 }
122
123 static int gdkEventToWindowsKeyCode(const GdkEventKey* event)
124 {
125     static const unsigned hardwareCodeToGDKKeyval[] = {
126         0,                 // 0x00:
127         0,                 // 0x01:
128         0,                 // 0x02:
129         0,                 // 0x03:
130         0,                 // 0x04:
131         0,                 // 0x05:
132         0,                 // 0x06:
133         0,                 // 0x07:
134         0,                 // 0x08:
135         0,                 // 0x09: GDK_Escape
136         GDK_1,             // 0x0A: GDK_1
137         GDK_2,             // 0x0B: GDK_2
138         GDK_3,             // 0x0C: GDK_3
139         GDK_4,             // 0x0D: GDK_4
140         GDK_5,             // 0x0E: GDK_5
141         GDK_6,             // 0x0F: GDK_6
142         GDK_7,             // 0x10: GDK_7
143         GDK_8,             // 0x11: GDK_8
144         GDK_9,             // 0x12: GDK_9
145         GDK_0,             // 0x13: GDK_0
146         GDK_minus,         // 0x14: GDK_minus
147         GDK_equal,         // 0x15: GDK_equal
148         0,                 // 0x16: GDK_BackSpace
149         0,                 // 0x17: GDK_Tab
150         GDK_q,             // 0x18: GDK_q
151         GDK_w,             // 0x19: GDK_w
152         GDK_e,             // 0x1A: GDK_e
153         GDK_r,             // 0x1B: GDK_r
154         GDK_t,             // 0x1C: GDK_t
155         GDK_y,             // 0x1D: GDK_y
156         GDK_u,             // 0x1E: GDK_u
157         GDK_i,             // 0x1F: GDK_i
158         GDK_o,             // 0x20: GDK_o
159         GDK_p,             // 0x21: GDK_p
160         GDK_bracketleft,   // 0x22: GDK_bracketleft
161         GDK_bracketright,  // 0x23: GDK_bracketright
162         0,                 // 0x24: GDK_Return
163         0,                 // 0x25: GDK_Control_L
164         GDK_a,             // 0x26: GDK_a
165         GDK_s,             // 0x27: GDK_s
166         GDK_d,             // 0x28: GDK_d
167         GDK_f,             // 0x29: GDK_f
168         GDK_g,             // 0x2A: GDK_g
169         GDK_h,             // 0x2B: GDK_h
170         GDK_j,             // 0x2C: GDK_j
171         GDK_k,             // 0x2D: GDK_k
172         GDK_l,             // 0x2E: GDK_l
173         GDK_semicolon,     // 0x2F: GDK_semicolon
174         GDK_apostrophe,    // 0x30: GDK_apostrophe
175         GDK_grave,         // 0x31: GDK_grave
176         0,                 // 0x32: GDK_Shift_L
177         GDK_backslash,     // 0x33: GDK_backslash
178         GDK_z,             // 0x34: GDK_z
179         GDK_x,             // 0x35: GDK_x
180         GDK_c,             // 0x36: GDK_c
181         GDK_v,             // 0x37: GDK_v
182         GDK_b,             // 0x38: GDK_b
183         GDK_n,             // 0x39: GDK_n
184         GDK_m,             // 0x3A: GDK_m
185         GDK_comma,         // 0x3B: GDK_comma
186         GDK_period,        // 0x3C: GDK_period
187         GDK_slash,         // 0x3D: GDK_slash
188         0,                 // 0x3E: GDK_Shift_R
189         0,                 // 0x3F:
190         0,                 // 0x40:
191         0,                 // 0x41:
192         0,                 // 0x42:
193         0,                 // 0x43:
194         0,                 // 0x44:
195         0,                 // 0x45:
196         0,                 // 0x46:
197         0,                 // 0x47:
198         0,                 // 0x48:
199         0,                 // 0x49:
200         0,                 // 0x4A:
201         0,                 // 0x4B:
202         0,                 // 0x4C:
203         0,                 // 0x4D:
204         0,                 // 0x4E:
205         0,                 // 0x4F:
206         0,                 // 0x50:
207         0,                 // 0x51:
208         0,                 // 0x52:
209         0,                 // 0x53:
210         0,                 // 0x54:
211         0,                 // 0x55:
212         0,                 // 0x56:
213         0,                 // 0x57:
214         0,                 // 0x58:
215         0,                 // 0x59:
216         0,                 // 0x5A:
217         0,                 // 0x5B:
218         0,                 // 0x5C:
219         0,                 // 0x5D:
220         0,                 // 0x5E:
221         0,                 // 0x5F:
222         0,                 // 0x60:
223         0,                 // 0x61:
224         0,                 // 0x62:
225         0,                 // 0x63:
226         0,                 // 0x64:
227         0,                 // 0x65:
228         0,                 // 0x66:
229         0,                 // 0x67:
230         0,                 // 0x68:
231         0,                 // 0x69:
232         0,                 // 0x6A:
233         0,                 // 0x6B:
234         0,                 // 0x6C:
235         0,                 // 0x6D:
236         0,                 // 0x6E:
237         0,                 // 0x6F:
238         0,                 // 0x70:
239         0,                 // 0x71:
240         0,                 // 0x72:
241         GDK_Super_L,       // 0x73: GDK_Super_L
242         GDK_Super_R,       // 0x74: GDK_Super_R
243     };
244
245     // |windowsKeyCode| has to include a valid virtual-key code even when we
246     // use non-US layouts, e.g. even when we type an 'A' key of a US keyboard
247     // on the Hebrew layout, |windowsKeyCode| should be VK_A.
248     // On the other hand, |event->keyval| value depends on the current
249     // GdkKeymap object, i.e. when we type an 'A' key of a US keyboard on
250     // the Hebrew layout, |event->keyval| becomes GDK_hebrew_shin and this
251     // WebCore::windowsKeyCodeForKeyEvent() call returns 0.
252     // To improve compatibilty with Windows, we use |event->hardware_keycode|
253     // for retrieving its Windows key-code for the keys when the
254     // WebCore::windowsKeyCodeForEvent() call returns 0.
255     // We shouldn't use |event->hardware_keycode| for keys that GdkKeymap
256     // objects cannot change because |event->hardware_keycode| doesn't change
257     // even when we change the layout options, e.g. when we swap a control
258     // key and a caps-lock key, GTK doesn't swap their
259     // |event->hardware_keycode| values but swap their |event->keyval| values.
260     int windowsKeyCode = WebCore::windowsKeyCodeForKeyEvent(event->keyval);
261     if (windowsKeyCode)
262         return windowsKeyCode;
263
264     const int tableSize = sizeof(hardwareCodeToGDKKeyval) / sizeof(hardwareCodeToGDKKeyval[0]);
265     if (event->hardware_keycode < tableSize) {
266         int keyval = hardwareCodeToGDKKeyval[event->hardware_keycode];
267         if (keyval)
268             return WebCore::windowsKeyCodeForKeyEvent(keyval);
269     }
270
271     // This key is one that keyboard-layout drivers cannot change.
272     // Use |event->keyval| to retrieve its |windowsKeyCode| value.
273     return WebCore::windowsKeyCodeForKeyEvent(event->keyval);
274 }
275
276 // Normalizes event->state to make it Windows/Mac compatible. Since the way
277 // of setting modifier mask on X is very different than Windows/Mac as shown
278 // in http://crbug.com/127142#c8, the normalization is necessary.
279 static guint normalizeEventState(const GdkEventKey* event)
280 {
281     guint mask = 0;
282     switch (gdkEventToWindowsKeyCode(event)) {
283     case WebCore::VKEY_CONTROL:
284     case WebCore::VKEY_LCONTROL:
285     case WebCore::VKEY_RCONTROL:
286         mask = GDK_CONTROL_MASK;
287         break;
288     case WebCore::VKEY_SHIFT:
289     case WebCore::VKEY_LSHIFT:
290     case WebCore::VKEY_RSHIFT:
291         mask = GDK_SHIFT_MASK;
292         break;
293     case WebCore::VKEY_MENU:
294     case WebCore::VKEY_LMENU:
295     case WebCore::VKEY_RMENU:
296         mask = GDK_MOD1_MASK;
297         break;
298     case WebCore::VKEY_CAPITAL:
299         mask = GDK_LOCK_MASK;
300         break;
301     default:
302         return event->state;
303     }
304     if (event->type == GDK_KEY_PRESS)
305         return event->state | mask;
306     return event->state & ~mask;
307 }
308
309 // Gets the corresponding control character of a specified key code. See:
310 // http://en.wikipedia.org/wiki/Control_characters
311 // We emulate Windows behavior here.
312 static WebUChar getControlCharacter(int windowsKeyCode, bool shift)
313 {
314     if (windowsKeyCode >= WebCore::VKEY_A && windowsKeyCode <= WebCore::VKEY_Z) {
315         // ctrl-A ~ ctrl-Z map to \x01 ~ \x1A
316         return windowsKeyCode - WebCore::VKEY_A + 1;
317     }
318     if (shift) {
319         // following graphics chars require shift key to input.
320         switch (windowsKeyCode) {
321         // ctrl-@ maps to \x00 (Null byte)
322         case WebCore::VKEY_2:
323             return 0;
324         // ctrl-^ maps to \x1E (Record separator, Information separator two)
325         case WebCore::VKEY_6:
326             return 0x1E;
327         // ctrl-_ maps to \x1F (Unit separator, Information separator one)
328         case WebCore::VKEY_OEM_MINUS:
329             return 0x1F;
330         // Returns 0 for all other keys to avoid inputting unexpected chars.
331         default:
332             return 0;
333         }
334     } else {
335         switch (windowsKeyCode) {
336         // ctrl-[ maps to \x1B (Escape)
337         case WebCore::VKEY_OEM_4:
338             return 0x1B;
339         // ctrl-\ maps to \x1C (File separator, Information separator four)
340         case WebCore::VKEY_OEM_5:
341             return 0x1C;
342         // ctrl-] maps to \x1D (Group separator, Information separator three)
343         case WebCore::VKEY_OEM_6:
344             return 0x1D;
345         // ctrl-Enter maps to \x0A (Line feed)
346         case WebCore::VKEY_RETURN:
347             return 0x0A;
348         // Returns 0 for all other keys to avoid inputting unexpected chars.
349         default:
350             return 0;
351         }
352     }
353 }
354
355 // WebKeyboardEvent -----------------------------------------------------------
356
357 WebKeyboardEvent WebInputEventFactory::keyboardEvent(const GdkEventKey* event)
358 {
359     WebKeyboardEvent result;
360
361     result.timeStampSeconds = gdkEventTimeToWebEventTime(event->time);
362     result.modifiers = gdkStateToWebEventModifiers(normalizeEventState(event));
363
364     switch (event->type) {
365     case GDK_KEY_RELEASE:
366         result.type = WebInputEvent::KeyUp;
367         break;
368     case GDK_KEY_PRESS:
369         result.type = WebInputEvent::RawKeyDown;
370         break;
371     default:
372         ASSERT_NOT_REACHED();
373     }
374
375     result.isSystemKey = WebInputEventFactory::isSystemKeyEvent(result);
376
377     // The key code tells us which physical key was pressed (for example, the
378     // A key went down or up).  It does not determine whether A should be lower
379     // or upper case.  This is what text does, which should be the keyval.
380     int windowsKeyCode = gdkEventToWindowsKeyCode(event);
381     result.windowsKeyCode = WebKeyboardEvent::windowsKeyCodeWithoutLocation(windowsKeyCode);
382     result.modifiers |= WebKeyboardEvent::locationModifiersFromWindowsKeyCode(windowsKeyCode);
383     result.nativeKeyCode = event->hardware_keycode;
384
385     if (result.windowsKeyCode == WebCore::VKEY_RETURN)
386         // We need to treat the enter key as a key press of character \r.  This
387         // is apparently just how webkit handles it and what it expects.
388         result.unmodifiedText[0] = '\r';
389     else
390         // FIXME: fix for non BMP chars
391         result.unmodifiedText[0] =
392             static_cast<WebUChar>(gdk_keyval_to_unicode(event->keyval));
393
394     // If ctrl key is pressed down, then control character shall be input.
395     if (result.modifiers & WebInputEvent::ControlKey)
396         result.text[0] = getControlCharacter(
397             result.windowsKeyCode, result.modifiers & WebInputEvent::ShiftKey);
398     else
399         result.text[0] = result.unmodifiedText[0];
400
401     result.setKeyIdentifierFromWindowsKeyCode();
402
403     // FIXME: Do we need to set IsAutoRepeat?
404     if (isKeyPadKeyval(event->keyval))
405         result.modifiers |= WebInputEvent::IsKeyPad;
406
407     return result;
408 }
409
410 bool WebInputEventFactory::isSystemKeyEvent(const WebKeyboardEvent& event)
411 {
412     // On Windows all keys with Alt modifier will be marked as system key.
413     // We keep the same behavior on Linux and everywhere non-Mac.
414     return event.modifiers & WebInputEvent::AltKey;
415 }
416
417 WebKeyboardEvent WebInputEventFactory::keyboardEvent(wchar_t character, int state, double timeStampSeconds)
418 {
419     // keyboardEvent(const GdkEventKey*) depends on the GdkEventKey object and
420     // it is hard to use/ it from signal handlers which don't use GdkEventKey
421     // objects (e.g. GtkIMContext signal handlers.) For such handlers, this
422     // function creates a WebInputEvent::Char event without using a
423     // GdkEventKey object.
424     WebKeyboardEvent result;
425     result.type = blink::WebInputEvent::Char;
426     result.timeStampSeconds = timeStampSeconds;
427     result.modifiers = gdkStateToWebEventModifiers(state);
428     result.windowsKeyCode = character;
429     result.nativeKeyCode = character;
430     result.text[0] = character;
431     result.unmodifiedText[0] = character;
432
433     // According to MSDN:
434     // http://msdn.microsoft.com/en-us/library/ms646286(VS.85).aspx
435     // Key events with Alt modifier and F10 are system key events.
436     // We just emulate this behavior. It's necessary to prevent webkit from
437     // processing keypress event generated by alt-d, etc.
438     // F10 is not special on Linux, so don't treat it as system key.
439     if (result.modifiers & WebInputEvent::AltKey)
440         result.isSystemKey = true;
441
442     return result;
443 }
444
445 // WebMouseEvent --------------------------------------------------------------
446
447 WebMouseEvent WebInputEventFactory::mouseEvent(const GdkEventButton* event)
448 {
449     WebMouseEvent result;
450
451     result.timeStampSeconds = gdkEventTimeToWebEventTime(event->time);
452
453     result.modifiers = gdkStateToWebEventModifiers(event->state);
454     result.x = static_cast<int>(event->x);
455     result.y = static_cast<int>(event->y);
456     result.windowX = result.x;
457     result.windowY = result.y;
458     result.globalX = static_cast<int>(event->x_root);
459     result.globalY = static_cast<int>(event->y_root);
460     result.clickCount = 0;
461
462     switch (event->type) {
463     case GDK_BUTTON_PRESS:
464         result.type = WebInputEvent::MouseDown;
465         break;
466     case GDK_BUTTON_RELEASE:
467         result.type = WebInputEvent::MouseUp;
468         break;
469     case GDK_3BUTTON_PRESS:
470     case GDK_2BUTTON_PRESS:
471     default:
472         ASSERT_NOT_REACHED();
473     };
474
475     result.button = WebMouseEvent::ButtonNone;
476     if (event->button == 1)
477         result.button = WebMouseEvent::ButtonLeft;
478     else if (event->button == 2)
479         result.button = WebMouseEvent::ButtonMiddle;
480     else if (event->button == 3)
481         result.button = WebMouseEvent::ButtonRight;
482
483     if (result.type == WebInputEvent::MouseDown) {
484         bool forgetPreviousClick = shouldForgetPreviousClick(event->window, event->time, event->x, event->y);
485
486         if (!forgetPreviousClick && result.button == gLastClickButton)
487             ++gNumClicks;
488         else {
489             gNumClicks = 1;
490
491             gLastClickEventWindow = event->window;
492             gLastClickX = event->x;
493             gLastClickY = event->y;
494             gLastClickButton = result.button;
495         }
496         gLastClickTime = event->time;
497     }
498     result.clickCount = gNumClicks;
499
500     return result;
501 }
502
503 WebMouseEvent WebInputEventFactory::mouseEvent(const GdkEventMotion* event)
504 {
505     WebMouseEvent result;
506
507     result.timeStampSeconds = gdkEventTimeToWebEventTime(event->time);
508     result.modifiers = gdkStateToWebEventModifiers(event->state);
509     result.x = static_cast<int>(event->x);
510     result.y = static_cast<int>(event->y);
511     result.windowX = result.x;
512     result.windowY = result.y;
513     result.globalX = static_cast<int>(event->x_root);
514     result.globalY = static_cast<int>(event->y_root);
515
516     switch (event->type) {
517     case GDK_MOTION_NOTIFY:
518         result.type = WebInputEvent::MouseMove;
519         break;
520     default:
521         ASSERT_NOT_REACHED();
522     }
523
524     result.button = WebMouseEvent::ButtonNone;
525     if (event->state & GDK_BUTTON1_MASK)
526         result.button = WebMouseEvent::ButtonLeft;
527     else if (event->state & GDK_BUTTON2_MASK)
528         result.button = WebMouseEvent::ButtonMiddle;
529     else if (event->state & GDK_BUTTON3_MASK)
530         result.button = WebMouseEvent::ButtonRight;
531
532     if (shouldForgetPreviousClick(event->window, event->time, event->x, event->y))
533         resetClickCountState();
534
535     return result;
536 }
537
538 WebMouseEvent WebInputEventFactory::mouseEvent(const GdkEventCrossing* event)
539 {
540     WebMouseEvent result;
541
542     result.timeStampSeconds = gdkEventTimeToWebEventTime(event->time);
543     result.modifiers = gdkStateToWebEventModifiers(event->state);
544     result.x = static_cast<int>(event->x);
545     result.y = static_cast<int>(event->y);
546     result.windowX = result.x;
547     result.windowY = result.y;
548     result.globalX = static_cast<int>(event->x_root);
549     result.globalY = static_cast<int>(event->y_root);
550
551     switch (event->type) {
552     case GDK_ENTER_NOTIFY:
553     case GDK_LEAVE_NOTIFY:
554         // Note that if we sent MouseEnter or MouseLeave to WebKit, it
555         // wouldn't work - they don't result in the proper JavaScript events.
556         // MouseMove does the right thing.
557         result.type = WebInputEvent::MouseMove;
558         break;
559     default:
560         ASSERT_NOT_REACHED();
561     }
562
563     result.button = WebMouseEvent::ButtonNone;
564     if (event->state & GDK_BUTTON1_MASK)
565         result.button = WebMouseEvent::ButtonLeft;
566     else if (event->state & GDK_BUTTON2_MASK)
567         result.button = WebMouseEvent::ButtonMiddle;
568     else if (event->state & GDK_BUTTON3_MASK)
569         result.button = WebMouseEvent::ButtonRight;
570
571     if (shouldForgetPreviousClick(event->window, event->time, event->x, event->y))
572         resetClickCountState();
573
574     return result;
575 }
576
577 // WebMouseWheelEvent ---------------------------------------------------------
578
579 WebMouseWheelEvent WebInputEventFactory::mouseWheelEvent(const GdkEventScroll* event)
580 {
581     WebMouseWheelEvent result;
582
583     result.type = WebInputEvent::MouseWheel;
584     result.button = WebMouseEvent::ButtonNone;
585
586     result.timeStampSeconds = gdkEventTimeToWebEventTime(event->time);
587     result.modifiers = gdkStateToWebEventModifiers(event->state);
588     result.x = static_cast<int>(event->x);
589     result.y = static_cast<int>(event->y);
590     result.windowX = result.x;
591     result.windowY = result.y;
592     result.globalX = static_cast<int>(event->x_root);
593     result.globalY = static_cast<int>(event->y_root);
594
595     // How much should we scroll per mouse wheel event?
596     // - Windows uses 3 lines by default and obeys a system setting.
597     // - Mozilla has a pref that lets you either use the "system" number of lines
598     //   to scroll, or lets the user override it.
599     //   For the "system" number of lines, it appears they've hardcoded 3.
600     //   See case NS_MOUSE_SCROLL in content/events/src/nsEventStateManager.cpp
601     //   and InitMouseScrollEvent in widget/src/gtk2/nsCommonWidget.cpp .
602     // - Gtk makes the scroll amount a function of the size of the scroll bar,
603     //   which is not available to us here.
604     // Instead, we pick a number that empirically matches Firefox's behavior.
605     static const float scrollbarPixelsPerTick = 160.0f / 3.0f;
606
607     switch (event->direction) {
608     case GDK_SCROLL_UP:
609         result.deltaY = scrollbarPixelsPerTick;
610         result.wheelTicksY = 1;
611         break;
612     case GDK_SCROLL_DOWN:
613         result.deltaY = -scrollbarPixelsPerTick;
614         result.wheelTicksY = -1;
615         break;
616     case GDK_SCROLL_LEFT:
617         result.deltaX = scrollbarPixelsPerTick;
618         result.wheelTicksX = 1;
619         break;
620     case GDK_SCROLL_RIGHT:
621         result.deltaX = -scrollbarPixelsPerTick;
622         result.wheelTicksX = -1;
623         break;
624     }
625
626     return result;
627 }
628
629 } // namespace blink