Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / ui / events / x / events_x.cc
blobf71fbcb9f8a5bb14c6fce9d16fef632aa1492e85
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.
5 #include "ui/events/event_constants.h"
7 #include <string.h>
8 #include <X11/extensions/XInput.h>
9 #include <X11/extensions/XInput2.h>
10 #include <X11/XKBlib.h>
11 #include <X11/Xlib.h>
12 #include <X11/Xutil.h>
13 #include <cmath>
15 #include "base/logging.h"
16 #include "base/memory/singleton.h"
17 #include "ui/events/devices/x11/device_data_manager_x11.h"
18 #include "ui/events/devices/x11/device_list_cache_x11.h"
19 #include "ui/events/devices/x11/touch_factory_x11.h"
20 #include "ui/events/event.h"
21 #include "ui/events/event_utils.h"
22 #include "ui/events/keycodes/keyboard_code_conversion_x.h"
23 #include "ui/gfx/display.h"
24 #include "ui/gfx/geometry/point.h"
25 #include "ui/gfx/geometry/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"
30 namespace {
32 // Scroll amount for each wheelscroll event. 53 is also the value used for GTK+.
33 const int kWheelScrollAmount = 53;
35 const int kMinWheelButton = 4;
36 const int kMaxWheelButton = 7;
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:
43 static XModifierStateWatcher* GetInstance() {
44 return base::Singleton<XModifierStateWatcher>::get();
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;
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;
90 break;
92 default:
93 NOTREACHED();
94 break;
98 // Returns the current modifer state in master device. It only contains the
99 // state of ctrl, shift, alt and caps lock keys.
100 unsigned int state() { return state_; }
102 private:
103 friend struct base::DefaultSingletonTraits<XModifierStateWatcher>;
105 XModifierStateWatcher() : state_(0) { }
107 unsigned int state_;
109 DISALLOW_COPY_AND_ASSIGN(XModifierStateWatcher);
112 // Detects if a touch event is a driver-generated 'special event'.
113 // A 'special event' is a touch event with maximum radius and pressure at
114 // location (0, 0).
115 // This needs to be done in a cleaner way: http://crbug.com/169256
116 bool TouchEventIsGeneratedHack(const base::NativeEvent& native_event) {
117 XIDeviceEvent* event =
118 static_cast<XIDeviceEvent*>(native_event->xcookie.data);
119 CHECK(event->evtype == XI_TouchBegin ||
120 event->evtype == XI_TouchUpdate ||
121 event->evtype == XI_TouchEnd);
123 // Force is normalized to [0, 1].
124 if (ui::GetTouchForce(native_event) < 1.0f)
125 return false;
127 if (ui::EventLocationFromNative(native_event) != gfx::Point())
128 return false;
130 // Radius is in pixels, and the valuator is the diameter in pixels.
131 double radius = ui::GetTouchRadiusX(native_event), min, max;
132 unsigned int deviceid =
133 static_cast<XIDeviceEvent*>(native_event->xcookie.data)->sourceid;
134 if (!ui::DeviceDataManagerX11::GetInstance()->GetDataRange(
135 deviceid, ui::DeviceDataManagerX11::DT_TOUCH_MAJOR, &min, &max)) {
136 return false;
139 return radius * 2 == max;
142 int GetEventFlagsFromXState(unsigned int state) {
143 int flags = 0;
144 if (state & ControlMask)
145 flags |= ui::EF_CONTROL_DOWN;
146 if (state & ShiftMask)
147 flags |= ui::EF_SHIFT_DOWN;
148 if (state & Mod1Mask)
149 flags |= ui::EF_ALT_DOWN;
150 if (state & LockMask)
151 flags |= ui::EF_CAPS_LOCK_DOWN;
152 if (state & Mod3Mask)
153 flags |= ui::EF_MOD3_DOWN;
154 if (state & Mod4Mask)
155 flags |= ui::EF_COMMAND_DOWN;
156 if (state & Mod5Mask)
157 flags |= ui::EF_ALTGR_DOWN;
158 if (state & Button1Mask)
159 flags |= ui::EF_LEFT_MOUSE_BUTTON;
160 if (state & Button2Mask)
161 flags |= ui::EF_MIDDLE_MOUSE_BUTTON;
162 if (state & Button3Mask)
163 flags |= ui::EF_RIGHT_MOUSE_BUTTON;
164 // There are no masks for EF_BACK_MOUSE_BUTTON and
165 // EF_FORWARD_MOUSE_BUTTON.
166 return flags;
169 int GetEventFlagsFromXKeyEvent(XEvent* xevent) {
170 DCHECK(xevent->type == KeyPress || xevent->type == KeyRelease);
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.
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
192 return GetEventFlagsFromXState(xevent->xkey.state) |
193 (xevent->xkey.send_event ? ui::EF_FINAL : 0) |
194 ime_fabricated_flag;
197 int GetEventFlagsFromXGenericEvent(XEvent* xevent) {
198 DCHECK(xevent->type == GenericEvent);
199 XIDeviceEvent* xievent = static_cast<XIDeviceEvent*>(xevent->xcookie.data);
200 DCHECK((xievent->evtype == XI_KeyPress) ||
201 (xievent->evtype == XI_KeyRelease));
202 return GetEventFlagsFromXState(xievent->mods.effective) |
203 (xevent->xkey.send_event ? ui::EF_FINAL : 0);
206 // Get the event flag for the button in XButtonEvent. During a ButtonPress
207 // event, |state| in XButtonEvent does not include the button that has just been
208 // pressed. Instead |state| contains flags for the buttons (if any) that had
209 // already been pressed before the current button, and |button| stores the most
210 // current pressed button. So, if you press down left mouse button, and while
211 // pressing it down, press down the right mouse button, then for the latter
212 // event, |state| would have Button1Mask set but not Button3Mask, and |button|
213 // would be 3.
214 int GetEventFlagsForButton(int button) {
215 switch (button) {
216 case 1:
217 return ui::EF_LEFT_MOUSE_BUTTON;
218 case 2:
219 return ui::EF_MIDDLE_MOUSE_BUTTON;
220 case 3:
221 return ui::EF_RIGHT_MOUSE_BUTTON;
222 case 8:
223 return ui::EF_BACK_MOUSE_BUTTON;
224 case 9:
225 return ui::EF_FORWARD_MOUSE_BUTTON;
226 default:
227 return 0;
231 int GetButtonMaskForX2Event(XIDeviceEvent* xievent) {
232 int buttonflags = 0;
233 for (int i = 0; i < 8 * xievent->buttons.mask_len; i++) {
234 if (XIMaskIsSet(xievent->buttons.mask, i)) {
235 int button = (xievent->sourceid == xievent->deviceid) ?
236 ui::DeviceDataManagerX11::GetInstance()->GetMappedButton(i) : i;
237 buttonflags |= GetEventFlagsForButton(button);
240 return buttonflags;
243 ui::EventType GetTouchEventType(const base::NativeEvent& native_event) {
244 XIDeviceEvent* event =
245 static_cast<XIDeviceEvent*>(native_event->xcookie.data);
246 switch(event->evtype) {
247 case XI_TouchBegin:
248 return TouchEventIsGeneratedHack(native_event) ? ui::ET_UNKNOWN :
249 ui::ET_TOUCH_PRESSED;
250 case XI_TouchUpdate:
251 return TouchEventIsGeneratedHack(native_event) ? ui::ET_UNKNOWN :
252 ui::ET_TOUCH_MOVED;
253 case XI_TouchEnd:
254 return TouchEventIsGeneratedHack(native_event) ? ui::ET_TOUCH_CANCELLED :
255 ui::ET_TOUCH_RELEASED;
258 DCHECK(ui::TouchFactory::GetInstance()->IsTouchDevice(event->sourceid));
259 switch (event->evtype) {
260 case XI_ButtonPress:
261 return ui::ET_TOUCH_PRESSED;
262 case XI_ButtonRelease:
263 return ui::ET_TOUCH_RELEASED;
264 case XI_Motion:
265 // Should not convert any emulated Motion event from touch device to
266 // touch event.
267 if (!(event->flags & XIPointerEmulated) &&
268 GetButtonMaskForX2Event(event))
269 return ui::ET_TOUCH_MOVED;
270 return ui::ET_UNKNOWN;
271 default:
272 NOTREACHED();
274 return ui::ET_UNKNOWN;
277 double GetTouchParamFromXEvent(XEvent* xev,
278 ui::DeviceDataManagerX11::DataType val,
279 double default_value) {
280 ui::DeviceDataManagerX11::GetInstance()->GetEventData(
281 *xev, val, &default_value);
282 return default_value;
285 void ScaleTouchRadius(XEvent* xev, double* radius) {
286 DCHECK_EQ(GenericEvent, xev->type);
287 XIDeviceEvent* xiev = static_cast<XIDeviceEvent*>(xev->xcookie.data);
288 ui::DeviceDataManagerX11::GetInstance()->ApplyTouchRadiusScale(
289 xiev->sourceid, radius);
292 unsigned int UpdateX11EventFlags(int ui_flags, unsigned int old_x_flags) {
293 static struct {
294 int ui;
295 int x;
296 } flags[] = {
297 {ui::EF_CONTROL_DOWN, ControlMask},
298 {ui::EF_SHIFT_DOWN, ShiftMask},
299 {ui::EF_ALT_DOWN, Mod1Mask},
300 {ui::EF_CAPS_LOCK_DOWN, LockMask},
301 {ui::EF_ALTGR_DOWN, Mod5Mask},
302 {ui::EF_COMMAND_DOWN, Mod4Mask},
303 {ui::EF_MOD3_DOWN, Mod3Mask},
304 {ui::EF_LEFT_MOUSE_BUTTON, Button1Mask},
305 {ui::EF_MIDDLE_MOUSE_BUTTON, Button2Mask},
306 {ui::EF_RIGHT_MOUSE_BUTTON, Button3Mask},
308 unsigned int new_x_flags = old_x_flags;
309 for (size_t i = 0; i < arraysize(flags); ++i) {
310 if (ui_flags & flags[i].ui)
311 new_x_flags |= flags[i].x;
312 else
313 new_x_flags &= ~flags[i].x;
315 return new_x_flags;
318 unsigned int UpdateX11EventButton(int ui_flag, unsigned int old_x_button) {
319 switch (ui_flag) {
320 case ui::EF_LEFT_MOUSE_BUTTON:
321 return Button1;
322 case ui::EF_MIDDLE_MOUSE_BUTTON:
323 return Button2;
324 case ui::EF_RIGHT_MOUSE_BUTTON:
325 return Button3;
326 default:
327 return old_x_button;
329 NOTREACHED();
332 bool GetGestureTimes(const base::NativeEvent& native_event,
333 double* start_time,
334 double* end_time) {
335 if (!ui::DeviceDataManagerX11::GetInstance()->HasGestureTimes(native_event))
336 return false;
338 double start_time_, end_time_;
339 if (!start_time)
340 start_time = &start_time_;
341 if (!end_time)
342 end_time = &end_time_;
344 ui::DeviceDataManagerX11::GetInstance()->GetGestureTimes(
345 native_event, start_time, end_time);
346 return true;
349 } // namespace
351 namespace ui {
353 void UpdateDeviceList() {
354 XDisplay* display = gfx::GetXDisplay();
355 DeviceListCacheX11::GetInstance()->UpdateDeviceList(display);
356 TouchFactory::GetInstance()->UpdateDeviceList(display);
357 DeviceDataManagerX11::GetInstance()->UpdateDeviceList(display);
360 EventType EventTypeFromNative(const base::NativeEvent& native_event) {
361 // Allow the DeviceDataManager to block the event. If blocked return
362 // ET_UNKNOWN as the type so this event will not be further processed.
363 // NOTE: During some events unittests there is no device data manager.
364 if (DeviceDataManager::HasInstance() &&
365 static_cast<DeviceDataManagerX11*>(DeviceDataManager::GetInstance())->
366 IsEventBlocked(native_event)) {
367 return ET_UNKNOWN;
370 switch (native_event->type) {
371 case KeyPress:
372 return ET_KEY_PRESSED;
373 case KeyRelease:
374 return ET_KEY_RELEASED;
375 case ButtonPress:
376 if (static_cast<int>(native_event->xbutton.button) >= kMinWheelButton &&
377 static_cast<int>(native_event->xbutton.button) <= kMaxWheelButton)
378 return ET_MOUSEWHEEL;
379 return ET_MOUSE_PRESSED;
380 case ButtonRelease:
381 // Drop wheel events; we should've already scrolled on the press.
382 if (static_cast<int>(native_event->xbutton.button) >= kMinWheelButton &&
383 static_cast<int>(native_event->xbutton.button) <= kMaxWheelButton)
384 return ET_UNKNOWN;
385 return ET_MOUSE_RELEASED;
386 case MotionNotify:
387 if (native_event->xmotion.state &
388 (Button1Mask | Button2Mask | Button3Mask))
389 return ET_MOUSE_DRAGGED;
390 return ET_MOUSE_MOVED;
391 case EnterNotify:
392 // The standard on Windows is to send a MouseMove event when the mouse
393 // first enters a window instead of sending a special mouse enter event.
394 // To be consistent we follow the same style.
395 return ET_MOUSE_MOVED;
396 case LeaveNotify:
397 return ET_MOUSE_EXITED;
398 case GenericEvent: {
399 TouchFactory* factory = TouchFactory::GetInstance();
400 if (!factory->ShouldProcessXI2Event(native_event))
401 return ET_UNKNOWN;
403 XIDeviceEvent* xievent =
404 static_cast<XIDeviceEvent*>(native_event->xcookie.data);
406 // This check works only for master and floating slave devices. That is
407 // why it is necessary to check for the XI_Touch* events in the following
408 // switch statement to account for attached-slave touchscreens.
409 if (factory->IsTouchDevice(xievent->sourceid))
410 return GetTouchEventType(native_event);
412 switch (xievent->evtype) {
413 case XI_TouchBegin:
414 return ui::ET_TOUCH_PRESSED;
415 case XI_TouchUpdate:
416 return ui::ET_TOUCH_MOVED;
417 case XI_TouchEnd:
418 return ui::ET_TOUCH_RELEASED;
419 case XI_ButtonPress: {
420 int button = EventButtonFromNative(native_event);
421 if (button >= kMinWheelButton && button <= kMaxWheelButton)
422 return ET_MOUSEWHEEL;
423 return ET_MOUSE_PRESSED;
425 case XI_ButtonRelease: {
426 int button = EventButtonFromNative(native_event);
427 // Drop wheel events; we should've already scrolled on the press.
428 if (button >= kMinWheelButton && button <= kMaxWheelButton)
429 return ET_UNKNOWN;
430 return ET_MOUSE_RELEASED;
432 case XI_Motion: {
433 bool is_cancel;
434 DeviceDataManagerX11* devices = DeviceDataManagerX11::GetInstance();
435 if (GetFlingData(native_event, NULL, NULL, NULL, NULL, &is_cancel))
436 return is_cancel ? ET_SCROLL_FLING_CANCEL : ET_SCROLL_FLING_START;
437 if (devices->IsScrollEvent(native_event)) {
438 return devices->IsTouchpadXInputEvent(native_event) ? ET_SCROLL
439 : ET_MOUSEWHEEL;
441 if (devices->IsCMTMetricsEvent(native_event))
442 return ET_UMA_DATA;
443 if (GetButtonMaskForX2Event(xievent))
444 return ET_MOUSE_DRAGGED;
445 if (DeviceDataManagerX11::GetInstance()->HasEventData(
446 xievent, DeviceDataManagerX11::DT_CMT_SCROLL_X) ||
447 DeviceDataManagerX11::GetInstance()->HasEventData(
448 xievent, DeviceDataManagerX11::DT_CMT_SCROLL_Y)) {
449 // Don't produce mouse move events for mousewheel scrolls.
450 return ET_UNKNOWN;
453 return ET_MOUSE_MOVED;
455 case XI_KeyPress:
456 return ET_KEY_PRESSED;
457 case XI_KeyRelease:
458 return ET_KEY_RELEASED;
461 default:
462 break;
464 return ET_UNKNOWN;
467 int EventFlagsFromNative(const base::NativeEvent& native_event) {
468 switch (native_event->type) {
469 case KeyPress:
470 case KeyRelease: {
471 XModifierStateWatcher::GetInstance()->UpdateStateFromXEvent(native_event);
472 return GetEventFlagsFromXKeyEvent(native_event);
474 case ButtonPress:
475 case ButtonRelease: {
476 int flags = GetEventFlagsFromXState(native_event->xbutton.state);
477 const EventType type = EventTypeFromNative(native_event);
478 if (type == ET_MOUSE_PRESSED || type == ET_MOUSE_RELEASED)
479 flags |= GetEventFlagsForButton(native_event->xbutton.button);
480 return flags;
482 case EnterNotify:
483 case LeaveNotify:
484 return GetEventFlagsFromXState(native_event->xcrossing.state);
485 case MotionNotify:
486 return GetEventFlagsFromXState(native_event->xmotion.state);
487 case GenericEvent: {
488 XIDeviceEvent* xievent =
489 static_cast<XIDeviceEvent*>(native_event->xcookie.data);
491 switch (xievent->evtype) {
492 case XI_TouchBegin:
493 case XI_TouchUpdate:
494 case XI_TouchEnd:
495 return GetButtonMaskForX2Event(xievent) |
496 GetEventFlagsFromXState(xievent->mods.effective) |
497 GetEventFlagsFromXState(
498 XModifierStateWatcher::GetInstance()->state());
499 break;
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());
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;
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);
529 return 0;
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);
564 break;
567 NOTREACHED();
568 return base::TimeDelta();
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;
597 #endif // defined(OS_CHROMEOS)
598 return gfx::Point(static_cast<int>(x), static_cast<int>(y));
601 return gfx::Point();
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);
612 case ButtonPress:
613 case ButtonRelease: {
614 return gfx::Point(native_event->xbutton.x_root,
615 native_event->xbutton.y_root);
617 case MotionNotify: {
618 return gfx::Point(native_event->xmotion.x_root,
619 native_event->xmotion.y_root);
621 case GenericEvent: {
622 XIDeviceEvent* xievent =
623 static_cast<XIDeviceEvent*>(native_event->xcookie.data);
624 return gfx::Point(xievent->root_x, xievent->root_y);
628 return gfx::Point();
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;
637 return (xievent->sourceid == xievent->deviceid) ?
638 DeviceDataManagerX11::GetInstance()->GetMappedButton(button) : button;
641 KeyboardCode KeyboardCodeFromNative(const base::NativeEvent& native_event) {
642 return KeyboardCodeFromXKeyEvent(native_event);
645 DomCode CodeFromNative(const base::NativeEvent& native_event) {
646 return CodeFromXEvent(native_event);
649 bool IsCharFromNative(const base::NativeEvent& native_event) {
650 return false;
653 int GetChangedMouseButtonFlagsFromNative(
654 const base::NativeEvent& native_event) {
655 switch (native_event->type) {
656 case ButtonPress:
657 case ButtonRelease:
658 return GetEventFlagsForButton(native_event->xbutton.button);
659 case GenericEvent: {
660 XIDeviceEvent* xievent =
661 static_cast<XIDeviceEvent*>(native_event->xcookie.data);
662 switch (xievent->evtype) {
663 case XI_ButtonPress:
664 case XI_ButtonRelease:
665 return GetEventFlagsForButton(EventButtonFromNative(native_event));
666 default:
667 break;
670 default:
671 break;
673 return 0;
676 gfx::Vector2d GetMouseWheelOffset(const base::NativeEvent& native_event) {
677 float x_offset, y_offset;
678 if (GetScrollOffsets(
679 native_event, &x_offset, &y_offset, NULL, NULL, NULL)) {
680 return gfx::Vector2d(static_cast<int>(x_offset),
681 static_cast<int>(y_offset));
684 int button = native_event->type == GenericEvent ?
685 EventButtonFromNative(native_event) : native_event->xbutton.button;
687 switch (button) {
688 case 4:
689 return gfx::Vector2d(0, kWheelScrollAmount);
690 case 5:
691 return gfx::Vector2d(0, -kWheelScrollAmount);
692 case 6:
693 return gfx::Vector2d(kWheelScrollAmount, 0);
694 case 7:
695 return gfx::Vector2d(-kWheelScrollAmount, 0);
696 default:
697 return gfx::Vector2d();
701 base::NativeEvent CopyNativeEvent(const base::NativeEvent& event) {
702 if (!event || event->type == GenericEvent)
703 return NULL;
704 XEvent* copy = new XEvent;
705 *copy = *event;
706 return copy;
709 void ReleaseCopiedNativeEvent(const base::NativeEvent& event) {
710 delete event;
713 void ClearTouchIdIfReleased(const base::NativeEvent& xev) {
714 ui::EventType type = ui::EventTypeFromNative(xev);
715 if (type == ui::ET_TOUCH_CANCELLED ||
716 type == ui::ET_TOUCH_RELEASED) {
717 ui::TouchFactory* factory = ui::TouchFactory::GetInstance();
718 ui::DeviceDataManagerX11* manager = ui::DeviceDataManagerX11::GetInstance();
719 double tracking_id;
720 if (manager->GetEventData(
721 *xev, ui::DeviceDataManagerX11::DT_TOUCH_TRACKING_ID, &tracking_id)) {
722 factory->ReleaseSlotForTrackingID(tracking_id);
727 int GetTouchId(const base::NativeEvent& xev) {
728 double slot = 0;
729 ui::DeviceDataManagerX11* manager = ui::DeviceDataManagerX11::GetInstance();
730 double tracking_id;
731 if (!manager->GetEventData(
732 *xev, ui::DeviceDataManagerX11::DT_TOUCH_TRACKING_ID, &tracking_id)) {
733 LOG(ERROR) << "Could not get the tracking ID for the event. Using 0.";
734 } else {
735 ui::TouchFactory* factory = ui::TouchFactory::GetInstance();
736 slot = factory->GetSlotForTrackingID(tracking_id);
738 return slot;
741 float GetTouchRadiusX(const base::NativeEvent& native_event) {
742 double radius = GetTouchParamFromXEvent(native_event,
743 ui::DeviceDataManagerX11::DT_TOUCH_MAJOR, 0.0) / 2.0;
744 ScaleTouchRadius(native_event, &radius);
745 return radius;
748 float GetTouchRadiusY(const base::NativeEvent& native_event) {
749 double radius = GetTouchParamFromXEvent(native_event,
750 ui::DeviceDataManagerX11::DT_TOUCH_MINOR, 0.0) / 2.0;
751 ScaleTouchRadius(native_event, &radius);
752 return radius;
755 float GetTouchAngle(const base::NativeEvent& native_event) {
756 return GetTouchParamFromXEvent(native_event,
757 ui::DeviceDataManagerX11::DT_TOUCH_ORIENTATION, 0.0) / 2.0;
760 float GetTouchForce(const base::NativeEvent& native_event) {
761 double force = 0.0;
762 force = GetTouchParamFromXEvent(native_event,
763 ui::DeviceDataManagerX11::DT_TOUCH_PRESSURE, 0.0);
764 unsigned int deviceid =
765 static_cast<XIDeviceEvent*>(native_event->xcookie.data)->sourceid;
766 // Force is normalized to fall into [0, 1]
767 if (!ui::DeviceDataManagerX11::GetInstance()->NormalizeData(
768 deviceid, ui::DeviceDataManagerX11::DT_TOUCH_PRESSURE, &force))
769 force = 0.0;
770 return force;
773 bool GetScrollOffsets(const base::NativeEvent& native_event,
774 float* x_offset,
775 float* y_offset,
776 float* x_offset_ordinal,
777 float* y_offset_ordinal,
778 int* finger_count) {
779 if (!DeviceDataManagerX11::GetInstance()->IsScrollEvent(native_event))
780 return false;
782 // Temp values to prevent passing NULLs to DeviceDataManager.
783 float x_offset_, y_offset_;
784 float x_offset_ordinal_, y_offset_ordinal_;
785 int finger_count_;
786 if (!x_offset)
787 x_offset = &x_offset_;
788 if (!y_offset)
789 y_offset = &y_offset_;
790 if (!x_offset_ordinal)
791 x_offset_ordinal = &x_offset_ordinal_;
792 if (!y_offset_ordinal)
793 y_offset_ordinal = &y_offset_ordinal_;
794 if (!finger_count)
795 finger_count = &finger_count_;
797 DeviceDataManagerX11::GetInstance()->GetScrollOffsets(
798 native_event,
799 x_offset, y_offset,
800 x_offset_ordinal, y_offset_ordinal,
801 finger_count);
802 return true;
805 bool GetFlingData(const base::NativeEvent& native_event,
806 float* vx,
807 float* vy,
808 float* vx_ordinal,
809 float* vy_ordinal,
810 bool* is_cancel) {
811 if (!DeviceDataManagerX11::GetInstance()->IsFlingEvent(native_event))
812 return false;
814 float vx_, vy_;
815 float vx_ordinal_, vy_ordinal_;
816 bool is_cancel_;
817 if (!vx)
818 vx = &vx_;
819 if (!vy)
820 vy = &vy_;
821 if (!vx_ordinal)
822 vx_ordinal = &vx_ordinal_;
823 if (!vy_ordinal)
824 vy_ordinal = &vy_ordinal_;
825 if (!is_cancel)
826 is_cancel = &is_cancel_;
828 DeviceDataManagerX11::GetInstance()->GetFlingData(
829 native_event, vx, vy, vx_ordinal, vy_ordinal, is_cancel);
830 return true;
833 void UpdateX11EventForFlags(Event* event) {
834 XEvent* xev = event->native_event();
835 if (!xev)
836 return;
837 switch (xev->type) {
838 case KeyPress:
839 case KeyRelease:
840 xev->xkey.state = UpdateX11EventFlags(event->flags(), xev->xkey.state);
841 break;
842 case ButtonPress:
843 case ButtonRelease:
844 xev->xbutton.state =
845 UpdateX11EventFlags(event->flags(), xev->xbutton.state);
846 break;
847 case GenericEvent: {
848 XIDeviceEvent* xievent = static_cast<XIDeviceEvent*>(xev->xcookie.data);
849 DCHECK(xievent);
850 xievent->mods.effective =
851 UpdateX11EventFlags(event->flags(), xievent->mods.effective);
852 break;
854 default:
855 break;
859 void UpdateX11EventForChangedButtonFlags(MouseEvent* event) {
860 XEvent* xev = event->native_event();
861 if (!xev)
862 return;
863 switch (xev->type) {
864 case ButtonPress:
865 case ButtonRelease:
866 xev->xbutton.button = UpdateX11EventButton(event->changed_button_flags(),
867 xev->xbutton.button);
868 break;
869 case GenericEvent: {
870 XIDeviceEvent* xievent = static_cast<XIDeviceEvent*>(xev->xcookie.data);
871 CHECK(xievent && (xievent->evtype == XI_ButtonPress ||
872 xievent->evtype == XI_ButtonRelease));
873 xievent->detail =
874 UpdateX11EventButton(event->changed_button_flags(), xievent->detail);
875 break;
877 default:
878 break;
882 } // namespace ui