Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / ui / events / x / events_x.cc
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
30 namespace {
31
32 // Scroll amount for each wheelscroll event. 53 is also the value used for GTK+.
33 const int kWheelScrollAmount = 53;
34
35 const int kMinWheelButton = 4;
36 const 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.
41 class 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
117 bool 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
144 int 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
169 int 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
200 int 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.
221 int 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
234 int 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
246 ui::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
282 double 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
290 void 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
297 unsigned 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
324 unsigned 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
338 bool 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
357 namespace ui {
358
359 void UpdateDeviceList() {
360   XDisplay* display = gfx::GetXDisplay();
361   DeviceListCacheX::GetInstance()->UpdateDeviceList(display);
362   TouchFactory::GetInstance()->UpdateDeviceList(display);
363   DeviceDataManagerX11::GetInstance()->UpdateDeviceList(display);
364 }
365
366 EventType 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
465 int 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
532 base::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
571 gfx::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
604 gfx::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
631 int 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
641 KeyboardCode KeyboardCodeFromNative(const base::NativeEvent& native_event) {
642   return KeyboardCodeFromXKeyEvent(native_event);
643 }
644
645 const char* CodeFromNative(const base::NativeEvent& native_event) {
646   return CodeFromXEvent(native_event);
647 }
648
649 uint32 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
684 bool IsCharFromNative(const base::NativeEvent& native_event) {
685   return false;
686 }
687
688 int 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
711 gfx::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
736 base::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
744 void ReleaseCopiedNativeEvent(const base::NativeEvent& event) {
745   delete event;
746 }
747
748 void 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
760 void 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
774 int 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
788 float 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
795 float 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
802 float GetTouchAngle(const base::NativeEvent& native_event) {
803   return GetTouchParamFromXEvent(native_event,
804       ui::DeviceDataManagerX11::DT_TOUCH_ORIENTATION, 0.0) / 2.0;
805 }
806
807 float 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
820 bool 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
852 bool 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
880 void 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
906 void 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