base: Change DCHECK_IS_ON to a macro DCHECK_IS_ON().
[chromium-blink-merge.git] / ui / events / x / events_x.cc
blob6678f01dac7983e7a637ae2c6a339409afb16081
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 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 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 return flags;
167 int GetEventFlagsFromXKeyEvent(XEvent* xevent) {
168 DCHECK(xevent->type == KeyPress || xevent->type == KeyRelease);
170 #if defined(OS_CHROMEOS)
171 const int ime_fabricated_flag = 0;
172 #else
173 // XIM fabricates key events for the character compositions by XK_Multi_key.
174 // For example, when a user hits XK_Multi_key, XK_apostrophe, and XK_e in
175 // order to input "é", then XIM generates a key event with keycode=0 and
176 // state=0 for the composition, and the sequence of X11 key events will be
177 // XK_Multi_key, XK_apostrophe, **NoSymbol**, and XK_e. If the user used
178 // shift key and/or caps lock key, state can be ShiftMask, LockMask or both.
180 // We have to send these fabricated key events to XIM so it can correctly
181 // handle the character compositions.
182 const unsigned int shift_lock_mask = ShiftMask | LockMask;
183 const bool fabricated_by_xim =
184 xevent->xkey.keycode == 0 &&
185 (xevent->xkey.state & ~shift_lock_mask) == 0;
186 const int ime_fabricated_flag =
187 fabricated_by_xim ? ui::EF_IME_FABRICATED_KEY : 0;
188 #endif
190 return GetEventFlagsFromXState(xevent->xkey.state) |
191 (xevent->xkey.send_event ? ui::EF_FINAL : 0) |
192 (IsKeypadKey(XLookupKeysym(&xevent->xkey, 0)) ? ui::EF_NUMPAD_KEY : 0) |
193 (IsFunctionKey(XLookupKeysym(&xevent->xkey, 0)) ?
194 ui::EF_FUNCTION_KEY : 0) |
195 ime_fabricated_flag;
198 int GetEventFlagsFromXGenericEvent(XEvent* xevent) {
199 DCHECK(xevent->type == GenericEvent);
200 XIDeviceEvent* xievent = static_cast<XIDeviceEvent*>(xevent->xcookie.data);
201 DCHECK((xievent->evtype == XI_KeyPress) ||
202 (xievent->evtype == XI_KeyRelease));
203 return GetEventFlagsFromXState(xievent->mods.effective) |
204 (xevent->xkey.send_event ? ui::EF_FINAL : 0) |
205 (IsKeypadKey(
206 XkbKeycodeToKeysym(xievent->display, xievent->detail, 0, 0))
207 ? ui::EF_NUMPAD_KEY
208 : 0);
211 // Get the event flag for the button in XButtonEvent. During a ButtonPress
212 // event, |state| in XButtonEvent does not include the button that has just been
213 // pressed. Instead |state| contains flags for the buttons (if any) that had
214 // already been pressed before the current button, and |button| stores the most
215 // current pressed button. So, if you press down left mouse button, and while
216 // pressing it down, press down the right mouse button, then for the latter
217 // event, |state| would have Button1Mask set but not Button3Mask, and |button|
218 // would be 3.
219 int GetEventFlagsForButton(int button) {
220 switch (button) {
221 case 1:
222 return ui::EF_LEFT_MOUSE_BUTTON;
223 case 2:
224 return ui::EF_MIDDLE_MOUSE_BUTTON;
225 case 3:
226 return ui::EF_RIGHT_MOUSE_BUTTON;
227 default:
228 return 0;
232 int GetButtonMaskForX2Event(XIDeviceEvent* xievent) {
233 int buttonflags = 0;
234 for (int i = 0; i < 8 * xievent->buttons.mask_len; i++) {
235 if (XIMaskIsSet(xievent->buttons.mask, i)) {
236 int button = (xievent->sourceid == xievent->deviceid) ?
237 ui::DeviceDataManagerX11::GetInstance()->GetMappedButton(i) : i;
238 buttonflags |= GetEventFlagsForButton(button);
241 return buttonflags;
244 ui::EventType GetTouchEventType(const base::NativeEvent& native_event) {
245 XIDeviceEvent* event =
246 static_cast<XIDeviceEvent*>(native_event->xcookie.data);
247 switch(event->evtype) {
248 case XI_TouchBegin:
249 return TouchEventIsGeneratedHack(native_event) ? ui::ET_UNKNOWN :
250 ui::ET_TOUCH_PRESSED;
251 case XI_TouchUpdate:
252 return TouchEventIsGeneratedHack(native_event) ? ui::ET_UNKNOWN :
253 ui::ET_TOUCH_MOVED;
254 case XI_TouchEnd:
255 return TouchEventIsGeneratedHack(native_event) ? ui::ET_TOUCH_CANCELLED :
256 ui::ET_TOUCH_RELEASED;
259 DCHECK(ui::TouchFactory::GetInstance()->IsTouchDevice(event->sourceid));
260 switch (event->evtype) {
261 case XI_ButtonPress:
262 return ui::ET_TOUCH_PRESSED;
263 case XI_ButtonRelease:
264 return ui::ET_TOUCH_RELEASED;
265 case XI_Motion:
266 // Should not convert any emulated Motion event from touch device to
267 // touch event.
268 if (!(event->flags & XIPointerEmulated) &&
269 GetButtonMaskForX2Event(event))
270 return ui::ET_TOUCH_MOVED;
271 return ui::ET_UNKNOWN;
272 default:
273 NOTREACHED();
275 return ui::ET_UNKNOWN;
278 double GetTouchParamFromXEvent(XEvent* xev,
279 ui::DeviceDataManagerX11::DataType val,
280 double default_value) {
281 ui::DeviceDataManagerX11::GetInstance()->GetEventData(
282 *xev, val, &default_value);
283 return default_value;
286 void ScaleTouchRadius(XEvent* xev, double* radius) {
287 DCHECK_EQ(GenericEvent, xev->type);
288 XIDeviceEvent* xiev = static_cast<XIDeviceEvent*>(xev->xcookie.data);
289 ui::DeviceDataManagerX11::GetInstance()->ApplyTouchRadiusScale(
290 xiev->sourceid, radius);
293 unsigned int UpdateX11EventFlags(int ui_flags, unsigned int old_x_flags) {
294 static struct {
295 int ui;
296 int x;
297 } flags[] = {
298 {ui::EF_CONTROL_DOWN, ControlMask},
299 {ui::EF_SHIFT_DOWN, ShiftMask},
300 {ui::EF_ALT_DOWN, Mod1Mask},
301 {ui::EF_CAPS_LOCK_DOWN, LockMask},
302 {ui::EF_ALTGR_DOWN, Mod5Mask},
303 {ui::EF_COMMAND_DOWN, Mod4Mask},
304 {ui::EF_MOD3_DOWN, Mod3Mask},
305 {ui::EF_NUMPAD_KEY, Mod2Mask},
306 {ui::EF_LEFT_MOUSE_BUTTON, Button1Mask},
307 {ui::EF_MIDDLE_MOUSE_BUTTON, Button2Mask},
308 {ui::EF_RIGHT_MOUSE_BUTTON, Button3Mask},
310 unsigned int new_x_flags = old_x_flags;
311 for (size_t i = 0; i < arraysize(flags); ++i) {
312 if (ui_flags & flags[i].ui)
313 new_x_flags |= flags[i].x;
314 else
315 new_x_flags &= ~flags[i].x;
317 return new_x_flags;
320 unsigned int UpdateX11EventButton(int ui_flag, unsigned int old_x_button) {
321 switch (ui_flag) {
322 case ui::EF_LEFT_MOUSE_BUTTON:
323 return Button1;
324 case ui::EF_MIDDLE_MOUSE_BUTTON:
325 return Button2;
326 case ui::EF_RIGHT_MOUSE_BUTTON:
327 return Button3;
328 default:
329 return old_x_button;
331 NOTREACHED();
334 bool GetGestureTimes(const base::NativeEvent& native_event,
335 double* start_time,
336 double* end_time) {
337 if (!ui::DeviceDataManagerX11::GetInstance()->HasGestureTimes(native_event))
338 return false;
340 double start_time_, end_time_;
341 if (!start_time)
342 start_time = &start_time_;
343 if (!end_time)
344 end_time = &end_time_;
346 ui::DeviceDataManagerX11::GetInstance()->GetGestureTimes(
347 native_event, start_time, end_time);
348 return true;
351 } // namespace
353 namespace ui {
355 void UpdateDeviceList() {
356 XDisplay* display = gfx::GetXDisplay();
357 DeviceListCacheX11::GetInstance()->UpdateDeviceList(display);
358 TouchFactory::GetInstance()->UpdateDeviceList(display);
359 DeviceDataManagerX11::GetInstance()->UpdateDeviceList(display);
362 EventType EventTypeFromNative(const base::NativeEvent& native_event) {
363 // Allow the DeviceDataManager to block the event. If blocked return
364 // ET_UNKNOWN as the type so this event will not be further processed.
365 // NOTE: During some events unittests there is no device data manager.
366 if (DeviceDataManager::HasInstance() &&
367 static_cast<DeviceDataManagerX11*>(DeviceDataManager::GetInstance())->
368 IsEventBlocked(native_event)) {
369 return ET_UNKNOWN;
372 switch (native_event->type) {
373 case KeyPress:
374 return ET_KEY_PRESSED;
375 case KeyRelease:
376 return ET_KEY_RELEASED;
377 case ButtonPress:
378 if (static_cast<int>(native_event->xbutton.button) >= kMinWheelButton &&
379 static_cast<int>(native_event->xbutton.button) <= kMaxWheelButton)
380 return ET_MOUSEWHEEL;
381 return ET_MOUSE_PRESSED;
382 case ButtonRelease:
383 // Drop wheel events; we should've already scrolled on the press.
384 if (static_cast<int>(native_event->xbutton.button) >= kMinWheelButton &&
385 static_cast<int>(native_event->xbutton.button) <= kMaxWheelButton)
386 return ET_UNKNOWN;
387 return ET_MOUSE_RELEASED;
388 case MotionNotify:
389 if (native_event->xmotion.state &
390 (Button1Mask | Button2Mask | Button3Mask))
391 return ET_MOUSE_DRAGGED;
392 return ET_MOUSE_MOVED;
393 case EnterNotify:
394 // The standard on Windows is to send a MouseMove event when the mouse
395 // first enters a window instead of sending a special mouse enter event.
396 // To be consistent we follow the same style.
397 return ET_MOUSE_MOVED;
398 case LeaveNotify:
399 return ET_MOUSE_EXITED;
400 case GenericEvent: {
401 TouchFactory* factory = TouchFactory::GetInstance();
402 if (!factory->ShouldProcessXI2Event(native_event))
403 return ET_UNKNOWN;
405 XIDeviceEvent* xievent =
406 static_cast<XIDeviceEvent*>(native_event->xcookie.data);
408 // This check works only for master and floating slave devices. That is
409 // why it is necessary to check for the XI_Touch* events in the following
410 // switch statement to account for attached-slave touchscreens.
411 if (factory->IsTouchDevice(xievent->sourceid))
412 return GetTouchEventType(native_event);
414 switch (xievent->evtype) {
415 case XI_TouchBegin:
416 return ui::ET_TOUCH_PRESSED;
417 case XI_TouchUpdate:
418 return ui::ET_TOUCH_MOVED;
419 case XI_TouchEnd:
420 return ui::ET_TOUCH_RELEASED;
421 case XI_ButtonPress: {
422 int button = EventButtonFromNative(native_event);
423 if (button >= kMinWheelButton && button <= kMaxWheelButton)
424 return ET_MOUSEWHEEL;
425 return ET_MOUSE_PRESSED;
427 case XI_ButtonRelease: {
428 int button = EventButtonFromNative(native_event);
429 // Drop wheel events; we should've already scrolled on the press.
430 if (button >= kMinWheelButton && button <= kMaxWheelButton)
431 return ET_UNKNOWN;
432 return ET_MOUSE_RELEASED;
434 case XI_Motion: {
435 bool is_cancel;
436 DeviceDataManagerX11* devices = DeviceDataManagerX11::GetInstance();
437 if (GetFlingData(native_event, NULL, NULL, NULL, NULL, &is_cancel))
438 return is_cancel ? ET_SCROLL_FLING_CANCEL : ET_SCROLL_FLING_START;
439 if (devices->IsScrollEvent(native_event)) {
440 return devices->IsTouchpadXInputEvent(native_event) ? ET_SCROLL
441 : ET_MOUSEWHEEL;
443 if (devices->IsCMTMetricsEvent(native_event))
444 return ET_UMA_DATA;
445 if (GetButtonMaskForX2Event(xievent))
446 return ET_MOUSE_DRAGGED;
447 return ET_MOUSE_MOVED;
449 case XI_KeyPress:
450 return ET_KEY_PRESSED;
451 case XI_KeyRelease:
452 return ET_KEY_RELEASED;
455 default:
456 break;
458 return ET_UNKNOWN;
461 int EventFlagsFromNative(const base::NativeEvent& native_event) {
462 switch (native_event->type) {
463 case KeyPress:
464 case KeyRelease: {
465 XModifierStateWatcher::GetInstance()->UpdateStateFromXEvent(native_event);
466 return GetEventFlagsFromXKeyEvent(native_event);
468 case ButtonPress:
469 case ButtonRelease: {
470 int flags = GetEventFlagsFromXState(native_event->xbutton.state);
471 const EventType type = EventTypeFromNative(native_event);
472 if (type == ET_MOUSE_PRESSED || type == ET_MOUSE_RELEASED)
473 flags |= GetEventFlagsForButton(native_event->xbutton.button);
474 return flags;
476 case EnterNotify:
477 case LeaveNotify:
478 return GetEventFlagsFromXState(native_event->xcrossing.state);
479 case MotionNotify:
480 return GetEventFlagsFromXState(native_event->xmotion.state);
481 case GenericEvent: {
482 XIDeviceEvent* xievent =
483 static_cast<XIDeviceEvent*>(native_event->xcookie.data);
485 switch (xievent->evtype) {
486 case XI_TouchBegin:
487 case XI_TouchUpdate:
488 case XI_TouchEnd:
489 return GetButtonMaskForX2Event(xievent) |
490 GetEventFlagsFromXState(xievent->mods.effective) |
491 GetEventFlagsFromXState(
492 XModifierStateWatcher::GetInstance()->state());
493 break;
494 case XI_ButtonPress:
495 case XI_ButtonRelease: {
496 const bool touch =
497 TouchFactory::GetInstance()->IsTouchDevice(xievent->sourceid);
498 int flags = GetButtonMaskForX2Event(xievent) |
499 GetEventFlagsFromXState(xievent->mods.effective);
500 if (touch) {
501 flags |= GetEventFlagsFromXState(
502 XModifierStateWatcher::GetInstance()->state());
505 const EventType type = EventTypeFromNative(native_event);
506 int button = EventButtonFromNative(native_event);
507 if ((type == ET_MOUSE_PRESSED || type == ET_MOUSE_RELEASED) && !touch)
508 flags |= GetEventFlagsForButton(button);
509 return flags;
511 case XI_Motion:
512 return GetButtonMaskForX2Event(xievent) |
513 GetEventFlagsFromXState(xievent->mods.effective);
514 case XI_KeyPress:
515 case XI_KeyRelease: {
516 XModifierStateWatcher::GetInstance()->UpdateStateFromXEvent(
517 native_event);
518 return GetEventFlagsFromXGenericEvent(native_event);
523 return 0;
526 base::TimeDelta EventTimeFromNative(const base::NativeEvent& native_event) {
527 switch(native_event->type) {
528 case KeyPress:
529 case KeyRelease:
530 return base::TimeDelta::FromMilliseconds(native_event->xkey.time);
531 case ButtonPress:
532 case ButtonRelease:
533 return base::TimeDelta::FromMilliseconds(native_event->xbutton.time);
534 break;
535 case MotionNotify:
536 return base::TimeDelta::FromMilliseconds(native_event->xmotion.time);
537 break;
538 case EnterNotify:
539 case LeaveNotify:
540 return base::TimeDelta::FromMilliseconds(native_event->xcrossing.time);
541 break;
542 case GenericEvent: {
543 double start, end;
544 double touch_timestamp;
545 if (GetGestureTimes(native_event, &start, &end)) {
546 // If the driver supports gesture times, use them.
547 return base::TimeDelta::FromMicroseconds(end * 1000000);
548 } else if (DeviceDataManagerX11::GetInstance()->GetEventData(
549 *native_event,
550 DeviceDataManagerX11::DT_TOUCH_RAW_TIMESTAMP,
551 &touch_timestamp)) {
552 return base::TimeDelta::FromMicroseconds(touch_timestamp * 1000000);
553 } else {
554 XIDeviceEvent* xide =
555 static_cast<XIDeviceEvent*>(native_event->xcookie.data);
556 return base::TimeDelta::FromMilliseconds(xide->time);
558 break;
561 NOTREACHED();
562 return base::TimeDelta();
565 gfx::Point EventLocationFromNative(const base::NativeEvent& native_event) {
566 switch (native_event->type) {
567 case EnterNotify:
568 case LeaveNotify:
569 return gfx::Point(native_event->xcrossing.x, native_event->xcrossing.y);
570 case ButtonPress:
571 case ButtonRelease:
572 return gfx::Point(native_event->xbutton.x, native_event->xbutton.y);
573 case MotionNotify:
574 return gfx::Point(native_event->xmotion.x, native_event->xmotion.y);
575 case GenericEvent: {
576 XIDeviceEvent* xievent =
577 static_cast<XIDeviceEvent*>(native_event->xcookie.data);
578 float x = xievent->event_x;
579 float y = xievent->event_y;
580 #if defined(OS_CHROMEOS)
581 switch (xievent->evtype) {
582 case XI_TouchBegin:
583 case XI_TouchUpdate:
584 case XI_TouchEnd:
585 ui::DeviceDataManagerX11::GetInstance()->ApplyTouchTransformer(
586 xievent->deviceid, &x, &y);
587 break;
588 default:
589 break;
591 #endif // defined(OS_CHROMEOS)
592 return gfx::Point(static_cast<int>(x), static_cast<int>(y));
595 return gfx::Point();
598 gfx::Point EventSystemLocationFromNative(
599 const base::NativeEvent& native_event) {
600 switch (native_event->type) {
601 case EnterNotify:
602 case LeaveNotify: {
603 return gfx::Point(native_event->xcrossing.x_root,
604 native_event->xcrossing.y_root);
606 case ButtonPress:
607 case ButtonRelease: {
608 return gfx::Point(native_event->xbutton.x_root,
609 native_event->xbutton.y_root);
611 case MotionNotify: {
612 return gfx::Point(native_event->xmotion.x_root,
613 native_event->xmotion.y_root);
615 case GenericEvent: {
616 XIDeviceEvent* xievent =
617 static_cast<XIDeviceEvent*>(native_event->xcookie.data);
618 return gfx::Point(xievent->root_x, xievent->root_y);
622 return gfx::Point();
625 int EventButtonFromNative(const base::NativeEvent& native_event) {
626 CHECK_EQ(GenericEvent, native_event->type);
627 XIDeviceEvent* xievent =
628 static_cast<XIDeviceEvent*>(native_event->xcookie.data);
629 int button = xievent->detail;
631 return (xievent->sourceid == xievent->deviceid) ?
632 DeviceDataManagerX11::GetInstance()->GetMappedButton(button) : button;
635 KeyboardCode KeyboardCodeFromNative(const base::NativeEvent& native_event) {
636 return KeyboardCodeFromXKeyEvent(native_event);
639 DomCode CodeFromNative(const base::NativeEvent& native_event) {
640 return CodeFromXEvent(native_event);
643 uint32 PlatformKeycodeFromNative(const base::NativeEvent& native_event) {
644 XKeyEvent* xkey = NULL;
645 XEvent xkey_from_xi2;
646 switch (native_event->type) {
647 case KeyPress:
648 case KeyRelease:
649 xkey = &native_event->xkey;
650 break;
651 case GenericEvent: {
652 XIDeviceEvent* xievent =
653 static_cast<XIDeviceEvent*>(native_event->xcookie.data);
654 switch (xievent->evtype) {
655 case XI_KeyPress:
656 case XI_KeyRelease:
657 // Build an XKeyEvent corresponding to the XI2 event,
658 // so that we can call XLookupString on it.
659 InitXKeyEventFromXIDeviceEvent(*native_event, &xkey_from_xi2);
660 xkey = &xkey_from_xi2.xkey;
661 break;
662 default:
663 NOTREACHED();
664 break;
666 break;
668 default:
669 NOTREACHED();
670 break;
672 KeySym keysym = XK_VoidSymbol;
673 if (xkey)
674 XLookupString(xkey, NULL, 0, &keysym, NULL);
675 return keysym;
678 bool IsCharFromNative(const base::NativeEvent& native_event) {
679 return false;
682 int GetChangedMouseButtonFlagsFromNative(
683 const base::NativeEvent& native_event) {
684 switch (native_event->type) {
685 case ButtonPress:
686 case ButtonRelease:
687 return GetEventFlagsFromXState(native_event->xbutton.state);
688 case GenericEvent: {
689 XIDeviceEvent* xievent =
690 static_cast<XIDeviceEvent*>(native_event->xcookie.data);
691 switch (xievent->evtype) {
692 case XI_ButtonPress:
693 case XI_ButtonRelease:
694 return GetEventFlagsForButton(EventButtonFromNative(native_event));
695 default:
696 break;
699 default:
700 break;
702 return 0;
705 gfx::Vector2d GetMouseWheelOffset(const base::NativeEvent& native_event) {
706 float x_offset, y_offset;
707 if (GetScrollOffsets(
708 native_event, &x_offset, &y_offset, NULL, NULL, NULL)) {
709 return gfx::Vector2d(static_cast<int>(x_offset),
710 static_cast<int>(y_offset));
713 int button = native_event->type == GenericEvent ?
714 EventButtonFromNative(native_event) : native_event->xbutton.button;
716 switch (button) {
717 case 4:
718 return gfx::Vector2d(0, kWheelScrollAmount);
719 case 5:
720 return gfx::Vector2d(0, -kWheelScrollAmount);
721 case 6:
722 return gfx::Vector2d(kWheelScrollAmount, 0);
723 case 7:
724 return gfx::Vector2d(-kWheelScrollAmount, 0);
725 default:
726 return gfx::Vector2d();
730 base::NativeEvent CopyNativeEvent(const base::NativeEvent& event) {
731 if (!event || event->type == GenericEvent)
732 return NULL;
733 XEvent* copy = new XEvent;
734 *copy = *event;
735 return copy;
738 void ReleaseCopiedNativeEvent(const base::NativeEvent& event) {
739 delete event;
742 void IncrementTouchIdRefCount(const base::NativeEvent& xev) {
743 ui::DeviceDataManagerX11* manager = ui::DeviceDataManagerX11::GetInstance();
744 double tracking_id;
745 if (!manager->GetEventData(
746 *xev, ui::DeviceDataManagerX11::DT_TOUCH_TRACKING_ID, &tracking_id)) {
747 return;
750 ui::TouchFactory* factory = ui::TouchFactory::GetInstance();
751 factory->AcquireSlotForTrackingID(tracking_id);
754 void ClearTouchIdIfReleased(const base::NativeEvent& xev) {
755 ui::EventType type = ui::EventTypeFromNative(xev);
756 if (type == ui::ET_TOUCH_CANCELLED ||
757 type == ui::ET_TOUCH_RELEASED) {
758 ui::TouchFactory* factory = ui::TouchFactory::GetInstance();
759 ui::DeviceDataManagerX11* manager = ui::DeviceDataManagerX11::GetInstance();
760 double tracking_id;
761 if (manager->GetEventData(
762 *xev, ui::DeviceDataManagerX11::DT_TOUCH_TRACKING_ID, &tracking_id)) {
763 factory->ReleaseSlotForTrackingID(tracking_id);
768 int GetTouchId(const base::NativeEvent& xev) {
769 double slot = 0;
770 ui::DeviceDataManagerX11* manager = ui::DeviceDataManagerX11::GetInstance();
771 double tracking_id;
772 if (!manager->GetEventData(
773 *xev, ui::DeviceDataManagerX11::DT_TOUCH_TRACKING_ID, &tracking_id)) {
774 LOG(ERROR) << "Could not get the tracking ID for the event. Using 0.";
775 } else {
776 ui::TouchFactory* factory = ui::TouchFactory::GetInstance();
777 slot = factory->GetSlotForTrackingID(tracking_id);
779 return slot;
782 float GetTouchRadiusX(const base::NativeEvent& native_event) {
783 double radius = GetTouchParamFromXEvent(native_event,
784 ui::DeviceDataManagerX11::DT_TOUCH_MAJOR, 0.0) / 2.0;
785 ScaleTouchRadius(native_event, &radius);
786 return radius;
789 float GetTouchRadiusY(const base::NativeEvent& native_event) {
790 double radius = GetTouchParamFromXEvent(native_event,
791 ui::DeviceDataManagerX11::DT_TOUCH_MINOR, 0.0) / 2.0;
792 ScaleTouchRadius(native_event, &radius);
793 return radius;
796 float GetTouchAngle(const base::NativeEvent& native_event) {
797 return GetTouchParamFromXEvent(native_event,
798 ui::DeviceDataManagerX11::DT_TOUCH_ORIENTATION, 0.0) / 2.0;
801 float GetTouchForce(const base::NativeEvent& native_event) {
802 double force = 0.0;
803 force = GetTouchParamFromXEvent(native_event,
804 ui::DeviceDataManagerX11::DT_TOUCH_PRESSURE, 0.0);
805 unsigned int deviceid =
806 static_cast<XIDeviceEvent*>(native_event->xcookie.data)->sourceid;
807 // Force is normalized to fall into [0, 1]
808 if (!ui::DeviceDataManagerX11::GetInstance()->NormalizeData(
809 deviceid, ui::DeviceDataManagerX11::DT_TOUCH_PRESSURE, &force))
810 force = 0.0;
811 return force;
814 bool GetScrollOffsets(const base::NativeEvent& native_event,
815 float* x_offset,
816 float* y_offset,
817 float* x_offset_ordinal,
818 float* y_offset_ordinal,
819 int* finger_count) {
820 if (!DeviceDataManagerX11::GetInstance()->IsScrollEvent(native_event))
821 return false;
823 // Temp values to prevent passing NULLs to DeviceDataManager.
824 float x_offset_, y_offset_;
825 float x_offset_ordinal_, y_offset_ordinal_;
826 int finger_count_;
827 if (!x_offset)
828 x_offset = &x_offset_;
829 if (!y_offset)
830 y_offset = &y_offset_;
831 if (!x_offset_ordinal)
832 x_offset_ordinal = &x_offset_ordinal_;
833 if (!y_offset_ordinal)
834 y_offset_ordinal = &y_offset_ordinal_;
835 if (!finger_count)
836 finger_count = &finger_count_;
838 DeviceDataManagerX11::GetInstance()->GetScrollOffsets(
839 native_event,
840 x_offset, y_offset,
841 x_offset_ordinal, y_offset_ordinal,
842 finger_count);
843 return true;
846 bool GetFlingData(const base::NativeEvent& native_event,
847 float* vx,
848 float* vy,
849 float* vx_ordinal,
850 float* vy_ordinal,
851 bool* is_cancel) {
852 if (!DeviceDataManagerX11::GetInstance()->IsFlingEvent(native_event))
853 return false;
855 float vx_, vy_;
856 float vx_ordinal_, vy_ordinal_;
857 bool is_cancel_;
858 if (!vx)
859 vx = &vx_;
860 if (!vy)
861 vy = &vy_;
862 if (!vx_ordinal)
863 vx_ordinal = &vx_ordinal_;
864 if (!vy_ordinal)
865 vy_ordinal = &vy_ordinal_;
866 if (!is_cancel)
867 is_cancel = &is_cancel_;
869 DeviceDataManagerX11::GetInstance()->GetFlingData(
870 native_event, vx, vy, vx_ordinal, vy_ordinal, is_cancel);
871 return true;
874 void UpdateX11EventForFlags(Event* event) {
875 XEvent* xev = event->native_event();
876 if (!xev)
877 return;
878 switch (xev->type) {
879 case KeyPress:
880 case KeyRelease:
881 xev->xkey.state = UpdateX11EventFlags(event->flags(), xev->xkey.state);
882 break;
883 case ButtonPress:
884 case ButtonRelease:
885 xev->xbutton.state =
886 UpdateX11EventFlags(event->flags(), xev->xbutton.state);
887 break;
888 case GenericEvent: {
889 XIDeviceEvent* xievent = static_cast<XIDeviceEvent*>(xev->xcookie.data);
890 DCHECK(xievent);
891 xievent->mods.effective =
892 UpdateX11EventFlags(event->flags(), xievent->mods.effective);
893 break;
895 default:
896 break;
900 void UpdateX11EventForChangedButtonFlags(MouseEvent* event) {
901 XEvent* xev = event->native_event();
902 if (!xev)
903 return;
904 switch (xev->type) {
905 case ButtonPress:
906 case ButtonRelease:
907 xev->xbutton.button = UpdateX11EventButton(event->changed_button_flags(),
908 xev->xbutton.button);
909 break;
910 case GenericEvent: {
911 XIDeviceEvent* xievent = static_cast<XIDeviceEvent*>(xev->xcookie.data);
912 CHECK(xievent && (xievent->evtype == XI_ButtonPress ||
913 xievent->evtype == XI_ButtonRelease));
914 xievent->detail =
915 UpdateX11EventButton(event->changed_button_flags(), xievent->detail);
916 break;
918 default:
919 break;
923 } // namespace ui