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