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