// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "ui/events/event_constants.h"

#include <string.h>
#include <X11/extensions/XInput.h>
#include <X11/extensions/XInput2.h>
#include <X11/XKBlib.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <cmath>

#include "base/logging.h"
#include "base/memory/singleton.h"
#include "ui/events/devices/x11/device_data_manager_x11.h"
#include "ui/events/devices/x11/device_list_cache_x11.h"
#include "ui/events/devices/x11/touch_factory_x11.h"
#include "ui/events/event.h"
#include "ui/events/event_utils.h"
#include "ui/events/keycodes/keyboard_code_conversion_x.h"
#include "ui/gfx/display.h"
#include "ui/gfx/geometry/point.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/screen.h"
#include "ui/gfx/x/x11_atom_cache.h"
#include "ui/gfx/x/x11_types.h"

namespace {

// Scroll amount for each wheelscroll event. 53 is also the value used for GTK+.
const int kWheelScrollAmount = 53;

const int kMinWheelButton = 4;
const int kMaxWheelButton = 7;

// A class to track current modifier state on master device. Only track ctrl,
// alt, shift and caps lock keys currently. The tracked state can then be used
// by floating device.
class XModifierStateWatcher{
 public:
  static XModifierStateWatcher* GetInstance() {
    return Singleton<XModifierStateWatcher>::get();
  }

  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.
    switch (native_event->type) {
      case KeyPress:
        state_ = native_event->xkey.state | mask;
        break;
      case KeyRelease:
        state_ = native_event->xkey.state & ~mask;
        break;
      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;
    }
  }

  // Returns the current modifer state in master device. It only contains the
  // state of ctrl, shift, alt and caps lock keys.
  unsigned int state() { return state_; }

 private:
  friend struct DefaultSingletonTraits<XModifierStateWatcher>;

  XModifierStateWatcher() : state_(0) { }

  unsigned int state_;

  DISALLOW_COPY_AND_ASSIGN(XModifierStateWatcher);
};

// Detects if a touch event is a driver-generated 'special event'.
// A 'special event' is a touch event with maximum radius and pressure at
// location (0, 0).
// This needs to be done in a cleaner way: http://crbug.com/169256
bool TouchEventIsGeneratedHack(const base::NativeEvent& native_event) {
  XIDeviceEvent* event =
      static_cast<XIDeviceEvent*>(native_event->xcookie.data);
  CHECK(event->evtype == XI_TouchBegin ||
        event->evtype == XI_TouchUpdate ||
        event->evtype == XI_TouchEnd);

  // Force is normalized to [0, 1].
  if (ui::GetTouchForce(native_event) < 1.0f)
    return false;

  if (ui::EventLocationFromNative(native_event) != gfx::Point())
    return false;

  // Radius is in pixels, and the valuator is the diameter in pixels.
  double radius = ui::GetTouchRadiusX(native_event), min, max;
  unsigned int deviceid =
      static_cast<XIDeviceEvent*>(native_event->xcookie.data)->sourceid;
  if (!ui::DeviceDataManagerX11::GetInstance()->GetDataRange(
      deviceid, ui::DeviceDataManagerX11::DT_TOUCH_MAJOR, &min, &max)) {
    return false;
  }

  return radius * 2 == max;
}

int GetEventFlagsFromXState(unsigned int state) {
  int flags = 0;
  if (state & ControlMask)
    flags |= ui::EF_CONTROL_DOWN;
  if (state & ShiftMask)
    flags |= ui::EF_SHIFT_DOWN;
  if (state & Mod1Mask)
    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)
    flags |= ui::EF_LEFT_MOUSE_BUTTON;
  if (state & Button2Mask)
    flags |= ui::EF_MIDDLE_MOUSE_BUTTON;
  if (state & Button3Mask)
    flags |= ui::EF_RIGHT_MOUSE_BUTTON;
  // There are no masks for EF_BACK_MOUSE_BUTTON and
  // EF_FORWARD_MOUSE_BUTTON.
  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) |
      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);
}

