Fix search results being clipped in app list.
[chromium-blink-merge.git] / ui / events / devices / x11 / device_data_manager_x11.cc
blobf7b3b124bf96d09ab63882d4bda6ace09c443a26
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, unsigned 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 if (xiev->sourceid >= kMaxDeviceNum || xiev->deviceid >= kMaxDeviceNum)
305 return;
306 data->clear();
307 const int sourceid = xiev->sourceid;
308 double* valuators = xiev->valuators.values;
309 for (int i = 0; i <= valuator_count_[sourceid]; ++i) {
310 if (XIMaskIsSet(xiev->valuators.mask, i)) {
311 int type = data_type_lookup_[sourceid][i];
312 if (type != DT_LAST_ENTRY) {
313 (*data)[type] = *valuators;
314 if (IsTouchDataType(type)) {
315 int slot = -1;
316 if (GetSlotNumber(xiev, &slot) && slot >= 0 && slot < kMaxSlotNum)
317 last_seen_valuator_[sourceid][slot][type] = *valuators;
320 valuators++;
325 bool DeviceDataManagerX11::GetEventData(const XEvent& xev,
326 const DataType type, double* value) {
327 if (xev.type != GenericEvent)
328 return false;
330 XIDeviceEvent* xiev = static_cast<XIDeviceEvent*>(xev.xcookie.data);
331 if (xiev->sourceid >= kMaxDeviceNum || xiev->deviceid >= kMaxDeviceNum)
332 return false;
333 const int sourceid = xiev->sourceid;
334 if (valuator_lookup_[sourceid].empty())
335 return false;
337 if (type == DT_TOUCH_TRACKING_ID) {
338 // With XInput2 MT, Tracking ID is provided in the detail field for touch
339 // events.
340 if (xiev->evtype == XI_TouchBegin ||
341 xiev->evtype == XI_TouchEnd ||
342 xiev->evtype == XI_TouchUpdate) {
343 *value = xiev->detail;
344 } else {
345 *value = 0;
347 return true;
350 int val_index = valuator_lookup_[sourceid][type];
351 int slot = 0;
352 if (val_index >= 0) {
353 if (XIMaskIsSet(xiev->valuators.mask, val_index)) {
354 double* valuators = xiev->valuators.values;
355 while (val_index--) {
356 if (XIMaskIsSet(xiev->valuators.mask, val_index))
357 ++valuators;
359 *value = *valuators;
360 if (IsTouchDataType(type)) {
361 if (GetSlotNumber(xiev, &slot) && slot >= 0 && slot < kMaxSlotNum)
362 last_seen_valuator_[sourceid][slot][type] = *value;
364 return true;
365 } else if (IsTouchDataType(type)) {
366 if (GetSlotNumber(xiev, &slot) && slot >= 0 && slot < kMaxSlotNum)
367 *value = last_seen_valuator_[sourceid][slot][type];
371 return false;
374 bool DeviceDataManagerX11::IsXIDeviceEvent(
375 const base::NativeEvent& native_event) const {
376 if (native_event->type != GenericEvent ||
377 native_event->xcookie.extension != xi_opcode_)
378 return false;
379 return xi_device_event_types_[native_event->xcookie.evtype];
382 bool DeviceDataManagerX11::IsTouchpadXInputEvent(
383 const base::NativeEvent& native_event) const {
384 if (native_event->type != GenericEvent)
385 return false;
387 XIDeviceEvent* xievent =
388 static_cast<XIDeviceEvent*>(native_event->xcookie.data);
389 if (xievent->sourceid >= kMaxDeviceNum)
390 return false;
391 return touchpads_[xievent->sourceid];
394 bool DeviceDataManagerX11::IsCMTDeviceEvent(
395 const base::NativeEvent& native_event) const {
396 if (native_event->type != GenericEvent)
397 return false;
399 XIDeviceEvent* xievent =
400 static_cast<XIDeviceEvent*>(native_event->xcookie.data);
401 if (xievent->sourceid >= kMaxDeviceNum)
402 return false;
403 return cmt_devices_[xievent->sourceid];
406 bool DeviceDataManagerX11::IsCMTGestureEvent(
407 const base::NativeEvent& native_event) const {
408 return (IsScrollEvent(native_event) ||
409 IsFlingEvent(native_event) ||
410 IsCMTMetricsEvent(native_event));
413 bool DeviceDataManagerX11::HasEventData(
414 const XIDeviceEvent* xiev, const DataType type) const {
415 const int idx = valuator_lookup_[xiev->sourceid][type];
416 return (idx >= 0) && XIMaskIsSet(xiev->valuators.mask, idx);
419 bool DeviceDataManagerX11::IsScrollEvent(
420 const base::NativeEvent& native_event) const {
421 if (!IsCMTDeviceEvent(native_event))
422 return false;
424 XIDeviceEvent* xiev =
425 static_cast<XIDeviceEvent*>(native_event->xcookie.data);
426 return (HasEventData(xiev, DT_CMT_SCROLL_X) ||
427 HasEventData(xiev, DT_CMT_SCROLL_Y));
430 bool DeviceDataManagerX11::IsFlingEvent(
431 const base::NativeEvent& native_event) const {
432 if (!IsCMTDeviceEvent(native_event))
433 return false;
435 XIDeviceEvent* xiev =
436 static_cast<XIDeviceEvent*>(native_event->xcookie.data);
437 return (HasEventData(xiev, DT_CMT_FLING_X) &&
438 HasEventData(xiev, DT_CMT_FLING_Y) &&
439 HasEventData(xiev, DT_CMT_FLING_STATE));
442 bool DeviceDataManagerX11::IsCMTMetricsEvent(
443 const base::NativeEvent& native_event) const {
444 if (!IsCMTDeviceEvent(native_event))
445 return false;
447 XIDeviceEvent* xiev =
448 static_cast<XIDeviceEvent*>(native_event->xcookie.data);
449 return (HasEventData(xiev, DT_CMT_METRICS_TYPE) &&
450 HasEventData(xiev, DT_CMT_METRICS_DATA1) &&
451 HasEventData(xiev, DT_CMT_METRICS_DATA2));
454 bool DeviceDataManagerX11::HasGestureTimes(
455 const base::NativeEvent& native_event) const {
456 if (!IsCMTDeviceEvent(native_event))
457 return false;
459 XIDeviceEvent* xiev =
460 static_cast<XIDeviceEvent*>(native_event->xcookie.data);
461 return (HasEventData(xiev, DT_CMT_START_TIME) &&
462 HasEventData(xiev, DT_CMT_END_TIME));
465 void DeviceDataManagerX11::GetScrollOffsets(
466 const base::NativeEvent& native_event,
467 float* x_offset,
468 float* y_offset,
469 float* x_offset_ordinal,
470 float* y_offset_ordinal,
471 int* finger_count) {
472 *x_offset = 0;
473 *y_offset = 0;
474 *x_offset_ordinal = 0;
475 *y_offset_ordinal = 0;
476 *finger_count = 2;
478 EventData data;
479 GetEventRawData(*native_event, &data);
481 if (data.find(DT_CMT_SCROLL_X) != data.end())
482 *x_offset = data[DT_CMT_SCROLL_X];
483 if (data.find(DT_CMT_SCROLL_Y) != data.end())
484 *y_offset = data[DT_CMT_SCROLL_Y];
485 if (data.find(DT_CMT_ORDINAL_X) != data.end())
486 *x_offset_ordinal = data[DT_CMT_ORDINAL_X];
487 if (data.find(DT_CMT_ORDINAL_Y) != data.end())
488 *y_offset_ordinal = data[DT_CMT_ORDINAL_Y];
489 if (data.find(DT_CMT_FINGER_COUNT) != data.end())
490 *finger_count = static_cast<int>(data[DT_CMT_FINGER_COUNT]);
493 void DeviceDataManagerX11::GetFlingData(
494 const base::NativeEvent& native_event,
495 float* vx,
496 float* vy,
497 float* vx_ordinal,
498 float* vy_ordinal,
499 bool* is_cancel) {
500 *vx = 0;
501 *vy = 0;
502 *vx_ordinal = 0;
503 *vy_ordinal = 0;
504 *is_cancel = false;
506 EventData data;
507 GetEventRawData(*native_event, &data);
509 if (data.find(DT_CMT_FLING_X) != data.end())
510 *vx = data[DT_CMT_FLING_X];
511 if (data.find(DT_CMT_FLING_Y) != data.end())
512 *vy = data[DT_CMT_FLING_Y];
513 if (data.find(DT_CMT_FLING_STATE) != data.end())
514 *is_cancel = !!static_cast<unsigned int>(data[DT_CMT_FLING_STATE]);
515 if (data.find(DT_CMT_ORDINAL_X) != data.end())
516 *vx_ordinal = data[DT_CMT_ORDINAL_X];
517 if (data.find(DT_CMT_ORDINAL_Y) != data.end())
518 *vy_ordinal = data[DT_CMT_ORDINAL_Y];
521 void DeviceDataManagerX11::GetMetricsData(
522 const base::NativeEvent& native_event,
523 GestureMetricsType* type,
524 float* data1,
525 float* data2) {
526 *type = kGestureMetricsTypeUnknown;
527 *data1 = 0;
528 *data2 = 0;
530 EventData data;
531 GetEventRawData(*native_event, &data);
533 if (data.find(DT_CMT_METRICS_TYPE) != data.end()) {
534 int val = static_cast<int>(data[DT_CMT_METRICS_TYPE]);
535 if (val == 0)
536 *type = kGestureMetricsTypeNoisyGround;
537 else
538 *type = kGestureMetricsTypeUnknown;
540 if (data.find(DT_CMT_METRICS_DATA1) != data.end())
541 *data1 = data[DT_CMT_METRICS_DATA1];
542 if (data.find(DT_CMT_METRICS_DATA2) != data.end())
543 *data2 = data[DT_CMT_METRICS_DATA2];
546 int DeviceDataManagerX11::GetMappedButton(int button) {
547 return button > 0 && button <= button_map_count_ ? button_map_[button - 1] :
548 button;
551 void DeviceDataManagerX11::UpdateButtonMap() {
552 button_map_count_ = XGetPointerMapping(gfx::GetXDisplay(),
553 button_map_,
554 arraysize(button_map_));
557 void DeviceDataManagerX11::GetGestureTimes(
558 const base::NativeEvent& native_event,
559 double* start_time,
560 double* end_time) {
561 *start_time = 0;
562 *end_time = 0;
564 EventData data;
565 GetEventRawData(*native_event, &data);
567 if (data.find(DT_CMT_START_TIME) != data.end())
568 *start_time = data[DT_CMT_START_TIME];
569 if (data.find(DT_CMT_END_TIME) != data.end())
570 *end_time = data[DT_CMT_END_TIME];
573 bool DeviceDataManagerX11::NormalizeData(unsigned int deviceid,
574 const DataType type,
575 double* value) {
576 double max_value;
577 double min_value;
578 if (GetDataRange(deviceid, type, &min_value, &max_value)) {
579 *value = (*value - min_value) / (max_value - min_value);
580 DCHECK(*value >= 0.0 && *value <= 1.0);
581 return true;
583 return false;
586 bool DeviceDataManagerX11::GetDataRange(unsigned int deviceid,
587 const DataType type,
588 double* min,
589 double* max) {
590 if (deviceid >= static_cast<unsigned int>(kMaxDeviceNum))
591 return false;
592 if (valuator_lookup_[deviceid][type] >= 0) {
593 *min = valuator_min_[deviceid][type];
594 *max = valuator_max_[deviceid][type];
595 return true;
597 return false;
600 void DeviceDataManagerX11::SetDeviceListForTest(
601 const std::vector<unsigned int>& touchscreen,
602 const std::vector<unsigned int>& cmt_devices) {
603 for (int i = 0; i < kMaxDeviceNum; ++i) {
604 valuator_count_[i] = 0;
605 valuator_lookup_[i].clear();
606 data_type_lookup_[i].clear();
607 valuator_min_[i].clear();
608 valuator_max_[i].clear();
609 for (int j = 0; j < kMaxSlotNum; j++)
610 last_seen_valuator_[i][j].clear();
613 for (size_t i = 0; i < touchscreen.size(); i++) {
614 unsigned int deviceid = touchscreen[i];
615 InitializeValuatorsForTest(deviceid, kTouchDataTypeStart, kTouchDataTypeEnd,
616 0, 1000);
619 cmt_devices_.reset();
620 for (size_t i = 0; i < cmt_devices.size(); ++i) {
621 unsigned int deviceid = cmt_devices[i];
622 cmt_devices_[deviceid] = true;
623 touchpads_[deviceid] = true;
624 InitializeValuatorsForTest(deviceid, kCMTDataTypeStart, kCMTDataTypeEnd,
625 -1000, 1000);
629 void DeviceDataManagerX11::SetValuatorDataForTest(XIDeviceEvent* xievent,
630 DataType type,
631 double value) {
632 int index = valuator_lookup_[xievent->deviceid][type];
633 CHECK(!XIMaskIsSet(xievent->valuators.mask, index));
634 CHECK(index >= 0 && index < valuator_count_[xievent->deviceid]);
635 XISetMask(xievent->valuators.mask, index);
637 double* valuators = xievent->valuators.values;
638 for (int i = 0; i < index; ++i) {
639 if (XIMaskIsSet(xievent->valuators.mask, i))
640 valuators++;
642 for (int i = DT_LAST_ENTRY - 1; i > valuators - xievent->valuators.values;
643 --i)
644 xievent->valuators.values[i] = xievent->valuators.values[i - 1];
645 *valuators = value;
648 void DeviceDataManagerX11::InitializeValuatorsForTest(int deviceid,
649 int start_valuator,
650 int end_valuator,
651 double min_value,
652 double max_value) {
653 valuator_lookup_[deviceid].resize(DT_LAST_ENTRY, -1);
654 data_type_lookup_[deviceid].resize(DT_LAST_ENTRY, DT_LAST_ENTRY);
655 valuator_min_[deviceid].resize(DT_LAST_ENTRY, 0);
656 valuator_max_[deviceid].resize(DT_LAST_ENTRY, 0);
657 for (int j = 0; j < kMaxSlotNum; j++)
658 last_seen_valuator_[deviceid][j].resize(DT_LAST_ENTRY, 0);
659 for (int j = start_valuator; j <= end_valuator; ++j) {
660 valuator_lookup_[deviceid][j] = valuator_count_[deviceid];
661 data_type_lookup_[deviceid][valuator_count_[deviceid]] = j;
662 valuator_min_[deviceid][j] = min_value;
663 valuator_max_[deviceid][j] = max_value;
664 valuator_count_[deviceid]++;
668 bool DeviceDataManagerX11::TouchEventNeedsCalibrate(
669 unsigned int touch_device_id) const {
670 #if defined(OS_CHROMEOS)
671 if (!base::SysInfo::IsRunningOnChromeOS())
672 return false;
674 const std::vector<TouchscreenDevice>& touch_devices =
675 ui::DeviceDataManager::GetInstance()->touchscreen_devices();
676 std::vector<TouchscreenDevice>::const_iterator it =
677 std::find_if(touch_devices.begin(), touch_devices.end(),
678 std::bind2nd(std::ptr_fun(&DeviceHasId), touch_device_id));
679 return it != touch_devices.end() && it->type == INPUT_DEVICE_INTERNAL;
680 #endif // defined(OS_CHROMEOS)
681 return false;
684 void DeviceDataManagerX11::SetDisabledKeyboardAllowedKeys(
685 scoped_ptr<std::set<KeyboardCode> > excepted_keys) {
686 DCHECK(!excepted_keys.get() ||
687 !blocked_keyboard_allowed_keys_.get());
688 blocked_keyboard_allowed_keys_ = excepted_keys.Pass();
691 void DeviceDataManagerX11::DisableDevice(unsigned int deviceid) {
692 blocked_devices_.set(deviceid, true);
693 // TODO(rsadam@): Support blocking touchscreen devices.
694 std::vector<KeyboardDevice> keyboards = keyboard_devices();
695 std::vector<KeyboardDevice>::iterator it =
696 std::find_if(keyboards.begin(),
697 keyboards.end(),
698 std::bind2nd(std::ptr_fun(&DeviceHasId), deviceid));
699 if (it != std::end(keyboards)) {
700 blocked_keyboards_.insert(
701 std::pair<unsigned int, KeyboardDevice>(deviceid, *it));
702 keyboards.erase(it);
703 DeviceDataManager::OnKeyboardDevicesUpdated(keyboards);
707 void DeviceDataManagerX11::EnableDevice(unsigned int deviceid) {
708 blocked_devices_.set(deviceid, false);
709 std::map<unsigned int, KeyboardDevice>::iterator it =
710 blocked_keyboards_.find(deviceid);
711 if (it != blocked_keyboards_.end()) {
712 std::vector<KeyboardDevice> devices = keyboard_devices();
713 // Add device to current list of active devices.
714 devices.push_back((*it).second);
715 blocked_keyboards_.erase(it);
716 DeviceDataManager::OnKeyboardDevicesUpdated(devices);
720 bool DeviceDataManagerX11::IsEventBlocked(
721 const base::NativeEvent& native_event) {
722 // Only check XI2 events which have a source device id.
723 if (native_event->type != GenericEvent)
724 return false;
726 XIDeviceEvent* xievent =
727 static_cast<XIDeviceEvent*>(native_event->xcookie.data);
728 // Allow any key events from blocked_keyboard_allowed_keys_.
729 if (blocked_keyboard_allowed_keys_ &&
730 (xievent->evtype == XI_KeyPress || xievent->evtype == XI_KeyRelease) &&
731 blocked_keyboard_allowed_keys_->find(
732 KeyboardCodeFromXKeyEvent(native_event)) !=
733 blocked_keyboard_allowed_keys_->end()) {
734 return false;
737 return blocked_devices_.test(xievent->sourceid);
740 void DeviceDataManagerX11::OnKeyboardDevicesUpdated(
741 const std::vector<KeyboardDevice>& devices) {
742 std::vector<KeyboardDevice> keyboards(devices);
743 for (std::map<unsigned int, KeyboardDevice>::iterator blocked_iter =
744 blocked_keyboards_.begin();
745 blocked_iter != blocked_keyboards_.end();) {
746 // Check if the blocked device still exists in list of devices.
747 std::vector<KeyboardDevice>::iterator it = std::find_if(
748 keyboards.begin(), keyboards.end(),
749 std::bind2nd(std::ptr_fun(&DeviceHasId), (*blocked_iter).first));
750 // If the device no longer exists, unblock it, else filter it out from our
751 // active list.
752 if (it == keyboards.end()) {
753 blocked_devices_.set((*blocked_iter).first, false);
754 blocked_keyboards_.erase(blocked_iter++);
755 } else {
756 keyboards.erase(it);
757 ++blocked_iter;
760 // Notify base class of updated list.
761 DeviceDataManager::OnKeyboardDevicesUpdated(keyboards);
764 } // namespace ui