MD Downloads: prevent search text from overlapping with the cancel search (X)
[chromium-blink-merge.git] / ui / events / devices / x11 / device_data_manager_x11.cc
blob39a1ff1cf092188510a856cf1172ca82845c549c
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/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
32 #endif
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
40 #endif
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"
50 // Ordinal values
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"
54 // Fling properties
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,
102 NULL
105 // Constants for checking if a data type lies in the range of CMT/Touch data
106 // types.
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;
112 namespace ui {
114 namespace {
116 bool DeviceHasId(const ui::InputDevice input_device, int id) {
117 return input_device.id == id;
120 } // namespace
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);
130 // static
131 void DeviceDataManagerX11::CreateInstance() {
132 if (instance())
133 return;
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);
144 // static
145 DeviceDataManagerX11* DeviceDataManagerX11::GetInstance() {
146 return static_cast<DeviceDataManagerX11*>(DeviceDataManager::GetInstance());
149 DeviceDataManagerX11::DeviceDataManagerX11()
150 : xi_opcode_(-1),
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());
159 UpdateButtonMap();
162 DeviceDataManagerX11::~DeviceDataManagerX11() {
165 bool DeviceDataManagerX11::InitializeXInputInternal() {
166 // Check if XInput is available on the system.
167 xi_opcode_ = -1;
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;
172 return false;
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.";
179 return false;
181 if (major < 2 || (major == 2 && minor < 2)) {
182 DVLOG(1) << "XI version on server is " << major << "." << minor << ". "
183 << "But 2.2 is required.";
184 return false;
187 xi_opcode_ = opcode;
188 CHECK_NE(-1, xi_opcode_);
190 // Possible XI event types for XIDeviceEvent. See the XI2 protocol
191 // specification.
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.
198 if (minor >= 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;
203 return true;
206 bool DeviceDataManagerX11::IsXInput2Available() const {
207 return xi_opcode_ != -1;
210 void DeviceDataManagerX11::UpdateDeviceList(Display* display) {
211 cmt_devices_.reset();
212 touchpads_.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())
233 return;
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)
250 continue;
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)
260 not_cmt = true;
263 // Skip devices that don't use any valuator
264 if (!valuator_count_[deviceid])
265 continue;
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)
276 continue;
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))
287 possible_cmt = true;
288 break;
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)) {
301 *slot = 0;
302 return true;
304 return factory->QuerySlotForTrackingID(xiev->detail, slot);
307 void DeviceDataManagerX11::GetEventRawData(const XEvent& xev, EventData* data) {
308 if (xev.type != GenericEvent)
309 return;
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)
315 return;
316 data->clear();
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)) {
325 int slot = -1;
326 if (GetSlotNumber(xiev, &slot) && slot >= 0 && slot < kMaxSlotNum)
327 last_seen_valuator_[sourceid][slot][type] = *valuators;
330 valuators++;
335 bool DeviceDataManagerX11::GetEventData(const XEvent& xev,
336 const DataType type, double* value) {
337 if (xev.type != GenericEvent)
338 return false;
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)
344 return false;
345 const int sourceid = xiev->sourceid;
346 if (valuator_lookup_[sourceid].empty())
347 return false;
349 if (type == DT_TOUCH_TRACKING_ID) {
350 // With XInput2 MT, Tracking ID is provided in the detail field for touch
351 // events.
352 if (xiev->evtype == XI_TouchBegin ||
353 xiev->evtype == XI_TouchEnd ||
354 xiev->evtype == XI_TouchUpdate) {
355 *value = xiev->detail;
356 } else {
357 *value = 0;
359 return true;
362 int val_index = valuator_lookup_[sourceid][type];
363 int slot = 0;
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))
369 ++valuators;
371 *value = *valuators;
372 if (IsTouchDataType(type)) {
373 if (GetSlotNumber(xiev, &slot) && slot >= 0 && slot < kMaxSlotNum)
374 last_seen_valuator_[sourceid][slot][type] = *value;
376 return true;
377 } else if (IsTouchDataType(type)) {
378 if (GetSlotNumber(xiev, &slot) && slot >= 0 && slot < kMaxSlotNum)
379 *value = last_seen_valuator_[sourceid][slot][type];
383 return false;
386 bool DeviceDataManagerX11::IsXIDeviceEvent(
387 const base::NativeEvent& native_event) const {
388 if (native_event->type != GenericEvent ||
389 native_event->xcookie.extension != xi_opcode_)
390 return false;
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)
397 return false;
399 XIDeviceEvent* xievent =
400 static_cast<XIDeviceEvent*>(native_event->xcookie.data);
401 CHECK(xievent->sourceid >= 0);
402 if (xievent->sourceid >= kMaxDeviceNum)
403 return false;
404 return touchpads_[xievent->sourceid];
407 bool DeviceDataManagerX11::IsCMTDeviceEvent(
408 const base::NativeEvent& native_event) const {
409 if (native_event->type != GenericEvent)
410 return false;
412 XIDeviceEvent* xievent =
413 static_cast<XIDeviceEvent*>(native_event->xcookie.data);
414 CHECK(xievent->sourceid >= 0);
415 if (xievent->sourceid >= kMaxDeviceNum)
416 return false;
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)
431 return false;
432 if (type >= valuator_lookup_[xiev->sourceid].size())
433 return false;
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))
441 return false;
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))
452 return false;
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))
464 return false;
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))
476 return false;
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,
486 float* x_offset,
487 float* y_offset,
488 float* x_offset_ordinal,
489 float* y_offset_ordinal,
490 int* finger_count) {
491 *x_offset = 0;
492 *y_offset = 0;
493 *x_offset_ordinal = 0;
494 *y_offset_ordinal = 0;
495 *finger_count = 2;
497 EventData data;
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,
514 float* vx,
515 float* vy,
516 float* vx_ordinal,
517 float* vy_ordinal,
518 bool* is_cancel) {
519 *vx = 0;
520 *vy = 0;
521 *vx_ordinal = 0;
522 *vy_ordinal = 0;
523 *is_cancel = false;
525 EventData data;
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,
543 float* data1,
544 float* data2) {
545 *type = kGestureMetricsTypeUnknown;
546 *data1 = 0;
547 *data2 = 0;
549 EventData data;
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]);
554 if (val == 0)
555 *type = kGestureMetricsTypeNoisyGround;
556 else
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] :
567 button;
570 void DeviceDataManagerX11::UpdateButtonMap() {
571 button_map_count_ = XGetPointerMapping(gfx::GetXDisplay(),
572 button_map_,
573 arraysize(button_map_));
576 void DeviceDataManagerX11::GetGestureTimes(
577 const base::NativeEvent& native_event,
578 double* start_time,
579 double* end_time) {
580 *start_time = 0;
581 *end_time = 0;
583 EventData data;
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,
593 const DataType type,
594 double* value) {
595 double max_value;
596 double min_value;
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);
600 return true;
602 return false;
605 bool DeviceDataManagerX11::GetDataRange(int deviceid,
606 const DataType type,
607 double* min,
608 double* max) {
609 CHECK(deviceid >= 0);
610 if (deviceid >= kMaxDeviceNum)
611 return false;
612 if (valuator_lookup_[deviceid][type] >= 0) {
613 *min = valuator_min_[deviceid][type];
614 *max = valuator_max_[deviceid][type];
615 return true;
617 return false;
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,
636 0, 1000);
639 cmt_devices_.reset();
640 for (int deviceid : cmt_devices) {
641 cmt_devices_[deviceid] = true;
642 touchpads_[deviceid] = true;
643 InitializeValuatorsForTest(deviceid, kCMTDataTypeStart, kCMTDataTypeEnd,
644 -1000, 1000);
647 for (int deviceid : other_devices) {
648 InitializeValuatorsForTest(deviceid, kCMTDataTypeStart, kCMTDataTypeEnd,
649 -1000, 1000);
653 void DeviceDataManagerX11::SetValuatorDataForTest(XIDeviceEvent* xievent,
654 DataType type,
655 double value) {
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))
664 valuators++;
666 for (int i = DT_LAST_ENTRY - 1; i > valuators - xievent->valuators.values;
667 --i)
668 xievent->valuators.values[i] = xievent->valuators.values[i - 1];
669 *valuators = value;
672 void DeviceDataManagerX11::InitializeValuatorsForTest(int deviceid,
673 int start_valuator,
674 int end_valuator,
675 double min_value,
676 double max_value) {
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())
695 return false;
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)
704 return false;
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(),
720 keyboards.end(),
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));
725 keyboards.erase(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)
747 return false;
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()) {
757 return false;
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
774 // active list.
775 if (it == keyboards.end()) {
776 blocked_devices_.set((*blocked_iter).first, false);
777 blocked_keyboards_.erase(blocked_iter++);
778 } else {
779 keyboards.erase(it);
780 ++blocked_iter;
783 // Notify base class of updated list.
784 DeviceDataManager::OnKeyboardDevicesUpdated(keyboards);
787 } // namespace ui