// 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
// already been pressed before the current button, and |button| stores the most
// current pressed button. So, if you press down left mouse button, and while
// pressing it down, press down the right mouse button, then for the latter
// event, |state| would have Button1Mask set but not Button3Mask, and |button|
// would be 3.
int GetEventFlagsForButton(int button) {
  switch (button) {
    case 1:
      return ui::EF_LEFT_MOUSE_BUTTON;
    case 2:
      return ui::EF_MIDDLE_MOUSE_BUTTON;
    case 3:
      return ui::EF_RIGHT_MOUSE_BUTTON;
    case 8:
      return ui::EF_BACK_MOUSE_BUTTON;
    case 9:
      return ui::EF_FORWARD_MOUSE_BUTTON;
    default:
      return 0;
  }
}

int GetButtonMaskForX2Event(XIDeviceEvent* xievent) {
  int buttonflags = 0;
  for (int i = 0; i < 8 * xievent->buttons.mask_len; i++) {
    if (XIMaskIsSet(xievent->buttons.mask, i)) {
      int button = (xievent->sourceid == xievent->deviceid) ?
          ui::DeviceDataManagerX11::GetInstance()->GetMappedButton(i) : i;
      buttonflags |= GetEventFlagsForButton(button);
    }
  }
  return buttonflags;
}

ui::EventType GetTouchEventType(const base::NativeEvent& native_event) {
  XIDeviceEvent* event =
      static_cast<XIDeviceEvent*>(native_event->xcookie.data);
  switch(event->evtype) {
    case XI_TouchBegin:
      return TouchEventIsGeneratedHack(native_event) ? ui::ET_UNKNOWN :
                                                       ui::ET_TOUCH_PRESSED;
    case XI_TouchUpdate:
      return TouchEventIsGeneratedHack(native_event) ? ui::ET_UNKNOWN :
                                                       ui::ET_TOUCH_MOVED;
    case XI_TouchEnd:
      return TouchEventIsGeneratedHack(native_event) ? ui::ET_TOUCH_CANCELLED :
                                                       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_UNKNOWN;
}

double GetTouchParamFromXEvent(XEvent* xev,
                              ui::DeviceDataManagerX11::DataType val,
                              double default_value) {
  ui::DeviceDataManagerX11::GetInstance()->GetEventData(
      *xev, val, &default_value);
  return default_value;
}

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_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(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

namespace ui {

void UpdateDeviceList() {
  XDisplay* display = gfx::GetXDisplay();
  DeviceListCacheX11::GetInstance()->UpdateDeviceList(display);
  TouchFactory::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;
    case KeyRelease:
      return ET_KEY_RELEASED;
    case ButtonPress:
      if (static_cast<int>(native_event->xbutton.button) >= kMinWheelButton &&
          static_cast<int>(native_event->xbutton.button) <= kMaxWheelButton)
        return ET_MOUSEWHEEL;
      return ET_MOUSE_PRESSED;
    case ButtonRelease:
      // Drop wheel events; we should've already scrolled on the press.
      if (static_cast<int>(native_event->xbutton.button) >= kMinWheelButton &&
          static_cast<int>(native_event->xbutton.button) <= kMaxWheelButton)
        return ET_UNKNOWN;
      return ET_MOUSE_RELEASED;
    case MotionNotify:
      if (native_event->xmotion.state &
          (Button1Mask | Button2Mask | Button3Mask))
        return ET_MOUSE_DRAGGED;
      return ET_MOUSE_MOVED;
    case EnterNotify:
      // The standard on Windows is to send a MouseMove event when the mouse
      // first enters a window instead of sending a special mouse enter event.
      // To be consistent we follow the same style.
      return ET_MOUSE_MOVED;
    case LeaveNotify:
      return ET_MOUSE_EXITED;
    case GenericEvent: {
      TouchFactory* factory = TouchFactory::GetInstance();
      if (!factory->ShouldProcessXI2Event(native_event))
        return ET_UNKNOWN;

      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)
            return ET_MOUSEWHEEL;
          return ET_MOUSE_PRESSED;
        }
        case XI_ButtonRelease: {
          int button = EventButtonFromNative(native_event);
          // Drop wheel events; we should've already scrolled on the press.
          if (button >= kMinWheelButton && button <= kMaxWheelButton)
            return ET_UNKNOWN;
          return ET_MOUSE_RELEASED;
        }
        case XI_Motion: {
          bool 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;
          if (devices->IsScrollEvent(native_event)) {
            return devices->IsTouchpadXInputEvent(native_event) ? ET_SCROLL
                                                                : ET_MOUSEWHEEL;
          }
          if (devices->IsCMTMetricsEvent(native_event))
            return ET_UMA_DATA;
          if (GetButtonMaskForX2Event(xievent))
            return ET_MOUSE_DRAGGED;
          if (DeviceDataManagerX11::GetInstance()->HasEventData(
                  xievent, DeviceDataManagerX11::DT_CMT_SCROLL_X) ||
              DeviceDataManagerX11::GetInstance()->HasEventData(
                  xievent, DeviceDataManagerX11::DT_CMT_SCROLL_Y)) {
            // Don't produce mouse move events for mousewheel scrolls.
            return ET_UNKNOWN;
          }

          return ET_MOUSE_MOVED;
        }
        case XI_KeyPress:
          return ET_KEY_PRESSED;
        case XI_KeyRelease:
          return ET_KEY_RELEASED;
      }
    }
    default:
      break;
  }
  return ET_UNKNOWN;
}

