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