|
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 "KeyboardCodes.h" |
|
35 #include "KeyCodeConversion.h" |
|
36 |
|
37 #include "WebInputEvent.h" |
|
38 |
|
39 #include <gdk/gdk.h> |
|
40 #include <gdk/gdkkeysyms.h> |
|
41 #include <gtk/gtk.h> |
|
42 #include <gtk/gtkversion.h> |
|
43 |
|
44 #include <wtf/Assertions.h> |
|
45 |
|
46 namespace { |
|
47 |
|
48 gint getDoubleClickTime() |
|
49 { |
|
50 static GtkSettings* settings = gtk_settings_get_default(); |
|
51 gint doubleClickTime = 250; |
|
52 g_object_get(G_OBJECT(settings), "gtk-double-click-time", &doubleClickTime, NULL); |
|
53 return doubleClickTime; |
|
54 } |
|
55 |
|
56 } // namespace |
|
57 |
|
58 namespace WebKit { |
|
59 |
|
60 static double gdkEventTimeToWebEventTime(guint32 time) |
|
61 { |
|
62 // Convert from time in ms to time in sec. |
|
63 return time / 1000.0; |
|
64 } |
|
65 |
|
66 static int gdkStateToWebEventModifiers(guint state) |
|
67 { |
|
68 int modifiers = 0; |
|
69 if (state & GDK_SHIFT_MASK) |
|
70 modifiers |= WebInputEvent::ShiftKey; |
|
71 if (state & GDK_CONTROL_MASK) |
|
72 modifiers |= WebInputEvent::ControlKey; |
|
73 if (state & GDK_MOD1_MASK) |
|
74 modifiers |= WebInputEvent::AltKey; |
|
75 #if GTK_CHECK_VERSION(2, 10, 0) |
|
76 if (state & GDK_META_MASK) |
|
77 modifiers |= WebInputEvent::MetaKey; |
|
78 #endif |
|
79 if (state & GDK_BUTTON1_MASK) |
|
80 modifiers |= WebInputEvent::LeftButtonDown; |
|
81 if (state & GDK_BUTTON2_MASK) |
|
82 modifiers |= WebInputEvent::MiddleButtonDown; |
|
83 if (state & GDK_BUTTON3_MASK) |
|
84 modifiers |= WebInputEvent::RightButtonDown; |
|
85 return modifiers; |
|
86 } |
|
87 |
|
88 static int gdkEventToWindowsKeyCode(const GdkEventKey* event) |
|
89 { |
|
90 static const unsigned int hardwareCodeToGDKKeyval[] = { |
|
91 0, // 0x00: |
|
92 0, // 0x01: |
|
93 0, // 0x02: |
|
94 0, // 0x03: |
|
95 0, // 0x04: |
|
96 0, // 0x05: |
|
97 0, // 0x06: |
|
98 0, // 0x07: |
|
99 0, // 0x08: |
|
100 0, // 0x09: GDK_Escape |
|
101 GDK_1, // 0x0A: GDK_1 |
|
102 GDK_2, // 0x0B: GDK_2 |
|
103 GDK_3, // 0x0C: GDK_3 |
|
104 GDK_4, // 0x0D: GDK_4 |
|
105 GDK_5, // 0x0E: GDK_5 |
|
106 GDK_6, // 0x0F: GDK_6 |
|
107 GDK_7, // 0x10: GDK_7 |
|
108 GDK_8, // 0x11: GDK_8 |
|
109 GDK_9, // 0x12: GDK_9 |
|
110 GDK_0, // 0x13: GDK_0 |
|
111 GDK_minus, // 0x14: GDK_minus |
|
112 GDK_equal, // 0x15: GDK_equal |
|
113 0, // 0x16: GDK_BackSpace |
|
114 0, // 0x17: GDK_Tab |
|
115 GDK_q, // 0x18: GDK_q |
|
116 GDK_w, // 0x19: GDK_w |
|
117 GDK_e, // 0x1A: GDK_e |
|
118 GDK_r, // 0x1B: GDK_r |
|
119 GDK_t, // 0x1C: GDK_t |
|
120 GDK_y, // 0x1D: GDK_y |
|
121 GDK_u, // 0x1E: GDK_u |
|
122 GDK_i, // 0x1F: GDK_i |
|
123 GDK_o, // 0x20: GDK_o |
|
124 GDK_p, // 0x21: GDK_p |
|
125 GDK_bracketleft, // 0x22: GDK_bracketleft |
|
126 GDK_bracketright, // 0x23: GDK_bracketright |
|
127 0, // 0x24: GDK_Return |
|
128 0, // 0x25: GDK_Control_L |
|
129 GDK_a, // 0x26: GDK_a |
|
130 GDK_s, // 0x27: GDK_s |
|
131 GDK_d, // 0x28: GDK_d |
|
132 GDK_f, // 0x29: GDK_f |
|
133 GDK_g, // 0x2A: GDK_g |
|
134 GDK_h, // 0x2B: GDK_h |
|
135 GDK_j, // 0x2C: GDK_j |
|
136 GDK_k, // 0x2D: GDK_k |
|
137 GDK_l, // 0x2E: GDK_l |
|
138 GDK_semicolon, // 0x2F: GDK_semicolon |
|
139 GDK_apostrophe, // 0x30: GDK_apostrophe |
|
140 GDK_grave, // 0x31: GDK_grave |
|
141 0, // 0x32: GDK_Shift_L |
|
142 GDK_backslash, // 0x33: GDK_backslash |
|
143 GDK_z, // 0x34: GDK_z |
|
144 GDK_x, // 0x35: GDK_x |
|
145 GDK_c, // 0x36: GDK_c |
|
146 GDK_v, // 0x37: GDK_v |
|
147 GDK_b, // 0x38: GDK_b |
|
148 GDK_n, // 0x39: GDK_n |
|
149 GDK_m, // 0x3A: GDK_m |
|
150 GDK_comma, // 0x3B: GDK_comma |
|
151 GDK_period, // 0x3C: GDK_period |
|
152 GDK_slash, // 0x3D: GDK_slash |
|
153 0, // 0x3E: GDK_Shift_R |
|
154 0, // 0x3F: |
|
155 0, // 0x40: |
|
156 0, // 0x41: |
|
157 0, // 0x42: |
|
158 0, // 0x43: |
|
159 0, // 0x44: |
|
160 0, // 0x45: |
|
161 0, // 0x46: |
|
162 0, // 0x47: |
|
163 0, // 0x48: |
|
164 0, // 0x49: |
|
165 0, // 0x4A: |
|
166 0, // 0x4B: |
|
167 0, // 0x4C: |
|
168 0, // 0x4D: |
|
169 0, // 0x4E: |
|
170 0, // 0x4F: |
|
171 0, // 0x50: |
|
172 0, // 0x51: |
|
173 0, // 0x52: |
|
174 0, // 0x53: |
|
175 0, // 0x54: |
|
176 0, // 0x55: |
|
177 0, // 0x56: |
|
178 0, // 0x57: |
|
179 0, // 0x58: |
|
180 0, // 0x59: |
|
181 0, // 0x5A: |
|
182 0, // 0x5B: |
|
183 0, // 0x5C: |
|
184 0, // 0x5D: |
|
185 0, // 0x5E: |
|
186 0, // 0x5F: |
|
187 0, // 0x60: |
|
188 0, // 0x61: |
|
189 0, // 0x62: |
|
190 0, // 0x63: |
|
191 0, // 0x64: |
|
192 0, // 0x65: |
|
193 0, // 0x66: |
|
194 0, // 0x67: |
|
195 0, // 0x68: |
|
196 0, // 0x69: |
|
197 0, // 0x6A: |
|
198 0, // 0x6B: |
|
199 0, // 0x6C: |
|
200 0, // 0x6D: |
|
201 0, // 0x6E: |
|
202 0, // 0x6F: |
|
203 0, // 0x70: |
|
204 0, // 0x71: |
|
205 0, // 0x72: |
|
206 GDK_Super_L, // 0x73: GDK_Super_L |
|
207 GDK_Super_R, // 0x74: GDK_Super_R |
|
208 }; |
|
209 |
|
210 // |windowsKeyCode| has to include a valid virtual-key code even when we |
|
211 // use non-US layouts, e.g. even when we type an 'A' key of a US keyboard |
|
212 // on the Hebrew layout, |windowsKeyCode| should be VK_A. |
|
213 // On the other hand, |event->keyval| value depends on the current |
|
214 // GdkKeymap object, i.e. when we type an 'A' key of a US keyboard on |
|
215 // the Hebrew layout, |event->keyval| becomes GDK_hebrew_shin and this |
|
216 // WebCore::windowsKeyCodeForKeyEvent() call returns 0. |
|
217 // To improve compatibilty with Windows, we use |event->hardware_keycode| |
|
218 // for retrieving its Windows key-code for the keys when the |
|
219 // WebCore::windowsKeyCodeForEvent() call returns 0. |
|
220 // We shouldn't use |event->hardware_keycode| for keys that GdkKeymap |
|
221 // objects cannot change because |event->hardware_keycode| doesn't change |
|
222 // even when we change the layout options, e.g. when we swap a control |
|
223 // key and a caps-lock key, GTK doesn't swap their |
|
224 // |event->hardware_keycode| values but swap their |event->keyval| values. |
|
225 int windowsKeyCode = WebCore::windowsKeyCodeForKeyEvent(event->keyval); |
|
226 if (windowsKeyCode) |
|
227 return windowsKeyCode; |
|
228 |
|
229 const int tableSize = sizeof(hardwareCodeToGDKKeyval) / sizeof(hardwareCodeToGDKKeyval[0]); |
|
230 if (event->hardware_keycode < tableSize) { |
|
231 int keyval = hardwareCodeToGDKKeyval[event->hardware_keycode]; |
|
232 if (keyval) |
|
233 return WebCore::windowsKeyCodeForKeyEvent(keyval); |
|
234 } |
|
235 |
|
236 // This key is one that keyboard-layout drivers cannot change. |
|
237 // Use |event->keyval| to retrieve its |windowsKeyCode| value. |
|
238 return WebCore::windowsKeyCodeForKeyEvent(event->keyval); |
|
239 } |
|
240 |
|
241 // Gets the corresponding control character of a specified key code. See: |
|
242 // http://en.wikipedia.org/wiki/Control_characters |
|
243 // We emulate Windows behavior here. |
|
244 static WebUChar getControlCharacter(int windowsKeyCode, bool shift) |
|
245 { |
|
246 if (windowsKeyCode >= WebCore::VKEY_A && windowsKeyCode <= WebCore::VKEY_Z) { |
|
247 // ctrl-A ~ ctrl-Z map to \x01 ~ \x1A |
|
248 return windowsKeyCode - WebCore::VKEY_A + 1; |
|
249 } |
|
250 if (shift) { |
|
251 // following graphics chars require shift key to input. |
|
252 switch (windowsKeyCode) { |
|
253 // ctrl-@ maps to \x00 (Null byte) |
|
254 case WebCore::VKEY_2: |
|
255 return 0; |
|
256 // ctrl-^ maps to \x1E (Record separator, Information separator two) |
|
257 case WebCore::VKEY_6: |
|
258 return 0x1E; |
|
259 // ctrl-_ maps to \x1F (Unit separator, Information separator one) |
|
260 case WebCore::VKEY_OEM_MINUS: |
|
261 return 0x1F; |
|
262 // Returns 0 for all other keys to avoid inputting unexpected chars. |
|
263 default: |
|
264 return 0; |
|
265 } |
|
266 } else { |
|
267 switch (windowsKeyCode) { |
|
268 // ctrl-[ maps to \x1B (Escape) |
|
269 case WebCore::VKEY_OEM_4: |
|
270 return 0x1B; |
|
271 // ctrl-\ maps to \x1C (File separator, Information separator four) |
|
272 case WebCore::VKEY_OEM_5: |
|
273 return 0x1C; |
|
274 // ctrl-] maps to \x1D (Group separator, Information separator three) |
|
275 case WebCore::VKEY_OEM_6: |
|
276 return 0x1D; |
|
277 // ctrl-Enter maps to \x0A (Line feed) |
|
278 case WebCore::VKEY_RETURN: |
|
279 return 0x0A; |
|
280 // Returns 0 for all other keys to avoid inputting unexpected chars. |
|
281 default: |
|
282 return 0; |
|
283 } |
|
284 } |
|
285 } |
|
286 |
|
287 // WebKeyboardEvent ----------------------------------------------------------- |
|
288 |
|
289 WebKeyboardEvent WebInputEventFactory::keyboardEvent(const GdkEventKey* event) |
|
290 { |
|
291 WebKeyboardEvent result; |
|
292 |
|
293 result.timeStampSeconds = gdkEventTimeToWebEventTime(event->time); |
|
294 result.modifiers = gdkStateToWebEventModifiers(event->state); |
|
295 |
|
296 switch (event->type) { |
|
297 case GDK_KEY_RELEASE: |
|
298 result.type = WebInputEvent::KeyUp; |
|
299 break; |
|
300 case GDK_KEY_PRESS: |
|
301 result.type = WebInputEvent::RawKeyDown; |
|
302 break; |
|
303 default: |
|
304 ASSERT_NOT_REACHED(); |
|
305 } |
|
306 |
|
307 // According to MSDN: |
|
308 // http://msdn.microsoft.com/en-us/library/ms646286(VS.85).aspx |
|
309 // Key events with Alt modifier and F10 are system key events. |
|
310 // We just emulate this behavior. It's necessary to prevent webkit from |
|
311 // processing keypress event generated by alt-d, etc. |
|
312 // F10 is not special on Linux, so don't treat it as system key. |
|
313 if (result.modifiers & WebInputEvent::AltKey) |
|
314 result.isSystemKey = true; |
|
315 |
|
316 // The key code tells us which physical key was pressed (for example, the |
|
317 // A key went down or up). It does not determine whether A should be lower |
|
318 // or upper case. This is what text does, which should be the keyval. |
|
319 result.windowsKeyCode = gdkEventToWindowsKeyCode(event); |
|
320 result.nativeKeyCode = event->hardware_keycode; |
|
321 |
|
322 if (result.windowsKeyCode == WebCore::VKEY_RETURN) |
|
323 // We need to treat the enter key as a key press of character \r. This |
|
324 // is apparently just how webkit handles it and what it expects. |
|
325 result.unmodifiedText[0] = '\r'; |
|
326 else |
|
327 // FIXME: fix for non BMP chars |
|
328 result.unmodifiedText[0] = |
|
329 static_cast<WebUChar>(gdk_keyval_to_unicode(event->keyval)); |
|
330 |
|
331 // If ctrl key is pressed down, then control character shall be input. |
|
332 if (result.modifiers & WebInputEvent::ControlKey) |
|
333 result.text[0] = getControlCharacter( |
|
334 result.windowsKeyCode, result.modifiers & WebInputEvent::ShiftKey); |
|
335 else |
|
336 result.text[0] = result.unmodifiedText[0]; |
|
337 |
|
338 result.setKeyIdentifierFromWindowsKeyCode(); |
|
339 |
|
340 // FIXME: Do we need to set IsAutoRepeat or IsKeyPad? |
|
341 |
|
342 return result; |
|
343 } |
|
344 |
|
345 WebKeyboardEvent WebInputEventFactory::keyboardEvent(wchar_t character, int state, double timeStampSeconds) |
|
346 { |
|
347 // keyboardEvent(const GdkEventKey*) depends on the GdkEventKey object and |
|
348 // it is hard to use/ it from signal handlers which don't use GdkEventKey |
|
349 // objects (e.g. GtkIMContext signal handlers.) For such handlers, this |
|
350 // function creates a WebInputEvent::Char event without using a |
|
351 // GdkEventKey object. |
|
352 WebKeyboardEvent result; |
|
353 result.type = WebKit::WebInputEvent::Char; |
|
354 result.timeStampSeconds = timeStampSeconds; |
|
355 result.modifiers = gdkStateToWebEventModifiers(state); |
|
356 result.windowsKeyCode = character; |
|
357 result.nativeKeyCode = character; |
|
358 result.text[0] = character; |
|
359 result.unmodifiedText[0] = character; |
|
360 |
|
361 // According to MSDN: |
|
362 // http://msdn.microsoft.com/en-us/library/ms646286(VS.85).aspx |
|
363 // Key events with Alt modifier and F10 are system key events. |
|
364 // We just emulate this behavior. It's necessary to prevent webkit from |
|
365 // processing keypress event generated by alt-d, etc. |
|
366 // F10 is not special on Linux, so don't treat it as system key. |
|
367 if (result.modifiers & WebInputEvent::AltKey) |
|
368 result.isSystemKey = true; |
|
369 |
|
370 return result; |
|
371 } |
|
372 |
|
373 // WebMouseEvent -------------------------------------------------------------- |
|
374 |
|
375 WebMouseEvent WebInputEventFactory::mouseEvent(const GdkEventButton* event) |
|
376 { |
|
377 WebMouseEvent result; |
|
378 |
|
379 result.timeStampSeconds = gdkEventTimeToWebEventTime(event->time); |
|
380 |
|
381 result.modifiers = gdkStateToWebEventModifiers(event->state); |
|
382 result.x = static_cast<int>(event->x); |
|
383 result.y = static_cast<int>(event->y); |
|
384 result.windowX = result.x; |
|
385 result.windowY = result.y; |
|
386 result.globalX = static_cast<int>(event->x_root); |
|
387 result.globalY = static_cast<int>(event->y_root); |
|
388 result.clickCount = 0; |
|
389 |
|
390 switch (event->type) { |
|
391 case GDK_BUTTON_PRESS: |
|
392 result.type = WebInputEvent::MouseDown; |
|
393 break; |
|
394 case GDK_BUTTON_RELEASE: |
|
395 result.type = WebInputEvent::MouseUp; |
|
396 break; |
|
397 case GDK_3BUTTON_PRESS: |
|
398 case GDK_2BUTTON_PRESS: |
|
399 default: |
|
400 ASSERT_NOT_REACHED(); |
|
401 }; |
|
402 |
|
403 if (GDK_BUTTON_PRESS == event->type) { |
|
404 static int numClicks = 0; |
|
405 static GdkWindow* eventWindow = 0; |
|
406 static gint lastLeftClickTime = 0; |
|
407 |
|
408 gint time_diff = event->time - lastLeftClickTime; |
|
409 if (eventWindow == event->window && time_diff < getDoubleClickTime()) |
|
410 numClicks++; |
|
411 else |
|
412 numClicks = 1; |
|
413 |
|
414 result.clickCount = numClicks; |
|
415 eventWindow = event->window; |
|
416 lastLeftClickTime = event->time; |
|
417 } |
|
418 |
|
419 result.button = WebMouseEvent::ButtonNone; |
|
420 if (event->button == 1) |
|
421 result.button = WebMouseEvent::ButtonLeft; |
|
422 else if (event->button == 2) |
|
423 result.button = WebMouseEvent::ButtonMiddle; |
|
424 else if (event->button == 3) |
|
425 result.button = WebMouseEvent::ButtonRight; |
|
426 |
|
427 return result; |
|
428 } |
|
429 |
|
430 WebMouseEvent WebInputEventFactory::mouseEvent(const GdkEventMotion* event) |
|
431 { |
|
432 WebMouseEvent result; |
|
433 |
|
434 result.timeStampSeconds = gdkEventTimeToWebEventTime(event->time); |
|
435 result.modifiers = gdkStateToWebEventModifiers(event->state); |
|
436 result.x = static_cast<int>(event->x); |
|
437 result.y = static_cast<int>(event->y); |
|
438 result.windowX = result.x; |
|
439 result.windowY = result.y; |
|
440 result.globalX = static_cast<int>(event->x_root); |
|
441 result.globalY = static_cast<int>(event->y_root); |
|
442 |
|
443 switch (event->type) { |
|
444 case GDK_MOTION_NOTIFY: |
|
445 result.type = WebInputEvent::MouseMove; |
|
446 break; |
|
447 default: |
|
448 ASSERT_NOT_REACHED(); |
|
449 } |
|
450 |
|
451 result.button = WebMouseEvent::ButtonNone; |
|
452 if (event->state & GDK_BUTTON1_MASK) |
|
453 result.button = WebMouseEvent::ButtonLeft; |
|
454 else if (event->state & GDK_BUTTON2_MASK) |
|
455 result.button = WebMouseEvent::ButtonMiddle; |
|
456 else if (event->state & GDK_BUTTON3_MASK) |
|
457 result.button = WebMouseEvent::ButtonRight; |
|
458 |
|
459 return result; |
|
460 } |
|
461 |
|
462 WebMouseEvent WebInputEventFactory::mouseEvent(const GdkEventCrossing* event) |
|
463 { |
|
464 WebMouseEvent result; |
|
465 |
|
466 result.timeStampSeconds = gdkEventTimeToWebEventTime(event->time); |
|
467 result.modifiers = gdkStateToWebEventModifiers(event->state); |
|
468 result.x = static_cast<int>(event->x); |
|
469 result.y = static_cast<int>(event->y); |
|
470 result.windowX = result.x; |
|
471 result.windowY = result.y; |
|
472 result.globalX = static_cast<int>(event->x_root); |
|
473 result.globalY = static_cast<int>(event->y_root); |
|
474 |
|
475 switch (event->type) { |
|
476 case GDK_ENTER_NOTIFY: |
|
477 case GDK_LEAVE_NOTIFY: |
|
478 // Note that if we sent MouseEnter or MouseLeave to WebKit, it |
|
479 // wouldn't work - they don't result in the proper JavaScript events. |
|
480 // MouseMove does the right thing. |
|
481 result.type = WebInputEvent::MouseMove; |
|
482 break; |
|
483 default: |
|
484 ASSERT_NOT_REACHED(); |
|
485 } |
|
486 |
|
487 result.button = WebMouseEvent::ButtonNone; |
|
488 if (event->state & GDK_BUTTON1_MASK) |
|
489 result.button = WebMouseEvent::ButtonLeft; |
|
490 else if (event->state & GDK_BUTTON2_MASK) |
|
491 result.button = WebMouseEvent::ButtonMiddle; |
|
492 else if (event->state & GDK_BUTTON3_MASK) |
|
493 result.button = WebMouseEvent::ButtonRight; |
|
494 |
|
495 return result; |
|
496 } |
|
497 |
|
498 // WebMouseWheelEvent --------------------------------------------------------- |
|
499 |
|
500 WebMouseWheelEvent WebInputEventFactory::mouseWheelEvent(const GdkEventScroll* event) |
|
501 { |
|
502 WebMouseWheelEvent result; |
|
503 |
|
504 result.type = WebInputEvent::MouseWheel; |
|
505 result.button = WebMouseEvent::ButtonNone; |
|
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 // How much should we scroll per mouse wheel event? |
|
517 // - Windows uses 3 lines by default and obeys a system setting. |
|
518 // - Mozilla has a pref that lets you either use the "system" number of lines |
|
519 // to scroll, or lets the user override it. |
|
520 // For the "system" number of lines, it appears they've hardcoded 3. |
|
521 // See case NS_MOUSE_SCROLL in content/events/src/nsEventStateManager.cpp |
|
522 // and InitMouseScrollEvent in widget/src/gtk2/nsCommonWidget.cpp . |
|
523 // - Gtk makes the scroll amount a function of the size of the scroll bar, |
|
524 // which is not available to us here. |
|
525 // Instead, we pick a number that empirically matches Firefox's behavior. |
|
526 static const float scrollbarPixelsPerTick = 160.0f / 3.0f; |
|
527 |
|
528 switch (event->direction) { |
|
529 case GDK_SCROLL_UP: |
|
530 result.deltaY = scrollbarPixelsPerTick; |
|
531 result.wheelTicksY = 1; |
|
532 break; |
|
533 case GDK_SCROLL_DOWN: |
|
534 result.deltaY = -scrollbarPixelsPerTick; |
|
535 result.wheelTicksY = -1; |
|
536 break; |
|
537 case GDK_SCROLL_LEFT: |
|
538 result.deltaX = scrollbarPixelsPerTick; |
|
539 result.wheelTicksX = 1; |
|
540 break; |
|
541 case GDK_SCROLL_RIGHT: |
|
542 result.deltaX = -scrollbarPixelsPerTick; |
|
543 result.wheelTicksX = -1; |
|
544 break; |
|
545 } |
|
546 |
|
547 return result; |
|
548 } |
|
549 |
|
550 } // namespace WebKit |