int EventFlagsFromNative(const base::NativeEvent& native_event) {
  switch (native_event->type) {
    case KeyPress:
    case KeyRelease: {
      XModifierStateWatcher::GetInstance()->UpdateStateFromXEvent(native_event);
      return GetEventFlagsFromXKeyEvent(native_event);
    }
    case ButtonPress:
    case ButtonRelease: {
      int flags = GetEventFlagsFromXState(native_event->xbutton.state);
      const EventType type = EventTypeFromNative(native_event);
      if (type == ET_MOUSE_PRESSED || type == ET_MOUSE_RELEASED)
        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: {
      XIDeviceEvent* xievent =
          static_cast<XIDeviceEvent*>(native_event->xcookie.data);

      switch (xievent->evtype) {
        case XI_TouchBegin:
        case XI_TouchUpdate:
        case XI_TouchEnd:
          return GetButtonMaskForX2Event(xievent) |
                 GetEventFlagsFromXState(xievent->mods.effective) |
                 GetEventFlagsFromXState(
                     XModifierStateWatcher::GetInstance()->state());
          break;
        case XI_ButtonPress:
        case XI_ButtonRelease: {
          const bool touch =
              TouchFactory::GetInstance()->IsTouchDevice(xievent->sourceid);
          int flags = GetButtonMaskForX2Event(xievent) |
                      GetEventFlagsFromXState(xievent->mods.effective);
          if (touch) {
            flags |= GetEventFlagsFromXState(
                XModifierStateWatcher::GetInstance()->state());
          }

          const EventType type = EventTypeFromNative(native_event);
          int button = EventButtonFromNative(native_event);
          if ((type == ET_MOUSE_PRESSED || type == ET_MOUSE_RELEASED) && !touch)
            flags |= GetEventFlagsForButton(button);
          return flags;
        }
        case XI_Motion:
          return GetButtonMaskForX2Event(xievent) |
                 GetEventFlagsFromXState(xievent->mods.effective);
        case XI_KeyPress:
        case XI_KeyRelease: {
          XModifierStateWatcher::GetInstance()->UpdateStateFromXEvent(
              native_event);
          return GetEventFlagsFromXGenericEvent(native_event);
        }
      }
    }
  }
  return 0;
}

base::TimeDelta EventTimeFromNative(const base::NativeEvent& native_event) {
  switch(native_event->type) {
    case KeyPress:
    case KeyRelease:
      return base::TimeDelta::FromMilliseconds(native_event->xkey.time);
    case ButtonPress:
    case ButtonRelease:
      return base::TimeDelta::FromMilliseconds(native_event->xbutton.time);
      break;
    case MotionNotify:
      return base::TimeDelta::FromMilliseconds(native_event->xmotion.time);
      break;
    case EnterNotify:
    case LeaveNotify:
      return base::TimeDelta::FromMilliseconds(native_event->xcrossing.time);
      break;
    case GenericEvent: {
      double start, end;
      double touch_timestamp;
      if (GetGestureTimes(native_event, &start, &end)) {
        // If the driver supports gesture times, use them.
        return base::TimeDelta::FromMicroseconds(end * 1000000);
      } else if (DeviceDataManagerX11::GetInstance()->GetEventData(
          *native_event,
          DeviceDataManagerX11::DT_TOUCH_RAW_TIMESTAMP,
          &touch_timestamp)) {
        return base::TimeDelta::FromMicroseconds(touch_timestamp * 1000000);
      } else {
        XIDeviceEvent* xide =
            static_cast<XIDeviceEvent*>(native_event->xcookie.data);
        return base::TimeDelta::FromMilliseconds(xide->time);
      }
      break;
    }
  }
  NOTREACHED();
  return base::TimeDelta();
}

gfx::Point EventLocationFromNative(const base::NativeEvent& native_event) {
  switch (native_event->type) {
    case EnterNotify:
    case LeaveNotify:
      return gfx::Point(native_event->xcrossing.x, native_event->xcrossing.y);
    case ButtonPress:
    case ButtonRelease:
      return gfx::Point(native_event->xbutton.x, native_event->xbutton.y);
    case MotionNotify:
      return gfx::Point(native_event->xmotion.x, native_event->xmotion.y);
    case GenericEvent: {
      XIDeviceEvent* xievent =
          static_cast<XIDeviceEvent*>(native_event->xcookie.data);
      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();
}

gfx::Point EventSystemLocationFromNative(
    const base::NativeEvent& native_event) {
  switch (native_event->type) {
    case EnterNotify:
    case LeaveNotify: {
      return gfx::Point(native_event->xcrossing.x_root,
                        native_event->xcrossing.y_root);
    }
    case ButtonPress:
    case ButtonRelease: {
      return gfx::Point(native_event->xbutton.x_root,
                        native_event->xbutton.y_root);
    }
    case MotionNotify: {
      return gfx::Point(native_event->xmotion.x_root,
                        native_event->xmotion.y_root);
    }
    case GenericEvent: {
      XIDeviceEvent* xievent =
          static_cast<XIDeviceEvent*>(native_event->xcookie.data);
      return gfx::Point(xievent->root_x, xievent->root_y);
    }
  }

  return gfx::Point();
}

int EventButtonFromNative(const base::NativeEvent& native_event) {
  CHECK_EQ(GenericEvent, native_event->type);
  XIDeviceEvent* xievent =
      static_cast<XIDeviceEvent*>(native_event->xcookie.data);
  int button = xievent->detail;

  return (xievent->sourceid == xievent->deviceid) ?
         DeviceDataManagerX11::GetInstance()->GetMappedButton(button) : button;
}

KeyboardCode KeyboardCodeFromNative(const base::NativeEvent& native_event) {
  return KeyboardCodeFromXKeyEvent(native_event);
}

DomCode 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;
}

int GetChangedMouseButtonFlagsFromNative(
    const base::NativeEvent& native_event) {
  switch (native_event->type) {
    case ButtonPress:
    case ButtonRelease:
      return GetEventFlagsForButton(native_event->xbutton.button);
    case GenericEvent: {
      XIDeviceEvent* xievent =
          static_cast<XIDeviceEvent*>(native_event->xcookie.data);
      switch (xievent->evtype) {
        case XI_ButtonPress:
        case XI_ButtonRelease:
          return GetEventFlagsForButton(EventButtonFromNative(native_event));
        default:
          break;
      }
    }
    default:
      break;
  }
  return 0;
}

gfx::Vector2d GetMouseWheelOffset(const base::NativeEvent& native_event) {
  float x_offset, y_offset;
  if (GetScrollOffsets(
      native_event, &x_offset, &y_offset, NULL, NULL, NULL)) {
    return gfx::Vector2d(static_cast<int>(x_offset),
                         static_cast<int>(y_offset));
  }

  int button = native_event->type == GenericEvent ?
      EventButtonFromNative(native_event) : native_event->xbutton.button;

  switch (button) {
    case 4:
      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:
      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 ClearTouchIdIfReleased(const base::NativeEvent& xev) {
  ui::EventType type = ui::EventTypeFromNative(xev);
  if (type == ui::ET_TOUCH_CANCELLED ||
      type == ui::ET_TOUCH_RELEASED) {
    ui::TouchFactory* factory = ui::TouchFactory::GetInstance();
    ui::DeviceDataManagerX11* manager = ui::DeviceDataManagerX11::GetInstance();
    double tracking_id;
    if (manager->GetEventData(
        *xev, ui::DeviceDataManagerX11::DT_TOUCH_TRACKING_ID, &tracking_id)) {
      factory->ReleaseSlotForTrackingID(tracking_id);
    }
  }
}

int GetTouchId(const base::NativeEvent& xev) {
  double slot = 0;
  ui::DeviceDataManagerX11* manager = ui::DeviceDataManagerX11::GetInstance();
  double tracking_id;
  if (!manager->GetEventData(
      *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);
  }
  return slot;
}

float GetTouchRadiusX(const base::NativeEvent& native_event) {
  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) {
  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::DeviceDataManagerX11::DT_TOUCH_ORIENTATION, 0.0) / 2.0;
}

float GetTouchForce(const base::NativeEvent& native_event) {
  double force = 0.0;
  force = GetTouchParamFromXEvent(native_event,
      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::DeviceDataManagerX11::GetInstance()->NormalizeData(
      deviceid, ui::DeviceDataManagerX11::DT_TOUCH_PRESSURE, &force))
    force = 0.0;
  return force;
}

bool GetScrollOffsets(const base::NativeEvent& native_event,
                      float* x_offset,
                      float* y_offset,
                      float* x_offset_ordinal,
                      float* y_offset_ordinal,
                      int* finger_count) {
  if (!DeviceDataManagerX11::GetInstance()->IsScrollEvent(native_event))
    return false;

  // Temp values to prevent passing NULLs to DeviceDataManager.
  float x_offset_, y_offset_;
  float x_offset_ordinal_, y_offset_ordinal_;
  int finger_count_;
  if (!x_offset)
    x_offset = &x_offset_;
  if (!y_offset)
    y_offset = &y_offset_;
  if (!x_offset_ordinal)
    x_offset_ordinal = &x_offset_ordinal_;
  if (!y_offset_ordinal)
    y_offset_ordinal = &y_offset_ordinal_;
  if (!finger_count)
    finger_count = &finger_count_;

  DeviceDataManagerX11::GetInstance()->GetScrollOffsets(
      native_event,
      x_offset, y_offset,
      x_offset_ordinal, y_offset_ordinal,
      finger_count);
  return true;
}

bool GetFlingData(const base::NativeEvent& native_event,
                  float* vx,
                  float* vy,
                  float* vx_ordinal,
                  float* vy_ordinal,
                  bool* is_cancel) {
  if (!DeviceDataManagerX11::GetInstance()->IsFlingEvent(native_event))
    return false;

  float vx_, vy_;
  float vx_ordinal_, vy_ordinal_;
  bool is_cancel_;
  if (!vx)
    vx = &vx_;
  if (!vy)
    vy = &vy_;
  if (!vx_ordinal)
    vx_ordinal = &vx_ordinal_;
  if (!vy_ordinal)
    vy_ordinal = &vy_ordinal_;
  if (!is_cancel)
    is_cancel = &is_cancel_;

  DeviceDataManagerX11::GetInstance()->GetFlingData(
      native_event, vx, vy, vx_ordinal, vy_ordinal, is_cancel);
  return true;
}

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;
  }
}

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;
  }
}

}  // namespace ui
