Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / ui / events / x / events_x.cc
index 4359f43..371c8f5 100644 (file)
@@ -4,17 +4,20 @@
 
 #include "ui/events/event_constants.h"
 
+#include <cmath>
 #include <string.h>
 #include <X11/extensions/XInput.h>
 #include <X11/extensions/XInput2.h>
 #include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/XKBlib.h>
 
 #include "base/logging.h"
 #include "base/memory/singleton.h"
-#include "base/message_loop/message_pump_x11.h"
+#include "ui/events/event.h"
 #include "ui/events/event_utils.h"
 #include "ui/events/keycodes/keyboard_code_conversion_x.h"
-#include "ui/events/x/device_data_manager.h"
+#include "ui/events/x/device_data_manager_x11.h"
 #include "ui/events/x/device_list_cache_x.h"
 #include "ui/events/x/touch_factory_x11.h"
 #include "ui/gfx/display.h"
@@ -41,43 +44,55 @@ class XModifierStateWatcher{
     return Singleton<XModifierStateWatcher>::get();
   }
 
-  void UpdateStateFromEvent(const base::NativeEvent& native_event) {
+  int StateFromKeyboardCode(ui::KeyboardCode keyboard_code) {
+    switch (keyboard_code) {
+      case ui::VKEY_CONTROL:
+        return ControlMask;
+      case ui::VKEY_SHIFT:
+        return ShiftMask;
+      case ui::VKEY_MENU:
+        return Mod1Mask;
+      case ui::VKEY_CAPITAL:
+        return LockMask;
+      default:
+        return 0;
+    }
+  }
+
+  void UpdateStateFromXEvent(const base::NativeEvent& native_event) {
+    ui::KeyboardCode keyboard_code = ui::KeyboardCodeFromNative(native_event);
+    unsigned int mask = StateFromKeyboardCode(keyboard_code);
     // Floating device can't access the modifer state from master device.
     // We need to track the states of modifier keys in a singleton for
     // floating devices such as touch screen. Issue 106426 is one example
     // of why we need the modifier states for floating device.
-    state_ = native_event->xkey.state;
-    // master_state is the state before key press. We need to track the
-    // state after key press for floating device. Currently only ctrl,
-    // shift, alt and caps lock keys are tracked.
-    ui::KeyboardCode keyboard_code = ui::KeyboardCodeFromNative(native_event);
-    unsigned int mask = 0;
-
-    switch (keyboard_code) {
-      case ui::VKEY_CONTROL: {
-        mask = ControlMask;
+    switch (native_event->type) {
+      case KeyPress:
+        state_ = native_event->xkey.state | mask;
         break;
-      }
-      case ui::VKEY_SHIFT: {
-        mask = ShiftMask;
-        break;
-      }
-      case ui::VKEY_MENU: {
-        mask = Mod1Mask;
+      case KeyRelease:
+        state_ = native_event->xkey.state & ~mask;
         break;
-      }
-      case ui::VKEY_CAPITAL: {
-        mask = LockMask;
+      case GenericEvent: {
+        XIDeviceEvent* xievent =
+            static_cast<XIDeviceEvent*>(native_event->xcookie.data);
+        switch (xievent->evtype) {
+          case XI_KeyPress:
+            state_ = xievent->mods.effective |= mask;
+            break;
+          case XI_KeyRelease:
+            state_ = xievent->mods.effective &= ~mask;
+            break;
+          default:
+            NOTREACHED();
+            break;
+        }
         break;
       }
       default:
+        NOTREACHED();
         break;
     }
-
-    if (native_event->type == KeyPress)
-      state_ |= mask;
-    else
-      state_ &= ~mask;
   }
 
   // Returns the current modifer state in master device. It only contains the
@@ -117,8 +132,8 @@ bool TouchEventIsGeneratedHack(const base::NativeEvent& native_event) {
   double radius = ui::GetTouchRadiusX(native_event), min, max;
   unsigned int deviceid =
       static_cast<XIDeviceEvent*>(native_event->xcookie.data)->sourceid;
-  if (!ui::DeviceDataManager::GetInstance()->GetDataRange(
-      deviceid, ui::DeviceDataManager::DT_TOUCH_MAJOR, &min, &max)) {
+  if (!ui::DeviceDataManagerX11::GetInstance()->GetDataRange(
+      deviceid, ui::DeviceDataManagerX11::DT_TOUCH_MAJOR, &min, &max)) {
     return false;
   }
 
@@ -136,6 +151,10 @@ int GetEventFlagsFromXState(unsigned int state) {
     flags |= ui::EF_ALT_DOWN;
   if (state & LockMask)
     flags |= ui::EF_CAPS_LOCK_DOWN;
+  if (state & Mod3Mask)
+    flags |= ui::EF_MOD3_DOWN;
+  if (state & Mod4Mask)
+    flags |= ui::EF_COMMAND_DOWN;
   if (state & Mod5Mask)
     flags |= ui::EF_ALTGR_DOWN;
   if (state & Button1Mask)
@@ -147,6 +166,50 @@ int GetEventFlagsFromXState(unsigned int state) {
   return flags;
 }
 
+int GetEventFlagsFromXKeyEvent(XEvent* xevent) {
+  DCHECK(xevent->type == KeyPress || xevent->type == KeyRelease);
+
+#if defined(OS_CHROMEOS)
+  const int ime_fabricated_flag = 0;
+#else
+  // XIM fabricates key events for the character compositions by XK_Multi_key.
+  // For example, when a user hits XK_Multi_key, XK_apostrophe, and XK_e in
+  // order to input "é", then XIM generates a key event with keycode=0 and
+  // state=0 for the composition, and the sequence of X11 key events will be
+  // XK_Multi_key, XK_apostrophe, **NoSymbol**, and XK_e.  If the user used
+  // shift key and/or caps lock key, state can be ShiftMask, LockMask or both.
+  //
+  // We have to send these fabricated key events to XIM so it can correctly
+  // handle the character compositions.
+  const unsigned int shift_lock_mask = ShiftMask | LockMask;
+  const bool fabricated_by_xim =
+      xevent->xkey.keycode == 0 &&
+      (xevent->xkey.state & ~shift_lock_mask) == 0;
+  const int ime_fabricated_flag =
+      fabricated_by_xim ? ui::EF_IME_FABRICATED_KEY : 0;
+#endif
+
+  return GetEventFlagsFromXState(xevent->xkey.state) |
+      (xevent->xkey.send_event ? ui::EF_FINAL : 0) |
+      (IsKeypadKey(XLookupKeysym(&xevent->xkey, 0)) ? ui::EF_NUMPAD_KEY : 0) |
+      (IsFunctionKey(XLookupKeysym(&xevent->xkey, 0)) ?
+          ui::EF_FUNCTION_KEY : 0) |
+      ime_fabricated_flag;
+}
+
+int GetEventFlagsFromXGenericEvent(XEvent* xevent) {
+  DCHECK(xevent->type == GenericEvent);
+  XIDeviceEvent* xievent = static_cast<XIDeviceEvent*>(xevent->xcookie.data);
+  DCHECK((xievent->evtype == XI_KeyPress) ||
+         (xievent->evtype == XI_KeyRelease));
+  return GetEventFlagsFromXState(xievent->mods.effective) |
+         (xevent->xkey.send_event ? ui::EF_FINAL : 0) |
+         (IsKeypadKey(
+              XkbKeycodeToKeysym(xievent->display, xievent->detail, 0, 0))
+              ? ui::EF_NUMPAD_KEY
+              : 0);
+}
+
 // Get the event flag for the button in XButtonEvent. During a ButtonPress
 // event, |state| in XButtonEvent does not include the button that has just been
 // pressed. Instead |state| contains flags for the buttons (if any) that had
@@ -173,7 +236,7 @@ int GetButtonMaskForX2Event(XIDeviceEvent* xievent) {
   for (int i = 0; i < 8 * xievent->buttons.mask_len; i++) {
     if (XIMaskIsSet(xievent->buttons.mask, i)) {
       int button = (xievent->sourceid == xievent->deviceid) ?
-                   ui::DeviceDataManager::GetInstance()->GetMappedButton(i) : i;
+          ui::DeviceDataManagerX11::GetInstance()->GetMappedButton(i) : i;
       buttonflags |= GetEventFlagsForButton(button);
     }
   }
@@ -195,72 +258,98 @@ ui::EventType GetTouchEventType(const base::NativeEvent& native_event) {
       return TouchEventIsGeneratedHack(native_event) ? ui::ET_TOUCH_CANCELLED :
                                                        ui::ET_TOUCH_RELEASED;
   }
+#endif  // defined(USE_XI2_MT)
 
-  return ui::ET_UNKNOWN;
-#else
-  ui::TouchFactory* factory = ui::TouchFactory::GetInstance();
-
-  // If this device doesn't support multi-touch, then just use the normal
-  // pressed/release events to indicate touch start/end.  With multi-touch,
-  // these events are sent only for the first (pressed) or last (released)
-  // touch point, and so we must infer start/end from motion events.
-  if (!factory->IsMultiTouchDevice(event->sourceid)) {
-    switch (event->evtype) {
-      case XI_ButtonPress:
-        return ui::ET_TOUCH_PRESSED;
-      case XI_ButtonRelease:
-        return ui::ET_TOUCH_RELEASED;
-      case XI_Motion:
-        if (GetButtonMaskForX2Event(event))
-          return ui::ET_TOUCH_MOVED;
-        return ui::ET_UNKNOWN;
-      default:
-        NOTREACHED();
-    }
-  }
-
-  DCHECK_EQ(event->evtype, XI_Motion);
-
-  // Note: We will not generate a _STATIONARY event here. It will be created,
-  // when necessary, by a RWHVV.
-  // TODO(sad): When should _CANCELLED be generated?
-
-  ui::DeviceDataManager* manager = ui::DeviceDataManager::GetInstance();
-
-  double slot;
-  if (!manager->GetEventData(
-      *native_event, ui::DeviceDataManager::DT_TOUCH_SLOT_ID, &slot))
-    return ui::ET_UNKNOWN;
-
-  if (!factory->IsSlotUsed(slot)) {
-    // This is a new touch point.
-    return ui::ET_TOUCH_PRESSED;
-  }
-
-  double tracking;
-  if (!manager->GetEventData(
-      *native_event, ui::DeviceDataManager::DT_TOUCH_TRACKING_ID, &tracking))
-    return ui::ET_UNKNOWN;
-
-  if (tracking == 0l) {
-    // The touch point has been released.
-    return ui::ET_TOUCH_RELEASED;
+  DCHECK(ui::TouchFactory::GetInstance()->IsTouchDevice(event->sourceid));
+  switch (event->evtype) {
+    case XI_ButtonPress:
+      return ui::ET_TOUCH_PRESSED;
+    case XI_ButtonRelease:
+      return ui::ET_TOUCH_RELEASED;
+    case XI_Motion:
+      // Should not convert any emulated Motion event from touch device to
+      // touch event.
+      if (!(event->flags & XIPointerEmulated) &&
+          GetButtonMaskForX2Event(event))
+        return ui::ET_TOUCH_MOVED;
+      return ui::ET_UNKNOWN;
+    default:
+      NOTREACHED();
   }
-
-  return ui::ET_TOUCH_MOVED;
-#endif  // defined(USE_XI2_MT)
+  return ui::ET_UNKNOWN;
 }
 
 double GetTouchParamFromXEvent(XEvent* xev,
-                              ui::DeviceDataManager::DataType val,
+                              ui::DeviceDataManagerX11::DataType val,
                               double default_value) {
-  ui::DeviceDataManager::GetInstance()->GetEventData(
+  ui::DeviceDataManagerX11::GetInstance()->GetEventData(
       *xev, val, &default_value);
   return default_value;
 }
 
-Atom GetNoopEventAtom() {
-  return XInternAtom(gfx::GetXDisplay(), "noop", False);
+void ScaleTouchRadius(XEvent* xev, double* radius) {
+  DCHECK_EQ(GenericEvent, xev->type);
+  XIDeviceEvent* xiev = static_cast<XIDeviceEvent*>(xev->xcookie.data);
+  ui::DeviceDataManagerX11::GetInstance()->ApplyTouchRadiusScale(
+      xiev->sourceid, radius);
+}
+
+unsigned int UpdateX11EventFlags(int ui_flags, unsigned int old_x_flags) {
+  static struct {
+    int ui;
+    int x;
+  } flags[] = {
+    {ui::EF_CONTROL_DOWN, ControlMask},
+    {ui::EF_SHIFT_DOWN, ShiftMask},
+    {ui::EF_ALT_DOWN, Mod1Mask},
+    {ui::EF_CAPS_LOCK_DOWN, LockMask},
+    {ui::EF_ALTGR_DOWN, Mod5Mask},
+    {ui::EF_COMMAND_DOWN, Mod4Mask},
+    {ui::EF_MOD3_DOWN, Mod3Mask},
+    {ui::EF_NUMPAD_KEY, Mod2Mask},
+    {ui::EF_LEFT_MOUSE_BUTTON, Button1Mask},
+    {ui::EF_MIDDLE_MOUSE_BUTTON, Button2Mask},
+    {ui::EF_RIGHT_MOUSE_BUTTON, Button3Mask},
+  };
+  unsigned int new_x_flags = old_x_flags;
+  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(flags); ++i) {
+    if (ui_flags & flags[i].ui)
+      new_x_flags |= flags[i].x;
+    else
+      new_x_flags &= ~flags[i].x;
+  }
+  return new_x_flags;
+}
+
+unsigned int UpdateX11EventButton(int ui_flag, unsigned int old_x_button) {
+  switch (ui_flag) {
+    case ui::EF_LEFT_MOUSE_BUTTON:
+      return Button1;
+    case ui::EF_MIDDLE_MOUSE_BUTTON:
+      return Button2;
+    case ui::EF_RIGHT_MOUSE_BUTTON:
+      return Button3;
+    default:
+      return old_x_button;
+  }
+  NOTREACHED();
+}
+
+bool GetGestureTimes(const base::NativeEvent& native_event,
+                     double* start_time,
+                     double* end_time) {
+  if (!ui::DeviceDataManagerX11::GetInstance()->HasGestureTimes(native_event))
+    return false;
+
+  double start_time_, end_time_;
+  if (!start_time)
+    start_time = &start_time_;
+  if (!end_time)
+    end_time = &end_time_;
+
+  ui::DeviceDataManagerX11::GetInstance()->GetGestureTimes(
+      native_event, start_time, end_time);
+  return true;
 }
 
 }  // namespace
@@ -271,10 +360,19 @@ void UpdateDeviceList() {
   XDisplay* display = gfx::GetXDisplay();
   DeviceListCacheX::GetInstance()->UpdateDeviceList(display);
   TouchFactory::GetInstance()->UpdateDeviceList(display);
-  DeviceDataManager::GetInstance()->UpdateDeviceList(display);
+  DeviceDataManagerX11::GetInstance()->UpdateDeviceList(display);
 }
 
 EventType EventTypeFromNative(const base::NativeEvent& native_event) {
+  // Allow the DeviceDataManager to block the event. If blocked return
+  // ET_UNKNOWN as the type so this event will not be further processed.
+  // NOTE: During some events unittests there is no device data manager.
+  if (DeviceDataManager::HasInstance() &&
+      static_cast<DeviceDataManagerX11*>(DeviceDataManager::GetInstance())->
+          IsEventBlocked(native_event)) {
+    return ET_UNKNOWN;
+  }
+
   switch (native_event->type) {
     case KeyPress:
       return ET_KEY_PRESSED;
@@ -311,10 +409,19 @@ EventType EventTypeFromNative(const base::NativeEvent& native_event) {
       XIDeviceEvent* xievent =
           static_cast<XIDeviceEvent*>(native_event->xcookie.data);
 
+      // This check works only for master and floating slave devices. That is
+      // why it is necessary to check for the XI_Touch* events in the following
+      // switch statement to account for attached-slave touchscreens.
       if (factory->IsTouchDevice(xievent->sourceid))
         return GetTouchEventType(native_event);
 
       switch (xievent->evtype) {
+        case XI_TouchBegin:
+          return ui::ET_TOUCH_PRESSED;
+        case XI_TouchUpdate:
+          return ui::ET_TOUCH_MOVED;
+        case XI_TouchEnd:
+          return ui::ET_TOUCH_RELEASED;
         case XI_ButtonPress: {
           int button = EventButtonFromNative(native_event);
           if (button >= kMinWheelButton && button <= kMaxWheelButton)
@@ -330,20 +437,23 @@ EventType EventTypeFromNative(const base::NativeEvent& native_event) {
         }
         case XI_Motion: {
           bool is_cancel;
-          if (GetFlingData(native_event, NULL, NULL, NULL, NULL, &is_cancel)) {
+          DeviceDataManagerX11* devices = DeviceDataManagerX11::GetInstance();
+          if (GetFlingData(native_event, NULL, NULL, NULL, NULL, &is_cancel))
             return is_cancel ? ET_SCROLL_FLING_CANCEL : ET_SCROLL_FLING_START;
-          } else if (DeviceDataManager::GetInstance()->IsScrollEvent(
-              native_event)) {
-            return IsTouchpadEvent(native_event) ? ET_SCROLL : ET_MOUSEWHEEL;
-          } else if (DeviceDataManager::GetInstance()->IsCMTMetricsEvent(
-              native_event)) {
+          if (devices->IsScrollEvent(native_event)) {
+            return devices->IsTouchpadXInputEvent(native_event) ? ET_SCROLL
+                                                                : ET_MOUSEWHEEL;
+          }
+          if (devices->IsCMTMetricsEvent(native_event))
             return ET_UMA_DATA;
-          } else if (GetButtonMaskForX2Event(xievent)) {
+          if (GetButtonMaskForX2Event(xievent))
             return ET_MOUSE_DRAGGED;
-          } else {
-            return ET_MOUSE_MOVED;
-          }
+          return ET_MOUSE_MOVED;
         }
+        case XI_KeyPress:
+          return ET_KEY_PRESSED;
+        case XI_KeyRelease:
+          return ET_KEY_RELEASED;
       }
     }
     default:
@@ -356,8 +466,8 @@ int EventFlagsFromNative(const base::NativeEvent& native_event) {
   switch (native_event->type) {
     case KeyPress:
     case KeyRelease: {
-      XModifierStateWatcher::GetInstance()->UpdateStateFromEvent(native_event);
-      return GetEventFlagsFromXState(native_event->xkey.state);
+      XModifierStateWatcher::GetInstance()->UpdateStateFromXEvent(native_event);
+      return GetEventFlagsFromXKeyEvent(native_event);
     }
     case ButtonPress:
     case ButtonRelease: {
@@ -367,6 +477,9 @@ int EventFlagsFromNative(const base::NativeEvent& native_event) {
         flags |= GetEventFlagsForButton(native_event->xbutton.button);
       return flags;
     }
+    case EnterNotify:
+    case LeaveNotify:
+      return GetEventFlagsFromXState(native_event->xcrossing.state);
     case MotionNotify:
       return GetEventFlagsFromXState(native_event->xmotion.state);
     case GenericEvent: {
@@ -389,7 +502,7 @@ int EventFlagsFromNative(const base::NativeEvent& native_event) {
           const bool touch =
               TouchFactory::GetInstance()->IsTouchDevice(xievent->sourceid);
           int flags = GetButtonMaskForX2Event(xievent) |
-              GetEventFlagsFromXState(xievent->mods.effective);
+                      GetEventFlagsFromXState(xievent->mods.effective);
           if (touch) {
             flags |= GetEventFlagsFromXState(
                 XModifierStateWatcher::GetInstance()->state());
@@ -402,8 +515,14 @@ int EventFlagsFromNative(const base::NativeEvent& native_event) {
           return flags;
         }
         case XI_Motion:
-           return GetButtonMaskForX2Event(xievent) |
-                  GetEventFlagsFromXState(xievent->mods.effective);
+          return GetButtonMaskForX2Event(xievent) |
+                 GetEventFlagsFromXState(xievent->mods.effective);
+        case XI_KeyPress:
+        case XI_KeyRelease: {
+          XModifierStateWatcher::GetInstance()->UpdateStateFromXEvent(
+              native_event);
+          return GetEventFlagsFromXGenericEvent(native_event);
+        }
       }
     }
   }
@@ -432,8 +551,10 @@ base::TimeDelta EventTimeFromNative(const base::NativeEvent& native_event) {
       if (GetGestureTimes(native_event, &start, &end)) {
         // If the driver supports gesture times, use them.
         return base::TimeDelta::FromMicroseconds(end * 1000000);
-      } else if (DeviceDataManager::GetInstance()->GetEventData(*native_event,
-                 DeviceDataManager::DT_TOUCH_RAW_TIMESTAMP, &touch_timestamp)) {
+      } else if (DeviceDataManagerX11::GetInstance()->GetEventData(
+          *native_event,
+          DeviceDataManagerX11::DT_TOUCH_RAW_TIMESTAMP,
+          &touch_timestamp)) {
         return base::TimeDelta::FromMicroseconds(touch_timestamp * 1000000);
       } else {
         XIDeviceEvent* xide =
@@ -460,8 +581,21 @@ gfx::Point EventLocationFromNative(const base::NativeEvent& native_event) {
     case GenericEvent: {
       XIDeviceEvent* xievent =
           static_cast<XIDeviceEvent*>(native_event->xcookie.data);
-      return gfx::Point(static_cast<int>(xievent->event_x),
-                        static_cast<int>(xievent->event_y));
+      float x = xievent->event_x;
+      float y = xievent->event_y;
+#if defined(OS_CHROMEOS)
+      switch (xievent->evtype) {
+        case XI_TouchBegin:
+        case XI_TouchUpdate:
+        case XI_TouchEnd:
+          ui::DeviceDataManagerX11::GetInstance()->ApplyTouchTransformer(
+              xievent->deviceid, &x, &y);
+          break;
+        default:
+          break;
+      }
+#endif  // defined(OS_CHROMEOS)
+      return gfx::Point(static_cast<int>(x), static_cast<int>(y));
     }
   }
   return gfx::Point();
@@ -501,27 +635,53 @@ int EventButtonFromNative(const base::NativeEvent& native_event) {
   int button = xievent->detail;
 
   return (xievent->sourceid == xievent->deviceid) ?
-         DeviceDataManager::GetInstance()->GetMappedButton(button) : button;
+         DeviceDataManagerX11::GetInstance()->GetMappedButton(button) : button;
 }
 
 KeyboardCode KeyboardCodeFromNative(const base::NativeEvent& native_event) {
   return KeyboardCodeFromXKeyEvent(native_event);
 }
 
-bool IsMouseEvent(const base::NativeEvent& native_event) {
-  if (native_event->type == EnterNotify ||
-      native_event->type == LeaveNotify ||
-      native_event->type == ButtonPress ||
-      native_event->type == ButtonRelease ||
-      native_event->type == MotionNotify)
-    return true;
-  if (native_event->type == GenericEvent) {
-    XIDeviceEvent* xievent =
-        static_cast<XIDeviceEvent*>(native_event->xcookie.data);
-    return xievent->evtype == XI_ButtonPress ||
-           xievent->evtype == XI_ButtonRelease ||
-           xievent->evtype == XI_Motion;
+const char* CodeFromNative(const base::NativeEvent& native_event) {
+  return CodeFromXEvent(native_event);
+}
+
+uint32 PlatformKeycodeFromNative(const base::NativeEvent& native_event) {
+  XKeyEvent* xkey = NULL;
+  XEvent xkey_from_xi2;
+  switch (native_event->type) {
+    case KeyPress:
+    case KeyRelease:
+      xkey = &native_event->xkey;
+      break;
+    case GenericEvent: {
+      XIDeviceEvent* xievent =
+          static_cast<XIDeviceEvent*>(native_event->xcookie.data);
+      switch (xievent->evtype) {
+        case XI_KeyPress:
+        case XI_KeyRelease:
+          // Build an XKeyEvent corresponding to the XI2 event,
+          // so that we can call XLookupString on it.
+          InitXKeyEventFromXIDeviceEvent(*native_event, &xkey_from_xi2);
+          xkey = &xkey_from_xi2.xkey;
+          break;
+        default:
+          NOTREACHED();
+          break;
+      }
+      break;
+    }
+    default:
+      NOTREACHED();
+      break;
   }
+  KeySym keysym = XK_VoidSymbol;
+  if (xkey)
+    XLookupString(xkey, NULL, 0, &keysym, NULL);
+  return keysym;
+}
+
+bool IsCharFromNative(const base::NativeEvent& native_event) {
   return false;
 }
 
@@ -564,85 +724,95 @@ gfx::Vector2d GetMouseWheelOffset(const base::NativeEvent& native_event) {
       return gfx::Vector2d(0, kWheelScrollAmount);
     case 5:
       return gfx::Vector2d(0, -kWheelScrollAmount);
+    case 6:
+      return gfx::Vector2d(kWheelScrollAmount, 0);
+    case 7:
+      return gfx::Vector2d(-kWheelScrollAmount, 0);
     default:
-      // TODO(derat): Do something for horizontal scrolls (buttons 6 and 7)?
       return gfx::Vector2d();
   }
 }
 
+base::NativeEvent CopyNativeEvent(const base::NativeEvent& event) {
+  if (!event || event->type == GenericEvent)
+    return NULL;
+  XEvent* copy = new XEvent;
+  *copy = *event;
+  return copy;
+}
+
+void ReleaseCopiedNativeEvent(const base::NativeEvent& event) {
+  delete event;
+}
+
+void IncrementTouchIdRefCount(const base::NativeEvent& xev) {
+  ui::DeviceDataManagerX11* manager = ui::DeviceDataManagerX11::GetInstance();
+  double tracking_id;
+  if (!manager->GetEventData(
+          *xev, ui::DeviceDataManagerX11::DT_TOUCH_TRACKING_ID, &tracking_id)) {
+    return;
+  }
+
+  ui::TouchFactory* factory = ui::TouchFactory::GetInstance();
+  factory->AcquireSlotForTrackingID(tracking_id);
+}
+
 void ClearTouchIdIfReleased(const base::NativeEvent& xev) {
-#if defined(USE_XI2_MT)
   ui::EventType type = ui::EventTypeFromNative(xev);
   if (type == ui::ET_TOUCH_CANCELLED ||
       type == ui::ET_TOUCH_RELEASED) {
     ui::TouchFactory* factory = ui::TouchFactory::GetInstance();
-    ui::DeviceDataManager* manager = ui::DeviceDataManager::GetInstance();
+    ui::DeviceDataManagerX11* manager = ui::DeviceDataManagerX11::GetInstance();
     double tracking_id;
     if (manager->GetEventData(
-        *xev, ui::DeviceDataManager::DT_TOUCH_TRACKING_ID, &tracking_id)) {
+        *xev, ui::DeviceDataManagerX11::DT_TOUCH_TRACKING_ID, &tracking_id)) {
       factory->ReleaseSlotForTrackingID(tracking_id);
     }
   }
-#endif
 }
 
 int GetTouchId(const base::NativeEvent& xev) {
   double slot = 0;
-  ui::TouchFactory* factory = ui::TouchFactory::GetInstance();
-  XIDeviceEvent* xievent = static_cast<XIDeviceEvent*>(xev->xcookie.data);
-#if defined(ENABLE_XI21_MT)
-  // If using XInput2.1 for multi-touch support, the slot is tracked by the
-  // source id of each device event.
-  slot = xievent->sourceid;
-#endif
-  if (!factory->IsMultiTouchDevice(xievent->sourceid)) {
-    // TODO(sad): Come up with a way to generate touch-ids for multi-touch
-    // events when touch-events are generated from a single-touch device.
-    return slot;
-  }
-
-  ui::DeviceDataManager* manager = ui::DeviceDataManager::GetInstance();
-
-#if defined(USE_XI2_MT)
+  ui::DeviceDataManagerX11* manager = ui::DeviceDataManagerX11::GetInstance();
   double tracking_id;
   if (!manager->GetEventData(
-      *xev, ui::DeviceDataManager::DT_TOUCH_TRACKING_ID, &tracking_id)) {
+      *xev, ui::DeviceDataManagerX11::DT_TOUCH_TRACKING_ID, &tracking_id)) {
     LOG(ERROR) << "Could not get the tracking ID for the event. Using 0.";
   } else {
+    ui::TouchFactory* factory = ui::TouchFactory::GetInstance();
     slot = factory->GetSlotForTrackingID(tracking_id);
   }
-#else
-  if (!manager->GetEventData(
-      *xev, ui::DeviceDataManager::DT_TOUCH_SLOT_ID, &slot))
-    LOG(ERROR) << "Could not get the slot ID for the event. Using 0.";
-#endif
   return slot;
 }
 
 float GetTouchRadiusX(const base::NativeEvent& native_event) {
-  return GetTouchParamFromXEvent(native_event,
-      ui::DeviceDataManager::DT_TOUCH_MAJOR, 0.0) / 2.0;
+  double radius = GetTouchParamFromXEvent(native_event,
+      ui::DeviceDataManagerX11::DT_TOUCH_MAJOR, 0.0) / 2.0;
+  ScaleTouchRadius(native_event, &radius);
+  return radius;
 }
 
 float GetTouchRadiusY(const base::NativeEvent& native_event) {
-  return GetTouchParamFromXEvent(native_event,
-      ui::DeviceDataManager::DT_TOUCH_MINOR, 0.0) / 2.0;
+  double radius = GetTouchParamFromXEvent(native_event,
+      ui::DeviceDataManagerX11::DT_TOUCH_MINOR, 0.0) / 2.0;
+  ScaleTouchRadius(native_event, &radius);
+  return radius;
 }
 
 float GetTouchAngle(const base::NativeEvent& native_event) {
   return GetTouchParamFromXEvent(native_event,
-      ui::DeviceDataManager::DT_TOUCH_ORIENTATION, 0.0) / 2.0;
+      ui::DeviceDataManagerX11::DT_TOUCH_ORIENTATION, 0.0) / 2.0;
 }
 
 float GetTouchForce(const base::NativeEvent& native_event) {
   double force = 0.0;
   force = GetTouchParamFromXEvent(native_event,
-      ui::DeviceDataManager::DT_TOUCH_PRESSURE, 0.0);
+      ui::DeviceDataManagerX11::DT_TOUCH_PRESSURE, 0.0);
   unsigned int deviceid =
       static_cast<XIDeviceEvent*>(native_event->xcookie.data)->sourceid;
   // Force is normalized to fall into [0, 1]
-  if (!ui::DeviceDataManager::GetInstance()->NormalizeData(
-      deviceid, ui::DeviceDataManager::DT_TOUCH_PRESSURE, &force))
+  if (!ui::DeviceDataManagerX11::GetInstance()->NormalizeData(
+      deviceid, ui::DeviceDataManagerX11::DT_TOUCH_PRESSURE, &force))
     force = 0.0;
   return force;
 }
@@ -653,7 +823,7 @@ bool GetScrollOffsets(const base::NativeEvent& native_event,
                       float* x_offset_ordinal,
                       float* y_offset_ordinal,
                       int* finger_count) {
-  if (!DeviceDataManager::GetInstance()->IsScrollEvent(native_event))
+  if (!DeviceDataManagerX11::GetInstance()->IsScrollEvent(native_event))
     return false;
 
   // Temp values to prevent passing NULLs to DeviceDataManager.
@@ -671,7 +841,7 @@ bool GetScrollOffsets(const base::NativeEvent& native_event,
   if (!finger_count)
     finger_count = &finger_count_;
 
-  DeviceDataManager::GetInstance()->GetScrollOffsets(
+  DeviceDataManagerX11::GetInstance()->GetScrollOffsets(
       native_event,
       x_offset, y_offset,
       x_offset_ordinal, y_offset_ordinal,
@@ -685,7 +855,7 @@ bool GetFlingData(const base::NativeEvent& native_event,
                   float* vx_ordinal,
                   float* vy_ordinal,
                   bool* is_cancel) {
-  if (!DeviceDataManager::GetInstance()->IsFlingEvent(native_event))
+  if (!DeviceDataManagerX11::GetInstance()->IsFlingEvent(native_event))
     return false;
 
   float vx_, vy_;
@@ -702,59 +872,58 @@ bool GetFlingData(const base::NativeEvent& native_event,
   if (!is_cancel)
     is_cancel = &is_cancel_;
 
-  DeviceDataManager::GetInstance()->GetFlingData(
+  DeviceDataManagerX11::GetInstance()->GetFlingData(
       native_event, vx, vy, vx_ordinal, vy_ordinal, is_cancel);
   return true;
 }
 
-bool GetGestureTimes(const base::NativeEvent& native_event,
-                     double* start_time,
-                     double* end_time) {
-  if (!DeviceDataManager::GetInstance()->HasGestureTimes(native_event))
-    return false;
-
-  double start_time_, end_time_;
-  if (!start_time)
-    start_time = &start_time_;
-  if (!end_time)
-    end_time = &end_time_;
-
-  DeviceDataManager::GetInstance()->GetGestureTimes(
-      native_event, start_time, end_time);
-  return true;
-}
-
-void SetNaturalScroll(bool enabled) {
-  DeviceDataManager::GetInstance()->set_natural_scroll_enabled(enabled);
-}
-
-bool IsNaturalScrollEnabled() {
-  return DeviceDataManager::GetInstance()->natural_scroll_enabled();
-}
-
-bool IsTouchpadEvent(const base::NativeEvent& event) {
-  return DeviceDataManager::GetInstance()->IsTouchpadXInputEvent(event);
-}
-
-bool IsNoopEvent(const base::NativeEvent& event) {
-  return (event->type == ClientMessage &&
-      event->xclient.message_type == GetNoopEventAtom());
+void UpdateX11EventForFlags(Event* event) {
+  XEvent* xev = event->native_event();
+  if (!xev)
+    return;
+  switch (xev->type) {
+    case KeyPress:
+    case KeyRelease:
+      xev->xkey.state = UpdateX11EventFlags(event->flags(), xev->xkey.state);
+      break;
+    case ButtonPress:
+    case ButtonRelease:
+      xev->xbutton.state =
+          UpdateX11EventFlags(event->flags(), xev->xbutton.state);
+      break;
+    case GenericEvent: {
+      XIDeviceEvent* xievent = static_cast<XIDeviceEvent*>(xev->xcookie.data);
+      DCHECK(xievent);
+      xievent->mods.effective =
+          UpdateX11EventFlags(event->flags(), xievent->mods.effective);
+      break;
+    }
+    default:
+      break;
+  }
 }
 
-base::NativeEvent CreateNoopEvent() {
-  static XEvent* noop = NULL;
-  if (!noop) {
-    noop = new XEvent();
-    memset(noop, 0, sizeof(XEvent));
-    noop->xclient.type = ClientMessage;
-    noop->xclient.window = None;
-    noop->xclient.format = 8;
-    DCHECK(!noop->xclient.display);
+void UpdateX11EventForChangedButtonFlags(MouseEvent* event) {
+  XEvent* xev = event->native_event();
+  if (!xev)
+    return;
+  switch (xev->type) {
+    case ButtonPress:
+    case ButtonRelease:
+      xev->xbutton.button = UpdateX11EventButton(event->changed_button_flags(),
+                                                 xev->xbutton.button);
+      break;
+    case GenericEvent: {
+      XIDeviceEvent* xievent = static_cast<XIDeviceEvent*>(xev->xcookie.data);
+      CHECK(xievent && (xievent->evtype == XI_ButtonPress ||
+                        xievent->evtype == XI_ButtonRelease));
+      xievent->detail =
+          UpdateX11EventButton(event->changed_button_flags(), xievent->detail);
+      break;
+    }
+    default:
+      break;
   }
-  // Make sure we use atom from current xdisplay, which may
-  // change during the test.
-  noop->xclient.message_type = GetNoopEventAtom();
-  return noop;
 }
 
 }  // namespace ui