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>
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
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
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"
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"
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
,
103 // Constants for checking if a data type lies in the range of CMT/Touch data
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
;
114 bool DeviceHasId(const ui::InputDevice input_device
, int id
) {
115 return input_device
.id
== id
;
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
);
129 void DeviceDataManagerX11::CreateInstance() {
133 new DeviceDataManagerX11();
137 DeviceDataManagerX11
* DeviceDataManagerX11::GetInstance() {
138 return static_cast<DeviceDataManagerX11
*>(DeviceDataManager::GetInstance());
141 DeviceDataManagerX11::DeviceDataManagerX11()
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());
154 DeviceDataManagerX11::~DeviceDataManagerX11() {
157 bool DeviceDataManagerX11::InitializeXInputInternal() {
158 // Check if XInput is available on the system.
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
;
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.";
173 if (major
< 2 || (major
== 2 && minor
< 2)) {
174 DVLOG(1) << "XI version on server is " << major
<< "." << minor
<< ". "
175 << "But 2.2 is required.";
180 CHECK_NE(-1, xi_opcode_
);
182 // Possible XI event types for XIDeviceEvent. See the XI2 protocol
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.
191 xi_device_event_types_
[XI_TouchBegin
] = true;
192 xi_device_event_types_
[XI_TouchUpdate
] = true;
193 xi_device_event_types_
[XI_TouchEnd
] = true;
198 bool DeviceDataManagerX11::IsXInput2Available() const {
199 return xi_opcode_
!= -1;
202 void DeviceDataManagerX11::UpdateDeviceList(Display
* display
) {
203 cmt_devices_
.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())
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
)
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
)
255 // Skip devices that don't use any valuator
256 if (!valuator_count_
[deviceid
])
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
)
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
))
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
)) {
296 return factory
->QuerySlotForTrackingID(xiev
->detail
, slot
);
299 void DeviceDataManagerX11::GetEventRawData(const XEvent
& xev
, EventData
* data
) {
300 if (xev
.type
!= GenericEvent
)
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
)
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
)) {
318 if (GetSlotNumber(xiev
, &slot
) && slot
>= 0 && slot
< kMaxSlotNum
)
319 last_seen_valuator_
[sourceid
][slot
][type
] = *valuators
;
327 bool DeviceDataManagerX11::GetEventData(const XEvent
& xev
,
328 const DataType type
, double* value
) {
329 if (xev
.type
!= GenericEvent
)
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
)
337 const int sourceid
= xiev
->sourceid
;
338 if (valuator_lookup_
[sourceid
].empty())
341 if (type
== DT_TOUCH_TRACKING_ID
) {
342 // With XInput2 MT, Tracking ID is provided in the detail field for touch
344 if (xiev
->evtype
== XI_TouchBegin
||
345 xiev
->evtype
== XI_TouchEnd
||
346 xiev
->evtype
== XI_TouchUpdate
) {
347 *value
= xiev
->detail
;
354 int val_index
= valuator_lookup_
[sourceid
][type
];
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
))
364 if (IsTouchDataType(type
)) {
365 if (GetSlotNumber(xiev
, &slot
) && slot
>= 0 && slot
< kMaxSlotNum
)
366 last_seen_valuator_
[sourceid
][slot
][type
] = *value
;
369 } else if (IsTouchDataType(type
)) {
370 if (GetSlotNumber(xiev
, &slot
) && slot
>= 0 && slot
< kMaxSlotNum
)
371 *value
= last_seen_valuator_
[sourceid
][slot
][type
];
378 bool DeviceDataManagerX11::IsXIDeviceEvent(
379 const base::NativeEvent
& native_event
) const {
380 if (native_event
->type
!= GenericEvent
||
381 native_event
->xcookie
.extension
!= xi_opcode_
)
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
)
391 XIDeviceEvent
* xievent
=
392 static_cast<XIDeviceEvent
*>(native_event
->xcookie
.data
);
393 CHECK(xievent
->sourceid
>= 0);
394 if (xievent
->sourceid
>= kMaxDeviceNum
)
396 return touchpads_
[xievent
->sourceid
];
399 bool DeviceDataManagerX11::IsCMTDeviceEvent(
400 const base::NativeEvent
& native_event
) const {
401 if (native_event
->type
!= GenericEvent
)
404 XIDeviceEvent
* xievent
=
405 static_cast<XIDeviceEvent
*>(native_event
->xcookie
.data
);
406 CHECK(xievent
->sourceid
>= 0);
407 if (xievent
->sourceid
>= kMaxDeviceNum
)
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
))
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
))
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
))
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
))
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
,
475 float* x_offset_ordinal
,
476 float* y_offset_ordinal
,
480 *x_offset_ordinal
= 0;
481 *y_offset_ordinal
= 0;
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
,
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
,
532 *type
= kGestureMetricsTypeUnknown
;
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
]);
542 *type
= kGestureMetricsTypeNoisyGround
;
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] :
557 void DeviceDataManagerX11::UpdateButtonMap() {
558 button_map_count_
= XGetPointerMapping(gfx::GetXDisplay(),
560 arraysize(button_map_
));
563 void DeviceDataManagerX11::GetGestureTimes(
564 const base::NativeEvent
& native_event
,
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
,
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);
592 bool DeviceDataManagerX11::GetDataRange(int deviceid
,
596 CHECK(deviceid
>= 0);
597 if (deviceid
>= kMaxDeviceNum
)
599 if (valuator_lookup_
[deviceid
][type
] >= 0) {
600 *min
= valuator_min_
[deviceid
][type
];
601 *max
= valuator_max_
[deviceid
][type
];
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
,
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
,
636 void DeviceDataManagerX11::SetValuatorDataForTest(XIDeviceEvent
* xievent
,
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
))
649 for (int i
= DT_LAST_ENTRY
- 1; i
> valuators
- xievent
->valuators
.values
;
651 xievent
->valuators
.values
[i
] = xievent
->valuators
.values
[i
- 1];
655 void DeviceDataManagerX11::InitializeValuatorsForTest(int deviceid
,
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())
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)
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(),
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
));
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
)
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()) {
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
758 if (it
== keyboards
.end()) {
759 blocked_devices_
.set((*blocked_iter
).first
, false);
760 blocked_keyboards_
.erase(blocked_iter
++);
766 // Notify base class of updated list.
767 DeviceDataManager::OnKeyboardDevicesUpdated(keyboards
);