ui: Remove some unnecessary functions from the API.
[chromium-blink-merge.git] / ui / events / x / events_x.cc
blobc9780ece12c93e45bfd00931e3b3e98d73e1ddc3
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 <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>
15 #include "base/logging.h"
16 #include "base/memory/singleton.h"
17 #include "ui/events/event_utils.h"
18 #include "ui/events/keycodes/keyboard_code_conversion_x.h"
19 #include "ui/events/x/device_data_manager_x11.h"
20 #include "ui/events/x/device_list_cache_x.h"
21 #include "ui/events/x/touch_factory_x11.h"
22 #include "ui/gfx/display.h"
23 #include "ui/gfx/point.h"
24 #include "ui/gfx/rect.h"
25 #include "ui/gfx/screen.h"
26 #include "ui/gfx/x/x11_atom_cache.h"
27 #include "ui/gfx/x/x11_types.h"
29 namespace {
31 // Scroll amount for each wheelscroll event. 53 is also the value used for GTK+.
32 const int kWheelScrollAmount = 53;
34 const int kMinWheelButton = 4;
35 const int kMaxWheelButton = 7;
37 // A class to track current modifier state on master device. Only track ctrl,
38 // alt, shift and caps lock keys currently. The tracked state can then be used
39 // by floating device.
40 class XModifierStateWatcher{
41 public:
42 static XModifierStateWatcher* GetInstance() {
43 return Singleton<XModifierStateWatcher>::get();
46 int StateFromKeyboardCode(ui::KeyboardCode keyboard_code) {
47 switch (keyboard_code) {
48 case ui::VKEY_CONTROL:
49 return ControlMask;
50 case ui::VKEY_SHIFT:
51 return ShiftMask;
52 case ui::VKEY_MENU:
53 return Mod1Mask;
54 case ui::VKEY_CAPITAL:
55 return LockMask;
56 default:
57 return 0;
61 void UpdateStateFromXEvent(const base::NativeEvent& native_event) {
62 ui::KeyboardCode keyboard_code = ui::KeyboardCodeFromNative(native_event);
63 unsigned int mask = StateFromKeyboardCode(keyboard_code);
64 // Floating device can't access the modifer state from master device.
65 // We need to track the states of modifier keys in a singleton for
66 // floating devices such as touch screen. Issue 106426 is one example
67 // of why we need the modifier states for floating device.
68 switch (native_event->type) {
69 case KeyPress:
70 state_ = native_event->xkey.state | mask;
71 break;
72 case KeyRelease:
73 state_ = native_event->xkey.state & ~mask;
74 break;
75 case GenericEvent: {
76 XIDeviceEvent* xievent =
77 static_cast<XIDeviceEvent*>(native_event->xcookie.data);
78 switch (xievent->evtype) {
79 case XI_KeyPress:
80 state_ = xievent->mods.effective |= mask;
81 break;
82 case XI_KeyRelease:
83 state_ = xievent->mods.effective &= ~mask;
84 break;
85 default:
86 NOTREACHED();
87 break;
89 break;
91 default:
92 NOTREACHED();
93 break;
97 // Returns the current modifer state in master device. It only contains the
98 // state of ctrl, shift, alt and caps lock keys.
99 unsigned int state() { return state_; }
101 private:
102 friend struct DefaultSingletonTraits<XModifierStateWatcher>;
104 XModifierStateWatcher() : state_(0) { }
106 unsigned int state_;
108 DISALLOW_COPY_AND_ASSIGN(XModifierStateWatcher);
111 #if defined(USE_XI2_MT)
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;
141 #endif
143 int GetEventFlagsFromXState(unsigned int state) {
144 int flags = 0;
145 if (state & ControlMask)
146 flags |= ui::EF_CONTROL_DOWN;
147 if (state & ShiftMask)
148 flags |= ui::EF_SHIFT_DOWN;
149 if (state & Mod1Mask)
150 flags |= ui::EF_ALT_DOWN;
151 if (state & LockMask)
152 flags |= ui::EF_CAPS_LOCK_DOWN;
153 if (state & Mod3Mask)
154 flags |= ui::EF_MOD3_DOWN;
155 if (state & Mod4Mask)
156 flags |= ui::EF_COMMAND_DOWN;
157 if (state & Mod5Mask)
158 flags |= ui::EF_ALTGR_DOWN;
159 if (state & Button1Mask)
160 flags |= ui::EF_LEFT_MOUSE_BUTTON;
161 if (state & Button2Mask)
162 flags |= ui::EF_MIDDLE_MOUSE_BUTTON;
163 if (state & Button3Mask)
164 flags |= ui::EF_RIGHT_MOUSE_BUTTON;
165 return flags;
168 int GetEventFlagsFromXKeyEvent(XEvent* xevent) {
169 DCHECK(xevent->type == KeyPress || xevent->type == KeyRelease);
171 #if defined(OS_CHROMEOS)
172 const int ime_fabricated_flag = 0;
173 #else
174 // XIM fabricates key events for the character compositions by XK_Multi_key.
175 // For example, when a user hits XK_Multi_key, XK_apostrophe, and XK_e in
176 // order to input "é", then XIM generates a key event with keycode=0 and
177 // state=0 for the composition, and the sequence of X11 key events will be
178 // XK_Multi_key, XK_apostrophe, **NoSymbol**, and XK_e. If the user used
179 // shift key and/or caps lock key, state can be ShiftMask, LockMask or both.
181 // We have to send these fabricated key events to XIM so it can correctly
182 // handle the character compositions.
183 const unsigned int shift_lock_mask = ShiftMask | LockMask;
184 const bool fabricated_by_xim =
185 xevent->xkey.keycode == 0 &&
186 (xevent->xkey.state & ~shift_lock_mask) == 0;
187 const int ime_fabricated_flag =
188 fabricated_by_xim ? ui::EF_IME_FABRICATED_KEY : 0;
189 #endif
191 return GetEventFlagsFromXState(xevent->xkey.state) |
192 (xevent->xkey.send_event ? ui::EF_FINAL : 0) |
193 (IsKeypadKey(XLookupKeysym(&xevent->xkey, 0)) ? ui::EF_NUMPAD_KEY : 0) |
194 (IsFunctionKey(XLookupKeysym(&xevent->xkey, 0)) ?
195 ui::EF_FUNCTION_KEY : 0) |
196 ime_fabricated_flag;
199 int GetEventFlagsFromXGenericEvent(XEvent* xevent) {
200 DCHECK(xevent->type == GenericEvent);
201 XIDeviceEvent* xievent = static_cast<XIDeviceEvent*>(xevent->xcookie.data);
202 DCHECK((xievent->evtype == XI_KeyPress) ||
203 (xievent->evtype == XI_KeyRelease));
204 return GetEventFlagsFromXState(xievent->mods.effective) |
205 (xevent->xkey.send_event ? ui::EF_FINAL : 0) |
206 (IsKeypadKey(
207 XkbKeycodeToKeysym(xievent->display, xievent->detail, 0, 0))
208 ? ui::EF_NUMPAD_KEY
209 : 0);
212 // Get the event flag for the button in XButtonEvent. During a ButtonPress
213 // event, |state| in XButtonEvent does not include the button that has just been
214 // pressed. Instead |state| contains flags for the buttons (if any) that had
215 // already been pressed before the current button, and |button| stores the most
216 // current pressed button. So, if you press down left mouse button, and while
217 // pressing it down, press down the right mouse button, then for the latter
218 // event, |state| would have Button1Mask set but not Button3Mask, and |button|
219 // would be 3.
220 int GetEventFlagsForButton(int button) {
221 switch (button) {
222 case 1:
223 return ui::EF_LEFT_MOUSE_BUTTON;
224 case 2:
225 return ui::EF_MIDDLE_MOUSE_BUTTON;
226 case 3:
227 return ui::EF_RIGHT_MOUSE_BUTTON;
228 default:
229 return 0;
233 int GetButtonMaskForX2Event(XIDeviceEvent* xievent) {
234 int buttonflags = 0;
235 for (int i = 0; i < 8 * xievent->buttons.mask_len; i++) {
236 if (XIMaskIsSet(xievent->buttons.mask, i)) {
237 int button = (xievent->sourceid == xievent->deviceid) ?
238 ui::DeviceDataManagerX11::GetInstance()->GetMappedButton(i) : i;
239 buttonflags |= GetEventFlagsForButton(button);
242 return buttonflags;
245 ui::EventType GetTouchEventType(const base::NativeEvent& native_event) {
246 XIDeviceEvent* event =
247 static_cast<XIDeviceEvent*>(native_event->xcookie.data);
248 #if defined(USE_XI2_MT)
249 switch(event->evtype) {
250 case XI_TouchBegin:
251 return TouchEventIsGeneratedHack(native_event) ? ui::ET_UNKNOWN :
252 ui::ET_TOUCH_PRESSED;
253 case XI_TouchUpdate:
254 return TouchEventIsGeneratedHack(native_event) ? ui::ET_UNKNOWN :
255 ui::ET_TOUCH_MOVED;
256 case XI_TouchEnd:
257 return TouchEventIsGeneratedHack(native_event) ? ui::ET_TOUCH_CANCELLED :
258 ui::ET_TOUCH_RELEASED;
260 #endif // defined(USE_XI2_MT)
262 DCHECK(ui::TouchFactory::GetInstance()->IsTouchDevice(event->sourceid));
263 switch (event->evtype) {
264 case XI_ButtonPress:
265 return ui::ET_TOUCH_PRESSED;
266 case XI_ButtonRelease:
267 return ui::ET_TOUCH_RELEASED;
268 case XI_Motion:
269 // Should not convert any emulated Motion event from touch device to
270 // touch event.
271 if (!(event->flags & XIPointerEmulated) &&
272 GetButtonMaskForX2Event(event))
273 return ui::ET_TOUCH_MOVED;
274 return ui::ET_UNKNOWN;
275 default:
276 NOTREACHED();
278 return ui::ET_UNKNOWN;
281 double GetTouchParamFromXEvent(XEvent* xev,
282 ui::DeviceDataManagerX11::DataType val,
283 double default_value) {
284 ui::DeviceDataManagerX11::GetInstance()->GetEventData(
285 *xev, val, &default_value);
286 return default_value;
289 } // namespace
291 namespace ui {
293 void UpdateDeviceList() {
294 XDisplay* display = gfx::GetXDisplay();
295 DeviceListCacheX::GetInstance()->UpdateDeviceList(display);
296 TouchFactory::GetInstance()->UpdateDeviceList(display);
297 DeviceDataManagerX11::GetInstance()->UpdateDeviceList(display);
300 EventType EventTypeFromNative(const base::NativeEvent& native_event) {
301 // Allow the DeviceDataManager to block the event. If blocked return
302 // ET_UNKNOWN as the type so this event will not be further processed.
303 // NOTE: During some events unittests there is no device data manager.
304 if (DeviceDataManager::HasInstance() &&
305 static_cast<DeviceDataManagerX11*>(DeviceDataManager::GetInstance())->
306 IsEventBlocked(native_event)) {
307 return ET_UNKNOWN;
310 switch (native_event->type) {
311 case KeyPress:
312 return ET_KEY_PRESSED;
313 case KeyRelease:
314 return ET_KEY_RELEASED;
315 case ButtonPress:
316 if (static_cast<int>(native_event->xbutton.button) >= kMinWheelButton &&
317 static_cast<int>(native_event->xbutton.button) <= kMaxWheelButton)
318 return ET_MOUSEWHEEL;
319 return ET_MOUSE_PRESSED;
320 case ButtonRelease:
321 // Drop wheel events; we should've already scrolled on the press.
322 if (static_cast<int>(native_event->xbutton.button) >= kMinWheelButton &&
323 static_cast<int>(native_event->xbutton.button) <= kMaxWheelButton)
324 return ET_UNKNOWN;
325 return ET_MOUSE_RELEASED;
326 case MotionNotify:
327 if (native_event->xmotion.state &
328 (Button1Mask | Button2Mask | Button3Mask))
329 return ET_MOUSE_DRAGGED;
330 return ET_MOUSE_MOVED;
331 case EnterNotify:
332 // The standard on Windows is to send a MouseMove event when the mouse
333 // first enters a window instead of sending a special mouse enter event.
334 // To be consistent we follow the same style.
335 return ET_MOUSE_MOVED;
336 case LeaveNotify:
337 return ET_MOUSE_EXITED;
338 case GenericEvent: {
339 TouchFactory* factory = TouchFactory::GetInstance();
340 if (!factory->ShouldProcessXI2Event(native_event))
341 return ET_UNKNOWN;
343 XIDeviceEvent* xievent =
344 static_cast<XIDeviceEvent*>(native_event->xcookie.data);
346 // This check works only for master and floating slave devices. That is
347 // why it is necessary to check for the XI_Touch* events in the following
348 // switch statement to account for attached-slave touchscreens.
349 if (factory->IsTouchDevice(xievent->sourceid))
350 return GetTouchEventType(native_event);
352 switch (xievent->evtype) {
353 case XI_TouchBegin:
354 return ui::ET_TOUCH_PRESSED;
355 case XI_TouchUpdate:
356 return ui::ET_TOUCH_MOVED;
357 case XI_TouchEnd:
358 return ui::ET_TOUCH_RELEASED;
359 case XI_ButtonPress: {
360 int button = EventButtonFromNative(native_event);
361 if (button >= kMinWheelButton && button <= kMaxWheelButton)
362 return ET_MOUSEWHEEL;
363 return ET_MOUSE_PRESSED;
365 case XI_ButtonRelease: {
366 int button = EventButtonFromNative(native_event);
367 // Drop wheel events; we should've already scrolled on the press.
368 if (button >= kMinWheelButton && button <= kMaxWheelButton)
369 return ET_UNKNOWN;
370 return ET_MOUSE_RELEASED;
372 case XI_Motion: {
373 bool is_cancel;
374 DeviceDataManagerX11* devices = DeviceDataManagerX11::GetInstance();
375 if (GetFlingData(native_event, NULL, NULL, NULL, NULL, &is_cancel))
376 return is_cancel ? ET_SCROLL_FLING_CANCEL : ET_SCROLL_FLING_START;
377 if (devices->IsScrollEvent(native_event)) {
378 return devices->IsTouchpadXInputEvent(native_event) ? ET_SCROLL
379 : ET_MOUSEWHEEL;
381 if (devices->IsCMTMetricsEvent(native_event))
382 return ET_UMA_DATA;
383 if (GetButtonMaskForX2Event(xievent))
384 return ET_MOUSE_DRAGGED;
385 return ET_MOUSE_MOVED;
387 case XI_KeyPress:
388 return ET_KEY_PRESSED;
389 case XI_KeyRelease:
390 return ET_KEY_RELEASED;
393 default:
394 break;
396 return ET_UNKNOWN;
399 int EventFlagsFromNative(const base::NativeEvent& native_event) {
400 switch (native_event->type) {
401 case KeyPress:
402 case KeyRelease: {
403 XModifierStateWatcher::GetInstance()->UpdateStateFromXEvent(native_event);
404 return GetEventFlagsFromXKeyEvent(native_event);
406 case ButtonPress:
407 case ButtonRelease: {
408 int flags = GetEventFlagsFromXState(native_event->xbutton.state);
409 const EventType type = EventTypeFromNative(native_event);
410 if (type == ET_MOUSE_PRESSED || type == ET_MOUSE_RELEASED)
411 flags |= GetEventFlagsForButton(native_event->xbutton.button);
412 return flags;
414 case EnterNotify:
415 case LeaveNotify:
416 return GetEventFlagsFromXState(native_event->xcrossing.state);
417 case MotionNotify:
418 return GetEventFlagsFromXState(native_event->xmotion.state);
419 case GenericEvent: {
420 XIDeviceEvent* xievent =
421 static_cast<XIDeviceEvent*>(native_event->xcookie.data);
423 switch (xievent->evtype) {
424 #if defined(USE_XI2_MT)
425 case XI_TouchBegin:
426 case XI_TouchUpdate:
427 case XI_TouchEnd:
428 return GetButtonMaskForX2Event(xievent) |
429 GetEventFlagsFromXState(xievent->mods.effective) |
430 GetEventFlagsFromXState(
431 XModifierStateWatcher::GetInstance()->state());
432 break;
433 #endif
434 case XI_ButtonPress:
435 case XI_ButtonRelease: {
436 const bool touch =
437 TouchFactory::GetInstance()->IsTouchDevice(xievent->sourceid);
438 int flags = GetButtonMaskForX2Event(xievent) |
439 GetEventFlagsFromXState(xievent->mods.effective);
440 if (touch) {
441 flags |= GetEventFlagsFromXState(
442 XModifierStateWatcher::GetInstance()->state());
445 const EventType type = EventTypeFromNative(native_event);
446 int button = EventButtonFromNative(native_event);
447 if ((type == ET_MOUSE_PRESSED || type == ET_MOUSE_RELEASED) && !touch)
448 flags |= GetEventFlagsForButton(button);
449 return flags;
451 case XI_Motion:
452 return GetButtonMaskForX2Event(xievent) |
453 GetEventFlagsFromXState(xievent->mods.effective);
454 case XI_KeyPress:
455 case XI_KeyRelease: {
456 XModifierStateWatcher::GetInstance()->UpdateStateFromXEvent(
457 native_event);
458 return GetEventFlagsFromXGenericEvent(native_event);
463 return 0;
466 base::TimeDelta EventTimeFromNative(const base::NativeEvent& native_event) {
467 switch(native_event->type) {
468 case KeyPress:
469 case KeyRelease:
470 return base::TimeDelta::FromMilliseconds(native_event->xkey.time);
471 case ButtonPress:
472 case ButtonRelease:
473 return base::TimeDelta::FromMilliseconds(native_event->xbutton.time);
474 break;
475 case MotionNotify:
476 return base::TimeDelta::FromMilliseconds(native_event->xmotion.time);
477 break;
478 case EnterNotify:
479 case LeaveNotify:
480 return base::TimeDelta::FromMilliseconds(native_event->xcrossing.time);
481 break;
482 case GenericEvent: {
483 double start, end;
484 double touch_timestamp;
485 if (GetGestureTimes(native_event, &start, &end)) {
486 // If the driver supports gesture times, use them.
487 return base::TimeDelta::FromMicroseconds(end * 1000000);
488 } else if (DeviceDataManagerX11::GetInstance()->GetEventData(
489 *native_event,
490 DeviceDataManagerX11::DT_TOUCH_RAW_TIMESTAMP,
491 &touch_timestamp)) {
492 return base::TimeDelta::FromMicroseconds(touch_timestamp * 1000000);
493 } else {
494 XIDeviceEvent* xide =
495 static_cast<XIDeviceEvent*>(native_event->xcookie.data);
496 return base::TimeDelta::FromMilliseconds(xide->time);
498 break;
501 NOTREACHED();
502 return base::TimeDelta();
505 gfx::Point EventLocationFromNative(const base::NativeEvent& native_event) {
506 switch (native_event->type) {
507 case EnterNotify:
508 case LeaveNotify:
509 return gfx::Point(native_event->xcrossing.x, native_event->xcrossing.y);
510 case ButtonPress:
511 case ButtonRelease:
512 return gfx::Point(native_event->xbutton.x, native_event->xbutton.y);
513 case MotionNotify:
514 return gfx::Point(native_event->xmotion.x, native_event->xmotion.y);
515 case GenericEvent: {
516 XIDeviceEvent* xievent =
517 static_cast<XIDeviceEvent*>(native_event->xcookie.data);
518 float x = xievent->event_x;
519 float y = xievent->event_y;
520 #if defined(OS_CHROMEOS)
521 switch (xievent->evtype) {
522 case XI_TouchBegin:
523 case XI_TouchUpdate:
524 case XI_TouchEnd:
525 ui::DeviceDataManagerX11::GetInstance()->ApplyTouchTransformer(
526 xievent->deviceid, &x, &y);
527 break;
528 default:
529 break;
531 #endif // defined(OS_CHROMEOS)
532 return gfx::Point(static_cast<int>(x), static_cast<int>(y));
535 return gfx::Point();
538 gfx::Point EventSystemLocationFromNative(
539 const base::NativeEvent& native_event) {
540 switch (native_event->type) {
541 case EnterNotify:
542 case LeaveNotify: {
543 return gfx::Point(native_event->xcrossing.x_root,
544 native_event->xcrossing.y_root);
546 case ButtonPress:
547 case ButtonRelease: {
548 return gfx::Point(native_event->xbutton.x_root,
549 native_event->xbutton.y_root);
551 case MotionNotify: {
552 return gfx::Point(native_event->xmotion.x_root,
553 native_event->xmotion.y_root);
555 case GenericEvent: {
556 XIDeviceEvent* xievent =
557 static_cast<XIDeviceEvent*>(native_event->xcookie.data);
558 return gfx::Point(xievent->root_x, xievent->root_y);
562 return gfx::Point();
565 int EventButtonFromNative(const base::NativeEvent& native_event) {
566 CHECK_EQ(GenericEvent, native_event->type);
567 XIDeviceEvent* xievent =
568 static_cast<XIDeviceEvent*>(native_event->xcookie.data);
569 int button = xievent->detail;
571 return (xievent->sourceid == xievent->deviceid) ?
572 DeviceDataManagerX11::GetInstance()->GetMappedButton(button) : button;
575 KeyboardCode KeyboardCodeFromNative(const base::NativeEvent& native_event) {
576 return KeyboardCodeFromXKeyEvent(native_event);
579 const char* CodeFromNative(const base::NativeEvent& native_event) {
580 return CodeFromXEvent(native_event);
583 uint32 PlatformKeycodeFromNative(const base::NativeEvent& native_event) {
584 XKeyEvent* xkey = NULL;
585 XEvent xkey_from_xi2;
586 switch (native_event->type) {
587 case KeyPress:
588 case KeyRelease:
589 xkey = &native_event->xkey;
590 break;
591 case GenericEvent: {
592 XIDeviceEvent* xievent =
593 static_cast<XIDeviceEvent*>(native_event->xcookie.data);
594 switch (xievent->evtype) {
595 case XI_KeyPress:
596 case XI_KeyRelease:
597 // Build an XKeyEvent corresponding to the XI2 event,
598 // so that we can call XLookupString on it.
599 InitXKeyEventFromXIDeviceEvent(*native_event, &xkey_from_xi2);
600 xkey = &xkey_from_xi2.xkey;
601 break;
602 default:
603 NOTREACHED();
604 break;
606 break;
608 default:
609 NOTREACHED();
610 break;
612 KeySym keysym = XK_VoidSymbol;
613 if (xkey)
614 XLookupString(xkey, NULL, 0, &keysym, NULL);
615 return keysym;
618 int GetChangedMouseButtonFlagsFromNative(
619 const base::NativeEvent& native_event) {
620 switch (native_event->type) {
621 case ButtonPress:
622 case ButtonRelease:
623 return GetEventFlagsFromXState(native_event->xbutton.state);
624 case GenericEvent: {
625 XIDeviceEvent* xievent =
626 static_cast<XIDeviceEvent*>(native_event->xcookie.data);
627 switch (xievent->evtype) {
628 case XI_ButtonPress:
629 case XI_ButtonRelease:
630 return GetEventFlagsForButton(EventButtonFromNative(native_event));
631 default:
632 break;
635 default:
636 break;
638 return 0;
641 gfx::Vector2d GetMouseWheelOffset(const base::NativeEvent& native_event) {
642 float x_offset, y_offset;
643 if (GetScrollOffsets(
644 native_event, &x_offset, &y_offset, NULL, NULL, NULL)) {
645 return gfx::Vector2d(static_cast<int>(x_offset),
646 static_cast<int>(y_offset));
649 int button = native_event->type == GenericEvent ?
650 EventButtonFromNative(native_event) : native_event->xbutton.button;
652 switch (button) {
653 case 4:
654 return gfx::Vector2d(0, kWheelScrollAmount);
655 case 5:
656 return gfx::Vector2d(0, -kWheelScrollAmount);
657 case 6:
658 return gfx::Vector2d(kWheelScrollAmount, 0);
659 case 7:
660 return gfx::Vector2d(-kWheelScrollAmount, 0);
661 default:
662 return gfx::Vector2d();
666 base::NativeEvent CopyNativeEvent(const base::NativeEvent& event) {
667 if (!event || event->type == GenericEvent)
668 return NULL;
669 XEvent* copy = new XEvent;
670 *copy = *event;
671 return copy;
674 void ReleaseCopiedNativeEvent(const base::NativeEvent& event) {
675 delete event;
678 void ClearTouchIdIfReleased(const base::NativeEvent& xev) {
679 ui::EventType type = ui::EventTypeFromNative(xev);
680 if (type == ui::ET_TOUCH_CANCELLED ||
681 type == ui::ET_TOUCH_RELEASED) {
682 ui::TouchFactory* factory = ui::TouchFactory::GetInstance();
683 ui::DeviceDataManagerX11* manager = ui::DeviceDataManagerX11::GetInstance();
684 double tracking_id;
685 if (manager->GetEventData(
686 *xev, ui::DeviceDataManagerX11::DT_TOUCH_TRACKING_ID, &tracking_id)) {
687 factory->ReleaseSlotForTrackingID(tracking_id);
692 int GetTouchId(const base::NativeEvent& xev) {
693 double slot = 0;
694 ui::DeviceDataManagerX11* manager = ui::DeviceDataManagerX11::GetInstance();
695 double tracking_id;
696 if (!manager->GetEventData(
697 *xev, ui::DeviceDataManagerX11::DT_TOUCH_TRACKING_ID, &tracking_id)) {
698 LOG(ERROR) << "Could not get the tracking ID for the event. Using 0.";
699 } else {
700 ui::TouchFactory* factory = ui::TouchFactory::GetInstance();
701 slot = factory->GetSlotForTrackingID(tracking_id);
703 return slot;
706 float GetTouchRadiusX(const base::NativeEvent& native_event) {
707 return GetTouchParamFromXEvent(native_event,
708 ui::DeviceDataManagerX11::DT_TOUCH_MAJOR, 0.0) / 2.0;
711 float GetTouchRadiusY(const base::NativeEvent& native_event) {
712 return GetTouchParamFromXEvent(native_event,
713 ui::DeviceDataManagerX11::DT_TOUCH_MINOR, 0.0) / 2.0;
716 float GetTouchAngle(const base::NativeEvent& native_event) {
717 return GetTouchParamFromXEvent(native_event,
718 ui::DeviceDataManagerX11::DT_TOUCH_ORIENTATION, 0.0) / 2.0;
721 float GetTouchForce(const base::NativeEvent& native_event) {
722 double force = 0.0;
723 force = GetTouchParamFromXEvent(native_event,
724 ui::DeviceDataManagerX11::DT_TOUCH_PRESSURE, 0.0);
725 unsigned int deviceid =
726 static_cast<XIDeviceEvent*>(native_event->xcookie.data)->sourceid;
727 // Force is normalized to fall into [0, 1]
728 if (!ui::DeviceDataManagerX11::GetInstance()->NormalizeData(
729 deviceid, ui::DeviceDataManagerX11::DT_TOUCH_PRESSURE, &force))
730 force = 0.0;
731 return force;
734 bool GetScrollOffsets(const base::NativeEvent& native_event,
735 float* x_offset,
736 float* y_offset,
737 float* x_offset_ordinal,
738 float* y_offset_ordinal,
739 int* finger_count) {
740 if (!DeviceDataManagerX11::GetInstance()->IsScrollEvent(native_event))
741 return false;
743 // Temp values to prevent passing NULLs to DeviceDataManager.
744 float x_offset_, y_offset_;
745 float x_offset_ordinal_, y_offset_ordinal_;
746 int finger_count_;
747 if (!x_offset)
748 x_offset = &x_offset_;
749 if (!y_offset)
750 y_offset = &y_offset_;
751 if (!x_offset_ordinal)
752 x_offset_ordinal = &x_offset_ordinal_;
753 if (!y_offset_ordinal)
754 y_offset_ordinal = &y_offset_ordinal_;
755 if (!finger_count)
756 finger_count = &finger_count_;
758 DeviceDataManagerX11::GetInstance()->GetScrollOffsets(
759 native_event,
760 x_offset, y_offset,
761 x_offset_ordinal, y_offset_ordinal,
762 finger_count);
763 return true;
766 bool GetFlingData(const base::NativeEvent& native_event,
767 float* vx,
768 float* vy,
769 float* vx_ordinal,
770 float* vy_ordinal,
771 bool* is_cancel) {
772 if (!DeviceDataManagerX11::GetInstance()->IsFlingEvent(native_event))
773 return false;
775 float vx_, vy_;
776 float vx_ordinal_, vy_ordinal_;
777 bool is_cancel_;
778 if (!vx)
779 vx = &vx_;
780 if (!vy)
781 vy = &vy_;
782 if (!vx_ordinal)
783 vx_ordinal = &vx_ordinal_;
784 if (!vy_ordinal)
785 vy_ordinal = &vy_ordinal_;
786 if (!is_cancel)
787 is_cancel = &is_cancel_;
789 DeviceDataManagerX11::GetInstance()->GetFlingData(
790 native_event, vx, vy, vx_ordinal, vy_ordinal, is_cancel);
791 return true;
794 bool GetGestureTimes(const base::NativeEvent& native_event,
795 double* start_time,
796 double* end_time) {
797 if (!DeviceDataManagerX11::GetInstance()->HasGestureTimes(native_event))
798 return false;
800 double start_time_, end_time_;
801 if (!start_time)
802 start_time = &start_time_;
803 if (!end_time)
804 end_time = &end_time_;
806 DeviceDataManagerX11::GetInstance()->GetGestureTimes(
807 native_event, start_time, end_time);
808 return true;
811 } // namespace ui