Upstream version 11.40.271.0
[platform/framework/web/crosswalk.git] / src / ui / events / devices / x11 / device_data_manager_x11.cc
1 // Copyright 2014 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/devices/x11/device_data_manager_x11.h"
6
7 #include <X11/extensions/XInput.h>
8 #include <X11/extensions/XInput2.h>
9 #include <X11/Xlib.h>
10
11 #include <utility>
12
13 #include "base/logging.h"
14 #include "base/memory/singleton.h"
15 #include "base/sys_info.h"
16 #include "ui/events/devices/keyboard_device.h"
17 #include "ui/events/devices/x11/device_list_cache_x11.h"
18 #include "ui/events/devices/x11/touch_factory_x11.h"
19 #include "ui/events/event_constants.h"
20 #include "ui/events/event_switches.h"
21 #include "ui/events/keycodes/keyboard_code_conversion_x.h"
22 #include "ui/gfx/display.h"
23 #include "ui/gfx/point3_f.h"
24 #include "ui/gfx/x/x11_types.h"
25
26 // XIScrollClass was introduced in XI 2.1 so we need to define it here
27 // for backward-compatibility with older versions of XInput.
28 #if !defined(XIScrollClass)
29 #define XIScrollClass 3
30 #endif
31
32 // Multi-touch support was introduced in XI 2.2. Add XI event types here
33 // for backward-compatibility with older versions of XInput.
34 #if !defined(XI_TouchBegin)
35 #define XI_TouchBegin  18
36 #define XI_TouchUpdate 19
37 #define XI_TouchEnd    20
38 #endif
39
40 // Copied from xserver-properties.h
41 #define AXIS_LABEL_PROP_REL_HWHEEL "Rel Horiz Wheel"
42 #define AXIS_LABEL_PROP_REL_WHEEL "Rel Vert Wheel"
43
44 // CMT specific timings
45 #define AXIS_LABEL_PROP_ABS_DBL_START_TIME "Abs Dbl Start Timestamp"
46 #define AXIS_LABEL_PROP_ABS_DBL_END_TIME   "Abs Dbl End Timestamp"
47
48 // Ordinal values
49 #define AXIS_LABEL_PROP_ABS_DBL_ORDINAL_X   "Abs Dbl Ordinal X"
50 #define AXIS_LABEL_PROP_ABS_DBL_ORDINAL_Y   "Abs Dbl Ordinal Y"
51
52 // Fling properties
53 #define AXIS_LABEL_PROP_ABS_DBL_FLING_VX   "Abs Dbl Fling X Velocity"
54 #define AXIS_LABEL_PROP_ABS_DBL_FLING_VY   "Abs Dbl Fling Y Velocity"
55 #define AXIS_LABEL_PROP_ABS_FLING_STATE   "Abs Fling State"
56
57 #define AXIS_LABEL_PROP_ABS_FINGER_COUNT   "Abs Finger Count"
58
59 // Cros metrics gesture from touchpad
60 #define AXIS_LABEL_PROP_ABS_METRICS_TYPE      "Abs Metrics Type"
61 #define AXIS_LABEL_PROP_ABS_DBL_METRICS_DATA1 "Abs Dbl Metrics Data 1"
62 #define AXIS_LABEL_PROP_ABS_DBL_METRICS_DATA2 "Abs Dbl Metrics Data 2"
63
64 // Touchscreen multi-touch
65 #define AXIS_LABEL_ABS_MT_TOUCH_MAJOR "Abs MT Touch Major"
66 #define AXIS_LABEL_ABS_MT_TOUCH_MINOR "Abs MT Touch Minor"
67 #define AXIS_LABEL_ABS_MT_ORIENTATION "Abs MT Orientation"
68 #define AXIS_LABEL_ABS_MT_PRESSURE    "Abs MT Pressure"
69 #define AXIS_LABEL_ABS_MT_POSITION_X  "Abs MT Position X"
70 #define AXIS_LABEL_ABS_MT_POSITION_Y  "Abs MT Position Y"
71 #define AXIS_LABEL_ABS_MT_TRACKING_ID "Abs MT Tracking ID"
72 #define AXIS_LABEL_TOUCH_TIMESTAMP    "Touch Timestamp"
73
74 // When you add new data types, please make sure the order here is aligned
75 // with the order in the DataType enum in the header file because we assume
76 // they are in sync when updating the device list (see UpdateDeviceList).
77 const char* kCachedAtoms[] = {
78   AXIS_LABEL_PROP_REL_HWHEEL,
79   AXIS_LABEL_PROP_REL_WHEEL,
80   AXIS_LABEL_PROP_ABS_DBL_ORDINAL_X,
81   AXIS_LABEL_PROP_ABS_DBL_ORDINAL_Y,
82   AXIS_LABEL_PROP_ABS_DBL_START_TIME,
83   AXIS_LABEL_PROP_ABS_DBL_END_TIME,
84   AXIS_LABEL_PROP_ABS_DBL_FLING_VX,
85   AXIS_LABEL_PROP_ABS_DBL_FLING_VY,
86   AXIS_LABEL_PROP_ABS_FLING_STATE,
87   AXIS_LABEL_PROP_ABS_METRICS_TYPE,
88   AXIS_LABEL_PROP_ABS_DBL_METRICS_DATA1,
89   AXIS_LABEL_PROP_ABS_DBL_METRICS_DATA2,
90   AXIS_LABEL_PROP_ABS_FINGER_COUNT,
91   AXIS_LABEL_ABS_MT_TOUCH_MAJOR,
92   AXIS_LABEL_ABS_MT_TOUCH_MINOR,
93   AXIS_LABEL_ABS_MT_ORIENTATION,
94   AXIS_LABEL_ABS_MT_PRESSURE,
95   AXIS_LABEL_ABS_MT_POSITION_X,
96   AXIS_LABEL_ABS_MT_POSITION_Y,
97   AXIS_LABEL_ABS_MT_TRACKING_ID,
98   AXIS_LABEL_TOUCH_TIMESTAMP,
99
100   NULL
101 };
102
103 // Constants for checking if a data type lies in the range of CMT/Touch data
104 // types.
105 const int kCMTDataTypeStart = ui::DeviceDataManagerX11::DT_CMT_SCROLL_X;
106 const int kCMTDataTypeEnd = ui::DeviceDataManagerX11::DT_CMT_FINGER_COUNT;
107 const int kTouchDataTypeStart = ui::DeviceDataManagerX11::DT_TOUCH_MAJOR;
108 const int kTouchDataTypeEnd = ui::DeviceDataManagerX11::DT_TOUCH_RAW_TIMESTAMP;
109
110 namespace ui {
111
112 namespace {
113
114 bool KeyboardDeviceHasId(const ui::KeyboardDevice keyboard, unsigned int id) {
115   return keyboard.id == id;
116 }
117
118 }  // namespace
119
120 bool DeviceDataManagerX11::IsCMTDataType(const int type) {
121   return (type >= kCMTDataTypeStart) && (type <= kCMTDataTypeEnd);
122 }
123
124 bool DeviceDataManagerX11::IsTouchDataType(const int type) {
125   return (type >= kTouchDataTypeStart) && (type <= kTouchDataTypeEnd);
126 }
127
128 // static
129 void DeviceDataManagerX11::CreateInstance() {
130   if (instance())
131     return;
132
133   new DeviceDataManagerX11();
134 }
135
136 // static
137 DeviceDataManagerX11* DeviceDataManagerX11::GetInstance() {
138   return static_cast<DeviceDataManagerX11*>(DeviceDataManager::GetInstance());
139 }
140
141 DeviceDataManagerX11::DeviceDataManagerX11()
142     : xi_opcode_(-1),
143       atom_cache_(gfx::GetXDisplay(), kCachedAtoms),
144       button_map_count_(0) {
145   CHECK(gfx::GetXDisplay());
146   InitializeXInputInternal();
147
148   // Make sure the sizes of enum and kCachedAtoms are aligned.
149   CHECK(arraysize(kCachedAtoms) == static_cast<size_t>(DT_LAST_ENTRY) + 1);
150   UpdateDeviceList(gfx::GetXDisplay());
151   UpdateButtonMap();
152 }
153
154 DeviceDataManagerX11::~DeviceDataManagerX11() {
155 }
156
157 bool DeviceDataManagerX11::InitializeXInputInternal() {
158   // Check if XInput is available on the system.
159   xi_opcode_ = -1;
160   int opcode, event, error;
161   if (!XQueryExtension(
162       gfx::GetXDisplay(), "XInputExtension", &opcode, &event, &error)) {
163     VLOG(1) << "X Input extension not available: error=" << error;
164     return false;
165   }
166
167   // Check the XInput version.
168 #if defined(USE_XI2_MT)
169   int major = 2, minor = USE_XI2_MT;
170 #else
171   int major = 2, minor = 0;
172 #endif
173   if (XIQueryVersion(gfx::GetXDisplay(), &major, &minor) == BadRequest) {
174     VLOG(1) << "XInput2 not supported in the server.";
175     return false;
176   }
177 #if defined(USE_XI2_MT)
178   if (major < 2 || (major == 2 && minor < USE_XI2_MT)) {
179     DVLOG(1) << "XI version on server is " << major << "." << minor << ". "
180             << "But 2." << USE_XI2_MT << " is required.";
181     return false;
182   }
183 #endif
184
185   xi_opcode_ = opcode;
186   CHECK_NE(-1, xi_opcode_);
187
188   // Possible XI event types for XIDeviceEvent. See the XI2 protocol
189   // specification.
190   xi_device_event_types_[XI_KeyPress] = true;
191   xi_device_event_types_[XI_KeyRelease] = true;
192   xi_device_event_types_[XI_ButtonPress] = true;
193   xi_device_event_types_[XI_ButtonRelease] = true;
194   xi_device_event_types_[XI_Motion] = true;
195   // Multi-touch support was introduced in XI 2.2.
196   if (minor >= 2) {
197     xi_device_event_types_[XI_TouchBegin] = true;
198     xi_device_event_types_[XI_TouchUpdate] = true;
199     xi_device_event_types_[XI_TouchEnd] = true;
200   }
201   return true;
202 }
203
204 bool DeviceDataManagerX11::IsXInput2Available() const {
205   return xi_opcode_ != -1;
206 }
207
208 void DeviceDataManagerX11::UpdateDeviceList(Display* display) {
209   cmt_devices_.reset();
210   touchpads_.reset();
211   for (int i = 0; i < kMaxDeviceNum; ++i) {
212     valuator_count_[i] = 0;
213     valuator_lookup_[i].clear();
214     data_type_lookup_[i].clear();
215     valuator_min_[i].clear();
216     valuator_max_[i].clear();
217     for (int j = 0; j < kMaxSlotNum; j++)
218       last_seen_valuator_[i][j].clear();
219   }
220
221   // Find all the touchpad devices.
222   XDeviceList dev_list =
223       ui::DeviceListCacheX11::GetInstance()->GetXDeviceList(display);
224   Atom xi_touchpad = XInternAtom(display, XI_TOUCHPAD, false);
225   for (int i = 0; i < dev_list.count; ++i)
226     if (dev_list[i].type == xi_touchpad)
227       touchpads_[dev_list[i].id] = true;
228
229   if (!IsXInput2Available())
230     return;
231
232   // Update the structs with new valuator information
233   XIDeviceList info_list =
234       ui::DeviceListCacheX11::GetInstance()->GetXI2DeviceList(display);
235   Atom atoms[DT_LAST_ENTRY];
236   for (int data_type = 0; data_type < DT_LAST_ENTRY; ++data_type)
237     atoms[data_type] = atom_cache_.GetAtom(kCachedAtoms[data_type]);
238
239   for (int i = 0; i < info_list.count; ++i) {
240     XIDeviceInfo* info = info_list.devices + i;
241
242     // We currently handle only slave, non-keyboard devices
243     if (info->use != XISlavePointer && info->use != XIFloatingSlave)
244       continue;
245
246     bool possible_cmt = false;
247     bool not_cmt = false;
248     const int deviceid = info->deviceid;
249
250     for (int j = 0; j < info->num_classes; ++j) {
251       if (info->classes[j]->type == XIValuatorClass)
252         ++valuator_count_[deviceid];
253       else if (info->classes[j]->type == XIScrollClass)
254         not_cmt = true;
255     }
256
257     // Skip devices that don't use any valuator
258     if (!valuator_count_[deviceid])
259       continue;
260
261     valuator_lookup_[deviceid].resize(DT_LAST_ENTRY, -1);
262     data_type_lookup_[deviceid].resize(
263         valuator_count_[deviceid], DT_LAST_ENTRY);
264     valuator_min_[deviceid].resize(DT_LAST_ENTRY, 0);
265     valuator_max_[deviceid].resize(DT_LAST_ENTRY, 0);
266     for (int j = 0; j < kMaxSlotNum; j++)
267       last_seen_valuator_[deviceid][j].resize(DT_LAST_ENTRY, 0);
268     for (int j = 0; j < info->num_classes; ++j) {
269       if (info->classes[j]->type != XIValuatorClass)
270         continue;
271
272       XIValuatorClassInfo* v =
273           reinterpret_cast<XIValuatorClassInfo*>(info->classes[j]);
274       for (int data_type = 0; data_type < DT_LAST_ENTRY; ++data_type) {
275         if (v->label == atoms[data_type]) {
276           valuator_lookup_[deviceid][data_type] = v->number;
277           data_type_lookup_[deviceid][v->number] = data_type;
278           valuator_min_[deviceid][data_type] = v->min;
279           valuator_max_[deviceid][data_type] = v->max;
280           if (IsCMTDataType(data_type))
281             possible_cmt = true;
282           break;
283         }
284       }
285     }
286
287     if (possible_cmt && !not_cmt)
288       cmt_devices_[deviceid] = true;
289   }
290 }
291
292 bool DeviceDataManagerX11::GetSlotNumber(const XIDeviceEvent* xiev, int* slot) {
293 #if defined(USE_XI2_MT)
294   ui::TouchFactory* factory = ui::TouchFactory::GetInstance();
295   if (!factory->IsMultiTouchDevice(xiev->sourceid)) {
296     *slot = 0;
297     return true;
298   }
299   return factory->QuerySlotForTrackingID(xiev->detail, slot);
300 #else
301   *slot = 0;
302   return true;
303 #endif
304 }
305
306 void DeviceDataManagerX11::GetEventRawData(const XEvent& xev, EventData* data) {
307   if (xev.type != GenericEvent)
308     return;
309
310   XIDeviceEvent* xiev = static_cast<XIDeviceEvent*>(xev.xcookie.data);
311   if (xiev->sourceid >= kMaxDeviceNum || xiev->deviceid >= kMaxDeviceNum)
312     return;
313   data->clear();
314   const int sourceid = xiev->sourceid;
315   double* valuators = xiev->valuators.values;
316   for (int i = 0; i <= valuator_count_[sourceid]; ++i) {
317     if (XIMaskIsSet(xiev->valuators.mask, i)) {
318       int type = data_type_lookup_[sourceid][i];
319       if (type != DT_LAST_ENTRY) {
320         (*data)[type] = *valuators;
321         if (IsTouchDataType(type)) {
322           int slot = -1;
323           if (GetSlotNumber(xiev, &slot) && slot >= 0 && slot < kMaxSlotNum)
324             last_seen_valuator_[sourceid][slot][type] = *valuators;
325         }
326       }
327       valuators++;
328     }
329   }
330 }
331
332 bool DeviceDataManagerX11::GetEventData(const XEvent& xev,
333     const DataType type, double* value) {
334   if (xev.type != GenericEvent)
335     return false;
336
337   XIDeviceEvent* xiev = static_cast<XIDeviceEvent*>(xev.xcookie.data);
338   if (xiev->sourceid >= kMaxDeviceNum || xiev->deviceid >= kMaxDeviceNum)
339     return false;
340   const int sourceid = xiev->sourceid;
341   if (valuator_lookup_[sourceid].empty())
342     return false;
343
344   if (type == DT_TOUCH_TRACKING_ID) {
345     // With XInput2 MT, Tracking ID is provided in the detail field for touch
346     // events.
347     if (xiev->evtype == XI_TouchBegin ||
348         xiev->evtype == XI_TouchEnd ||
349         xiev->evtype == XI_TouchUpdate) {
350       *value = xiev->detail;
351     } else {
352       *value = 0;
353     }
354     return true;
355   }
356
357   int val_index = valuator_lookup_[sourceid][type];
358   int slot = 0;
359   if (val_index >= 0) {
360     if (XIMaskIsSet(xiev->valuators.mask, val_index)) {
361       double* valuators = xiev->valuators.values;
362       while (val_index--) {
363         if (XIMaskIsSet(xiev->valuators.mask, val_index))
364           ++valuators;
365       }
366       *value = *valuators;
367       if (IsTouchDataType(type)) {
368         if (GetSlotNumber(xiev, &slot) && slot >= 0 && slot < kMaxSlotNum)
369           last_seen_valuator_[sourceid][slot][type] = *value;
370       }
371       return true;
372     } else if (IsTouchDataType(type)) {
373       if (GetSlotNumber(xiev, &slot) && slot >= 0 && slot < kMaxSlotNum)
374         *value = last_seen_valuator_[sourceid][slot][type];
375     }
376   }
377
378   return false;
379 }
380
381 bool DeviceDataManagerX11::IsXIDeviceEvent(
382     const base::NativeEvent& native_event) const {
383   if (native_event->type != GenericEvent ||
384       native_event->xcookie.extension != xi_opcode_)
385     return false;
386   return xi_device_event_types_[native_event->xcookie.evtype];
387 }
388
389 bool DeviceDataManagerX11::IsTouchpadXInputEvent(
390     const base::NativeEvent& native_event) const {
391   if (native_event->type != GenericEvent)
392     return false;
393
394   XIDeviceEvent* xievent =
395       static_cast<XIDeviceEvent*>(native_event->xcookie.data);
396   if (xievent->sourceid >= kMaxDeviceNum)
397     return false;
398   return touchpads_[xievent->sourceid];
399 }
400
401 bool DeviceDataManagerX11::IsCMTDeviceEvent(
402     const base::NativeEvent& native_event) const {
403   if (native_event->type != GenericEvent)
404     return false;
405
406   XIDeviceEvent* xievent =
407       static_cast<XIDeviceEvent*>(native_event->xcookie.data);
408   if (xievent->sourceid >= kMaxDeviceNum)
409     return false;
410   return cmt_devices_[xievent->sourceid];
411 }
412
413 bool DeviceDataManagerX11::IsCMTGestureEvent(
414     const base::NativeEvent& native_event) const {
415   return (IsScrollEvent(native_event) ||
416           IsFlingEvent(native_event) ||
417           IsCMTMetricsEvent(native_event));
418 }
419
420 bool DeviceDataManagerX11::HasEventData(
421     const XIDeviceEvent* xiev, const DataType type) const {
422   const int idx = valuator_lookup_[xiev->sourceid][type];
423   return (idx >= 0) && XIMaskIsSet(xiev->valuators.mask, idx);
424 }
425
426 bool DeviceDataManagerX11::IsScrollEvent(
427     const base::NativeEvent& native_event) const {
428   if (!IsCMTDeviceEvent(native_event))
429     return false;
430
431   XIDeviceEvent* xiev =
432       static_cast<XIDeviceEvent*>(native_event->xcookie.data);
433   return (HasEventData(xiev, DT_CMT_SCROLL_X) ||
434           HasEventData(xiev, DT_CMT_SCROLL_Y));
435 }
436
437 bool DeviceDataManagerX11::IsFlingEvent(
438     const base::NativeEvent& native_event) const {
439   if (!IsCMTDeviceEvent(native_event))
440     return false;
441
442   XIDeviceEvent* xiev =
443       static_cast<XIDeviceEvent*>(native_event->xcookie.data);
444   return (HasEventData(xiev, DT_CMT_FLING_X) &&
445           HasEventData(xiev, DT_CMT_FLING_Y) &&
446           HasEventData(xiev, DT_CMT_FLING_STATE));
447 }
448
449 bool DeviceDataManagerX11::IsCMTMetricsEvent(
450     const base::NativeEvent& native_event) const {
451   if (!IsCMTDeviceEvent(native_event))
452     return false;
453
454   XIDeviceEvent* xiev =
455       static_cast<XIDeviceEvent*>(native_event->xcookie.data);
456   return (HasEventData(xiev, DT_CMT_METRICS_TYPE) &&
457           HasEventData(xiev, DT_CMT_METRICS_DATA1) &&
458           HasEventData(xiev, DT_CMT_METRICS_DATA2));
459 }
460
461 bool DeviceDataManagerX11::HasGestureTimes(
462     const base::NativeEvent& native_event) const {
463   if (!IsCMTDeviceEvent(native_event))
464     return false;
465
466   XIDeviceEvent* xiev =
467       static_cast<XIDeviceEvent*>(native_event->xcookie.data);
468   return (HasEventData(xiev, DT_CMT_START_TIME) &&
469           HasEventData(xiev, DT_CMT_END_TIME));
470 }
471
472 void DeviceDataManagerX11::GetScrollOffsets(
473     const base::NativeEvent& native_event,
474     float* x_offset,
475     float* y_offset,
476     float* x_offset_ordinal,
477     float* y_offset_ordinal,
478     int* finger_count) {
479   *x_offset = 0;
480   *y_offset = 0;
481   *x_offset_ordinal = 0;
482   *y_offset_ordinal = 0;
483   *finger_count = 2;
484
485   EventData data;
486   GetEventRawData(*native_event, &data);
487
488   if (data.find(DT_CMT_SCROLL_X) != data.end())
489     *x_offset = data[DT_CMT_SCROLL_X];
490   if (data.find(DT_CMT_SCROLL_Y) != data.end())
491     *y_offset = data[DT_CMT_SCROLL_Y];
492   if (data.find(DT_CMT_ORDINAL_X) != data.end())
493     *x_offset_ordinal = data[DT_CMT_ORDINAL_X];
494   if (data.find(DT_CMT_ORDINAL_Y) != data.end())
495     *y_offset_ordinal = data[DT_CMT_ORDINAL_Y];
496   if (data.find(DT_CMT_FINGER_COUNT) != data.end())
497     *finger_count = static_cast<int>(data[DT_CMT_FINGER_COUNT]);
498 }
499
500 void DeviceDataManagerX11::GetFlingData(
501     const base::NativeEvent& native_event,
502     float* vx,
503     float* vy,
504     float* vx_ordinal,
505     float* vy_ordinal,
506     bool* is_cancel) {
507   *vx = 0;
508   *vy = 0;
509   *vx_ordinal = 0;
510   *vy_ordinal = 0;
511   *is_cancel = false;
512
513   EventData data;
514   GetEventRawData(*native_event, &data);
515
516   if (data.find(DT_CMT_FLING_X) != data.end())
517     *vx = data[DT_CMT_FLING_X];
518   if (data.find(DT_CMT_FLING_Y) != data.end())
519     *vy = data[DT_CMT_FLING_Y];
520   if (data.find(DT_CMT_FLING_STATE) != data.end())
521     *is_cancel = !!static_cast<unsigned int>(data[DT_CMT_FLING_STATE]);
522   if (data.find(DT_CMT_ORDINAL_X) != data.end())
523     *vx_ordinal = data[DT_CMT_ORDINAL_X];
524   if (data.find(DT_CMT_ORDINAL_Y) != data.end())
525     *vy_ordinal = data[DT_CMT_ORDINAL_Y];
526 }
527
528 void DeviceDataManagerX11::GetMetricsData(
529     const base::NativeEvent& native_event,
530     GestureMetricsType* type,
531     float* data1,
532     float* data2) {
533   *type = kGestureMetricsTypeUnknown;
534   *data1 = 0;
535   *data2 = 0;
536
537   EventData data;
538   GetEventRawData(*native_event, &data);
539
540   if (data.find(DT_CMT_METRICS_TYPE) != data.end()) {
541     int val = static_cast<int>(data[DT_CMT_METRICS_TYPE]);
542     if (val == 0)
543       *type = kGestureMetricsTypeNoisyGround;
544     else
545       *type = kGestureMetricsTypeUnknown;
546   }
547   if (data.find(DT_CMT_METRICS_DATA1) != data.end())
548     *data1 = data[DT_CMT_METRICS_DATA1];
549   if (data.find(DT_CMT_METRICS_DATA2) != data.end())
550     *data2 = data[DT_CMT_METRICS_DATA2];
551 }
552
553 int DeviceDataManagerX11::GetMappedButton(int button) {
554   return button > 0 && button <= button_map_count_ ? button_map_[button - 1] :
555                                                      button;
556 }
557
558 void DeviceDataManagerX11::UpdateButtonMap() {
559   button_map_count_ = XGetPointerMapping(gfx::GetXDisplay(),
560                                          button_map_,
561                                          arraysize(button_map_));
562 }
563
564 void DeviceDataManagerX11::GetGestureTimes(
565     const base::NativeEvent& native_event,
566     double* start_time,
567     double* end_time) {
568   *start_time = 0;
569   *end_time = 0;
570
571   EventData data;
572   GetEventRawData(*native_event, &data);
573
574   if (data.find(DT_CMT_START_TIME) != data.end())
575     *start_time = data[DT_CMT_START_TIME];
576   if (data.find(DT_CMT_END_TIME) != data.end())
577     *end_time = data[DT_CMT_END_TIME];
578 }
579
580 bool DeviceDataManagerX11::NormalizeData(unsigned int deviceid,
581                                          const DataType type,
582                                          double* value) {
583   double max_value;
584   double min_value;
585   if (GetDataRange(deviceid, type, &min_value, &max_value)) {
586     *value = (*value - min_value) / (max_value - min_value);
587     DCHECK(*value >= 0.0 && *value <= 1.0);
588     return true;
589   }
590   return false;
591 }
592
593 bool DeviceDataManagerX11::GetDataRange(unsigned int deviceid,
594                                         const DataType type,
595                                         double* min,
596                                         double* max) {
597   if (deviceid >= static_cast<unsigned int>(kMaxDeviceNum))
598     return false;
599   if (valuator_lookup_[deviceid][type] >= 0) {
600     *min = valuator_min_[deviceid][type];
601     *max = valuator_max_[deviceid][type];
602     return true;
603   }
604   return false;
605 }
606
607 void DeviceDataManagerX11::SetDeviceListForTest(
608     const std::vector<unsigned int>& touchscreen,
609     const std::vector<unsigned int>& cmt_devices) {
610   for (int i = 0; i < kMaxDeviceNum; ++i) {
611     valuator_count_[i] = 0;
612     valuator_lookup_[i].clear();
613     data_type_lookup_[i].clear();
614     valuator_min_[i].clear();
615     valuator_max_[i].clear();
616     for (int j = 0; j < kMaxSlotNum; j++)
617       last_seen_valuator_[i][j].clear();
618   }
619
620   for (size_t i = 0; i < touchscreen.size(); i++) {
621     unsigned int deviceid = touchscreen[i];
622     InitializeValuatorsForTest(deviceid, kTouchDataTypeStart, kTouchDataTypeEnd,
623                                0, 1000);
624   }
625
626   cmt_devices_.reset();
627   for (size_t i = 0; i < cmt_devices.size(); ++i) {
628     unsigned int deviceid = cmt_devices[i];
629     cmt_devices_[deviceid] = true;
630     touchpads_[deviceid] = true;
631     InitializeValuatorsForTest(deviceid, kCMTDataTypeStart, kCMTDataTypeEnd,
632                                -1000, 1000);
633   }
634 }
635
636 void DeviceDataManagerX11::SetValuatorDataForTest(XIDeviceEvent* xievent,
637                                                   DataType type,
638                                                   double value) {
639   int index = valuator_lookup_[xievent->deviceid][type];
640   CHECK(!XIMaskIsSet(xievent->valuators.mask, index));
641   CHECK(index >= 0 && index < valuator_count_[xievent->deviceid]);
642   XISetMask(xievent->valuators.mask, index);
643
644   double* valuators = xievent->valuators.values;
645   for (int i = 0; i < index; ++i) {
646     if (XIMaskIsSet(xievent->valuators.mask, i))
647       valuators++;
648   }
649   for (int i = DT_LAST_ENTRY - 1; i > valuators - xievent->valuators.values;
650        --i)
651     xievent->valuators.values[i] = xievent->valuators.values[i - 1];
652   *valuators = value;
653 }
654
655 void DeviceDataManagerX11::InitializeValuatorsForTest(int deviceid,
656                                                       int start_valuator,
657                                                       int end_valuator,
658                                                       double min_value,
659                                                       double max_value) {
660   valuator_lookup_[deviceid].resize(DT_LAST_ENTRY, -1);
661   data_type_lookup_[deviceid].resize(DT_LAST_ENTRY, DT_LAST_ENTRY);
662   valuator_min_[deviceid].resize(DT_LAST_ENTRY, 0);
663   valuator_max_[deviceid].resize(DT_LAST_ENTRY, 0);
664   for (int j = 0; j < kMaxSlotNum; j++)
665     last_seen_valuator_[deviceid][j].resize(DT_LAST_ENTRY, 0);
666   for (int j = start_valuator; j <= end_valuator; ++j) {
667     valuator_lookup_[deviceid][j] = valuator_count_[deviceid];
668     data_type_lookup_[deviceid][valuator_count_[deviceid]] = j;
669     valuator_min_[deviceid][j] = min_value;
670     valuator_max_[deviceid][j] = max_value;
671     valuator_count_[deviceid]++;
672   }
673 }
674
675 bool DeviceDataManagerX11::TouchEventNeedsCalibrate(
676     unsigned int touch_device_id) const {
677 #if defined(OS_CHROMEOS) && defined(USE_XI2_MT)
678   int64 touch_display_id = GetDisplayForTouchDevice(touch_device_id);
679   if (base::SysInfo::IsRunningOnChromeOS() &&
680       touch_display_id == gfx::Display::InternalDisplayId()) {
681     return true;
682   }
683 #endif  // defined(OS_CHROMEOS) && defined(USE_XI2_MT)
684   return false;
685 }
686
687 void DeviceDataManagerX11::SetDisabledKeyboardAllowedKeys(
688     scoped_ptr<std::set<KeyboardCode> > excepted_keys) {
689   DCHECK(!excepted_keys.get() ||
690          !blocked_keyboard_allowed_keys_.get());
691   blocked_keyboard_allowed_keys_ = excepted_keys.Pass();
692 }
693
694 void DeviceDataManagerX11::DisableDevice(unsigned int deviceid) {
695   blocked_devices_.set(deviceid, true);
696   // TODO(rsadam@): Support blocking touchscreen devices.
697   std::vector<KeyboardDevice> keyboards = keyboard_devices();
698   std::vector<KeyboardDevice>::iterator it =
699       std::find_if(keyboards.begin(),
700                    keyboards.end(),
701                    std::bind2nd(std::ptr_fun(&KeyboardDeviceHasId), deviceid));
702   if (it != std::end(keyboards)) {
703     blocked_keyboards_.insert(
704         std::pair<unsigned int, KeyboardDevice>(deviceid, *it));
705     keyboards.erase(it);
706     DeviceDataManager::OnKeyboardDevicesUpdated(keyboards);
707   }
708 }
709
710 void DeviceDataManagerX11::EnableDevice(unsigned int deviceid) {
711   blocked_devices_.set(deviceid, false);
712   std::map<unsigned int, KeyboardDevice>::iterator it =
713       blocked_keyboards_.find(deviceid);
714   if (it != blocked_keyboards_.end()) {
715     std::vector<KeyboardDevice> devices = keyboard_devices();
716     // Add device to current list of active devices.
717     devices.push_back((*it).second);
718     blocked_keyboards_.erase(it);
719     DeviceDataManager::OnKeyboardDevicesUpdated(devices);
720   }
721 }
722
723 bool DeviceDataManagerX11::IsEventBlocked(
724     const base::NativeEvent& native_event) {
725   // Only check XI2 events which have a source device id.
726   if (native_event->type != GenericEvent)
727     return false;
728
729   XIDeviceEvent* xievent =
730       static_cast<XIDeviceEvent*>(native_event->xcookie.data);
731   // Allow any key events from blocked_keyboard_allowed_keys_.
732   if (blocked_keyboard_allowed_keys_ &&
733       (xievent->evtype == XI_KeyPress || xievent->evtype == XI_KeyRelease) &&
734       blocked_keyboard_allowed_keys_->find(
735           KeyboardCodeFromXKeyEvent(native_event)) !=
736           blocked_keyboard_allowed_keys_->end()) {
737     return false;
738   }
739
740   return blocked_devices_.test(xievent->sourceid);
741 }
742
743 void DeviceDataManagerX11::OnKeyboardDevicesUpdated(
744     const std::vector<KeyboardDevice>& devices) {
745   std::vector<KeyboardDevice> keyboards(devices);
746   for (std::map<unsigned int, KeyboardDevice>::iterator blocked_iter =
747            blocked_keyboards_.begin();
748        blocked_iter != blocked_keyboards_.end();) {
749     // Check if the blocked device still exists in list of devices.
750     std::vector<KeyboardDevice>::iterator it =
751         std::find_if(keyboards.begin(),
752                      keyboards.end(),
753                      std::bind2nd(std::ptr_fun(&KeyboardDeviceHasId),
754                                   (*blocked_iter).first));
755     // If the device no longer exists, unblock it, else filter it out from our
756     // active list.
757     if (it == keyboards.end()) {
758       blocked_devices_.set((*blocked_iter).first, false);
759       blocked_keyboards_.erase(blocked_iter++);
760     } else {
761       keyboards.erase(it);
762       ++blocked_iter;
763     }
764   }
765   // Notify base class of updated list.
766   DeviceDataManager::OnKeyboardDevicesUpdated(keyboards);
767 }
768
769 }  // namespace ui