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