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/bind.h"
14 #include "base/bind_helpers.h"
15 #include "base/logging.h"
16 #include "base/memory/singleton.h"
17 #include "base/sys_info.h"
18 #include "ui/events/devices/keyboard_device.h"
19 #include "ui/events/devices/x11/device_list_cache_x11.h"
20 #include "ui/events/devices/x11/touch_factory_x11.h"
21 #include "ui/events/event_constants.h"
22 #include "ui/events/event_switches.h"
23 #include "ui/events/keycodes/keyboard_code_conversion_x.h"
24 #include "ui/gfx/display.h"
25 #include "ui/gfx/geometry/point3_f.h"
26 #include "ui/gfx/x/x11_types.h"
28 // XIScrollClass was introduced in XI 2.1 so we need to define it here
29 // for backward-compatibility with older versions of XInput.
30 #if !defined(XIScrollClass)
31 #define XIScrollClass 3
34 // Multi-touch support was introduced in XI 2.2. Add XI event types here
35 // for backward-compatibility with older versions of XInput.
36 #if !defined(XI_TouchBegin)
37 #define XI_TouchBegin 18
38 #define XI_TouchUpdate 19
39 #define XI_TouchEnd 20
42 // Copied from xserver-properties.h
43 #define AXIS_LABEL_PROP_REL_HWHEEL "Rel Horiz Wheel"
44 #define AXIS_LABEL_PROP_REL_WHEEL "Rel Vert Wheel"
46 // CMT specific timings
47 #define AXIS_LABEL_PROP_ABS_DBL_START_TIME "Abs Dbl Start Timestamp"
48 #define AXIS_LABEL_PROP_ABS_DBL_END_TIME "Abs Dbl End Timestamp"
51 #define AXIS_LABEL_PROP_ABS_DBL_ORDINAL_X "Abs Dbl Ordinal X"
52 #define AXIS_LABEL_PROP_ABS_DBL_ORDINAL_Y "Abs Dbl Ordinal Y"
55 #define AXIS_LABEL_PROP_ABS_DBL_FLING_VX "Abs Dbl Fling X Velocity"
56 #define AXIS_LABEL_PROP_ABS_DBL_FLING_VY "Abs Dbl Fling Y Velocity"
57 #define AXIS_LABEL_PROP_ABS_FLING_STATE "Abs Fling State"
59 #define AXIS_LABEL_PROP_ABS_FINGER_COUNT "Abs Finger Count"
61 // Cros metrics gesture from touchpad
62 #define AXIS_LABEL_PROP_ABS_METRICS_TYPE "Abs Metrics Type"
63 #define AXIS_LABEL_PROP_ABS_DBL_METRICS_DATA1 "Abs Dbl Metrics Data 1"
64 #define AXIS_LABEL_PROP_ABS_DBL_METRICS_DATA2 "Abs Dbl Metrics Data 2"
66 // Touchscreen multi-touch
67 #define AXIS_LABEL_ABS_MT_TOUCH_MAJOR "Abs MT Touch Major"
68 #define AXIS_LABEL_ABS_MT_TOUCH_MINOR "Abs MT Touch Minor"
69 #define AXIS_LABEL_ABS_MT_ORIENTATION "Abs MT Orientation"
70 #define AXIS_LABEL_ABS_MT_PRESSURE "Abs MT Pressure"
71 #define AXIS_LABEL_ABS_MT_POSITION_X "Abs MT Position X"
72 #define AXIS_LABEL_ABS_MT_POSITION_Y "Abs MT Position Y"
73 #define AXIS_LABEL_ABS_MT_TRACKING_ID "Abs MT Tracking ID"
74 #define AXIS_LABEL_TOUCH_TIMESTAMP "Touch Timestamp"
76 // When you add new data types, please make sure the order here is aligned
77 // with the order in the DataType enum in the header file because we assume
78 // they are in sync when updating the device list (see UpdateDeviceList).
79 const char* kCachedAtoms
[] = {
80 AXIS_LABEL_PROP_REL_HWHEEL
,
81 AXIS_LABEL_PROP_REL_WHEEL
,
82 AXIS_LABEL_PROP_ABS_DBL_ORDINAL_X
,
83 AXIS_LABEL_PROP_ABS_DBL_ORDINAL_Y
,
84 AXIS_LABEL_PROP_ABS_DBL_START_TIME
,
85 AXIS_LABEL_PROP_ABS_DBL_END_TIME
,
86 AXIS_LABEL_PROP_ABS_DBL_FLING_VX
,
87 AXIS_LABEL_PROP_ABS_DBL_FLING_VY
,
88 AXIS_LABEL_PROP_ABS_FLING_STATE
,
89 AXIS_LABEL_PROP_ABS_METRICS_TYPE
,
90 AXIS_LABEL_PROP_ABS_DBL_METRICS_DATA1
,
91 AXIS_LABEL_PROP_ABS_DBL_METRICS_DATA2
,
92 AXIS_LABEL_PROP_ABS_FINGER_COUNT
,
93 AXIS_LABEL_ABS_MT_TOUCH_MAJOR
,
94 AXIS_LABEL_ABS_MT_TOUCH_MINOR
,
95 AXIS_LABEL_ABS_MT_ORIENTATION
,
96 AXIS_LABEL_ABS_MT_PRESSURE
,
97 AXIS_LABEL_ABS_MT_POSITION_X
,
98 AXIS_LABEL_ABS_MT_POSITION_Y
,
99 AXIS_LABEL_ABS_MT_TRACKING_ID
,
100 AXIS_LABEL_TOUCH_TIMESTAMP
,
105 // Constants for checking if a data type lies in the range of CMT/Touch data
107 const int kCMTDataTypeStart
= ui::DeviceDataManagerX11::DT_CMT_SCROLL_X
;
108 const int kCMTDataTypeEnd
= ui::DeviceDataManagerX11::DT_CMT_FINGER_COUNT
;
109 const int kTouchDataTypeStart
= ui::DeviceDataManagerX11::DT_TOUCH_MAJOR
;
110 const int kTouchDataTypeEnd
= ui::DeviceDataManagerX11::DT_TOUCH_RAW_TIMESTAMP
;
116 bool DeviceHasId(const ui::InputDevice input_device
, int id
) {
117 return input_device
.id
== id
;
122 bool DeviceDataManagerX11::IsCMTDataType(const int type
) {
123 return (type
>= kCMTDataTypeStart
) && (type
<= kCMTDataTypeEnd
);
126 bool DeviceDataManagerX11::IsTouchDataType(const int type
) {
127 return (type
>= kTouchDataTypeStart
) && (type
<= kTouchDataTypeEnd
);
131 void DeviceDataManagerX11::CreateInstance() {
135 DeviceDataManagerX11
* device_data_manager
= new DeviceDataManagerX11();
137 // TODO(bruthig): Replace the DeleteInstance callbacks with explicit calls.
138 base::AtExitManager::RegisterTask(
139 base::Bind(DeviceDataManager::DeleteInstance
));
141 set_instance(device_data_manager
);
145 DeviceDataManagerX11
* DeviceDataManagerX11::GetInstance() {
146 return static_cast<DeviceDataManagerX11
*>(DeviceDataManager::GetInstance());
149 DeviceDataManagerX11::DeviceDataManagerX11()
151 atom_cache_(gfx::GetXDisplay(), kCachedAtoms
),
152 button_map_count_(0) {
153 CHECK(gfx::GetXDisplay());
154 InitializeXInputInternal();
156 // Make sure the sizes of enum and kCachedAtoms are aligned.
157 CHECK(arraysize(kCachedAtoms
) == static_cast<size_t>(DT_LAST_ENTRY
) + 1);
158 UpdateDeviceList(gfx::GetXDisplay());
162 DeviceDataManagerX11::~DeviceDataManagerX11() {
165 bool DeviceDataManagerX11::InitializeXInputInternal() {
166 // Check if XInput is available on the system.
168 int opcode
, event
, error
;
169 if (!XQueryExtension(
170 gfx::GetXDisplay(), "XInputExtension", &opcode
, &event
, &error
)) {
171 VLOG(1) << "X Input extension not available: error=" << error
;
175 // Check the XInput version.
176 int major
= 2, minor
= 2;
177 if (XIQueryVersion(gfx::GetXDisplay(), &major
, &minor
) == BadRequest
) {
178 VLOG(1) << "XInput2 not supported in the server.";
181 if (major
< 2 || (major
== 2 && minor
< 2)) {
182 DVLOG(1) << "XI version on server is " << major
<< "." << minor
<< ". "
183 << "But 2.2 is required.";
188 CHECK_NE(-1, xi_opcode_
);
190 // Possible XI event types for XIDeviceEvent. See the XI2 protocol
192 xi_device_event_types_
[XI_KeyPress
] = true;
193 xi_device_event_types_
[XI_KeyRelease
] = true;
194 xi_device_event_types_
[XI_ButtonPress
] = true;
195 xi_device_event_types_
[XI_ButtonRelease
] = true;
196 xi_device_event_types_
[XI_Motion
] = true;
197 // Multi-touch support was introduced in XI 2.2.
199 xi_device_event_types_
[XI_TouchBegin
] = true;
200 xi_device_event_types_
[XI_TouchUpdate
] = true;
201 xi_device_event_types_
[XI_TouchEnd
] = true;
206 bool DeviceDataManagerX11::IsXInput2Available() const {
207 return xi_opcode_
!= -1;
210 void DeviceDataManagerX11::UpdateDeviceList(Display
* display
) {
211 cmt_devices_
.reset();
213 master_pointers_
.clear();
214 for (int i
= 0; i
< kMaxDeviceNum
; ++i
) {
215 valuator_count_
[i
] = 0;
216 valuator_lookup_
[i
].clear();
217 data_type_lookup_
[i
].clear();
218 valuator_min_
[i
].clear();
219 valuator_max_
[i
].clear();
220 for (int j
= 0; j
< kMaxSlotNum
; j
++)
221 last_seen_valuator_
[i
][j
].clear();
224 // Find all the touchpad devices.
225 const XDeviceList
& dev_list
=
226 ui::DeviceListCacheX11::GetInstance()->GetXDeviceList(display
);
227 Atom xi_touchpad
= XInternAtom(display
, XI_TOUCHPAD
, false);
228 for (int i
= 0; i
< dev_list
.count
; ++i
)
229 if (dev_list
[i
].type
== xi_touchpad
)
230 touchpads_
[dev_list
[i
].id
] = true;
232 if (!IsXInput2Available())
235 // Update the structs with new valuator information
236 const XIDeviceList
& info_list
=
237 ui::DeviceListCacheX11::GetInstance()->GetXI2DeviceList(display
);
238 Atom atoms
[DT_LAST_ENTRY
];
239 for (int data_type
= 0; data_type
< DT_LAST_ENTRY
; ++data_type
)
240 atoms
[data_type
] = atom_cache_
.GetAtom(kCachedAtoms
[data_type
]);
242 for (int i
= 0; i
< info_list
.count
; ++i
) {
243 const XIDeviceInfo
& info
= info_list
[i
];
245 if (info
.use
== XIMasterPointer
)
246 master_pointers_
.push_back(info
.deviceid
);
248 // We currently handle only slave, non-keyboard devices
249 if (info
.use
!= XISlavePointer
&& info
.use
!= XIFloatingSlave
)
252 bool possible_cmt
= false;
253 bool not_cmt
= false;
254 const int deviceid
= info
.deviceid
;
256 for (int j
= 0; j
< info
.num_classes
; ++j
) {
257 if (info
.classes
[j
]->type
== XIValuatorClass
)
258 ++valuator_count_
[deviceid
];
259 else if (info
.classes
[j
]->type
== XIScrollClass
)
263 // Skip devices that don't use any valuator
264 if (!valuator_count_
[deviceid
])
267 valuator_lookup_
[deviceid
].resize(DT_LAST_ENTRY
, -1);
268 data_type_lookup_
[deviceid
].resize(
269 valuator_count_
[deviceid
], DT_LAST_ENTRY
);
270 valuator_min_
[deviceid
].resize(DT_LAST_ENTRY
, 0);
271 valuator_max_
[deviceid
].resize(DT_LAST_ENTRY
, 0);
272 for (int j
= 0; j
< kMaxSlotNum
; j
++)
273 last_seen_valuator_
[deviceid
][j
].resize(DT_LAST_ENTRY
, 0);
274 for (int j
= 0; j
< info
.num_classes
; ++j
) {
275 if (info
.classes
[j
]->type
!= XIValuatorClass
)
278 XIValuatorClassInfo
* v
=
279 reinterpret_cast<XIValuatorClassInfo
*>(info
.classes
[j
]);
280 for (int data_type
= 0; data_type
< DT_LAST_ENTRY
; ++data_type
) {
281 if (v
->label
== atoms
[data_type
]) {
282 valuator_lookup_
[deviceid
][data_type
] = v
->number
;
283 data_type_lookup_
[deviceid
][v
->number
] = data_type
;
284 valuator_min_
[deviceid
][data_type
] = v
->min
;
285 valuator_max_
[deviceid
][data_type
] = v
->max
;
286 if (IsCMTDataType(data_type
))
293 if (possible_cmt
&& !not_cmt
)
294 cmt_devices_
[deviceid
] = true;
298 bool DeviceDataManagerX11::GetSlotNumber(const XIDeviceEvent
* xiev
, int* slot
) {
299 ui::TouchFactory
* factory
= ui::TouchFactory::GetInstance();
300 if (!factory
->IsMultiTouchDevice(xiev
->sourceid
)) {
304 return factory
->QuerySlotForTrackingID(xiev
->detail
, slot
);
307 void DeviceDataManagerX11::GetEventRawData(const XEvent
& xev
, EventData
* data
) {
308 if (xev
.type
!= GenericEvent
)
311 XIDeviceEvent
* xiev
= static_cast<XIDeviceEvent
*>(xev
.xcookie
.data
);
312 CHECK(xiev
->sourceid
>= 0);
313 CHECK(xiev
->deviceid
>= 0);
314 if (xiev
->sourceid
>= kMaxDeviceNum
|| xiev
->deviceid
>= kMaxDeviceNum
)
317 const int sourceid
= xiev
->sourceid
;
318 double* valuators
= xiev
->valuators
.values
;
319 for (int i
= 0; i
<= valuator_count_
[sourceid
]; ++i
) {
320 if (XIMaskIsSet(xiev
->valuators
.mask
, i
)) {
321 int type
= data_type_lookup_
[sourceid
][i
];
322 if (type
!= DT_LAST_ENTRY
) {
323 (*data
)[type
] = *valuators
;
324 if (IsTouchDataType(type
)) {
326 if (GetSlotNumber(xiev
, &slot
) && slot
>= 0 && slot
< kMaxSlotNum
)
327 last_seen_valuator_
[sourceid
][slot
][type
] = *valuators
;
335 bool DeviceDataManagerX11::GetEventData(const XEvent
& xev
,
336 const DataType type
, double* value
) {
337 if (xev
.type
!= GenericEvent
)
340 XIDeviceEvent
* xiev
= static_cast<XIDeviceEvent
*>(xev
.xcookie
.data
);
341 CHECK(xiev
->sourceid
>= 0);
342 CHECK(xiev
->deviceid
>= 0);
343 if (xiev
->sourceid
>= kMaxDeviceNum
|| xiev
->deviceid
>= kMaxDeviceNum
)
345 const int sourceid
= xiev
->sourceid
;
346 if (valuator_lookup_
[sourceid
].empty())
349 if (type
== DT_TOUCH_TRACKING_ID
) {
350 // With XInput2 MT, Tracking ID is provided in the detail field for touch
352 if (xiev
->evtype
== XI_TouchBegin
||
353 xiev
->evtype
== XI_TouchEnd
||
354 xiev
->evtype
== XI_TouchUpdate
) {
355 *value
= xiev
->detail
;
362 int val_index
= valuator_lookup_
[sourceid
][type
];
364 if (val_index
>= 0) {
365 if (XIMaskIsSet(xiev
->valuators
.mask
, val_index
)) {
366 double* valuators
= xiev
->valuators
.values
;
367 while (val_index
--) {
368 if (XIMaskIsSet(xiev
->valuators
.mask
, val_index
))
372 if (IsTouchDataType(type
)) {
373 if (GetSlotNumber(xiev
, &slot
) && slot
>= 0 && slot
< kMaxSlotNum
)
374 last_seen_valuator_
[sourceid
][slot
][type
] = *value
;
377 } else if (IsTouchDataType(type
)) {
378 if (GetSlotNumber(xiev
, &slot
) && slot
>= 0 && slot
< kMaxSlotNum
)
379 *value
= last_seen_valuator_
[sourceid
][slot
][type
];
386 bool DeviceDataManagerX11::IsXIDeviceEvent(
387 const base::NativeEvent
& native_event
) const {
388 if (native_event
->type
!= GenericEvent
||
389 native_event
->xcookie
.extension
!= xi_opcode_
)
391 return xi_device_event_types_
[native_event
->xcookie
.evtype
];
394 bool DeviceDataManagerX11::IsTouchpadXInputEvent(
395 const base::NativeEvent
& native_event
) const {
396 if (native_event
->type
!= GenericEvent
)
399 XIDeviceEvent
* xievent
=
400 static_cast<XIDeviceEvent
*>(native_event
->xcookie
.data
);
401 CHECK(xievent
->sourceid
>= 0);
402 if (xievent
->sourceid
>= kMaxDeviceNum
)
404 return touchpads_
[xievent
->sourceid
];
407 bool DeviceDataManagerX11::IsCMTDeviceEvent(
408 const base::NativeEvent
& native_event
) const {
409 if (native_event
->type
!= GenericEvent
)
412 XIDeviceEvent
* xievent
=
413 static_cast<XIDeviceEvent
*>(native_event
->xcookie
.data
);
414 CHECK(xievent
->sourceid
>= 0);
415 if (xievent
->sourceid
>= kMaxDeviceNum
)
417 return cmt_devices_
[xievent
->sourceid
];
420 bool DeviceDataManagerX11::IsCMTGestureEvent(
421 const base::NativeEvent
& native_event
) const {
422 return (IsScrollEvent(native_event
) ||
423 IsFlingEvent(native_event
) ||
424 IsCMTMetricsEvent(native_event
));
427 bool DeviceDataManagerX11::HasEventData(
428 const XIDeviceEvent
* xiev
, const DataType type
) const {
429 CHECK(xiev
->sourceid
>= 0);
430 if (xiev
->sourceid
>= kMaxDeviceNum
)
432 if (type
>= valuator_lookup_
[xiev
->sourceid
].size())
434 const int idx
= valuator_lookup_
[xiev
->sourceid
][type
];
435 return (idx
>= 0) && XIMaskIsSet(xiev
->valuators
.mask
, idx
);
438 bool DeviceDataManagerX11::IsScrollEvent(
439 const base::NativeEvent
& native_event
) const {
440 if (!IsCMTDeviceEvent(native_event
))
443 XIDeviceEvent
* xiev
=
444 static_cast<XIDeviceEvent
*>(native_event
->xcookie
.data
);
445 return (HasEventData(xiev
, DT_CMT_SCROLL_X
) ||
446 HasEventData(xiev
, DT_CMT_SCROLL_Y
));
449 bool DeviceDataManagerX11::IsFlingEvent(
450 const base::NativeEvent
& native_event
) const {
451 if (!IsCMTDeviceEvent(native_event
))
454 XIDeviceEvent
* xiev
=
455 static_cast<XIDeviceEvent
*>(native_event
->xcookie
.data
);
456 return (HasEventData(xiev
, DT_CMT_FLING_X
) &&
457 HasEventData(xiev
, DT_CMT_FLING_Y
) &&
458 HasEventData(xiev
, DT_CMT_FLING_STATE
));
461 bool DeviceDataManagerX11::IsCMTMetricsEvent(
462 const base::NativeEvent
& native_event
) const {
463 if (!IsCMTDeviceEvent(native_event
))
466 XIDeviceEvent
* xiev
=
467 static_cast<XIDeviceEvent
*>(native_event
->xcookie
.data
);
468 return (HasEventData(xiev
, DT_CMT_METRICS_TYPE
) &&
469 HasEventData(xiev
, DT_CMT_METRICS_DATA1
) &&
470 HasEventData(xiev
, DT_CMT_METRICS_DATA2
));
473 bool DeviceDataManagerX11::HasGestureTimes(
474 const base::NativeEvent
& native_event
) const {
475 if (!IsCMTDeviceEvent(native_event
))
478 XIDeviceEvent
* xiev
=
479 static_cast<XIDeviceEvent
*>(native_event
->xcookie
.data
);
480 return (HasEventData(xiev
, DT_CMT_START_TIME
) &&
481 HasEventData(xiev
, DT_CMT_END_TIME
));
484 void DeviceDataManagerX11::GetScrollOffsets(
485 const base::NativeEvent
& native_event
,
488 float* x_offset_ordinal
,
489 float* y_offset_ordinal
,
493 *x_offset_ordinal
= 0;
494 *y_offset_ordinal
= 0;
498 GetEventRawData(*native_event
, &data
);
500 if (data
.find(DT_CMT_SCROLL_X
) != data
.end())
501 *x_offset
= data
[DT_CMT_SCROLL_X
];
502 if (data
.find(DT_CMT_SCROLL_Y
) != data
.end())
503 *y_offset
= data
[DT_CMT_SCROLL_Y
];
504 if (data
.find(DT_CMT_ORDINAL_X
) != data
.end())
505 *x_offset_ordinal
= data
[DT_CMT_ORDINAL_X
];
506 if (data
.find(DT_CMT_ORDINAL_Y
) != data
.end())
507 *y_offset_ordinal
= data
[DT_CMT_ORDINAL_Y
];
508 if (data
.find(DT_CMT_FINGER_COUNT
) != data
.end())
509 *finger_count
= static_cast<int>(data
[DT_CMT_FINGER_COUNT
]);
512 void DeviceDataManagerX11::GetFlingData(
513 const base::NativeEvent
& native_event
,
526 GetEventRawData(*native_event
, &data
);
528 if (data
.find(DT_CMT_FLING_X
) != data
.end())
529 *vx
= data
[DT_CMT_FLING_X
];
530 if (data
.find(DT_CMT_FLING_Y
) != data
.end())
531 *vy
= data
[DT_CMT_FLING_Y
];
532 if (data
.find(DT_CMT_FLING_STATE
) != data
.end())
533 *is_cancel
= !!static_cast<unsigned int>(data
[DT_CMT_FLING_STATE
]);
534 if (data
.find(DT_CMT_ORDINAL_X
) != data
.end())
535 *vx_ordinal
= data
[DT_CMT_ORDINAL_X
];
536 if (data
.find(DT_CMT_ORDINAL_Y
) != data
.end())
537 *vy_ordinal
= data
[DT_CMT_ORDINAL_Y
];
540 void DeviceDataManagerX11::GetMetricsData(
541 const base::NativeEvent
& native_event
,
542 GestureMetricsType
* type
,
545 *type
= kGestureMetricsTypeUnknown
;
550 GetEventRawData(*native_event
, &data
);
552 if (data
.find(DT_CMT_METRICS_TYPE
) != data
.end()) {
553 int val
= static_cast<int>(data
[DT_CMT_METRICS_TYPE
]);
555 *type
= kGestureMetricsTypeNoisyGround
;
557 *type
= kGestureMetricsTypeUnknown
;
559 if (data
.find(DT_CMT_METRICS_DATA1
) != data
.end())
560 *data1
= data
[DT_CMT_METRICS_DATA1
];
561 if (data
.find(DT_CMT_METRICS_DATA2
) != data
.end())
562 *data2
= data
[DT_CMT_METRICS_DATA2
];
565 int DeviceDataManagerX11::GetMappedButton(int button
) {
566 return button
> 0 && button
<= button_map_count_
? button_map_
[button
- 1] :
570 void DeviceDataManagerX11::UpdateButtonMap() {
571 button_map_count_
= XGetPointerMapping(gfx::GetXDisplay(),
573 arraysize(button_map_
));
576 void DeviceDataManagerX11::GetGestureTimes(
577 const base::NativeEvent
& native_event
,
584 GetEventRawData(*native_event
, &data
);
586 if (data
.find(DT_CMT_START_TIME
) != data
.end())
587 *start_time
= data
[DT_CMT_START_TIME
];
588 if (data
.find(DT_CMT_END_TIME
) != data
.end())
589 *end_time
= data
[DT_CMT_END_TIME
];
592 bool DeviceDataManagerX11::NormalizeData(int deviceid
,
597 if (GetDataRange(deviceid
, type
, &min_value
, &max_value
)) {
598 *value
= (*value
- min_value
) / (max_value
- min_value
);
599 DCHECK(*value
>= 0.0 && *value
<= 1.0);
605 bool DeviceDataManagerX11::GetDataRange(int deviceid
,
609 CHECK(deviceid
>= 0);
610 if (deviceid
>= kMaxDeviceNum
)
612 if (valuator_lookup_
[deviceid
][type
] >= 0) {
613 *min
= valuator_min_
[deviceid
][type
];
614 *max
= valuator_max_
[deviceid
][type
];
620 void DeviceDataManagerX11::SetDeviceListForTest(
621 const std::vector
<int>& touchscreen
,
622 const std::vector
<int>& cmt_devices
,
623 const std::vector
<int>& other_devices
) {
624 for (int i
= 0; i
< kMaxDeviceNum
; ++i
) {
625 valuator_count_
[i
] = 0;
626 valuator_lookup_
[i
].clear();
627 data_type_lookup_
[i
].clear();
628 valuator_min_
[i
].clear();
629 valuator_max_
[i
].clear();
630 for (int j
= 0; j
< kMaxSlotNum
; j
++)
631 last_seen_valuator_
[i
][j
].clear();
634 for (int deviceid
: touchscreen
) {
635 InitializeValuatorsForTest(deviceid
, kTouchDataTypeStart
, kTouchDataTypeEnd
,
639 cmt_devices_
.reset();
640 for (int deviceid
: cmt_devices
) {
641 cmt_devices_
[deviceid
] = true;
642 touchpads_
[deviceid
] = true;
643 InitializeValuatorsForTest(deviceid
, kCMTDataTypeStart
, kCMTDataTypeEnd
,
647 for (int deviceid
: other_devices
) {
648 InitializeValuatorsForTest(deviceid
, kCMTDataTypeStart
, kCMTDataTypeEnd
,
653 void DeviceDataManagerX11::SetValuatorDataForTest(XIDeviceEvent
* xievent
,
656 int index
= valuator_lookup_
[xievent
->deviceid
][type
];
657 CHECK(!XIMaskIsSet(xievent
->valuators
.mask
, index
));
658 CHECK(index
>= 0 && index
< valuator_count_
[xievent
->deviceid
]);
659 XISetMask(xievent
->valuators
.mask
, index
);
661 double* valuators
= xievent
->valuators
.values
;
662 for (int i
= 0; i
< index
; ++i
) {
663 if (XIMaskIsSet(xievent
->valuators
.mask
, i
))
666 for (int i
= DT_LAST_ENTRY
- 1; i
> valuators
- xievent
->valuators
.values
;
668 xievent
->valuators
.values
[i
] = xievent
->valuators
.values
[i
- 1];
672 void DeviceDataManagerX11::InitializeValuatorsForTest(int deviceid
,
677 valuator_lookup_
[deviceid
].resize(DT_LAST_ENTRY
, -1);
678 data_type_lookup_
[deviceid
].resize(DT_LAST_ENTRY
, DT_LAST_ENTRY
);
679 valuator_min_
[deviceid
].resize(DT_LAST_ENTRY
, 0);
680 valuator_max_
[deviceid
].resize(DT_LAST_ENTRY
, 0);
681 for (int j
= 0; j
< kMaxSlotNum
; j
++)
682 last_seen_valuator_
[deviceid
][j
].resize(DT_LAST_ENTRY
, 0);
683 for (int j
= start_valuator
; j
<= end_valuator
; ++j
) {
684 valuator_lookup_
[deviceid
][j
] = valuator_count_
[deviceid
];
685 data_type_lookup_
[deviceid
][valuator_count_
[deviceid
]] = j
;
686 valuator_min_
[deviceid
][j
] = min_value
;
687 valuator_max_
[deviceid
][j
] = max_value
;
688 valuator_count_
[deviceid
]++;
692 bool DeviceDataManagerX11::TouchEventNeedsCalibrate(int touch_device_id
) const {
693 #if defined(OS_CHROMEOS)
694 if (!base::SysInfo::IsRunningOnChromeOS())
697 const std::vector
<TouchscreenDevice
>& touch_devices
=
698 ui::DeviceDataManager::GetInstance()->touchscreen_devices();
699 std::vector
<TouchscreenDevice
>::const_iterator it
=
700 std::find_if(touch_devices
.begin(), touch_devices
.end(),
701 std::bind2nd(std::ptr_fun(&DeviceHasId
), touch_device_id
));
702 return it
!= touch_devices
.end() && it
->type
== INPUT_DEVICE_INTERNAL
;
703 #endif // defined(OS_CHROMEOS)
707 void DeviceDataManagerX11::SetDisabledKeyboardAllowedKeys(
708 scoped_ptr
<std::set
<KeyboardCode
> > excepted_keys
) {
709 DCHECK(!excepted_keys
.get() ||
710 !blocked_keyboard_allowed_keys_
.get());
711 blocked_keyboard_allowed_keys_
= excepted_keys
.Pass();
714 void DeviceDataManagerX11::DisableDevice(int deviceid
) {
715 blocked_devices_
.set(deviceid
, true);
716 // TODO(rsadam@): Support blocking touchscreen devices.
717 std::vector
<KeyboardDevice
> keyboards
= keyboard_devices();
718 std::vector
<KeyboardDevice
>::iterator it
=
719 std::find_if(keyboards
.begin(),
721 std::bind2nd(std::ptr_fun(&DeviceHasId
), deviceid
));
722 if (it
!= std::end(keyboards
)) {
723 blocked_keyboards_
.insert(
724 std::pair
<int, KeyboardDevice
>(deviceid
, *it
));
726 DeviceDataManager::OnKeyboardDevicesUpdated(keyboards
);
730 void DeviceDataManagerX11::EnableDevice(int deviceid
) {
731 blocked_devices_
.set(deviceid
, false);
732 std::map
<int, KeyboardDevice
>::iterator it
=
733 blocked_keyboards_
.find(deviceid
);
734 if (it
!= blocked_keyboards_
.end()) {
735 std::vector
<KeyboardDevice
> devices
= keyboard_devices();
736 // Add device to current list of active devices.
737 devices
.push_back((*it
).second
);
738 blocked_keyboards_
.erase(it
);
739 DeviceDataManager::OnKeyboardDevicesUpdated(devices
);
743 bool DeviceDataManagerX11::IsEventBlocked(
744 const base::NativeEvent
& native_event
) {
745 // Only check XI2 events which have a source device id.
746 if (native_event
->type
!= GenericEvent
)
749 XIDeviceEvent
* xievent
=
750 static_cast<XIDeviceEvent
*>(native_event
->xcookie
.data
);
751 // Allow any key events from blocked_keyboard_allowed_keys_.
752 if (blocked_keyboard_allowed_keys_
&&
753 (xievent
->evtype
== XI_KeyPress
|| xievent
->evtype
== XI_KeyRelease
) &&
754 blocked_keyboard_allowed_keys_
->find(
755 KeyboardCodeFromXKeyEvent(native_event
)) !=
756 blocked_keyboard_allowed_keys_
->end()) {
760 return blocked_devices_
.test(xievent
->sourceid
);
763 void DeviceDataManagerX11::OnKeyboardDevicesUpdated(
764 const std::vector
<KeyboardDevice
>& devices
) {
765 std::vector
<KeyboardDevice
> keyboards(devices
);
766 for (std::map
<int, KeyboardDevice
>::iterator blocked_iter
=
767 blocked_keyboards_
.begin();
768 blocked_iter
!= blocked_keyboards_
.end();) {
769 // Check if the blocked device still exists in list of devices.
770 std::vector
<KeyboardDevice
>::iterator it
= std::find_if(
771 keyboards
.begin(), keyboards
.end(),
772 std::bind2nd(std::ptr_fun(&DeviceHasId
), (*blocked_iter
).first
));
773 // If the device no longer exists, unblock it, else filter it out from our
775 if (it
== keyboards
.end()) {
776 blocked_devices_
.set((*blocked_iter
).first
, false);
777 blocked_keyboards_
.erase(blocked_iter
++);
783 // Notify base class of updated list.
784 DeviceDataManager::OnKeyboardDevicesUpdated(keyboards
);