1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "ui/events/event_constants.h"
6
7 #include <cmath>
8 #include <string.h>
9 #include <X11/extensions/XInput.h>
10 #include <X11/extensions/XInput2.h>
11 #include <X11/Xlib.h>
12 #include <X11/Xutil.h>
13 #include <X11/XKBlib.h>
14
15 #include "base/logging.h"
16 #include "base/memory/singleton.h"
17 #include "ui/events/event.h"
18 #include "ui/events/event_utils.h"
19 #include "ui/events/keycodes/keyboard_code_conversion_x.h"
20 #include "ui/events/x/device_data_manager_x11.h"
21 #include "ui/events/x/device_list_cache_x.h"
22 #include "ui/events/x/touch_factory_x11.h"
23 #include "ui/gfx/display.h"
24 #include "ui/gfx/point.h"
25 #include "ui/gfx/rect.h"
26 #include "ui/gfx/screen.h"
27 #include "ui/gfx/x/x11_atom_cache.h"
28 #include "ui/gfx/x/x11_types.h"
29
30 namespace {
31
32 // Scroll amount for each wheelscroll event. 53 is also the value used for GTK+.
33 const int kWheelScrollAmount = 53;
34
35 const int kMinWheelButton = 4;
36 const int kMaxWheelButton = 7;
37
38 // A class to track current modifier state on master device. Only track ctrl,
39 // alt, shift and caps lock keys currently. The tracked state can then be used
40 // by floating device.
41 class XModifierStateWatcher{
42 public:
GetInstance()43 static XModifierStateWatcher* GetInstance() {
44 return Singleton<XModifierStateWatcher>::get();
45 }
46
StateFromKeyboardCode(ui::KeyboardCode keyboard_code)47 int StateFromKeyboardCode(ui::KeyboardCode keyboard_code) {
48 switch (keyboard_code) {
49 case ui::VKEY_CONTROL:
50 return ControlMask;
51 case ui::VKEY_SHIFT:
52 return ShiftMask;
53 case ui::VKEY_MENU:
54 return Mod1Mask;
55 case ui::VKEY_CAPITAL:
56 return LockMask;
57 default:
58 return 0;
59 }
60 }
61
UpdateStateFromXEvent(const base::NativeEvent & native_event)62 void UpdateStateFromXEvent(const base::NativeEvent& native_event) {
63 ui::KeyboardCode keyboard_code = ui::KeyboardCodeFromNative(native_event);
64 unsigned int mask = StateFromKeyboardCode(keyboard_code);
65 // Floating device can't access the modifer state from master device.
66 // We need to track the states of modifier keys in a singleton for
67 // floating devices such as touch screen. Issue 106426 is one example
68 // of why we need the modifier states for floating device.
69 switch (native_event->type) {
70 case KeyPress:
71 state_ = native_event->xkey.state | mask;
72 break;
73 case KeyRelease:
74 state_ = native_event->xkey.state & ~mask;
75 break;
76 case GenericEvent: {
77 XIDeviceEvent* xievent =
78 static_cast<XIDeviceEvent*>(native_event->xcookie.data);
79 switch (xievent->evtype) {
80 case XI_KeyPress:
81 state_ = xievent->mods.effective |= mask;
82 break;
83 case XI_KeyRelease:
84 state_ = xievent->mods.effective &= ~mask;
85 break;
86 default:
87 NOTREACHED();
88 break;
89 }
90 break;
91 }
92 default:
93 NOTREACHED();
94 break;
95 }
96 }
97
98 // Returns the current modifer state in master device. It only contains the
99 // state of ctrl, shift, alt and caps lock keys.
state()100 unsigned int state() { return state_; }
101
102 private:
103 friend struct DefaultSingletonTraits<XModifierStateWatcher>;
104
XModifierStateWatcher()105 XModifierStateWatcher() : state_(0) { }
106
107 unsigned int state_;
108
109 DISALLOW_COPY_AND_ASSIGN(XModifierStateWatcher);
110 };
111
112 #if defined(USE_XI2_MT)
113 // Detects if a touch event is a driver-generated 'special event'.
114 // A 'special event' is a touch event with maximum radius and pressure at
115 // location (0, 0).
116 // This needs to be done in a cleaner way: http://crbug.com/169256
TouchEventIsGeneratedHack(const base::NativeEvent & native_event)117 bool TouchEventIsGeneratedHack(const base::NativeEvent& native_event) {
118 XIDeviceEvent* event =
119 static_cast<XIDeviceEvent*>(native_event->xcookie.data);
120 CHECK(event->evtype == XI_TouchBegin ||
121 event->evtype == XI_TouchUpdate ||
122 event->evtype == XI_TouchEnd);
123
124 // Force is normalized to [0, 1].
125 if (ui::GetTouchForce(native_event) < 1.0f)
126 return false;
127
128 if (ui::EventLocationFromNative(native_event) != gfx::Point())
129 return false;
130
131 // Radius is in pixels, and the valuator is the diameter in pixels.
132 double radius = ui::GetTouchRadiusX(native_event), min, max;
133 unsigned int deviceid =
134 static_cast<XIDeviceEvent*>(native_event->xcookie.data)->sourceid;
135 if (!ui::DeviceDataManagerX11::GetInstance()->GetDataRange(
136 deviceid, ui::DeviceDataManagerX11::DT_TOUCH_MAJOR, &min, &max)) {
137 return false;
138 }
139
140 return radius * 2 == max;
141 }
142 #endif
143
GetEventFlagsFromXState(unsigned int state)144 int GetEventFlagsFromXState(unsigned int state) {
145 int flags = 0;
146 if (state & ControlMask)
147 flags |= ui::EF_CONTROL_DOWN;
148 if (state & ShiftMask)
149 flags |= ui::EF_SHIFT_DOWN;
150 if (state & Mod1Mask)
151 flags |= ui::EF_ALT_DOWN;
152 if (state & LockMask)
153 flags |= ui::EF_CAPS_LOCK_DOWN;
154 if (state & Mod3Mask)
155 flags |= ui::EF_MOD3_DOWN;
156 if (state & Mod4Mask)
157 flags |= ui::EF_COMMAND_DOWN;
158 if (state & Mod5Mask)
159 flags |= ui::EF_ALTGR_DOWN;
160 if (state & Button1Mask)
161 flags |= ui::EF_LEFT_MOUSE_BUTTON;
162 if (state & Button2Mask)
163 flags |= ui::EF_MIDDLE_MOUSE_BUTTON;
164 if (state & Button3Mask)
165 flags |= ui::EF_RIGHT_MOUSE_BUTTON;
166 return flags;
167 }
168
GetEventFlagsFromXKeyEvent(XEvent * xevent)169 int GetEventFlagsFromXKeyEvent(XEvent* xevent) {
170 DCHECK(xevent->type == KeyPress || xevent->type == KeyRelease);
171
172 #if defined(OS_CHROMEOS)
173 const int ime_fabricated_flag = 0;
174 #else
175 // XIM fabricates key events for the character compositions by XK_Multi_key.
176 // For example, when a user hits XK_Multi_key, XK_apostrophe, and XK_e in
177 // order to input "é", then XIM generates a key event with keycode=0 and
178 // state=0 for the composition, and the sequence of X11 key events will be
179 // XK_Multi_key, XK_apostrophe, **NoSymbol**, and XK_e. If the user used
180 // shift key and/or caps lock key, state can be ShiftMask, LockMask or both.
181 //
182 // We have to send these fabricated key events to XIM so it can correctly
183 // handle the character compositions.
184 const unsigned int shift_lock_mask = ShiftMask | LockMask;
185 const bool fabricated_by_xim =
186 xevent->xkey.keycode == 0 &&
187 (xevent->xkey.state & ~shift_lock_mask) == 0;
188 const int ime_fabricated_flag =
189 fabricated_by_xim ? ui::EF_IME_FABRICATED_KEY : 0;
190 #endif
191
192 return GetEventFlagsFromXState(xevent->xkey.state) |
193 (xevent->xkey.send_event ? ui::EF_FINAL : 0) |
194 (IsKeypadKey(XLookupKeysym(&xevent->xkey, 0)) ? ui::EF_NUMPAD_KEY : 0) |
195 (IsFunctionKey(XLookupKeysym(&xevent->xkey, 0)) ?
196 ui::EF_FUNCTION_KEY : 0) |
197 ime_fabricated_flag;
198 }
199
GetEventFlagsFromXGenericEvent(XEvent * xevent)200 int GetEventFlagsFromXGenericEvent(XEvent* xevent) {
201 DCHECK(xevent->type == GenericEvent);
202 XIDeviceEvent* xievent = static_cast<XIDeviceEvent*>(xevent->xcookie.data);
203 DCHECK((xievent->evtype == XI_KeyPress) ||
204 (xievent->evtype == XI_KeyRelease));
205 return GetEventFlagsFromXState(xievent->mods.effective) |
206 (xevent->xkey.send_event ? ui::EF_FINAL : 0) |
207 (IsKeypadKey(
208 XkbKeycodeToKeysym(xievent->display, xievent->detail, 0, 0))
209 ? ui::EF_NUMPAD_KEY
210 : 0);
211 }
212
213 // Get the event flag for the button in XButtonEvent. During a ButtonPress
214 // event, |state| in XButtonEvent does not include the button that has just been
215 // pressed. Instead |state| contains flags for the buttons (if any) that had
216 // already been pressed before the current button, and |button| stores the most
217 // current pressed button. So, if you press down left mouse button, and while
218 // pressing it down, press down the right mouse button, then for the latter
219 // event, |state| would have Button1Mask set but not Button3Mask, and |button|
220 // would be 3.
GetEventFlagsForButton(int button)221 int GetEventFlagsForButton(int button) {
222 switch (button) {
223 case 1:
224 return ui::EF_LEFT_MOUSE_BUTTON;
225 case 2:
226 return ui::EF_MIDDLE_MOUSE_BUTTON;
227 case 3:
228 return ui::EF_RIGHT_MOUSE_BUTTON;
229 default:
230 return 0;
231 }
232 }
233
GetButtonMaskForX2Event(XIDeviceEvent * xievent)234 int GetButtonMaskForX2Event(XIDeviceEvent* xievent) {
235 int buttonflags = 0;
236 for (int i = 0; i < 8 * xievent->buttons.mask_len; i++) {
237 if (XIMaskIsSet(xievent->buttons.mask, i)) {
238 int button = (xievent->sourceid == xievent->deviceid) ?
239 ui::DeviceDataManagerX11::GetInstance()->GetMappedButton(i) : i;
240 buttonflags |= GetEventFlagsForButton(button);
241 }
242 }
243 return buttonflags;
244 }
245
GetTouchEventType(const base::NativeEvent & native_event)246 ui::EventType GetTouchEventType(const base::NativeEvent& native_event) {
247 XIDeviceEvent* event =
248 static_cast<XIDeviceEvent*>(native_event->xcookie.data);
249 #if defined(USE_XI2_MT)
250 switch(event->evtype) {
251 case XI_TouchBegin:
252 return TouchEventIsGeneratedHack(native_event) ? ui::ET_UNKNOWN :
253 ui::ET_TOUCH_PRESSED;
254 case XI_TouchUpdate:
255 return TouchEventIsGeneratedHack(native_event) ? ui::ET_UNKNOWN :
256 ui::ET_TOUCH_MOVED;
257 case XI_TouchEnd:
258 return TouchEventIsGeneratedHack(native_event) ? ui::ET_TOUCH_CANCELLED :
259 ui::ET_TOUCH_RELEASED;
260 }
261 #endif // defined(USE_XI2_MT)
262
263 DCHECK(ui::TouchFactory::GetInstance()->IsTouchDevice(event->sourceid));
264 switch (event->evtype) {
265 case XI_ButtonPress:
266 return ui::ET_TOUCH_PRESSED;
267 case XI_ButtonRelease:
268 return ui::ET_TOUCH_RELEASED;
269 case XI_Motion:
270 // Should not convert any emulated Motion event from touch device to
271 // touch event.
272 if (!(event->flags & XIPointerEmulated) &&
273 GetButtonMaskForX2Event(event))
274 return ui::ET_TOUCH_MOVED;
275 return ui::ET_UNKNOWN;
276 default:
277 NOTREACHED();
278 }
279 return ui::ET_UNKNOWN;
280 }
281
GetTouchParamFromXEvent(XEvent * xev,ui::DeviceDataManagerX11::DataType val,double default_value)282 double GetTouchParamFromXEvent(XEvent* xev,
283 ui::DeviceDataManagerX11::DataType val,
284 double default_value) {
285 ui::DeviceDataManagerX11::GetInstance()->GetEventData(
286 *xev, val, &default_value);
287 return default_value;
288 }
289
ScaleTouchRadius(XEvent * xev,double * radius)290 void ScaleTouchRadius(XEvent* xev, double* radius) {
291 DCHECK_EQ(GenericEvent, xev->type);
292 XIDeviceEvent* xiev = static_cast<XIDeviceEvent*>(xev->xcookie.data);
293 ui::DeviceDataManagerX11::GetInstance()->ApplyTouchRadiusScale(
294 xiev->sourceid, radius);
295 }
296
UpdateX11EventFlags(int ui_flags,unsigned int old_x_flags)297 unsigned int UpdateX11EventFlags(int ui_flags, unsigned int old_x_flags) {
298 static struct {
299 int ui;
300 int x;
301 } flags[] = {
302 {ui::EF_CONTROL_DOWN, ControlMask},
303 {ui::EF_SHIFT_DOWN, ShiftMask},
304 {ui::EF_ALT_DOWN, Mod1Mask},
305 {ui::EF_CAPS_LOCK_DOWN, LockMask},
306 {ui::EF_ALTGR_DOWN, Mod5Mask},
307 {ui::EF_COMMAND_DOWN, Mod4Mask},
308 {ui::EF_MOD3_DOWN, Mod3Mask},
309 {ui::EF_NUMPAD_KEY, Mod2Mask},
310 {ui::EF_LEFT_MOUSE_BUTTON, Button1Mask},
311 {ui::EF_MIDDLE_MOUSE_BUTTON, Button2Mask},
312 {ui::EF_RIGHT_MOUSE_BUTTON, Button3Mask},
313 };
314 unsigned int new_x_flags = old_x_flags;
315 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(flags); ++i) {
316 if (ui_flags & flags[i].ui)
317 new_x_flags |= flags[i].x;
318 else
319 new_x_flags &= ~flags[i].x;
320 }
321 return new_x_flags;
322 }
323
UpdateX11EventButton(int ui_flag,unsigned int old_x_button)324 unsigned int UpdateX11EventButton(int ui_flag, unsigned int old_x_button) {
325 switch (ui_flag) {
326 case ui::EF_LEFT_MOUSE_BUTTON:
327 return Button1;
328 case ui::EF_MIDDLE_MOUSE_BUTTON:
329 return Button2;
330 case ui::EF_RIGHT_MOUSE_BUTTON:
331 return Button3;
332 default:
333 return old_x_button;
334 }
335 NOTREACHED();
336 }
337
GetGestureTimes(const base::NativeEvent & native_event,double * start_time,double * end_time)338 bool GetGestureTimes(const base::NativeEvent& native_event,
339 double* start_time,
340 double* end_time) {
341 if (!ui::DeviceDataManagerX11::GetInstance()->HasGestureTimes(native_event))
342 return false;
343
344 double start_time_, end_time_;
345 if (!start_time)
346 start_time = &start_time_;
347 if (!end_time)
348 end_time = &end_time_;
349
350 ui::DeviceDataManagerX11::GetInstance()->GetGestureTimes(
351 native_event, start_time, end_time);
352 return true;
353 }
354
355 } // namespace
356
357 namespace ui {
358
UpdateDeviceList()359 void UpdateDeviceList() {
360 XDisplay* display = gfx::GetXDisplay();
361 DeviceListCacheX::GetInstance()->UpdateDeviceList(display);
362 TouchFactory::GetInstance()->UpdateDeviceList(display);
363 DeviceDataManagerX11::GetInstance()->UpdateDeviceList(display);
364 }
365
EventTypeFromNative(const base::NativeEvent & native_event)366 EventType EventTypeFromNative(const base::NativeEvent& native_event) {
367 // Allow the DeviceDataManager to block the event. If blocked return
368 // ET_UNKNOWN as the type so this event will not be further processed.
369 // NOTE: During some events unittests there is no device data manager.
370 if (DeviceDataManager::HasInstance() &&
371 static_cast<DeviceDataManagerX11*>(DeviceDataManager::GetInstance())->
372 IsEventBlocked(native_event)) {
373 return ET_UNKNOWN;
374 }
375
376 switch (native_event->type) {
377 case KeyPress:
378 return ET_KEY_PRESSED;
379 case KeyRelease:
380 return ET_KEY_RELEASED;
381 case ButtonPress:
382 if (static_cast<int>(native_event->xbutton.button) >= kMinWheelButton &&
383 static_cast<int>(native_event->xbutton.button) <= kMaxWheelButton)
384 return ET_MOUSEWHEEL;
385 return ET_MOUSE_PRESSED;
386 case ButtonRelease:
387 // Drop wheel events; we should've already scrolled on the press.
388 if (static_cast<int>(native_event->xbutton.button) >= kMinWheelButton &&
389 static_cast<int>(native_event->xbutton.button) <= kMaxWheelButton)
390 return ET_UNKNOWN;
391 return ET_MOUSE_RELEASED;
392 case MotionNotify:
393 if (native_event->xmotion.state &
394 (Button1Mask | Button2Mask | Button3Mask))
395 return ET_MOUSE_DRAGGED;
396 return ET_MOUSE_MOVED;
397 case EnterNotify:
398 // The standard on Windows is to send a MouseMove event when the mouse
399 // first enters a window instead of sending a special mouse enter event.
400 // To be consistent we follow the same style.
401 return ET_MOUSE_MOVED;
402 case LeaveNotify:
403 return ET_MOUSE_EXITED;
404 case GenericEvent: {
405 TouchFactory* factory = TouchFactory::GetInstance();
406 if (!factory->ShouldProcessXI2Event(native_event))
407 return ET_UNKNOWN;
408
409 XIDeviceEvent* xievent =
410 static_cast<XIDeviceEvent*>(native_event->xcookie.data);
411
412 // This check works only for master and floating slave devices. That is
413 // why it is necessary to check for the XI_Touch* events in the following
414 // switch statement to account for attached-slave touchscreens.
415 if (factory->IsTouchDevice(xievent->sourceid))
416 return GetTouchEventType(native_event);
417
418 switch (xievent->evtype) {
419 case XI_TouchBegin:
420 return ui::ET_TOUCH_PRESSED;
421 case XI_TouchUpdate:
422 return ui::ET_TOUCH_MOVED;
423 case XI_TouchEnd:
424 return ui::ET_TOUCH_RELEASED;
425 case XI_ButtonPress: {
426 int button = EventButtonFromNative(native_event);
427 if (button >= kMinWheelButton && button <= kMaxWheelButton)
428 return ET_MOUSEWHEEL;
429 return ET_MOUSE_PRESSED;
430 }
431 case XI_ButtonRelease: {
432 int button = EventButtonFromNative(native_event);
433 // Drop wheel events; we should've already scrolled on the press.
434 if (button >= kMinWheelButton && button <= kMaxWheelButton)
435 return ET_UNKNOWN;
436 return ET_MOUSE_RELEASED;
437 }
438 case XI_Motion: {
439 bool is_cancel;
440 DeviceDataManagerX11* devices = DeviceDataManagerX11::GetInstance();
441 if (GetFlingData(native_event, NULL, NULL, NULL, NULL, &is_cancel))
442 return is_cancel ? ET_SCROLL_FLING_CANCEL : ET_SCROLL_FLING_START;
443 if (devices->IsScrollEvent(native_event)) {
444 return devices->IsTouchpadXInputEvent(native_event) ? ET_SCROLL
445 : ET_MOUSEWHEEL;
446 }
447 if (devices->IsCMTMetricsEvent(native_event))
448 return ET_UMA_DATA;
449 if (GetButtonMaskForX2Event(xievent))
450 return ET_MOUSE_DRAGGED;
451 return ET_MOUSE_MOVED;
452 }
453 case XI_KeyPress:
454 return ET_KEY_PRESSED;
455 case XI_KeyRelease:
456 return ET_KEY_RELEASED;
457 }
458 }
459 default:
460 break;
461 }
462 return ET_UNKNOWN;
463 }
464
EventFlagsFromNative(const base::NativeEvent & native_event)465 int EventFlagsFromNative(const base::NativeEvent& native_event) {
466 switch (native_event->type) {
467 case KeyPress:
468 case KeyRelease: {
469 XModifierStateWatcher::GetInstance()->UpdateStateFromXEvent(native_event);
470 return GetEventFlagsFromXKeyEvent(native_event);
471 }
472 case ButtonPress:
473 case ButtonRelease: {
474 int flags = GetEventFlagsFromXState(native_event->xbutton.state);
475 const EventType type = EventTypeFromNative(native_event);
476 if (type == ET_MOUSE_PRESSED || type == ET_MOUSE_RELEASED)
477 flags |= GetEventFlagsForButton(native_event->xbutton.button);
478 return flags;
479 }
480 case EnterNotify:
481 case LeaveNotify:
482 return GetEventFlagsFromXState(native_event->xcrossing.state);
483 case MotionNotify:
484 return GetEventFlagsFromXState(native_event->xmotion.state);
485 case GenericEvent: {
486 XIDeviceEvent* xievent =
487 static_cast<XIDeviceEvent*>(native_event->xcookie.data);
488
489 switch (xievent->evtype) {
490 #if defined(USE_XI2_MT)
491 case XI_TouchBegin:
492 case XI_TouchUpdate:
493 case XI_TouchEnd:
494 return GetButtonMaskForX2Event(xievent) |
495 GetEventFlagsFromXState(xievent->mods.effective) |
496 GetEventFlagsFromXState(
497 XModifierStateWatcher::GetInstance()->state());
498 break;
499 #endif
500 case XI_ButtonPress:
501 case XI_ButtonRelease: {
502 const bool touch =
503 TouchFactory::GetInstance()->IsTouchDevice(xievent->sourceid);
504 int flags = GetButtonMaskForX2Event(xievent) |
505 GetEventFlagsFromXState(xievent->mods.effective);
506 if (touch) {
507 flags |= GetEventFlagsFromXState(
508 XModifierStateWatcher::GetInstance()->state());
509 }
510
511 const EventType type = EventTypeFromNative(native_event);
512 int button = EventButtonFromNative(native_event);
513 if ((type == ET_MOUSE_PRESSED || type == ET_MOUSE_RELEASED) && !touch)
514 flags |= GetEventFlagsForButton(button);
515 return flags;
516 }
517 case XI_Motion:
518 return GetButtonMaskForX2Event(xievent) |
519 GetEventFlagsFromXState(xievent->mods.effective);
520 case XI_KeyPress:
521 case XI_KeyRelease: {
522 XModifierStateWatcher::GetInstance()->UpdateStateFromXEvent(
523 native_event);
524 return GetEventFlagsFromXGenericEvent(native_event);
525 }
526 }
527 }
528 }
529 return 0;
530 }
531
EventTimeFromNative(const base::NativeEvent & native_event)532 base::TimeDelta EventTimeFromNative(const base::NativeEvent& native_event) {
533 switch(native_event->type) {
534 case KeyPress:
535 case KeyRelease:
536 return base::TimeDelta::FromMilliseconds(native_event->xkey.time);
537 case ButtonPress:
538 case ButtonRelease:
539 return base::TimeDelta::FromMilliseconds(native_event->xbutton.time);
540 break;
541 case MotionNotify:
542 return base::TimeDelta::FromMilliseconds(native_event->xmotion.time);
543 break;
544 case EnterNotify:
545 case LeaveNotify:
546 return base::TimeDelta::FromMilliseconds(native_event->xcrossing.time);
547 break;
548 case GenericEvent: {
549 double start, end;
550 double touch_timestamp;
551 if (GetGestureTimes(native_event, &start, &end)) {
552 // If the driver supports gesture times, use them.
553 return base::TimeDelta::FromMicroseconds(end * 1000000);
554 } else if (DeviceDataManagerX11::GetInstance()->GetEventData(
555 *native_event,
556 DeviceDataManagerX11::DT_TOUCH_RAW_TIMESTAMP,
557 &touch_timestamp)) {
558 return base::TimeDelta::FromMicroseconds(touch_timestamp * 1000000);
559 } else {
560 XIDeviceEvent* xide =
561 static_cast<XIDeviceEvent*>(native_event->xcookie.data);
562 return base::TimeDelta::FromMilliseconds(xide->time);
563 }
564 break;
565 }
566 }
567 NOTREACHED();
568 return base::TimeDelta();
569 }
570
EventLocationFromNative(const base::NativeEvent & native_event)571 gfx::Point EventLocationFromNative(const base::NativeEvent& native_event) {
572 switch (native_event->type) {
573 case EnterNotify:
574 case LeaveNotify:
575 return gfx::Point(native_event->xcrossing.x, native_event->xcrossing.y);
576 case ButtonPress:
577 case ButtonRelease:
578 return gfx::Point(native_event->xbutton.x, native_event->xbutton.y);
579 case MotionNotify:
580 return gfx::Point(native_event->xmotion.x, native_event->xmotion.y);
581 case GenericEvent: {
582 XIDeviceEvent* xievent =
583 static_cast<XIDeviceEvent*>(native_event->xcookie.data);
584 float x = xievent->event_x;
585 float y = xievent->event_y;
586 #if defined(OS_CHROMEOS)
587 switch (xievent->evtype) {
588 case XI_TouchBegin:
589 case XI_TouchUpdate:
590 case XI_TouchEnd:
591 ui::DeviceDataManagerX11::GetInstance()->ApplyTouchTransformer(
592 xievent->deviceid, &x, &y);
593 break;
594 default:
595 break;
596 }
597 #endif // defined(OS_CHROMEOS)
598 return gfx::Point(static_cast<int>(x), static_cast<int>(y));
599 }
600 }
601 return gfx::Point();
602 }
603
EventSystemLocationFromNative(const base::NativeEvent & native_event)604 gfx::Point EventSystemLocationFromNative(
605 const base::NativeEvent& native_event) {
606 switch (native_event->type) {
607 case EnterNotify:
608 case LeaveNotify: {
609 return gfx::Point(native_event->xcrossing.x_root,
610 native_event->xcrossing.y_root);
611 }
612 case ButtonPress:
613 case ButtonRelease: {
614 return gfx::Point(native_event->xbutton.x_root,
615 native_event->xbutton.y_root);
616 }
617 case MotionNotify: {
618 return gfx::Point(native_event->xmotion.x_root,
619 native_event->xmotion.y_root);
620 }
621 case GenericEvent: {
622 XIDeviceEvent* xievent =
623 static_cast<XIDeviceEvent*>(native_event->xcookie.data);
624 return gfx::Point(xievent->root_x, xievent->root_y);
625 }
626 }
627
628 return gfx::Point();
629 }
630
EventButtonFromNative(const base::NativeEvent & native_event)631 int EventButtonFromNative(const base::NativeEvent& native_event) {
632 CHECK_EQ(GenericEvent, native_event->type);
633 XIDeviceEvent* xievent =
634 static_cast<XIDeviceEvent*>(native_event->xcookie.data);
635 int button = xievent->detail;
636
637 return (xievent->sourceid == xievent->deviceid) ?
638 DeviceDataManagerX11::GetInstance()->GetMappedButton(button) : button;
639 }
640
KeyboardCodeFromNative(const base::NativeEvent & native_event)641 KeyboardCode KeyboardCodeFromNative(const base::NativeEvent& native_event) {
642 return KeyboardCodeFromXKeyEvent(native_event);
643 }
644
CodeFromNative(const base::NativeEvent & native_event)645 const char* CodeFromNative(const base::NativeEvent& native_event) {
646 return CodeFromXEvent(native_event);
647 }
648
PlatformKeycodeFromNative(const base::NativeEvent & native_event)649 uint32 PlatformKeycodeFromNative(const base::NativeEvent& native_event) {
650 XKeyEvent* xkey = NULL;
651 XEvent xkey_from_xi2;
652 switch (native_event->type) {
653 case KeyPress:
654 case KeyRelease:
655 xkey = &native_event->xkey;
656 break;
657 case GenericEvent: {
658 XIDeviceEvent* xievent =
659 static_cast<XIDeviceEvent*>(native_event->xcookie.data);
660 switch (xievent->evtype) {
661 case XI_KeyPress:
662 case XI_KeyRelease:
663 // Build an XKeyEvent corresponding to the XI2 event,
664 // so that we can call XLookupString on it.
665 InitXKeyEventFromXIDeviceEvent(*native_event, &xkey_from_xi2);
666 xkey = &xkey_from_xi2.xkey;
667 break;
668 default:
669 NOTREACHED();
670 break;
671 }
672 break;
673 }
674 default:
675 NOTREACHED();
676 break;
677 }
678 KeySym keysym = XK_VoidSymbol;
679 if (xkey)
680 XLookupString(xkey, NULL, 0, &keysym, NULL);
681 return keysym;
682 }
683
IsCharFromNative(const base::NativeEvent & native_event)684 bool IsCharFromNative(const base::NativeEvent& native_event) {
685 return false;
686 }
687
GetChangedMouseButtonFlagsFromNative(const base::NativeEvent & native_event)688 int GetChangedMouseButtonFlagsFromNative(
689 const base::NativeEvent& native_event) {
690 switch (native_event->type) {
691 case ButtonPress:
692 case ButtonRelease:
693 return GetEventFlagsFromXState(native_event->xbutton.state);
694 case GenericEvent: {
695 XIDeviceEvent* xievent =
696 static_cast<XIDeviceEvent*>(native_event->xcookie.data);
697 switch (xievent->evtype) {
698 case XI_ButtonPress:
699 case XI_ButtonRelease:
700 return GetEventFlagsForButton(EventButtonFromNative(native_event));
701 default:
702 break;
703 }
704 }
705 default:
706 break;
707 }
708 return 0;
709 }
710
GetMouseWheelOffset(const base::NativeEvent & native_event)711 gfx::Vector2d GetMouseWheelOffset(const base::NativeEvent& native_event) {
712 float x_offset, y_offset;
713 if (GetScrollOffsets(
714 native_event, &x_offset, &y_offset, NULL, NULL, NULL)) {
715 return gfx::Vector2d(static_cast<int>(x_offset),
716 static_cast<int>(y_offset));
717 }
718
719 int button = native_event->type == GenericEvent ?
720 EventButtonFromNative(native_event) : native_event->xbutton.button;
721
722 switch (button) {
723 case 4:
724 return gfx::Vector2d(0, kWheelScrollAmount);
725 case 5:
726 return gfx::Vector2d(0, -kWheelScrollAmount);
727 case 6:
728 return gfx::Vector2d(kWheelScrollAmount, 0);
729 case 7:
730 return gfx::Vector2d(-kWheelScrollAmount, 0);
731 default:
732 return gfx::Vector2d();
733 }
734 }
735
CopyNativeEvent(const base::NativeEvent & event)736 base::NativeEvent CopyNativeEvent(const base::NativeEvent& event) {
737 if (!event || event->type == GenericEvent)
738 return NULL;
739 XEvent* copy = new XEvent;
740 *copy = *event;
741 return copy;
742 }
743
ReleaseCopiedNativeEvent(const base::NativeEvent & event)744 void ReleaseCopiedNativeEvent(const base::NativeEvent& event) {
745 delete event;
746 }
747
IncrementTouchIdRefCount(const base::NativeEvent & xev)748 void IncrementTouchIdRefCount(const base::NativeEvent& xev) {
749 ui::DeviceDataManagerX11* manager = ui::DeviceDataManagerX11::GetInstance();
750 double tracking_id;
751 if (!manager->GetEventData(
752 *xev, ui::DeviceDataManagerX11::DT_TOUCH_TRACKING_ID, &tracking_id)) {
753 return;
754 }
755
756 ui::TouchFactory* factory = ui::TouchFactory::GetInstance();
757 factory->AcquireSlotForTrackingID(tracking_id);
758 }
759
ClearTouchIdIfReleased(const base::NativeEvent & xev)760 void ClearTouchIdIfReleased(const base::NativeEvent& xev) {
761 ui::EventType type = ui::EventTypeFromNative(xev);
762 if (type == ui::ET_TOUCH_CANCELLED ||
763 type == ui::ET_TOUCH_RELEASED) {
764 ui::TouchFactory* factory = ui::TouchFactory::GetInstance();
765 ui::DeviceDataManagerX11* manager = ui::DeviceDataManagerX11::GetInstance();
766 double tracking_id;
767 if (manager->GetEventData(
768 *xev, ui::DeviceDataManagerX11::DT_TOUCH_TRACKING_ID, &tracking_id)) {
769 factory->ReleaseSlotForTrackingID(tracking_id);
770 }
771 }
772 }
773
GetTouchId(const base::NativeEvent & xev)774 int GetTouchId(const base::NativeEvent& xev) {
775 double slot = 0;
776 ui::DeviceDataManagerX11* manager = ui::DeviceDataManagerX11::GetInstance();
777 double tracking_id;
778 if (!manager->GetEventData(
779 *xev, ui::DeviceDataManagerX11::DT_TOUCH_TRACKING_ID, &tracking_id)) {
780 LOG(ERROR) << "Could not get the tracking ID for the event. Using 0.";
781 } else {
782 ui::TouchFactory* factory = ui::TouchFactory::GetInstance();
783 slot = factory->GetSlotForTrackingID(tracking_id);
784 }
785 return slot;
786 }
787
GetTouchRadiusX(const base::NativeEvent & native_event)788 float GetTouchRadiusX(const base::NativeEvent& native_event) {
789 double radius = GetTouchParamFromXEvent(native_event,
790 ui::DeviceDataManagerX11::DT_TOUCH_MAJOR, 0.0) / 2.0;
791 ScaleTouchRadius(native_event, &radius);
792 return radius;
793 }
794
GetTouchRadiusY(const base::NativeEvent & native_event)795 float GetTouchRadiusY(const base::NativeEvent& native_event) {
796 double radius = GetTouchParamFromXEvent(native_event,
797 ui::DeviceDataManagerX11::DT_TOUCH_MINOR, 0.0) / 2.0;
798 ScaleTouchRadius(native_event, &radius);
799 return radius;
800 }
801
GetTouchAngle(const base::NativeEvent & native_event)802 float GetTouchAngle(const base::NativeEvent& native_event) {
803 return GetTouchParamFromXEvent(native_event,
804 ui::DeviceDataManagerX11::DT_TOUCH_ORIENTATION, 0.0) / 2.0;
805 }
806
GetTouchForce(const base::NativeEvent & native_event)807 float GetTouchForce(const base::NativeEvent& native_event) {
808 double force = 0.0;
809 force = GetTouchParamFromXEvent(native_event,
810 ui::DeviceDataManagerX11::DT_TOUCH_PRESSURE, 0.0);
811 unsigned int deviceid =
812 static_cast<XIDeviceEvent*>(native_event->xcookie.data)->sourceid;
813 // Force is normalized to fall into [0, 1]
814 if (!ui::DeviceDataManagerX11::GetInstance()->NormalizeData(
815 deviceid, ui::DeviceDataManagerX11::DT_TOUCH_PRESSURE, &force))
816 force = 0.0;
817 return force;
818 }
819
GetScrollOffsets(const base::NativeEvent & native_event,float * x_offset,float * y_offset,float * x_offset_ordinal,float * y_offset_ordinal,int * finger_count)820 bool GetScrollOffsets(const base::NativeEvent& native_event,
821 float* x_offset,
822 float* y_offset,
823 float* x_offset_ordinal,
824 float* y_offset_ordinal,
825 int* finger_count) {
826 if (!DeviceDataManagerX11::GetInstance()->IsScrollEvent(native_event))
827 return false;
828
829 // Temp values to prevent passing NULLs to DeviceDataManager.
830 float x_offset_, y_offset_;
831 float x_offset_ordinal_, y_offset_ordinal_;
832 int finger_count_;
833 if (!x_offset)
834 x_offset = &x_offset_;
835 if (!y_offset)
836 y_offset = &y_offset_;
837 if (!x_offset_ordinal)
838 x_offset_ordinal = &x_offset_ordinal_;
839 if (!y_offset_ordinal)
840 y_offset_ordinal = &y_offset_ordinal_;
841 if (!finger_count)
842 finger_count = &finger_count_;
843
844 DeviceDataManagerX11::GetInstance()->GetScrollOffsets(
845 native_event,
846 x_offset, y_offset,
847 x_offset_ordinal, y_offset_ordinal,
848 finger_count);
849 return true;
850 }
851
GetFlingData(const base::NativeEvent & native_event,float * vx,float * vy,float * vx_ordinal,float * vy_ordinal,bool * is_cancel)852 bool GetFlingData(const base::NativeEvent& native_event,
853 float* vx,
854 float* vy,
855 float* vx_ordinal,
856 float* vy_ordinal,
857 bool* is_cancel) {
858 if (!DeviceDataManagerX11::GetInstance()->IsFlingEvent(native_event))
859 return false;
860
861 float vx_, vy_;
862 float vx_ordinal_, vy_ordinal_;
863 bool is_cancel_;
864 if (!vx)
865 vx = &vx_;
866 if (!vy)
867 vy = &vy_;
868 if (!vx_ordinal)
869 vx_ordinal = &vx_ordinal_;
870 if (!vy_ordinal)
871 vy_ordinal = &vy_ordinal_;
872 if (!is_cancel)
873 is_cancel = &is_cancel_;
874
875 DeviceDataManagerX11::GetInstance()->GetFlingData(
876 native_event, vx, vy, vx_ordinal, vy_ordinal, is_cancel);
877 return true;
878 }
879
UpdateX11EventForFlags(Event * event)880 void UpdateX11EventForFlags(Event* event) {
881 XEvent* xev = event->native_event();
882 if (!xev)
883 return;
884 switch (xev->type) {
885 case KeyPress:
886 case KeyRelease:
887 xev->xkey.state = UpdateX11EventFlags(event->flags(), xev->xkey.state);
888 break;
889 case ButtonPress:
890 case ButtonRelease:
891 xev->xbutton.state =
892 UpdateX11EventFlags(event->flags(), xev->xbutton.state);
893 break;
894 case GenericEvent: {
895 XIDeviceEvent* xievent = static_cast<XIDeviceEvent*>(xev->xcookie.data);
896 DCHECK(xievent);
897 xievent->mods.effective =
898 UpdateX11EventFlags(event->flags(), xievent->mods.effective);
899 break;
900 }
901 default:
902 break;
903 }
904 }
905
UpdateX11EventForChangedButtonFlags(MouseEvent * event)906 void UpdateX11EventForChangedButtonFlags(MouseEvent* event) {
907 XEvent* xev = event->native_event();
908 if (!xev)
909 return;
910 switch (xev->type) {
911 case ButtonPress:
912 case ButtonRelease:
913 xev->xbutton.button = UpdateX11EventButton(event->changed_button_flags(),
914 xev->xbutton.button);
915 break;
916 case GenericEvent: {
917 XIDeviceEvent* xievent = static_cast<XIDeviceEvent*>(xev->xcookie.data);
918 CHECK(xievent && (xievent->evtype == XI_ButtonPress ||
919 xievent->evtype == XI_ButtonRelease));
920 xievent->detail =
921 UpdateX11EventButton(event->changed_button_flags(), xievent->detail);
922 break;
923 }
924 default:
925 break;
926 }
927 }
928
929 } // namespace ui
930