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