1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "ui/events/event_constants.h"
6
7#include <cmath>
8#include <string.h>
9#include <X11/extensions/XInput.h>
10#include <X11/extensions/XInput2.h>
11#include <X11/Xlib.h>
12#include <X11/Xutil.h>
13#include <X11/XKBlib.h>
14
15#include "base/logging.h"
16#include "base/memory/singleton.h"
17#include "ui/events/event.h"
18#include "ui/events/event_utils.h"
19#include "ui/events/keycodes/keyboard_code_conversion_x.h"
20#include "ui/events/x/device_data_manager_x11.h"
21#include "ui/events/x/device_list_cache_x.h"
22#include "ui/events/x/touch_factory_x11.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#include "ui/gfx/x/x11_atom_cache.h"
28#include "ui/gfx/x/x11_types.h"
29
30namespace {
31
32// Scroll amount for each wheelscroll event. 53 is also the value used for GTK+.
33const int kWheelScrollAmount = 53;
34
35const int kMinWheelButton = 4;
36const int kMaxWheelButton = 7;
37
38// A class to track current modifier state on master device. Only track ctrl,
39// alt, shift and caps lock keys currently. The tracked state can then be used
40// by floating device.
41class XModifierStateWatcher{
42 public:
43  static XModifierStateWatcher* GetInstance() {
44    return Singleton<XModifierStateWatcher>::get();
45  }
46
47  int StateFromKeyboardCode(ui::KeyboardCode keyboard_code) {
48    switch (keyboard_code) {
49      case ui::VKEY_CONTROL:
50        return ControlMask;
51      case ui::VKEY_SHIFT:
52        return ShiftMask;
53      case ui::VKEY_MENU:
54        return Mod1Mask;
55      case ui::VKEY_CAPITAL:
56        return LockMask;
57      default:
58        return 0;
59    }
60  }
61
62  void UpdateStateFromXEvent(const base::NativeEvent& native_event) {
63    ui::KeyboardCode keyboard_code = ui::KeyboardCodeFromNative(native_event);
64    unsigned int mask = StateFromKeyboardCode(keyboard_code);
65    // Floating device can't access the modifer state from master device.
66    // We need to track the states of modifier keys in a singleton for
67    // floating devices such as touch screen. Issue 106426 is one example
68    // of why we need the modifier states for floating device.
69    switch (native_event->type) {
70      case KeyPress:
71        state_ = native_event->xkey.state | mask;
72        break;
73      case KeyRelease:
74        state_ = native_event->xkey.state & ~mask;
75        break;
76      case GenericEvent: {
77        XIDeviceEvent* xievent =
78            static_cast<XIDeviceEvent*>(native_event->xcookie.data);
79        switch (xievent->evtype) {
80          case XI_KeyPress:
81            state_ = xievent->mods.effective |= mask;
82            break;
83          case XI_KeyRelease:
84            state_ = xievent->mods.effective &= ~mask;
85            break;
86          default:
87            NOTREACHED();
88            break;
89        }
90        break;
91      }
92      default:
93        NOTREACHED();
94        break;
95    }
96  }
97
98  // Returns the current modifer state in master device. It only contains the
99  // state of ctrl, shift, alt and caps lock keys.
100  unsigned int state() { return state_; }
101
102 private:
103  friend struct DefaultSingletonTraits<XModifierStateWatcher>;
104
105  XModifierStateWatcher() : state_(0) { }
106
107  unsigned int state_;
108
109  DISALLOW_COPY_AND_ASSIGN(XModifierStateWatcher);
110};
111
112#if defined(USE_XI2_MT)
113// Detects if a touch event is a driver-generated 'special event'.
114// A 'special event' is a touch event with maximum radius and pressure at
115// location (0, 0).
116// This needs to be done in a cleaner way: http://crbug.com/169256
117bool TouchEventIsGeneratedHack(const base::NativeEvent& native_event) {
118  XIDeviceEvent* event =
119      static_cast<XIDeviceEvent*>(native_event->xcookie.data);
120  CHECK(event->evtype == XI_TouchBegin ||
121        event->evtype == XI_TouchUpdate ||
122        event->evtype == XI_TouchEnd);
123
124  // Force is normalized to [0, 1].
125  if (ui::GetTouchForce(native_event) < 1.0f)
126    return false;
127
128  if (ui::EventLocationFromNative(native_event) != gfx::Point())
129    return false;
130
131  // Radius is in pixels, and the valuator is the diameter in pixels.
132  double radius = ui::GetTouchRadiusX(native_event), min, max;
133  unsigned int deviceid =
134      static_cast<XIDeviceEvent*>(native_event->xcookie.data)->sourceid;
135  if (!ui::DeviceDataManagerX11::GetInstance()->GetDataRange(
136      deviceid, ui::DeviceDataManagerX11::DT_TOUCH_MAJOR, &min, &max)) {
137    return false;
138  }
139
140  return radius * 2 == max;
141}
142#endif
143
144int GetEventFlagsFromXState(unsigned int state) {
145  int flags = 0;
146  if (state & ControlMask)
147    flags |= ui::EF_CONTROL_DOWN;
148  if (state & ShiftMask)
149    flags |= ui::EF_SHIFT_DOWN;
150  if (state & Mod1Mask)
151    flags |= ui::EF_ALT_DOWN;
152  if (state & LockMask)
153    flags |= ui::EF_CAPS_LOCK_DOWN;
154  if (state & Mod3Mask)
155    flags |= ui::EF_MOD3_DOWN;
156  if (state & Mod4Mask)
157    flags |= ui::EF_COMMAND_DOWN;
158  if (state & Mod5Mask)
159    flags |= ui::EF_ALTGR_DOWN;
160  if (state & Button1Mask)
161    flags |= ui::EF_LEFT_MOUSE_BUTTON;
162  if (state & Button2Mask)
163    flags |= ui::EF_MIDDLE_MOUSE_BUTTON;
164  if (state & Button3Mask)
165    flags |= ui::EF_RIGHT_MOUSE_BUTTON;
166  return flags;
167}
168
169int GetEventFlagsFromXKeyEvent(XEvent* xevent) {
170  DCHECK(xevent->type == KeyPress || xevent->type == KeyRelease);
171
172#if defined(OS_CHROMEOS)
173  const int ime_fabricated_flag = 0;
174#else
175  // XIM fabricates key events for the character compositions by XK_Multi_key.
176  // For example, when a user hits XK_Multi_key, XK_apostrophe, and XK_e in
177  // order to input "é", then XIM generates a key event with keycode=0 and
178  // state=0 for the composition, and the sequence of X11 key events will be
179  // XK_Multi_key, XK_apostrophe, **NoSymbol**, and XK_e.  If the user used
180  // shift key and/or caps lock key, state can be ShiftMask, LockMask or both.
181  //
182  // We have to send these fabricated key events to XIM so it can correctly
183  // handle the character compositions.
184  const unsigned int shift_lock_mask = ShiftMask | LockMask;
185  const bool fabricated_by_xim =
186      xevent->xkey.keycode == 0 &&
187      (xevent->xkey.state & ~shift_lock_mask) == 0;
188  const int ime_fabricated_flag =
189      fabricated_by_xim ? ui::EF_IME_FABRICATED_KEY : 0;
190#endif
191
192  return GetEventFlagsFromXState(xevent->xkey.state) |
193      (xevent->xkey.send_event ? ui::EF_FINAL : 0) |
194      (IsKeypadKey(XLookupKeysym(&xevent->xkey, 0)) ? ui::EF_NUMPAD_KEY : 0) |
195      (IsFunctionKey(XLookupKeysym(&xevent->xkey, 0)) ?
196          ui::EF_FUNCTION_KEY : 0) |
197      ime_fabricated_flag;
198}
199
200int GetEventFlagsFromXGenericEvent(XEvent* xevent) {
201  DCHECK(xevent->type == GenericEvent);
202  XIDeviceEvent* xievent = static_cast<XIDeviceEvent*>(xevent->xcookie.data);
203  DCHECK((xievent->evtype == XI_KeyPress) ||
204         (xievent->evtype == XI_KeyRelease));
205  return GetEventFlagsFromXState(xievent->mods.effective) |
206         (xevent->xkey.send_event ? ui::EF_FINAL : 0) |
207         (IsKeypadKey(
208              XkbKeycodeToKeysym(xievent->display, xievent->detail, 0, 0))
209              ? ui::EF_NUMPAD_KEY
210              : 0);
211}
212
213// Get the event flag for the button in XButtonEvent. During a ButtonPress
214// event, |state| in XButtonEvent does not include the button that has just been
215// pressed. Instead |state| contains flags for the buttons (if any) that had
216// already been pressed before the current button, and |button| stores the most
217// current pressed button. So, if you press down left mouse button, and while
218// pressing it down, press down the right mouse button, then for the latter
219// event, |state| would have Button1Mask set but not Button3Mask, and |button|
220// would be 3.
221int GetEventFlagsForButton(int button) {
222  switch (button) {
223    case 1:
224      return ui::EF_LEFT_MOUSE_BUTTON;
225    case 2:
226      return ui::EF_MIDDLE_MOUSE_BUTTON;
227    case 3:
228      return ui::EF_RIGHT_MOUSE_BUTTON;
229    default:
230      return 0;
231  }
232}
233
234int GetButtonMaskForX2Event(XIDeviceEvent* xievent) {
235  int buttonflags = 0;
236  for (int i = 0; i < 8 * xievent->buttons.mask_len; i++) {
237    if (XIMaskIsSet(xievent->buttons.mask, i)) {
238      int button = (xievent->sourceid == xievent->deviceid) ?
239          ui::DeviceDataManagerX11::GetInstance()->GetMappedButton(i) : i;
240      buttonflags |= GetEventFlagsForButton(button);
241    }
242  }
243  return buttonflags;
244}
245
246ui::EventType GetTouchEventType(const base::NativeEvent& native_event) {
247  XIDeviceEvent* event =
248      static_cast<XIDeviceEvent*>(native_event->xcookie.data);
249#if defined(USE_XI2_MT)
250  switch(event->evtype) {
251    case XI_TouchBegin:
252      return TouchEventIsGeneratedHack(native_event) ? ui::ET_UNKNOWN :
253                                                       ui::ET_TOUCH_PRESSED;
254    case XI_TouchUpdate:
255      return TouchEventIsGeneratedHack(native_event) ? ui::ET_UNKNOWN :
256                                                       ui::ET_TOUCH_MOVED;
257    case XI_TouchEnd:
258      return TouchEventIsGeneratedHack(native_event) ? ui::ET_TOUCH_CANCELLED :
259                                                       ui::ET_TOUCH_RELEASED;
260  }
261#endif  // defined(USE_XI2_MT)
262
263  DCHECK(ui::TouchFactory::GetInstance()->IsTouchDevice(event->sourceid));
264  switch (event->evtype) {
265    case XI_ButtonPress:
266      return ui::ET_TOUCH_PRESSED;
267    case XI_ButtonRelease:
268      return ui::ET_TOUCH_RELEASED;
269    case XI_Motion:
270      // Should not convert any emulated Motion event from touch device to
271      // touch event.
272      if (!(event->flags & XIPointerEmulated) &&
273          GetButtonMaskForX2Event(event))
274        return ui::ET_TOUCH_MOVED;
275      return ui::ET_UNKNOWN;
276    default:
277      NOTREACHED();
278  }
279  return ui::ET_UNKNOWN;
280}
281
282double GetTouchParamFromXEvent(XEvent* xev,
283                              ui::DeviceDataManagerX11::DataType val,
284                              double default_value) {
285  ui::DeviceDataManagerX11::GetInstance()->GetEventData(
286      *xev, val, &default_value);
287  return default_value;
288}
289
290void ScaleTouchRadius(XEvent* xev, double* radius) {
291  DCHECK_EQ(GenericEvent, xev->type);
292  XIDeviceEvent* xiev = static_cast<XIDeviceEvent*>(xev->xcookie.data);
293  ui::DeviceDataManagerX11::GetInstance()->ApplyTouchRadiusScale(
294      xiev->sourceid, radius);
295}
296
297unsigned int UpdateX11EventFlags(int ui_flags, unsigned int old_x_flags) {
298  static struct {
299    int ui;
300    int x;
301  } flags[] = {
302    {ui::EF_CONTROL_DOWN, ControlMask},
303    {ui::EF_SHIFT_DOWN, ShiftMask},
304    {ui::EF_ALT_DOWN, Mod1Mask},
305    {ui::EF_CAPS_LOCK_DOWN, LockMask},
306    {ui::EF_ALTGR_DOWN, Mod5Mask},
307    {ui::EF_COMMAND_DOWN, Mod4Mask},
308    {ui::EF_MOD3_DOWN, Mod3Mask},
309    {ui::EF_NUMPAD_KEY, Mod2Mask},
310    {ui::EF_LEFT_MOUSE_BUTTON, Button1Mask},
311    {ui::EF_MIDDLE_MOUSE_BUTTON, Button2Mask},
312    {ui::EF_RIGHT_MOUSE_BUTTON, Button3Mask},
313  };
314  unsigned int new_x_flags = old_x_flags;
315  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(flags); ++i) {
316    if (ui_flags & flags[i].ui)
317      new_x_flags |= flags[i].x;
318    else
319      new_x_flags &= ~flags[i].x;
320  }
321  return new_x_flags;
322}
323
324unsigned int UpdateX11EventButton(int ui_flag, unsigned int old_x_button) {
325  switch (ui_flag) {
326    case ui::EF_LEFT_MOUSE_BUTTON:
327      return Button1;
328    case ui::EF_MIDDLE_MOUSE_BUTTON:
329      return Button2;
330    case ui::EF_RIGHT_MOUSE_BUTTON:
331      return Button3;
332    default:
333      return old_x_button;
334  }
335  NOTREACHED();
336}
337
338bool GetGestureTimes(const base::NativeEvent& native_event,
339                     double* start_time,
340                     double* end_time) {
341  if (!ui::DeviceDataManagerX11::GetInstance()->HasGestureTimes(native_event))
342    return false;
343
344  double start_time_, end_time_;
345  if (!start_time)
346    start_time = &start_time_;
347  if (!end_time)
348    end_time = &end_time_;
349
350  ui::DeviceDataManagerX11::GetInstance()->GetGestureTimes(
351      native_event, start_time, end_time);
352  return true;
353}
354
355}  // namespace
356
357namespace ui {
358
359void UpdateDeviceList() {
360  XDisplay* display = gfx::GetXDisplay();
361  DeviceListCacheX::GetInstance()->UpdateDeviceList(display);
362  TouchFactory::GetInstance()->UpdateDeviceList(display);
363  DeviceDataManagerX11::GetInstance()->UpdateDeviceList(display);
364}
365
366EventType EventTypeFromNative(const base::NativeEvent& native_event) {
367  // Allow the DeviceDataManager to block the event. If blocked return
368  // ET_UNKNOWN as the type so this event will not be further processed.
369  // NOTE: During some events unittests there is no device data manager.
370  if (DeviceDataManager::HasInstance() &&
371      static_cast<DeviceDataManagerX11*>(DeviceDataManager::GetInstance())->
372          IsEventBlocked(native_event)) {
373    return ET_UNKNOWN;
374  }
375
376  switch (native_event->type) {
377    case KeyPress:
378      return ET_KEY_PRESSED;
379    case KeyRelease:
380      return ET_KEY_RELEASED;
381    case ButtonPress:
382      if (static_cast<int>(native_event->xbutton.button) >= kMinWheelButton &&
383          static_cast<int>(native_event->xbutton.button) <= kMaxWheelButton)
384        return ET_MOUSEWHEEL;
385      return ET_MOUSE_PRESSED;
386    case ButtonRelease:
387      // Drop wheel events; we should've already scrolled on the press.
388      if (static_cast<int>(native_event->xbutton.button) >= kMinWheelButton &&
389          static_cast<int>(native_event->xbutton.button) <= kMaxWheelButton)
390        return ET_UNKNOWN;
391      return ET_MOUSE_RELEASED;
392    case MotionNotify:
393      if (native_event->xmotion.state &
394          (Button1Mask | Button2Mask | Button3Mask))
395        return ET_MOUSE_DRAGGED;
396      return ET_MOUSE_MOVED;
397    case EnterNotify:
398      // The standard on Windows is to send a MouseMove event when the mouse
399      // first enters a window instead of sending a special mouse enter event.
400      // To be consistent we follow the same style.
401      return ET_MOUSE_MOVED;
402    case LeaveNotify:
403      return ET_MOUSE_EXITED;
404    case GenericEvent: {
405      TouchFactory* factory = TouchFactory::GetInstance();
406      if (!factory->ShouldProcessXI2Event(native_event))
407        return ET_UNKNOWN;
408
409      XIDeviceEvent* xievent =
410          static_cast<XIDeviceEvent*>(native_event->xcookie.data);
411
412      // This check works only for master and floating slave devices. That is
413      // why it is necessary to check for the XI_Touch* events in the following
414      // switch statement to account for attached-slave touchscreens.
415      if (factory->IsTouchDevice(xievent->sourceid))
416        return GetTouchEventType(native_event);
417
418      switch (xievent->evtype) {
419        case XI_TouchBegin:
420          return ui::ET_TOUCH_PRESSED;
421        case XI_TouchUpdate:
422          return ui::ET_TOUCH_MOVED;
423        case XI_TouchEnd:
424          return ui::ET_TOUCH_RELEASED;
425        case XI_ButtonPress: {
426          int button = EventButtonFromNative(native_event);
427          if (button >= kMinWheelButton && button <= kMaxWheelButton)
428            return ET_MOUSEWHEEL;
429          return ET_MOUSE_PRESSED;
430        }
431        case XI_ButtonRelease: {
432          int button = EventButtonFromNative(native_event);
433          // Drop wheel events; we should've already scrolled on the press.
434          if (button >= kMinWheelButton && button <= kMaxWheelButton)
435            return ET_UNKNOWN;
436          return ET_MOUSE_RELEASED;
437        }
438        case XI_Motion: {
439          bool is_cancel;
440          DeviceDataManagerX11* devices = DeviceDataManagerX11::GetInstance();
441          if (GetFlingData(native_event, NULL, NULL, NULL, NULL, &is_cancel))
442            return is_cancel ? ET_SCROLL_FLING_CANCEL : ET_SCROLL_FLING_START;
443          if (devices->IsScrollEvent(native_event)) {
444            return devices->IsTouchpadXInputEvent(native_event) ? ET_SCROLL
445                                                                : ET_MOUSEWHEEL;
446          }
447          if (devices->IsCMTMetricsEvent(native_event))
448            return ET_UMA_DATA;
449          if (GetButtonMaskForX2Event(xievent))
450            return ET_MOUSE_DRAGGED;
451          return ET_MOUSE_MOVED;
452        }
453        case XI_KeyPress:
454          return ET_KEY_PRESSED;
455        case XI_KeyRelease:
456          return ET_KEY_RELEASED;
457      }
458    }
459    default:
460      break;
461  }
462  return ET_UNKNOWN;
463}
464
465int EventFlagsFromNative(const base::NativeEvent& native_event) {
466  switch (native_event->type) {
467    case KeyPress:
468    case KeyRelease: {
469      XModifierStateWatcher::GetInstance()->UpdateStateFromXEvent(native_event);
470      return GetEventFlagsFromXKeyEvent(native_event);
471    }
472    case ButtonPress:
473    case ButtonRelease: {
474      int flags = GetEventFlagsFromXState(native_event->xbutton.state);
475      const EventType type = EventTypeFromNative(native_event);
476      if (type == ET_MOUSE_PRESSED || type == ET_MOUSE_RELEASED)
477        flags |= GetEventFlagsForButton(native_event->xbutton.button);
478      return flags;
479    }
480    case EnterNotify:
481    case LeaveNotify:
482      return GetEventFlagsFromXState(native_event->xcrossing.state);
483    case MotionNotify:
484      return GetEventFlagsFromXState(native_event->xmotion.state);
485    case GenericEvent: {
486      XIDeviceEvent* xievent =
487          static_cast<XIDeviceEvent*>(native_event->xcookie.data);
488
489      switch (xievent->evtype) {
490#if defined(USE_XI2_MT)
491        case XI_TouchBegin:
492        case XI_TouchUpdate:
493        case XI_TouchEnd:
494          return GetButtonMaskForX2Event(xievent) |
495                 GetEventFlagsFromXState(xievent->mods.effective) |
496                 GetEventFlagsFromXState(
497                     XModifierStateWatcher::GetInstance()->state());
498          break;
499#endif
500        case XI_ButtonPress:
501        case XI_ButtonRelease: {
502          const bool touch =
503              TouchFactory::GetInstance()->IsTouchDevice(xievent->sourceid);
504          int flags = GetButtonMaskForX2Event(xievent) |
505                      GetEventFlagsFromXState(xievent->mods.effective);
506          if (touch) {
507            flags |= GetEventFlagsFromXState(
508                XModifierStateWatcher::GetInstance()->state());
509          }
510
511          const EventType type = EventTypeFromNative(native_event);
512          int button = EventButtonFromNative(native_event);
513          if ((type == ET_MOUSE_PRESSED || type == ET_MOUSE_RELEASED) && !touch)
514            flags |= GetEventFlagsForButton(button);
515          return flags;
516        }
517        case XI_Motion:
518          return GetButtonMaskForX2Event(xievent) |
519                 GetEventFlagsFromXState(xievent->mods.effective);
520        case XI_KeyPress:
521        case XI_KeyRelease: {
522          XModifierStateWatcher::GetInstance()->UpdateStateFromXEvent(
523              native_event);
524          return GetEventFlagsFromXGenericEvent(native_event);
525        }
526      }
527    }
528  }
529  return 0;
530}
531
532base::TimeDelta EventTimeFromNative(const base::NativeEvent& native_event) {
533  switch(native_event->type) {
534    case KeyPress:
535    case KeyRelease:
536      return base::TimeDelta::FromMilliseconds(native_event->xkey.time);
537    case ButtonPress:
538    case ButtonRelease:
539      return base::TimeDelta::FromMilliseconds(native_event->xbutton.time);
540      break;
541    case MotionNotify:
542      return base::TimeDelta::FromMilliseconds(native_event->xmotion.time);
543      break;
544    case EnterNotify:
545    case LeaveNotify:
546      return base::TimeDelta::FromMilliseconds(native_event->xcrossing.time);
547      break;
548    case GenericEvent: {
549      double start, end;
550      double touch_timestamp;
551      if (GetGestureTimes(native_event, &start, &end)) {
552        // If the driver supports gesture times, use them.
553        return base::TimeDelta::FromMicroseconds(end * 1000000);
554      } else if (DeviceDataManagerX11::GetInstance()->GetEventData(
555          *native_event,
556          DeviceDataManagerX11::DT_TOUCH_RAW_TIMESTAMP,
557          &touch_timestamp)) {
558        return base::TimeDelta::FromMicroseconds(touch_timestamp * 1000000);
559      } else {
560        XIDeviceEvent* xide =
561            static_cast<XIDeviceEvent*>(native_event->xcookie.data);
562        return base::TimeDelta::FromMilliseconds(xide->time);
563      }
564      break;
565    }
566  }
567  NOTREACHED();
568  return base::TimeDelta();
569}
570
571gfx::Point EventLocationFromNative(const base::NativeEvent& native_event) {
572  switch (native_event->type) {
573    case EnterNotify:
574    case LeaveNotify:
575      return gfx::Point(native_event->xcrossing.x, native_event->xcrossing.y);
576    case ButtonPress:
577    case ButtonRelease:
578      return gfx::Point(native_event->xbutton.x, native_event->xbutton.y);
579    case MotionNotify:
580      return gfx::Point(native_event->xmotion.x, native_event->xmotion.y);
581    case GenericEvent: {
582      XIDeviceEvent* xievent =
583          static_cast<XIDeviceEvent*>(native_event->xcookie.data);
584      float x = xievent->event_x;
585      float y = xievent->event_y;
586#if defined(OS_CHROMEOS)
587      switch (xievent->evtype) {
588        case XI_TouchBegin:
589        case XI_TouchUpdate:
590        case XI_TouchEnd:
591          ui::DeviceDataManagerX11::GetInstance()->ApplyTouchTransformer(
592              xievent->deviceid, &x, &y);
593          break;
594        default:
595          break;
596      }
597#endif  // defined(OS_CHROMEOS)
598      return gfx::Point(static_cast<int>(x), static_cast<int>(y));
599    }
600  }
601  return gfx::Point();
602}
603
604gfx::Point EventSystemLocationFromNative(
605    const base::NativeEvent& native_event) {
606  switch (native_event->type) {
607    case EnterNotify:
608    case LeaveNotify: {
609      return gfx::Point(native_event->xcrossing.x_root,
610                        native_event->xcrossing.y_root);
611    }
612    case ButtonPress:
613    case ButtonRelease: {
614      return gfx::Point(native_event->xbutton.x_root,
615                        native_event->xbutton.y_root);
616    }
617    case MotionNotify: {
618      return gfx::Point(native_event->xmotion.x_root,
619                        native_event->xmotion.y_root);
620    }
621    case GenericEvent: {
622      XIDeviceEvent* xievent =
623          static_cast<XIDeviceEvent*>(native_event->xcookie.data);
624      return gfx::Point(xievent->root_x, xievent->root_y);
625    }
626  }
627
628  return gfx::Point();
629}
630
631int EventButtonFromNative(const base::NativeEvent& native_event) {
632  CHECK_EQ(GenericEvent, native_event->type);
633  XIDeviceEvent* xievent =
634      static_cast<XIDeviceEvent*>(native_event->xcookie.data);
635  int button = xievent->detail;
636
637  return (xievent->sourceid == xievent->deviceid) ?
638         DeviceDataManagerX11::GetInstance()->GetMappedButton(button) : button;
639}
640
641KeyboardCode KeyboardCodeFromNative(const base::NativeEvent& native_event) {
642  return KeyboardCodeFromXKeyEvent(native_event);
643}
644
645const char* CodeFromNative(const base::NativeEvent& native_event) {
646  return CodeFromXEvent(native_event);
647}
648
649uint32 PlatformKeycodeFromNative(const base::NativeEvent& native_event) {
650  XKeyEvent* xkey = NULL;
651  XEvent xkey_from_xi2;
652  switch (native_event->type) {
653    case KeyPress:
654    case KeyRelease:
655      xkey = &native_event->xkey;
656      break;
657    case GenericEvent: {
658      XIDeviceEvent* xievent =
659          static_cast<XIDeviceEvent*>(native_event->xcookie.data);
660      switch (xievent->evtype) {
661        case XI_KeyPress:
662        case XI_KeyRelease:
663          // Build an XKeyEvent corresponding to the XI2 event,
664          // so that we can call XLookupString on it.
665          InitXKeyEventFromXIDeviceEvent(*native_event, &xkey_from_xi2);
666          xkey = &xkey_from_xi2.xkey;
667          break;
668        default:
669          NOTREACHED();
670          break;
671      }
672      break;
673    }
674    default:
675      NOTREACHED();
676      break;
677  }
678  KeySym keysym = XK_VoidSymbol;
679  if (xkey)
680    XLookupString(xkey, NULL, 0, &keysym, NULL);
681  return keysym;
682}
683
684bool IsCharFromNative(const base::NativeEvent& native_event) {
685  return false;
686}
687
688int GetChangedMouseButtonFlagsFromNative(
689    const base::NativeEvent& native_event) {
690  switch (native_event->type) {
691    case ButtonPress:
692    case ButtonRelease:
693      return GetEventFlagsFromXState(native_event->xbutton.state);
694    case GenericEvent: {
695      XIDeviceEvent* xievent =
696          static_cast<XIDeviceEvent*>(native_event->xcookie.data);
697      switch (xievent->evtype) {
698        case XI_ButtonPress:
699        case XI_ButtonRelease:
700          return GetEventFlagsForButton(EventButtonFromNative(native_event));
701        default:
702          break;
703      }
704    }
705    default:
706      break;
707  }
708  return 0;
709}
710
711gfx::Vector2d GetMouseWheelOffset(const base::NativeEvent& native_event) {
712  float x_offset, y_offset;
713  if (GetScrollOffsets(
714      native_event, &x_offset, &y_offset, NULL, NULL, NULL)) {
715    return gfx::Vector2d(static_cast<int>(x_offset),
716                         static_cast<int>(y_offset));
717  }
718
719  int button = native_event->type == GenericEvent ?
720      EventButtonFromNative(native_event) : native_event->xbutton.button;
721
722  switch (button) {
723    case 4:
724      return gfx::Vector2d(0, kWheelScrollAmount);
725    case 5:
726      return gfx::Vector2d(0, -kWheelScrollAmount);
727    case 6:
728      return gfx::Vector2d(kWheelScrollAmount, 0);
729    case 7:
730      return gfx::Vector2d(-kWheelScrollAmount, 0);
731    default:
732      return gfx::Vector2d();
733  }
734}
735
736base::NativeEvent CopyNativeEvent(const base::NativeEvent& event) {
737  if (!event || event->type == GenericEvent)
738    return NULL;
739  XEvent* copy = new XEvent;
740  *copy = *event;
741  return copy;
742}
743
744void ReleaseCopiedNativeEvent(const base::NativeEvent& event) {
745  delete event;
746}
747
748void IncrementTouchIdRefCount(const base::NativeEvent& xev) {
749  ui::DeviceDataManagerX11* manager = ui::DeviceDataManagerX11::GetInstance();
750  double tracking_id;
751  if (!manager->GetEventData(
752          *xev, ui::DeviceDataManagerX11::DT_TOUCH_TRACKING_ID, &tracking_id)) {
753    return;
754  }
755
756  ui::TouchFactory* factory = ui::TouchFactory::GetInstance();
757  factory->AcquireSlotForTrackingID(tracking_id);
758}
759
760void ClearTouchIdIfReleased(const base::NativeEvent& xev) {
761  ui::EventType type = ui::EventTypeFromNative(xev);
762  if (type == ui::ET_TOUCH_CANCELLED ||
763      type == ui::ET_TOUCH_RELEASED) {
764    ui::TouchFactory* factory = ui::TouchFactory::GetInstance();
765    ui::DeviceDataManagerX11* manager = ui::DeviceDataManagerX11::GetInstance();
766    double tracking_id;
767    if (manager->GetEventData(
768        *xev, ui::DeviceDataManagerX11::DT_TOUCH_TRACKING_ID, &tracking_id)) {
769      factory->ReleaseSlotForTrackingID(tracking_id);
770    }
771  }
772}
773
774int GetTouchId(const base::NativeEvent& xev) {
775  double slot = 0;
776  ui::DeviceDataManagerX11* manager = ui::DeviceDataManagerX11::GetInstance();
777  double tracking_id;
778  if (!manager->GetEventData(
779      *xev, ui::DeviceDataManagerX11::DT_TOUCH_TRACKING_ID, &tracking_id)) {
780    LOG(ERROR) << "Could not get the tracking ID for the event. Using 0.";
781  } else {
782    ui::TouchFactory* factory = ui::TouchFactory::GetInstance();
783    slot = factory->GetSlotForTrackingID(tracking_id);
784  }
785  return slot;
786}
787
788float GetTouchRadiusX(const base::NativeEvent& native_event) {
789  double radius = GetTouchParamFromXEvent(native_event,
790      ui::DeviceDataManagerX11::DT_TOUCH_MAJOR, 0.0) / 2.0;
791  ScaleTouchRadius(native_event, &radius);
792  return radius;
793}
794
795float GetTouchRadiusY(const base::NativeEvent& native_event) {
796  double radius = GetTouchParamFromXEvent(native_event,
797      ui::DeviceDataManagerX11::DT_TOUCH_MINOR, 0.0) / 2.0;
798  ScaleTouchRadius(native_event, &radius);
799  return radius;
800}
801
802float GetTouchAngle(const base::NativeEvent& native_event) {
803  return GetTouchParamFromXEvent(native_event,
804      ui::DeviceDataManagerX11::DT_TOUCH_ORIENTATION, 0.0) / 2.0;
805}
806
807float GetTouchForce(const base::NativeEvent& native_event) {
808  double force = 0.0;
809  force = GetTouchParamFromXEvent(native_event,
810      ui::DeviceDataManagerX11::DT_TOUCH_PRESSURE, 0.0);
811  unsigned int deviceid =
812      static_cast<XIDeviceEvent*>(native_event->xcookie.data)->sourceid;
813  // Force is normalized to fall into [0, 1]
814  if (!ui::DeviceDataManagerX11::GetInstance()->NormalizeData(
815      deviceid, ui::DeviceDataManagerX11::DT_TOUCH_PRESSURE, &force))
816    force = 0.0;
817  return force;
818}
819
820bool GetScrollOffsets(const base::NativeEvent& native_event,
821                      float* x_offset,
822                      float* y_offset,
823                      float* x_offset_ordinal,
824                      float* y_offset_ordinal,
825                      int* finger_count) {
826  if (!DeviceDataManagerX11::GetInstance()->IsScrollEvent(native_event))
827    return false;
828
829  // Temp values to prevent passing NULLs to DeviceDataManager.
830  float x_offset_, y_offset_;
831  float x_offset_ordinal_, y_offset_ordinal_;
832  int finger_count_;
833  if (!x_offset)
834    x_offset = &x_offset_;
835  if (!y_offset)
836    y_offset = &y_offset_;
837  if (!x_offset_ordinal)
838    x_offset_ordinal = &x_offset_ordinal_;
839  if (!y_offset_ordinal)
840    y_offset_ordinal = &y_offset_ordinal_;
841  if (!finger_count)
842    finger_count = &finger_count_;
843
844  DeviceDataManagerX11::GetInstance()->GetScrollOffsets(
845      native_event,
846      x_offset, y_offset,
847      x_offset_ordinal, y_offset_ordinal,
848      finger_count);
849  return true;
850}
851
852bool GetFlingData(const base::NativeEvent& native_event,
853                  float* vx,
854                  float* vy,
855                  float* vx_ordinal,
856                  float* vy_ordinal,
857                  bool* is_cancel) {
858  if (!DeviceDataManagerX11::GetInstance()->IsFlingEvent(native_event))
859    return false;
860
861  float vx_, vy_;
862  float vx_ordinal_, vy_ordinal_;
863  bool is_cancel_;
864  if (!vx)
865    vx = &vx_;
866  if (!vy)
867    vy = &vy_;
868  if (!vx_ordinal)
869    vx_ordinal = &vx_ordinal_;
870  if (!vy_ordinal)
871    vy_ordinal = &vy_ordinal_;
872  if (!is_cancel)
873    is_cancel = &is_cancel_;
874
875  DeviceDataManagerX11::GetInstance()->GetFlingData(
876      native_event, vx, vy, vx_ordinal, vy_ordinal, is_cancel);
877  return true;
878}
879
880void UpdateX11EventForFlags(Event* event) {
881  XEvent* xev = event->native_event();
882  if (!xev)
883    return;
884  switch (xev->type) {
885    case KeyPress:
886    case KeyRelease:
887      xev->xkey.state = UpdateX11EventFlags(event->flags(), xev->xkey.state);
888      break;
889    case ButtonPress:
890    case ButtonRelease:
891      xev->xbutton.state =
892          UpdateX11EventFlags(event->flags(), xev->xbutton.state);
893      break;
894    case GenericEvent: {
895      XIDeviceEvent* xievent = static_cast<XIDeviceEvent*>(xev->xcookie.data);
896      DCHECK(xievent);
897      xievent->mods.effective =
898          UpdateX11EventFlags(event->flags(), xievent->mods.effective);
899      break;
900    }
901    default:
902      break;
903  }
904}
905
906void UpdateX11EventForChangedButtonFlags(MouseEvent* event) {
907  XEvent* xev = event->native_event();
908  if (!xev)
909    return;
910  switch (xev->type) {
911    case ButtonPress:
912    case ButtonRelease:
913      xev->xbutton.button = UpdateX11EventButton(event->changed_button_flags(),
914                                                 xev->xbutton.button);
915      break;
916    case GenericEvent: {
917      XIDeviceEvent* xievent = static_cast<XIDeviceEvent*>(xev->xcookie.data);
918      CHECK(xievent && (xievent->evtype == XI_ButtonPress ||
919                        xievent->evtype == XI_ButtonRelease));
920      xievent->detail =
921          UpdateX11EventButton(event->changed_button_flags(), xievent->detail);
922      break;
923    }
924    default:
925      break;
926  }
927}
928
929}  // namespace ui
930