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