Home | History | Annotate | Download | only in x
      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 
    100 bool DeviceDataManager::IsCMTDataType(const int type) {
    101   return (type >= kCMTDataTypeStart) && (type <= kCMTDataTypeEnd);
    102 }
    103 
    104 bool DeviceDataManager::IsTouchDataType(const int type) {
    105   return (type >= kTouchDataTypeStart) && (type <= kTouchDataTypeEnd);
    106 }
    107 
    108 DeviceDataManager* DeviceDataManager::GetInstance() {
    109   return Singleton<DeviceDataManager>::get();
    110 }
    111 
    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 
    126 DeviceDataManager::~DeviceDataManager() {
    127 }
    128 
    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 
    176 bool DeviceDataManager::IsXInput2Available() const {
    177   return xi_opcode_ != -1;
    178 }
    179 
    180 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 
    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 
    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 
    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 
    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 
    361 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 
    369 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 
    381 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 
    393 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 
    400 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 
    406 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 
    417 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 
    429 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 
    441 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 
    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 
    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 
    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 
    532 int DeviceDataManager::GetMappedButton(int button) {
    533   return button > 0 && button <= button_map_count_ ? button_map_[button - 1] :
    534                                                      button;
    535 }
    536 
    537 void DeviceDataManager::UpdateButtonMap() {
    538   button_map_count_ = XGetPointerMapping(gfx::GetXDisplay(),
    539                                          button_map_,
    540                                          arraysize(button_map_));
    541 }
    542 
    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 
    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 
    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 
    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 
    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 
    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