Change device IDs from unsigned to signed.
[chromium-blink-merge.git] / ui / events / devices / x11 / device_data_manager_x11.cc
blob85704437dfd2a84923762d0c9d770d7f18649661
1 // Copyright 2014 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.
5 #include "ui/events/devices/x11/device_data_manager_x11.h"
7 #include <X11/extensions/XInput.h>
8 #include <X11/extensions/XInput2.h>
9 #include <X11/Xlib.h>
11 #include <utility>
13 #include "base/logging.h"
14 #include "base/memory/singleton.h"
15 #include "base/sys_info.h"
16 #include "ui/events/devices/keyboard_device.h"
17 #include "ui/events/devices/x11/device_list_cache_x11.h"
18 #include "ui/events/devices/x11/touch_factory_x11.h"
19 #include "ui/events/event_constants.h"
20 #include "ui/events/event_switches.h"
21 #include "ui/events/keycodes/keyboard_code_conversion_x.h"
22 #include "ui/gfx/display.h"
23 #include "ui/gfx/geometry/point3_f.h"
24 #include "ui/gfx/x/x11_types.h"
26 // XIScrollClass was introduced in XI 2.1 so we need to define it here
27 // for backward-compatibility with older versions of XInput.
28 #if !defined(XIScrollClass)
29 #define XIScrollClass 3
30 #endif
32 // Multi-touch support was introduced in XI 2.2. Add XI event types here
33 // for backward-compatibility with older versions of XInput.
34 #if !defined(XI_TouchBegin)
35 #define XI_TouchBegin 18
36 #define XI_TouchUpdate 19
37 #define XI_TouchEnd 20
38 #endif
40 // Copied from xserver-properties.h
41 #define AXIS_LABEL_PROP_REL_HWHEEL "Rel Horiz Wheel"
42 #define AXIS_LABEL_PROP_REL_WHEEL "Rel Vert Wheel"
44 // CMT specific timings
45 #define AXIS_LABEL_PROP_ABS_DBL_START_TIME "Abs Dbl Start Timestamp"
46 #define AXIS_LABEL_PROP_ABS_DBL_END_TIME "Abs Dbl End Timestamp"
48 // Ordinal values
49 #define AXIS_LABEL_PROP_ABS_DBL_ORDINAL_X "Abs Dbl Ordinal X"
50 #define AXIS_LABEL_PROP_ABS_DBL_ORDINAL_Y "Abs Dbl Ordinal Y"
52 // Fling properties
53 #define AXIS_LABEL_PROP_ABS_DBL_FLING_VX "Abs Dbl Fling X Velocity"
54 #define AXIS_LABEL_PROP_ABS_DBL_FLING_VY "Abs Dbl Fling Y Velocity"
55 #define AXIS_LABEL_PROP_ABS_FLING_STATE "Abs Fling State"
57 #define AXIS_LABEL_PROP_ABS_FINGER_COUNT "Abs Finger Count"
59 // Cros metrics gesture from touchpad
60 #define AXIS_LABEL_PROP_ABS_METRICS_TYPE "Abs Metrics Type"
61 #define AXIS_LABEL_PROP_ABS_DBL_METRICS_DATA1 "Abs Dbl Metrics Data 1"
62 #define AXIS_LABEL_PROP_ABS_DBL_METRICS_DATA2 "Abs Dbl Metrics Data 2"
64 // Touchscreen multi-touch
65 #define AXIS_LABEL_ABS_MT_TOUCH_MAJOR "Abs MT Touch Major"
66 #define AXIS_LABEL_ABS_MT_TOUCH_MINOR "Abs MT Touch Minor"
67 #define AXIS_LABEL_ABS_MT_ORIENTATION "Abs MT Orientation"
68 #define AXIS_LABEL_ABS_MT_PRESSURE "Abs MT Pressure"
69 #define AXIS_LABEL_ABS_MT_POSITION_X "Abs MT Position X"
70 #define AXIS_LABEL_ABS_MT_POSITION_Y "Abs MT Position Y"
71 #define AXIS_LABEL_ABS_MT_TRACKING_ID "Abs MT Tracking ID"
72 #define AXIS_LABEL_TOUCH_TIMESTAMP "Touch Timestamp"
74 // When you add new data types, please make sure the order here is aligned
75 // with the order in the DataType enum in the header file because we assume
76 // they are in sync when updating the device list (see UpdateDeviceList).
77 const char* kCachedAtoms[] = {
78 AXIS_LABEL_PROP_REL_HWHEEL,
79 AXIS_LABEL_PROP_REL_WHEEL,
80 AXIS_LABEL_PROP_ABS_DBL_ORDINAL_X,
81 AXIS_LABEL_PROP_ABS_DBL_ORDINAL_Y,
82 AXIS_LABEL_PROP_ABS_DBL_START_TIME,
83 AXIS_LABEL_PROP_ABS_DBL_END_TIME,
84 AXIS_LABEL_PROP_ABS_DBL_FLING_VX,
85 AXIS_LABEL_PROP_ABS_DBL_FLING_VY,
86 AXIS_LABEL_PROP_ABS_FLING_STATE,
87 AXIS_LABEL_PROP_ABS_METRICS_TYPE,
88 AXIS_LABEL_PROP_ABS_DBL_METRICS_DATA1,
89 AXIS_LABEL_PROP_ABS_DBL_METRICS_DATA2,
90 AXIS_LABEL_PROP_ABS_FINGER_COUNT,
91 AXIS_LABEL_ABS_MT_TOUCH_MAJOR,
92 AXIS_LABEL_ABS_MT_TOUCH_MINOR,
93 AXIS_LABEL_ABS_MT_ORIENTATION,
94 AXIS_LABEL_ABS_MT_PRESSURE,
95 AXIS_LABEL_ABS_MT_POSITION_X,
96 AXIS_LABEL_ABS_MT_POSITION_Y,
97 AXIS_LABEL_ABS_MT_TRACKING_ID,
98 AXIS_LABEL_TOUCH_TIMESTAMP,
100 NULL
103 // Constants for checking if a data type lies in the range of CMT/Touch data
104 // types.
105 const int kCMTDataTypeStart = ui::DeviceDataManagerX11::DT_CMT_SCROLL_X;
106 const int kCMTDataTypeEnd = ui::DeviceDataManagerX11::DT_CMT_FINGER_COUNT;
107 const int kTouchDataTypeStart = ui::DeviceDataManagerX11::DT_TOUCH_MAJOR;
108 const int kTouchDataTypeEnd = ui::DeviceDataManagerX11::DT_TOUCH_RAW_TIMESTAMP;
110 namespace ui {
112 namespace {
114 bool DeviceHasId(const ui::InputDevice input_device, int id) {
115 return input_device.id == id;
118 } // namespace
120 bool DeviceDataManagerX11::IsCMTDataType(const int type) {
121 return (type >= kCMTDataTypeStart) && (type <= kCMTDataTypeEnd);
124 bool DeviceDataManagerX11::IsTouchDataType(const int type) {
125 return (type >= kTouchDataTypeStart) && (type <= kTouchDataTypeEnd);
128 // static
129 void DeviceDataManagerX11::CreateInstance() {
130 if (instance())
131 return;
133 new DeviceDataManagerX11();
136 // static
137 DeviceDataManagerX11* DeviceDataManagerX11::GetInstance() {
138 return static_cast<DeviceDataManagerX11*>(DeviceDataManager::GetInstance());
141 DeviceDataManagerX11::DeviceDataManagerX11()
142 : xi_opcode_(-1),
143 atom_cache_(gfx::GetXDisplay(), kCachedAtoms),
144 button_map_count_(0) {
145 CHECK(gfx::GetXDisplay());
146 InitializeXInputInternal();
148 // Make sure the sizes of enum and kCachedAtoms are aligned.
149 CHECK(arraysize(kCachedAtoms) == static_cast<size_t>(DT_LAST_ENTRY) + 1);
150 UpdateDeviceList(gfx::GetXDisplay());
151 UpdateButtonMap();
154 DeviceDataManagerX11::~DeviceDataManagerX11() {
157 bool DeviceDataManagerX11::InitializeXInputInternal() {
158 // Check if XInput is available on the system.
159 xi_opcode_ = -1;
160 int opcode, event, error;
161 if (!XQueryExtension(
162 gfx::GetXDisplay(), "XInputExtension", &opcode, &event, &error)) {
163 VLOG(1) << "X Input extension not available: error=" << error;
164 return false;
167 // Check the XInput version.
168 int major = 2, minor = 2;
169 if (XIQueryVersion(gfx::GetXDisplay(), &major, &minor) == BadRequest) {
170 VLOG(1) << "XInput2 not supported in the server.";
171 return false;
173 if (major < 2 || (major == 2 && minor < 2)) {
174 DVLOG(1) << "XI version on server is " << major << "." << minor << ". "
175 << "But 2.2 is required.";
176 return false;
179 xi_opcode_ = opcode;
180 CHECK_NE(-1, xi_opcode_);
182 // Possible XI event types for XIDeviceEvent. See the XI2 protocol
183 // specification.
184 xi_device_event_types_[XI_KeyPress] = true;
185 xi_device_event_types_[XI_KeyRelease] = true;
186 xi_device_event_types_[XI_ButtonPress] = true;
187 xi_device_event_types_[XI_ButtonRelease] = true;
188 xi_device_event_types_[XI_Motion] = true;
189 // Multi-touch support was introduced in XI 2.2.
190 if (minor >= 2) {
191 xi_device_event_types_[XI_TouchBegin] = true;
192 xi_device_event_types_[XI_TouchUpdate] = true;
193 xi_device_event_types_[XI_TouchEnd] = true;
195 return true;
198 bool DeviceDataManagerX11::IsXInput2Available() const {
199 return xi_opcode_ != -1;
202 void DeviceDataManagerX11::UpdateDeviceList(Display* display) {
203 cmt_devices_.reset();
204 touchpads_.reset();
205 master_pointers_.clear();
206 for (int i = 0; i < kMaxDeviceNum; ++i) {
207 valuator_count_[i] = 0;
208 valuator_lookup_[i].clear();
209 data_type_lookup_[i].clear();
210 valuator_min_[i].clear();
211 valuator_max_[i].clear();
212 for (int j = 0; j < kMaxSlotNum; j++)
213 last_seen_valuator_[i][j].clear();
216 // Find all the touchpad devices.
217 const XDeviceList& dev_list =
218 ui::DeviceListCacheX11::GetInstance()->GetXDeviceList(display);
219 Atom xi_touchpad = XInternAtom(display, XI_TOUCHPAD, false);
220 for (int i = 0; i < dev_list.count; ++i)
221 if (dev_list[i].type == xi_touchpad)
222 touchpads_[dev_list[i].id] = true;
224 if (!IsXInput2Available())
225 return;
227 // Update the structs with new valuator information
228 const XIDeviceList& info_list =
229 ui::DeviceListCacheX11::GetInstance()->GetXI2DeviceList(display);
230 Atom atoms[DT_LAST_ENTRY];
231 for (int data_type = 0; data_type < DT_LAST_ENTRY; ++data_type)
232 atoms[data_type] = atom_cache_.GetAtom(kCachedAtoms[data_type]);
234 for (int i = 0; i < info_list.count; ++i) {
235 const XIDeviceInfo& info = info_list[i];
237 if (info.use == XIMasterPointer)
238 master_pointers_.push_back(info.deviceid);
240 // We currently handle only slave, non-keyboard devices
241 if (info.use != XISlavePointer && info.use != XIFloatingSlave)
242 continue;
244 bool possible_cmt = false;
245 bool not_cmt = false;
246 const int deviceid = info.deviceid;
248 for (int j = 0; j < info.num_classes; ++j) {
249 if (info.classes[j]->type == XIValuatorClass)
250 ++valuator_count_[deviceid];
251 else if (info.classes[j]->type == XIScrollClass)
252 not_cmt = true;
255 // Skip devices that don't use any valuator
256 if (!valuator_count_[deviceid])
257 continue;
259 valuator_lookup_[deviceid].resize(DT_LAST_ENTRY, -1);
260 data_type_lookup_[deviceid].resize(
261 valuator_count_[deviceid], DT_LAST_ENTRY);
262 valuator_min_[deviceid].resize(DT_LAST_ENTRY, 0);
263 valuator_max_[deviceid].resize(DT_LAST_ENTRY, 0);
264 for (int j = 0; j < kMaxSlotNum; j++)
265 last_seen_valuator_[deviceid][j].resize(DT_LAST_ENTRY, 0);
266 for (int j = 0; j < info.num_classes; ++j) {
267 if (info.classes[j]->type != XIValuatorClass)
268 continue;
270 XIValuatorClassInfo* v =
271 reinterpret_cast<XIValuatorClassInfo*>(info.classes[j]);
272 for (int data_type = 0; data_type < DT_LAST_ENTRY; ++data_type) {
273 if (v->label == atoms[data_type]) {
274 valuator_lookup_[deviceid][data_type] = v->number;
275 data_type_lookup_[deviceid][v->number] = data_type;
276 valuator_min_[deviceid][data_type] = v->min;
277 valuator_max_[deviceid][data_type] = v->max;
278 if (IsCMTDataType(data_type))
279 possible_cmt = true;
280 break;
285 if (possible_cmt && !not_cmt)
286 cmt_devices_[deviceid] = true;
290 bool DeviceDataManagerX11::GetSlotNumber(const XIDeviceEvent* xiev, int* slot) {
291 ui::TouchFactory* factory = ui::TouchFactory::GetInstance();
292 if (!factory->IsMultiTouchDevice(xiev->sourceid)) {
293 *slot = 0;
294 return true;
296 return factory->QuerySlotForTrackingID(xiev->detail, slot);
299 void DeviceDataManagerX11::GetEventRawData(const XEvent& xev, EventData* data) {
300 if (xev.type != GenericEvent)
301 return;
303 XIDeviceEvent* xiev = static_cast<XIDeviceEvent*>(xev.xcookie.data);
304 CHECK(xiev->sourceid >= 0);
305 CHECK(xiev->deviceid >= 0);
306 if (xiev->sourceid >= kMaxDeviceNum || xiev->deviceid >= kMaxDeviceNum)
307 return;
308 data->clear();
309 const int sourceid = xiev->sourceid;
310 double* valuators = xiev->valuators.values;
311 for (int i = 0; i <= valuator_count_[sourceid]; ++i) {
312 if (XIMaskIsSet(xiev->valuators.mask, i)) {
313 int type = data_type_lookup_[sourceid][i];
314 if (type != DT_LAST_ENTRY) {
315 (*data)[type] = *valuators;
316 if (IsTouchDataType(type)) {
317 int slot = -1;
318 if (GetSlotNumber(xiev, &slot) && slot >= 0 && slot < kMaxSlotNum)
319 last_seen_valuator_[sourceid][slot][type] = *valuators;
322 valuators++;
327 bool DeviceDataManagerX11::GetEventData(const XEvent& xev,
328 const DataType type, double* value) {
329 if (xev.type != GenericEvent)
330 return false;
332 XIDeviceEvent* xiev = static_cast<XIDeviceEvent*>(xev.xcookie.data);
333 CHECK(xiev->sourceid >= 0);
334 CHECK(xiev->deviceid >= 0);
335 if (xiev->sourceid >= kMaxDeviceNum || xiev->deviceid >= kMaxDeviceNum)
336 return false;
337 const int sourceid = xiev->sourceid;
338 if (valuator_lookup_[sourceid].empty())
339 return false;
341 if (type == DT_TOUCH_TRACKING_ID) {
342 // With XInput2 MT, Tracking ID is provided in the detail field for touch
343 // events.
344 if (xiev->evtype == XI_TouchBegin ||
345 xiev->evtype == XI_TouchEnd ||
346 xiev->evtype == XI_TouchUpdate) {
347 *value = xiev->detail;
348 } else {
349 *value = 0;
351 return true;
354 int val_index = valuator_lookup_[sourceid][type];
355 int slot = 0;
356 if (val_index >= 0) {
357 if (XIMaskIsSet(xiev->valuators.mask, val_index)) {
358 double* valuators = xiev->valuators.values;
359 while (val_index--) {
360 if (XIMaskIsSet(xiev->valuators.mask, val_index))
361 ++valuators;
363 *value = *valuators;
364 if (IsTouchDataType(type)) {
365 if (GetSlotNumber(xiev, &slot) && slot >= 0 && slot < kMaxSlotNum)
366 last_seen_valuator_[sourceid][slot][type] = *value;
368 return true;
369 } else if (IsTouchDataType(type)) {
370 if (GetSlotNumber(xiev, &slot) && slot >= 0 && slot < kMaxSlotNum)
371 *value = last_seen_valuator_[sourceid][slot][type];
375 return false;
378 bool DeviceDataManagerX11::IsXIDeviceEvent(
379 const base::NativeEvent& native_event) const {
380 if (native_event->type != GenericEvent ||
381 native_event->xcookie.extension != xi_opcode_)
382 return false;
383 return xi_device_event_types_[native_event->xcookie.evtype];
386 bool DeviceDataManagerX11::IsTouchpadXInputEvent(
387 const base::NativeEvent& native_event) const {
388 if (native_event->type != GenericEvent)
389 return false;
391 XIDeviceEvent* xievent =
392 static_cast<XIDeviceEvent*>(native_event->xcookie.data);
393 CHECK(xievent->sourceid >= 0);
394 if (xievent->sourceid >= kMaxDeviceNum)
395 return false;
396 return touchpads_[xievent->sourceid];
399 bool DeviceDataManagerX11::IsCMTDeviceEvent(
400 const base::NativeEvent& native_event) const {
401 if (native_event->type != GenericEvent)
402 return false;
404 XIDeviceEvent* xievent =
405 static_cast<XIDeviceEvent*>(native_event->xcookie.data);
406 CHECK(xievent->sourceid >= 0);
407 if (xievent->sourceid >= kMaxDeviceNum)
408 return false;
409 return cmt_devices_[xievent->sourceid];
412 bool DeviceDataManagerX11::IsCMTGestureEvent(
413 const base::NativeEvent& native_event) const {
414 return (IsScrollEvent(native_event) ||
415 IsFlingEvent(native_event) ||
416 IsCMTMetricsEvent(native_event));
419 bool DeviceDataManagerX11::HasEventData(
420 const XIDeviceEvent* xiev, const DataType type) const {
421 const int idx = valuator_lookup_[xiev->sourceid][type];
422 return (idx >= 0) && XIMaskIsSet(xiev->valuators.mask, idx);
425 bool DeviceDataManagerX11::IsScrollEvent(
426 const base::NativeEvent& native_event) const {
427 if (!IsCMTDeviceEvent(native_event))
428 return false;
430 XIDeviceEvent* xiev =
431 static_cast<XIDeviceEvent*>(native_event->xcookie.data);
432 return (HasEventData(xiev, DT_CMT_SCROLL_X) ||
433 HasEventData(xiev, DT_CMT_SCROLL_Y));
436 bool DeviceDataManagerX11::IsFlingEvent(
437 const base::NativeEvent& native_event) const {
438 if (!IsCMTDeviceEvent(native_event))
439 return false;
441 XIDeviceEvent* xiev =
442 static_cast<XIDeviceEvent*>(native_event->xcookie.data);
443 return (HasEventData(xiev, DT_CMT_FLING_X) &&
444 HasEventData(xiev, DT_CMT_FLING_Y) &&
445 HasEventData(xiev, DT_CMT_FLING_STATE));
448 bool DeviceDataManagerX11::IsCMTMetricsEvent(
449 const base::NativeEvent& native_event) const {
450 if (!IsCMTDeviceEvent(native_event))
451 return false;
453 XIDeviceEvent* xiev =
454 static_cast<XIDeviceEvent*>(native_event->xcookie.data);
455 return (HasEventData(xiev, DT_CMT_METRICS_TYPE) &&
456 HasEventData(xiev, DT_CMT_METRICS_DATA1) &&
457 HasEventData(xiev, DT_CMT_METRICS_DATA2));
460 bool DeviceDataManagerX11::HasGestureTimes(
461 const base::NativeEvent& native_event) const {
462 if (!IsCMTDeviceEvent(native_event))
463 return false;
465 XIDeviceEvent* xiev =
466 static_cast<XIDeviceEvent*>(native_event->xcookie.data);
467 return (HasEventData(xiev, DT_CMT_START_TIME) &&
468 HasEventData(xiev, DT_CMT_END_TIME));
471 void DeviceDataManagerX11::GetScrollOffsets(
472 const base::NativeEvent& native_event,
473 float* x_offset,
474 float* y_offset,
475 float* x_offset_ordinal,
476 float* y_offset_ordinal,
477 int* finger_count) {
478 *x_offset = 0;
479 *y_offset = 0;
480 *x_offset_ordinal = 0;
481 *y_offset_ordinal = 0;
482 *finger_count = 2;
484 EventData data;
485 GetEventRawData(*native_event, &data);
487 if (data.find(DT_CMT_SCROLL_X) != data.end())
488 *x_offset = data[DT_CMT_SCROLL_X];
489 if (data.find(DT_CMT_SCROLL_Y) != data.end())
490 *y_offset = data[DT_CMT_SCROLL_Y];
491 if (data.find(DT_CMT_ORDINAL_X) != data.end())
492 *x_offset_ordinal = data[DT_CMT_ORDINAL_X];
493 if (data.find(DT_CMT_ORDINAL_Y) != data.end())
494 *y_offset_ordinal = data[DT_CMT_ORDINAL_Y];
495 if (data.find(DT_CMT_FINGER_COUNT) != data.end())
496 *finger_count = static_cast<int>(data[DT_CMT_FINGER_COUNT]);
499 void DeviceDataManagerX11::GetFlingData(
500 const base::NativeEvent& native_event,
501 float* vx,
502 float* vy,
503 float* vx_ordinal,
504 float* vy_ordinal,
505 bool* is_cancel) {
506 *vx = 0;
507 *vy = 0;
508 *vx_ordinal = 0;
509 *vy_ordinal = 0;
510 *is_cancel = false;
512 EventData data;
513 GetEventRawData(*native_event, &data);
515 if (data.find(DT_CMT_FLING_X) != data.end())
516 *vx = data[DT_CMT_FLING_X];
517 if (data.find(DT_CMT_FLING_Y) != data.end())
518 *vy = data[DT_CMT_FLING_Y];
519 if (data.find(DT_CMT_FLING_STATE) != data.end())
520 *is_cancel = !!static_cast<unsigned int>(data[DT_CMT_FLING_STATE]);
521 if (data.find(DT_CMT_ORDINAL_X) != data.end())
522 *vx_ordinal = data[DT_CMT_ORDINAL_X];
523 if (data.find(DT_CMT_ORDINAL_Y) != data.end())
524 *vy_ordinal = data[DT_CMT_ORDINAL_Y];
527 void DeviceDataManagerX11::GetMetricsData(
528 const base::NativeEvent& native_event,
529 GestureMetricsType* type,
530 float* data1,
531 float* data2) {
532 *type = kGestureMetricsTypeUnknown;
533 *data1 = 0;
534 *data2 = 0;
536 EventData data;
537 GetEventRawData(*native_event, &data);
539 if (data.find(DT_CMT_METRICS_TYPE) != data.end()) {
540 int val = static_cast<int>(data[DT_CMT_METRICS_TYPE]);
541 if (val == 0)
542 *type = kGestureMetricsTypeNoisyGround;
543 else
544 *type = kGestureMetricsTypeUnknown;
546 if (data.find(DT_CMT_METRICS_DATA1) != data.end())
547 *data1 = data[DT_CMT_METRICS_DATA1];
548 if (data.find(DT_CMT_METRICS_DATA2) != data.end())
549 *data2 = data[DT_CMT_METRICS_DATA2];
552 int DeviceDataManagerX11::GetMappedButton(int button) {
553 return button > 0 && button <= button_map_count_ ? button_map_[button - 1] :
554 button;
557 void DeviceDataManagerX11::UpdateButtonMap() {
558 button_map_count_ = XGetPointerMapping(gfx::GetXDisplay(),
559 button_map_,
560 arraysize(button_map_));
563 void DeviceDataManagerX11::GetGestureTimes(
564 const base::NativeEvent& native_event,
565 double* start_time,
566 double* end_time) {
567 *start_time = 0;
568 *end_time = 0;
570 EventData data;
571 GetEventRawData(*native_event, &data);
573 if (data.find(DT_CMT_START_TIME) != data.end())
574 *start_time = data[DT_CMT_START_TIME];
575 if (data.find(DT_CMT_END_TIME) != data.end())
576 *end_time = data[DT_CMT_END_TIME];
579 bool DeviceDataManagerX11::NormalizeData(int deviceid,
580 const DataType type,
581 double* value) {
582 double max_value;
583 double min_value;
584 if (GetDataRange(deviceid, type, &min_value, &max_value)) {
585 *value = (*value - min_value) / (max_value - min_value);
586 DCHECK(*value >= 0.0 && *value <= 1.0);
587 return true;
589 return false;
592 bool DeviceDataManagerX11::GetDataRange(int deviceid,
593 const DataType type,
594 double* min,
595 double* max) {
596 CHECK(deviceid >= 0);
597 if (deviceid >= kMaxDeviceNum)
598 return false;
599 if (valuator_lookup_[deviceid][type] >= 0) {
600 *min = valuator_min_[deviceid][type];
601 *max = valuator_max_[deviceid][type];
602 return true;
604 return false;
607 void DeviceDataManagerX11::SetDeviceListForTest(
608 const std::vector<int>& touchscreen,
609 const std::vector<int>& cmt_devices) {
610 for (int i = 0; i < kMaxDeviceNum; ++i) {
611 valuator_count_[i] = 0;
612 valuator_lookup_[i].clear();
613 data_type_lookup_[i].clear();
614 valuator_min_[i].clear();
615 valuator_max_[i].clear();
616 for (int j = 0; j < kMaxSlotNum; j++)
617 last_seen_valuator_[i][j].clear();
620 for (size_t i = 0; i < touchscreen.size(); i++) {
621 int deviceid = touchscreen[i];
622 InitializeValuatorsForTest(deviceid, kTouchDataTypeStart, kTouchDataTypeEnd,
623 0, 1000);
626 cmt_devices_.reset();
627 for (size_t i = 0; i < cmt_devices.size(); ++i) {
628 int deviceid = cmt_devices[i];
629 cmt_devices_[deviceid] = true;
630 touchpads_[deviceid] = true;
631 InitializeValuatorsForTest(deviceid, kCMTDataTypeStart, kCMTDataTypeEnd,
632 -1000, 1000);
636 void DeviceDataManagerX11::SetValuatorDataForTest(XIDeviceEvent* xievent,
637 DataType type,
638 double value) {
639 int index = valuator_lookup_[xievent->deviceid][type];
640 CHECK(!XIMaskIsSet(xievent->valuators.mask, index));
641 CHECK(index >= 0 && index < valuator_count_[xievent->deviceid]);
642 XISetMask(xievent->valuators.mask, index);
644 double* valuators = xievent->valuators.values;
645 for (int i = 0; i < index; ++i) {
646 if (XIMaskIsSet(xievent->valuators.mask, i))
647 valuators++;
649 for (int i = DT_LAST_ENTRY - 1; i > valuators - xievent->valuators.values;
650 --i)
651 xievent->valuators.values[i] = xievent->valuators.values[i - 1];
652 *valuators = value;
655 void DeviceDataManagerX11::InitializeValuatorsForTest(int deviceid,
656 int start_valuator,
657 int end_valuator,
658 double min_value,
659 double max_value) {
660 valuator_lookup_[deviceid].resize(DT_LAST_ENTRY, -1);
661 data_type_lookup_[deviceid].resize(DT_LAST_ENTRY, DT_LAST_ENTRY);
662 valuator_min_[deviceid].resize(DT_LAST_ENTRY, 0);
663 valuator_max_[deviceid].resize(DT_LAST_ENTRY, 0);
664 for (int j = 0; j < kMaxSlotNum; j++)
665 last_seen_valuator_[deviceid][j].resize(DT_LAST_ENTRY, 0);
666 for (int j = start_valuator; j <= end_valuator; ++j) {
667 valuator_lookup_[deviceid][j] = valuator_count_[deviceid];
668 data_type_lookup_[deviceid][valuator_count_[deviceid]] = j;
669 valuator_min_[deviceid][j] = min_value;
670 valuator_max_[deviceid][j] = max_value;
671 valuator_count_[deviceid]++;
675 bool DeviceDataManagerX11::TouchEventNeedsCalibrate(int touch_device_id) const {
676 #if defined(OS_CHROMEOS)
677 if (!base::SysInfo::IsRunningOnChromeOS())
678 return false;
680 const std::vector<TouchscreenDevice>& touch_devices =
681 ui::DeviceDataManager::GetInstance()->touchscreen_devices();
682 std::vector<TouchscreenDevice>::const_iterator it =
683 std::find_if(touch_devices.begin(), touch_devices.end(),
684 std::bind2nd(std::ptr_fun(&DeviceHasId), touch_device_id));
685 return it != touch_devices.end() && it->type == INPUT_DEVICE_INTERNAL;
686 #endif // defined(OS_CHROMEOS)
687 return false;
690 void DeviceDataManagerX11::SetDisabledKeyboardAllowedKeys(
691 scoped_ptr<std::set<KeyboardCode> > excepted_keys) {
692 DCHECK(!excepted_keys.get() ||
693 !blocked_keyboard_allowed_keys_.get());
694 blocked_keyboard_allowed_keys_ = excepted_keys.Pass();
697 void DeviceDataManagerX11::DisableDevice(int deviceid) {
698 blocked_devices_.set(deviceid, true);
699 // TODO(rsadam@): Support blocking touchscreen devices.
700 std::vector<KeyboardDevice> keyboards = keyboard_devices();
701 std::vector<KeyboardDevice>::iterator it =
702 std::find_if(keyboards.begin(),
703 keyboards.end(),
704 std::bind2nd(std::ptr_fun(&DeviceHasId), deviceid));
705 if (it != std::end(keyboards)) {
706 blocked_keyboards_.insert(
707 std::pair<int, KeyboardDevice>(deviceid, *it));
708 keyboards.erase(it);
709 DeviceDataManager::OnKeyboardDevicesUpdated(keyboards);
713 void DeviceDataManagerX11::EnableDevice(int deviceid) {
714 blocked_devices_.set(deviceid, false);
715 std::map<int, KeyboardDevice>::iterator it =
716 blocked_keyboards_.find(deviceid);
717 if (it != blocked_keyboards_.end()) {
718 std::vector<KeyboardDevice> devices = keyboard_devices();
719 // Add device to current list of active devices.
720 devices.push_back((*it).second);
721 blocked_keyboards_.erase(it);
722 DeviceDataManager::OnKeyboardDevicesUpdated(devices);
726 bool DeviceDataManagerX11::IsEventBlocked(
727 const base::NativeEvent& native_event) {
728 // Only check XI2 events which have a source device id.
729 if (native_event->type != GenericEvent)
730 return false;
732 XIDeviceEvent* xievent =
733 static_cast<XIDeviceEvent*>(native_event->xcookie.data);
734 // Allow any key events from blocked_keyboard_allowed_keys_.
735 if (blocked_keyboard_allowed_keys_ &&
736 (xievent->evtype == XI_KeyPress || xievent->evtype == XI_KeyRelease) &&
737 blocked_keyboard_allowed_keys_->find(
738 KeyboardCodeFromXKeyEvent(native_event)) !=
739 blocked_keyboard_allowed_keys_->end()) {
740 return false;
743 return blocked_devices_.test(xievent->sourceid);
746 void DeviceDataManagerX11::OnKeyboardDevicesUpdated(
747 const std::vector<KeyboardDevice>& devices) {
748 std::vector<KeyboardDevice> keyboards(devices);
749 for (std::map<int, KeyboardDevice>::iterator blocked_iter =
750 blocked_keyboards_.begin();
751 blocked_iter != blocked_keyboards_.end();) {
752 // Check if the blocked device still exists in list of devices.
753 std::vector<KeyboardDevice>::iterator it = std::find_if(
754 keyboards.begin(), keyboards.end(),
755 std::bind2nd(std::ptr_fun(&DeviceHasId), (*blocked_iter).first));
756 // If the device no longer exists, unblock it, else filter it out from our
757 // active list.
758 if (it == keyboards.end()) {
759 blocked_devices_.set((*blocked_iter).first, false);
760 blocked_keyboards_.erase(blocked_iter++);
761 } else {
762 keyboards.erase(it);
763 ++blocked_iter;
766 // Notify base class of updated list.
767 DeviceDataManager::OnKeyboardDevicesUpdated(keyboards);
770 } // namespace ui