blob: 3d204ba000423b3881c1a37a9ab1ef8ddc7af367 [file] [log] [blame]
Torne (Richard Coles)5c87bf82012-11-14 11:46:17 +00001/*
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
Torne (Richard Coles)09380292014-02-21 12:17:33 +000034#include "platform/KeyCodeConversion.h"
35#include "platform/KeyboardCodes.h"
Torne (Richard Coles)5c87bf82012-11-14 11:46:17 +000036
37#include "WebInputEvent.h"
38
39#include <gdk/gdk.h>
40#include <gdk/gdkkeysyms.h>
41#include <gtk/gtk.h>
Torne (Richard Coles)51b29062013-11-28 11:56:03 +000042#include <stdlib.h>
Torne (Richard Coles)5c87bf82012-11-14 11:46:17 +000043
Ben Murdoch591b9582013-07-10 11:41:44 +010044#include "wtf/Assertions.h"
Torne (Richard Coles)5c87bf82012-11-14 11:46:17 +000045
46namespace {
47
48// For click count tracking.
49static int gNumClicks = 0;
50static GdkWindow* gLastClickEventWindow = 0;
51static gint gLastClickTime = 0;
52static gint gLastClickX = 0;
53static gint gLastClickY = 0;
Torne (Richard Coles)51b29062013-11-28 11:56:03 +000054static blink::WebMouseEvent::Button gLastClickButton = blink::WebMouseEvent::ButtonNone;
Torne (Richard Coles)5c87bf82012-11-14 11:46:17 +000055
56bool 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
73void resetClickCountState()
74{
75 gNumClicks = 0;
76 gLastClickEventWindow = 0;
77 gLastClickTime = 0;
78 gLastClickX = 0;
79 gLastClickY = 0;
Torne (Richard Coles)51b29062013-11-28 11:56:03 +000080 gLastClickButton = blink::WebMouseEvent::ButtonNone;
Torne (Richard Coles)5c87bf82012-11-14 11:46:17 +000081}
82
83bool 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
Torne (Richard Coles)51b29062013-11-28 11:56:03 +000091namespace blink {
Torne (Richard Coles)5c87bf82012-11-14 11:46:17 +000092
93static double gdkEventTimeToWebEventTime(guint32 time)
94{
95 // Convert from time in ms to time in sec.
96 return time / 1000.0;
97}
98
99static 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
123static int gdkEventToWindowsKeyCode(const GdkEventKey* event)
124{
Ben Murdoch07a852d2014-03-31 11:51:52 +0100125 static const unsigned hardwareCodeToGDKKeyval[] = {
Torne (Richard Coles)5c87bf82012-11-14 11:46:17 +0000126 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.
279static 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.
312static 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
357WebKeyboardEvent 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
Torne (Richard Coles)51b29062013-11-28 11:56:03 +0000375 result.isSystemKey = WebInputEventFactory::isSystemKeyEvent(result);
Torne (Richard Coles)5c87bf82012-11-14 11:46:17 +0000376
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
Torne (Richard Coles)51b29062013-11-28 11:56:03 +0000410bool 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
Torne (Richard Coles)5c87bf82012-11-14 11:46:17 +0000417WebKeyboardEvent 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;
Torne (Richard Coles)51b29062013-11-28 11:56:03 +0000425 result.type = blink::WebInputEvent::Char;
Torne (Richard Coles)5c87bf82012-11-14 11:46:17 +0000426 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
447WebMouseEvent 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
503WebMouseEvent 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
538WebMouseEvent 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
579WebMouseWheelEvent 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
Torne (Richard Coles)51b29062013-11-28 11:56:03 +0000629} // namespace blink