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