- add sources.
[platform/framework/web/crosswalk.git] / src / ui / events / x / events_x.cc
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 <string.h>
8 #include <X11/extensions/XInput.h>
9 #include <X11/extensions/XInput2.h>
10 #include <X11/Xlib.h>
11
12 #include "base/logging.h"
13 #include "base/memory/singleton.h"
14 #include "base/message_loop/message_pump_x11.h"
15 #include "ui/events/event_utils.h"
16 #include "ui/events/keycodes/keyboard_code_conversion_x.h"
17 #include "ui/events/x/device_data_manager.h"
18 #include "ui/events/x/device_list_cache_x.h"
19 #include "ui/events/x/touch_factory_x11.h"
20 #include "ui/gfx/display.h"
21 #include "ui/gfx/point.h"
22 #include "ui/gfx/rect.h"
23 #include "ui/gfx/screen.h"
24 #include "ui/gfx/x/x11_atom_cache.h"
25 #include "ui/gfx/x/x11_types.h"
26
27 namespace {
28
29 // Scroll amount for each wheelscroll event. 53 is also the value used for GTK+.
30 const int kWheelScrollAmount = 53;
31
32 const int kMinWheelButton = 4;
33 const int kMaxWheelButton = 7;
34
35 // A class to track current modifier state on master device. Only track ctrl,
36 // alt, shift and caps lock keys currently. The tracked state can then be used
37 // by floating device.
38 class XModifierStateWatcher{
39  public:
40   static XModifierStateWatcher* GetInstance() {
41     return Singleton<XModifierStateWatcher>::get();
42   }
43
44   void UpdateStateFromEvent(const base::NativeEvent& native_event) {
45     // Floating device can't access the modifer state from master device.
46     // We need to track the states of modifier keys in a singleton for
47     // floating devices such as touch screen. Issue 106426 is one example
48     // of why we need the modifier states for floating device.
49     state_ = native_event->xkey.state;
50     // master_state is the state before key press. We need to track the
51     // state after key press for floating device. Currently only ctrl,
52     // shift, alt and caps lock keys are tracked.
53     ui::KeyboardCode keyboard_code = ui::KeyboardCodeFromNative(native_event);
54     unsigned int mask = 0;
55
56     switch (keyboard_code) {
57       case ui::VKEY_CONTROL: {
58         mask = ControlMask;
59         break;
60       }
61       case ui::VKEY_SHIFT: {
62         mask = ShiftMask;
63         break;
64       }
65       case ui::VKEY_MENU: {
66         mask = Mod1Mask;
67         break;
68       }
69       case ui::VKEY_CAPITAL: {
70         mask = LockMask;
71         break;
72       }
73       default:
74         break;
75     }
76
77     if (native_event->type == KeyPress)
78       state_ |= mask;
79     else
80       state_ &= ~mask;
81   }
82
83   // Returns the current modifer state in master device. It only contains the
84   // state of ctrl, shift, alt and caps lock keys.
85   unsigned int state() { return state_; }
86
87  private:
88   friend struct DefaultSingletonTraits<XModifierStateWatcher>;
89
90   XModifierStateWatcher() : state_(0) { }
91
92   unsigned int state_;
93
94   DISALLOW_COPY_AND_ASSIGN(XModifierStateWatcher);
95 };
96
97 #if defined(USE_XI2_MT)
98 // Detects if a touch event is a driver-generated 'special event'.
99 // A 'special event' is a touch event with maximum radius and pressure at
100 // location (0, 0).
101 // This needs to be done in a cleaner way: http://crbug.com/169256
102 bool TouchEventIsGeneratedHack(const base::NativeEvent& native_event) {
103   XIDeviceEvent* event =
104       static_cast<XIDeviceEvent*>(native_event->xcookie.data);
105   CHECK(event->evtype == XI_TouchBegin ||
106         event->evtype == XI_TouchUpdate ||
107         event->evtype == XI_TouchEnd);
108
109   // Force is normalized to [0, 1].
110   if (ui::GetTouchForce(native_event) < 1.0f)
111     return false;
112
113   if (ui::EventLocationFromNative(native_event) != gfx::Point())
114     return false;
115
116   // Radius is in pixels, and the valuator is the diameter in pixels.
117   double radius = ui::GetTouchRadiusX(native_event), min, max;
118   unsigned int deviceid =
119       static_cast<XIDeviceEvent*>(native_event->xcookie.data)->sourceid;
120   if (!ui::DeviceDataManager::GetInstance()->GetDataRange(
121       deviceid, ui::DeviceDataManager::DT_TOUCH_MAJOR, &min, &max)) {
122     return false;
123   }
124
125   return radius * 2 == max;
126 }
127 #endif
128
129 int GetEventFlagsFromXState(unsigned int state) {
130   int flags = 0;
131   if (state & ControlMask)
132     flags |= ui::EF_CONTROL_DOWN;
133   if (state & ShiftMask)
134     flags |= ui::EF_SHIFT_DOWN;
135   if (state & Mod1Mask)
136     flags |= ui::EF_ALT_DOWN;
137   if (state & LockMask)
138     flags |= ui::EF_CAPS_LOCK_DOWN;
139   if (state & Mod5Mask)
140     flags |= ui::EF_ALTGR_DOWN;
141   if (state & Button1Mask)
142     flags |= ui::EF_LEFT_MOUSE_BUTTON;
143   if (state & Button2Mask)
144     flags |= ui::EF_MIDDLE_MOUSE_BUTTON;
145   if (state & Button3Mask)
146     flags |= ui::EF_RIGHT_MOUSE_BUTTON;
147   return flags;
148 }
149
150 // Get the event flag for the button in XButtonEvent. During a ButtonPress
151 // event, |state| in XButtonEvent does not include the button that has just been
152 // pressed. Instead |state| contains flags for the buttons (if any) that had
153 // already been pressed before the current button, and |button| stores the most
154 // current pressed button. So, if you press down left mouse button, and while
155 // pressing it down, press down the right mouse button, then for the latter
156 // event, |state| would have Button1Mask set but not Button3Mask, and |button|
157 // would be 3.
158 int GetEventFlagsForButton(int button) {
159   switch (button) {
160     case 1:
161       return ui::EF_LEFT_MOUSE_BUTTON;
162     case 2:
163       return ui::EF_MIDDLE_MOUSE_BUTTON;
164     case 3:
165       return ui::EF_RIGHT_MOUSE_BUTTON;
166     default:
167       return 0;
168   }
169 }
170
171 int GetButtonMaskForX2Event(XIDeviceEvent* xievent) {
172   int buttonflags = 0;
173   for (int i = 0; i < 8 * xievent->buttons.mask_len; i++) {
174     if (XIMaskIsSet(xievent->buttons.mask, i)) {
175       int button = (xievent->sourceid == xievent->deviceid) ?
176                    ui::DeviceDataManager::GetInstance()->GetMappedButton(i) : i;
177       buttonflags |= GetEventFlagsForButton(button);
178     }
179   }
180   return buttonflags;
181 }
182
183 ui::EventType GetTouchEventType(const base::NativeEvent& native_event) {
184   XIDeviceEvent* event =
185       static_cast<XIDeviceEvent*>(native_event->xcookie.data);
186 #if defined(USE_XI2_MT)
187   switch(event->evtype) {
188     case XI_TouchBegin:
189       return TouchEventIsGeneratedHack(native_event) ? ui::ET_UNKNOWN :
190                                                        ui::ET_TOUCH_PRESSED;
191     case XI_TouchUpdate:
192       return TouchEventIsGeneratedHack(native_event) ? ui::ET_UNKNOWN :
193                                                        ui::ET_TOUCH_MOVED;
194     case XI_TouchEnd:
195       return TouchEventIsGeneratedHack(native_event) ? ui::ET_TOUCH_CANCELLED :
196                                                        ui::ET_TOUCH_RELEASED;
197   }
198
199   return ui::ET_UNKNOWN;
200 #else
201   ui::TouchFactory* factory = ui::TouchFactory::GetInstance();
202
203   // If this device doesn't support multi-touch, then just use the normal
204   // pressed/release events to indicate touch start/end.  With multi-touch,
205   // these events are sent only for the first (pressed) or last (released)
206   // touch point, and so we must infer start/end from motion events.
207   if (!factory->IsMultiTouchDevice(event->sourceid)) {
208     switch (event->evtype) {
209       case XI_ButtonPress:
210         return ui::ET_TOUCH_PRESSED;
211       case XI_ButtonRelease:
212         return ui::ET_TOUCH_RELEASED;
213       case XI_Motion:
214         if (GetButtonMaskForX2Event(event))
215           return ui::ET_TOUCH_MOVED;
216         return ui::ET_UNKNOWN;
217       default:
218         NOTREACHED();
219     }
220   }
221
222   DCHECK_EQ(event->evtype, XI_Motion);
223
224   // Note: We will not generate a _STATIONARY event here. It will be created,
225   // when necessary, by a RWHVV.
226   // TODO(sad): When should _CANCELLED be generated?
227
228   ui::DeviceDataManager* manager = ui::DeviceDataManager::GetInstance();
229
230   double slot;
231   if (!manager->GetEventData(
232       *native_event, ui::DeviceDataManager::DT_TOUCH_SLOT_ID, &slot))
233     return ui::ET_UNKNOWN;
234
235   if (!factory->IsSlotUsed(slot)) {
236     // This is a new touch point.
237     return ui::ET_TOUCH_PRESSED;
238   }
239
240   double tracking;
241   if (!manager->GetEventData(
242       *native_event, ui::DeviceDataManager::DT_TOUCH_TRACKING_ID, &tracking))
243     return ui::ET_UNKNOWN;
244
245   if (tracking == 0l) {
246     // The touch point has been released.
247     return ui::ET_TOUCH_RELEASED;
248   }
249
250   return ui::ET_TOUCH_MOVED;
251 #endif  // defined(USE_XI2_MT)
252 }
253
254 double GetTouchParamFromXEvent(XEvent* xev,
255                               ui::DeviceDataManager::DataType val,
256                               double default_value) {
257   ui::DeviceDataManager::GetInstance()->GetEventData(
258       *xev, val, &default_value);
259   return default_value;
260 }
261
262 Atom GetNoopEventAtom() {
263   return XInternAtom(gfx::GetXDisplay(), "noop", False);
264 }
265
266 }  // namespace
267
268 namespace ui {
269
270 void UpdateDeviceList() {
271   XDisplay* display = gfx::GetXDisplay();
272   DeviceListCacheX::GetInstance()->UpdateDeviceList(display);
273   TouchFactory::GetInstance()->UpdateDeviceList(display);
274   DeviceDataManager::GetInstance()->UpdateDeviceList(display);
275 }
276
277 EventType EventTypeFromNative(const base::NativeEvent& native_event) {
278   switch (native_event->type) {
279     case KeyPress:
280       return ET_KEY_PRESSED;
281     case KeyRelease:
282       return ET_KEY_RELEASED;
283     case ButtonPress:
284       if (static_cast<int>(native_event->xbutton.button) >= kMinWheelButton &&
285           static_cast<int>(native_event->xbutton.button) <= kMaxWheelButton)
286         return ET_MOUSEWHEEL;
287       return ET_MOUSE_PRESSED;
288     case ButtonRelease:
289       // Drop wheel events; we should've already scrolled on the press.
290       if (static_cast<int>(native_event->xbutton.button) >= kMinWheelButton &&
291           static_cast<int>(native_event->xbutton.button) <= kMaxWheelButton)
292         return ET_UNKNOWN;
293       return ET_MOUSE_RELEASED;
294     case MotionNotify:
295       if (native_event->xmotion.state &
296           (Button1Mask | Button2Mask | Button3Mask))
297         return ET_MOUSE_DRAGGED;
298       return ET_MOUSE_MOVED;
299     case EnterNotify:
300       // The standard on Windows is to send a MouseMove event when the mouse
301       // first enters a window instead of sending a special mouse enter event.
302       // To be consistent we follow the same style.
303       return ET_MOUSE_MOVED;
304     case LeaveNotify:
305       return ET_MOUSE_EXITED;
306     case GenericEvent: {
307       TouchFactory* factory = TouchFactory::GetInstance();
308       if (!factory->ShouldProcessXI2Event(native_event))
309         return ET_UNKNOWN;
310
311       XIDeviceEvent* xievent =
312           static_cast<XIDeviceEvent*>(native_event->xcookie.data);
313
314       if (factory->IsTouchDevice(xievent->sourceid))
315         return GetTouchEventType(native_event);
316
317       switch (xievent->evtype) {
318         case XI_ButtonPress: {
319           int button = EventButtonFromNative(native_event);
320           if (button >= kMinWheelButton && button <= kMaxWheelButton)
321             return ET_MOUSEWHEEL;
322           return ET_MOUSE_PRESSED;
323         }
324         case XI_ButtonRelease: {
325           int button = EventButtonFromNative(native_event);
326           // Drop wheel events; we should've already scrolled on the press.
327           if (button >= kMinWheelButton && button <= kMaxWheelButton)
328             return ET_UNKNOWN;
329           return ET_MOUSE_RELEASED;
330         }
331         case XI_Motion: {
332           bool is_cancel;
333           if (GetFlingData(native_event, NULL, NULL, NULL, NULL, &is_cancel)) {
334             return is_cancel ? ET_SCROLL_FLING_CANCEL : ET_SCROLL_FLING_START;
335           } else if (DeviceDataManager::GetInstance()->IsScrollEvent(
336               native_event)) {
337             return IsTouchpadEvent(native_event) ? ET_SCROLL : ET_MOUSEWHEEL;
338           } else if (DeviceDataManager::GetInstance()->IsCMTMetricsEvent(
339               native_event)) {
340             return ET_UMA_DATA;
341           } else if (GetButtonMaskForX2Event(xievent)) {
342             return ET_MOUSE_DRAGGED;
343           } else {
344             return ET_MOUSE_MOVED;
345           }
346         }
347       }
348     }
349     default:
350       break;
351   }
352   return ET_UNKNOWN;
353 }
354
355 int EventFlagsFromNative(const base::NativeEvent& native_event) {
356   switch (native_event->type) {
357     case KeyPress:
358     case KeyRelease: {
359       XModifierStateWatcher::GetInstance()->UpdateStateFromEvent(native_event);
360       return GetEventFlagsFromXState(native_event->xkey.state);
361     }
362     case ButtonPress:
363     case ButtonRelease: {
364       int flags = GetEventFlagsFromXState(native_event->xbutton.state);
365       const EventType type = EventTypeFromNative(native_event);
366       if (type == ET_MOUSE_PRESSED || type == ET_MOUSE_RELEASED)
367         flags |= GetEventFlagsForButton(native_event->xbutton.button);
368       return flags;
369     }
370     case MotionNotify:
371       return GetEventFlagsFromXState(native_event->xmotion.state);
372     case GenericEvent: {
373       XIDeviceEvent* xievent =
374           static_cast<XIDeviceEvent*>(native_event->xcookie.data);
375
376       switch (xievent->evtype) {
377 #if defined(USE_XI2_MT)
378         case XI_TouchBegin:
379         case XI_TouchUpdate:
380         case XI_TouchEnd:
381           return GetButtonMaskForX2Event(xievent) |
382                  GetEventFlagsFromXState(xievent->mods.effective) |
383                  GetEventFlagsFromXState(
384                      XModifierStateWatcher::GetInstance()->state());
385           break;
386 #endif
387         case XI_ButtonPress:
388         case XI_ButtonRelease: {
389           const bool touch =
390               TouchFactory::GetInstance()->IsTouchDevice(xievent->sourceid);
391           int flags = GetButtonMaskForX2Event(xievent) |
392               GetEventFlagsFromXState(xievent->mods.effective);
393           if (touch) {
394             flags |= GetEventFlagsFromXState(
395                 XModifierStateWatcher::GetInstance()->state());
396           }
397
398           const EventType type = EventTypeFromNative(native_event);
399           int button = EventButtonFromNative(native_event);
400           if ((type == ET_MOUSE_PRESSED || type == ET_MOUSE_RELEASED) && !touch)
401             flags |= GetEventFlagsForButton(button);
402           return flags;
403         }
404         case XI_Motion:
405            return GetButtonMaskForX2Event(xievent) |
406                   GetEventFlagsFromXState(xievent->mods.effective);
407       }
408     }
409   }
410   return 0;
411 }
412
413 base::TimeDelta EventTimeFromNative(const base::NativeEvent& native_event) {
414   switch(native_event->type) {
415     case KeyPress:
416     case KeyRelease:
417       return base::TimeDelta::FromMilliseconds(native_event->xkey.time);
418     case ButtonPress:
419     case ButtonRelease:
420       return base::TimeDelta::FromMilliseconds(native_event->xbutton.time);
421       break;
422     case MotionNotify:
423       return base::TimeDelta::FromMilliseconds(native_event->xmotion.time);
424       break;
425     case EnterNotify:
426     case LeaveNotify:
427       return base::TimeDelta::FromMilliseconds(native_event->xcrossing.time);
428       break;
429     case GenericEvent: {
430       double start, end;
431       double touch_timestamp;
432       if (GetGestureTimes(native_event, &start, &end)) {
433         // If the driver supports gesture times, use them.
434         return base::TimeDelta::FromMicroseconds(end * 1000000);
435       } else if (DeviceDataManager::GetInstance()->GetEventData(*native_event,
436                  DeviceDataManager::DT_TOUCH_RAW_TIMESTAMP, &touch_timestamp)) {
437         return base::TimeDelta::FromMicroseconds(touch_timestamp * 1000000);
438       } else {
439         XIDeviceEvent* xide =
440             static_cast<XIDeviceEvent*>(native_event->xcookie.data);
441         return base::TimeDelta::FromMilliseconds(xide->time);
442       }
443       break;
444     }
445   }
446   NOTREACHED();
447   return base::TimeDelta();
448 }
449
450 gfx::Point EventLocationFromNative(const base::NativeEvent& native_event) {
451   switch (native_event->type) {
452     case EnterNotify:
453     case LeaveNotify:
454       return gfx::Point(native_event->xcrossing.x, native_event->xcrossing.y);
455     case ButtonPress:
456     case ButtonRelease:
457       return gfx::Point(native_event->xbutton.x, native_event->xbutton.y);
458     case MotionNotify:
459       return gfx::Point(native_event->xmotion.x, native_event->xmotion.y);
460     case GenericEvent: {
461       XIDeviceEvent* xievent =
462           static_cast<XIDeviceEvent*>(native_event->xcookie.data);
463       return gfx::Point(static_cast<int>(xievent->event_x),
464                         static_cast<int>(xievent->event_y));
465     }
466   }
467   return gfx::Point();
468 }
469
470 gfx::Point EventSystemLocationFromNative(
471     const base::NativeEvent& native_event) {
472   switch (native_event->type) {
473     case EnterNotify:
474     case LeaveNotify: {
475       return gfx::Point(native_event->xcrossing.x_root,
476                         native_event->xcrossing.y_root);
477     }
478     case ButtonPress:
479     case ButtonRelease: {
480       return gfx::Point(native_event->xbutton.x_root,
481                         native_event->xbutton.y_root);
482     }
483     case MotionNotify: {
484       return gfx::Point(native_event->xmotion.x_root,
485                         native_event->xmotion.y_root);
486     }
487     case GenericEvent: {
488       XIDeviceEvent* xievent =
489           static_cast<XIDeviceEvent*>(native_event->xcookie.data);
490       return gfx::Point(xievent->root_x, xievent->root_y);
491     }
492   }
493
494   return gfx::Point();
495 }
496
497 int EventButtonFromNative(const base::NativeEvent& native_event) {
498   CHECK_EQ(GenericEvent, native_event->type);
499   XIDeviceEvent* xievent =
500       static_cast<XIDeviceEvent*>(native_event->xcookie.data);
501   int button = xievent->detail;
502
503   return (xievent->sourceid == xievent->deviceid) ?
504          DeviceDataManager::GetInstance()->GetMappedButton(button) : button;
505 }
506
507 KeyboardCode KeyboardCodeFromNative(const base::NativeEvent& native_event) {
508   return KeyboardCodeFromXKeyEvent(native_event);
509 }
510
511 bool IsMouseEvent(const base::NativeEvent& native_event) {
512   if (native_event->type == EnterNotify ||
513       native_event->type == LeaveNotify ||
514       native_event->type == ButtonPress ||
515       native_event->type == ButtonRelease ||
516       native_event->type == MotionNotify)
517     return true;
518   if (native_event->type == GenericEvent) {
519     XIDeviceEvent* xievent =
520         static_cast<XIDeviceEvent*>(native_event->xcookie.data);
521     return xievent->evtype == XI_ButtonPress ||
522            xievent->evtype == XI_ButtonRelease ||
523            xievent->evtype == XI_Motion;
524   }
525   return false;
526 }
527
528 int GetChangedMouseButtonFlagsFromNative(
529     const base::NativeEvent& native_event) {
530   switch (native_event->type) {
531     case ButtonPress:
532     case ButtonRelease:
533       return GetEventFlagsFromXState(native_event->xbutton.state);
534     case GenericEvent: {
535       XIDeviceEvent* xievent =
536           static_cast<XIDeviceEvent*>(native_event->xcookie.data);
537       switch (xievent->evtype) {
538         case XI_ButtonPress:
539         case XI_ButtonRelease:
540           return GetEventFlagsForButton(EventButtonFromNative(native_event));
541         default:
542           break;
543       }
544     }
545     default:
546       break;
547   }
548   return 0;
549 }
550
551 gfx::Vector2d GetMouseWheelOffset(const base::NativeEvent& native_event) {
552   float x_offset, y_offset;
553   if (GetScrollOffsets(
554       native_event, &x_offset, &y_offset, NULL, NULL, NULL)) {
555     return gfx::Vector2d(static_cast<int>(x_offset),
556                          static_cast<int>(y_offset));
557   }
558
559   int button = native_event->type == GenericEvent ?
560       EventButtonFromNative(native_event) : native_event->xbutton.button;
561
562   switch (button) {
563     case 4:
564       return gfx::Vector2d(0, kWheelScrollAmount);
565     case 5:
566       return gfx::Vector2d(0, -kWheelScrollAmount);
567     default:
568       // TODO(derat): Do something for horizontal scrolls (buttons 6 and 7)?
569       return gfx::Vector2d();
570   }
571 }
572
573 void ClearTouchIdIfReleased(const base::NativeEvent& xev) {
574 #if defined(USE_XI2_MT)
575   ui::EventType type = ui::EventTypeFromNative(xev);
576   if (type == ui::ET_TOUCH_CANCELLED ||
577       type == ui::ET_TOUCH_RELEASED) {
578     ui::TouchFactory* factory = ui::TouchFactory::GetInstance();
579     ui::DeviceDataManager* manager = ui::DeviceDataManager::GetInstance();
580     double tracking_id;
581     if (manager->GetEventData(
582         *xev, ui::DeviceDataManager::DT_TOUCH_TRACKING_ID, &tracking_id)) {
583       factory->ReleaseSlotForTrackingID(tracking_id);
584     }
585   }
586 #endif
587 }
588
589 int GetTouchId(const base::NativeEvent& xev) {
590   double slot = 0;
591   ui::TouchFactory* factory = ui::TouchFactory::GetInstance();
592   XIDeviceEvent* xievent = static_cast<XIDeviceEvent*>(xev->xcookie.data);
593 #if defined(ENABLE_XI21_MT)
594   // If using XInput2.1 for multi-touch support, the slot is tracked by the
595   // source id of each device event.
596   slot = xievent->sourceid;
597 #endif
598   if (!factory->IsMultiTouchDevice(xievent->sourceid)) {
599     // TODO(sad): Come up with a way to generate touch-ids for multi-touch
600     // events when touch-events are generated from a single-touch device.
601     return slot;
602   }
603
604   ui::DeviceDataManager* manager = ui::DeviceDataManager::GetInstance();
605
606 #if defined(USE_XI2_MT)
607   double tracking_id;
608   if (!manager->GetEventData(
609       *xev, ui::DeviceDataManager::DT_TOUCH_TRACKING_ID, &tracking_id)) {
610     LOG(ERROR) << "Could not get the tracking ID for the event. Using 0.";
611   } else {
612     slot = factory->GetSlotForTrackingID(tracking_id);
613   }
614 #else
615   if (!manager->GetEventData(
616       *xev, ui::DeviceDataManager::DT_TOUCH_SLOT_ID, &slot))
617     LOG(ERROR) << "Could not get the slot ID for the event. Using 0.";
618 #endif
619   return slot;
620 }
621
622 float GetTouchRadiusX(const base::NativeEvent& native_event) {
623   return GetTouchParamFromXEvent(native_event,
624       ui::DeviceDataManager::DT_TOUCH_MAJOR, 0.0) / 2.0;
625 }
626
627 float GetTouchRadiusY(const base::NativeEvent& native_event) {
628   return GetTouchParamFromXEvent(native_event,
629       ui::DeviceDataManager::DT_TOUCH_MINOR, 0.0) / 2.0;
630 }
631
632 float GetTouchAngle(const base::NativeEvent& native_event) {
633   return GetTouchParamFromXEvent(native_event,
634       ui::DeviceDataManager::DT_TOUCH_ORIENTATION, 0.0) / 2.0;
635 }
636
637 float GetTouchForce(const base::NativeEvent& native_event) {
638   double force = 0.0;
639   force = GetTouchParamFromXEvent(native_event,
640       ui::DeviceDataManager::DT_TOUCH_PRESSURE, 0.0);
641   unsigned int deviceid =
642       static_cast<XIDeviceEvent*>(native_event->xcookie.data)->sourceid;
643   // Force is normalized to fall into [0, 1]
644   if (!ui::DeviceDataManager::GetInstance()->NormalizeData(
645       deviceid, ui::DeviceDataManager::DT_TOUCH_PRESSURE, &force))
646     force = 0.0;
647   return force;
648 }
649
650 bool GetScrollOffsets(const base::NativeEvent& native_event,
651                       float* x_offset,
652                       float* y_offset,
653                       float* x_offset_ordinal,
654                       float* y_offset_ordinal,
655                       int* finger_count) {
656   if (!DeviceDataManager::GetInstance()->IsScrollEvent(native_event))
657     return false;
658
659   // Temp values to prevent passing NULLs to DeviceDataManager.
660   float x_offset_, y_offset_;
661   float x_offset_ordinal_, y_offset_ordinal_;
662   int finger_count_;
663   if (!x_offset)
664     x_offset = &x_offset_;
665   if (!y_offset)
666     y_offset = &y_offset_;
667   if (!x_offset_ordinal)
668     x_offset_ordinal = &x_offset_ordinal_;
669   if (!y_offset_ordinal)
670     y_offset_ordinal = &y_offset_ordinal_;
671   if (!finger_count)
672     finger_count = &finger_count_;
673
674   DeviceDataManager::GetInstance()->GetScrollOffsets(
675       native_event,
676       x_offset, y_offset,
677       x_offset_ordinal, y_offset_ordinal,
678       finger_count);
679   return true;
680 }
681
682 bool GetFlingData(const base::NativeEvent& native_event,
683                   float* vx,
684                   float* vy,
685                   float* vx_ordinal,
686                   float* vy_ordinal,
687                   bool* is_cancel) {
688   if (!DeviceDataManager::GetInstance()->IsFlingEvent(native_event))
689     return false;
690
691   float vx_, vy_;
692   float vx_ordinal_, vy_ordinal_;
693   bool is_cancel_;
694   if (!vx)
695     vx = &vx_;
696   if (!vy)
697     vy = &vy_;
698   if (!vx_ordinal)
699     vx_ordinal = &vx_ordinal_;
700   if (!vy_ordinal)
701     vy_ordinal = &vy_ordinal_;
702   if (!is_cancel)
703     is_cancel = &is_cancel_;
704
705   DeviceDataManager::GetInstance()->GetFlingData(
706       native_event, vx, vy, vx_ordinal, vy_ordinal, is_cancel);
707   return true;
708 }
709
710 bool GetGestureTimes(const base::NativeEvent& native_event,
711                      double* start_time,
712                      double* end_time) {
713   if (!DeviceDataManager::GetInstance()->HasGestureTimes(native_event))
714     return false;
715
716   double start_time_, end_time_;
717   if (!start_time)
718     start_time = &start_time_;
719   if (!end_time)
720     end_time = &end_time_;
721
722   DeviceDataManager::GetInstance()->GetGestureTimes(
723       native_event, start_time, end_time);
724   return true;
725 }
726
727 void SetNaturalScroll(bool enabled) {
728   DeviceDataManager::GetInstance()->set_natural_scroll_enabled(enabled);
729 }
730
731 bool IsNaturalScrollEnabled() {
732   return DeviceDataManager::GetInstance()->natural_scroll_enabled();
733 }
734
735 bool IsTouchpadEvent(const base::NativeEvent& event) {
736   return DeviceDataManager::GetInstance()->IsTouchpadXInputEvent(event);
737 }
738
739 bool IsNoopEvent(const base::NativeEvent& event) {
740   return (event->type == ClientMessage &&
741       event->xclient.message_type == GetNoopEventAtom());
742 }
743
744 base::NativeEvent CreateNoopEvent() {
745   static XEvent* noop = NULL;
746   if (!noop) {
747     noop = new XEvent();
748     memset(noop, 0, sizeof(XEvent));
749     noop->xclient.type = ClientMessage;
750     noop->xclient.window = None;
751     noop->xclient.format = 8;
752     DCHECK(!noop->xclient.display);
753   }
754   // Make sure we use atom from current xdisplay, which may
755   // change during the test.
756   noop->xclient.message_type = GetNoopEventAtom();
757   return noop;
758 }
759
760 }  // namespace ui