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).
71const 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.
97const int kCMTDataTypeStart = ui::DeviceDataManager::DT_CMT_SCROLL_X;
98const int kCMTDataTypeEnd = ui::DeviceDataManager::DT_CMT_FINGER_COUNT;
99const int kTouchDataTypeStart = ui::DeviceDataManager::DT_TOUCH_MAJOR;
100const int kTouchDataTypeEnd = ui::DeviceDataManager::DT_TOUCH_RAW_TIMESTAMP;
101
102namespace ui {
103
104bool DeviceDataManager::IsCMTDataType(const int type) {
105  return (type >= kCMTDataTypeStart) && (type <= kCMTDataTypeEnd);
106}
107
108bool DeviceDataManager::IsTouchDataType(const int type) {
109  return (type >= kTouchDataTypeStart) && (type <= kTouchDataTypeEnd);
110}
111
112DeviceDataManager* DeviceDataManager::GetInstance() {
113  return Singleton<DeviceDataManager>::get();
114}
115
116DeviceDataManager::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
131DeviceDataManager::~DeviceDataManager() {
132}
133
134bool 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
181bool DeviceDataManager::IsXInput2Available() const {
182  return xi_opcode_ != -1;
183}
184
185void 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
269bool 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
283void 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
309bool 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
358bool 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
366bool 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
378bool 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
390bool DeviceDataManager::IsCMTGestureEvent(
391    const base::NativeEvent& native_event) const {
392  return (IsScrollEvent(native_event) ||
393          IsFlingEvent(native_event) ||
394          IsCMTMetricsEvent(native_event));
395}
396
397bool 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
403bool 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
414bool 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
426bool 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
438bool 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
449void 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
475void 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
500void 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
523int DeviceDataManager::GetMappedButton(int button) {
524  return button > 0 && button <= button_map_count_ ? button_map_[button - 1] :
525                                                     button;
526}
527
528void DeviceDataManager::UpdateButtonMap() {
529  button_map_count_ = XGetPointerMapping(gfx::GetXDisplay(),
530                                         button_map_,
531                                         arraysize(button_map_));
532}
533
534void 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
549bool 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
562bool 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
575void 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
604void 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
623void 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
643bool 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
654void 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
661bool DeviceDataManager::IsTouchDeviceIdValid(int touch_device_id) const {
662  return (touch_device_id > 0 && touch_device_id < kMaxDeviceNum);
663}
664
665void 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
675void 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
687int64 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