OLD | NEW |
| (Empty) |
1 // Copyright 2013 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. | |
4 | |
5 #include "ui/events/x/device_data_manager.h" | |
6 | |
7 #include <X11/extensions/XInput.h> | |
8 #include <X11/extensions/XInput2.h> | |
9 #include <X11/Xlib.h> | |
10 | |
11 #include "base/logging.h" | |
12 #include "base/memory/singleton.h" | |
13 #include "base/sys_info.h" | |
14 #include "ui/events/event_constants.h" | |
15 #include "ui/events/event_switches.h" | |
16 #include "ui/events/x/device_list_cache_x.h" | |
17 #include "ui/events/x/touch_factory_x11.h" | |
18 #include "ui/gfx/display.h" | |
19 #include "ui/gfx/point3_f.h" | |
20 #include "ui/gfx/x/x11_types.h" | |
21 | |
22 // XIScrollClass was introduced in XI 2.1 so we need to define it here | |
23 // for backward-compatibility with older versions of XInput. | |
24 #if !defined(XIScrollClass) | |
25 #define XIScrollClass 3 | |
26 #endif | |
27 | |
28 // Multi-touch support was introduced in XI 2.2. Add XI event types here | |
29 // for backward-compatibility with older versions of XInput. | |
30 #if !defined(XI_TouchBegin) | |
31 #define XI_TouchBegin 18 | |
32 #define XI_TouchUpdate 19 | |
33 #define XI_TouchEnd 20 | |
34 #endif | |
35 | |
36 // Copied from xserver-properties.h | |
37 #define AXIS_LABEL_PROP_REL_HWHEEL "Rel Horiz Wheel" | |
38 #define AXIS_LABEL_PROP_REL_WHEEL "Rel Vert Wheel" | |
39 | |
40 // CMT specific timings | |
41 #define AXIS_LABEL_PROP_ABS_DBL_START_TIME "Abs Dbl Start Timestamp" | |
42 #define AXIS_LABEL_PROP_ABS_DBL_END_TIME "Abs Dbl End Timestamp" | |
43 | |
44 // Ordinal values | |
45 #define AXIS_LABEL_PROP_ABS_DBL_ORDINAL_X "Abs Dbl Ordinal X" | |
46 #define AXIS_LABEL_PROP_ABS_DBL_ORDINAL_Y "Abs Dbl Ordinal Y" | |
47 | |
48 // Fling properties | |
49 #define AXIS_LABEL_PROP_ABS_DBL_FLING_VX "Abs Dbl Fling X Velocity" | |
50 #define AXIS_LABEL_PROP_ABS_DBL_FLING_VY "Abs Dbl Fling Y Velocity" | |
51 #define AXIS_LABEL_PROP_ABS_FLING_STATE "Abs Fling State" | |
52 | |
53 #define AXIS_LABEL_PROP_ABS_FINGER_COUNT "Abs Finger Count" | |
54 | |
55 // Cros metrics gesture from touchpad | |
56 #define AXIS_LABEL_PROP_ABS_METRICS_TYPE "Abs Metrics Type" | |
57 #define AXIS_LABEL_PROP_ABS_DBL_METRICS_DATA1 "Abs Dbl Metrics Data 1" | |
58 #define AXIS_LABEL_PROP_ABS_DBL_METRICS_DATA2 "Abs Dbl Metrics Data 2" | |
59 | |
60 // Touchscreen multi-touch | |
61 #define AXIS_LABEL_ABS_MT_TOUCH_MAJOR "Abs MT Touch Major" | |
62 #define AXIS_LABEL_ABS_MT_TOUCH_MINOR "Abs MT Touch Minor" | |
63 #define AXIS_LABEL_ABS_MT_ORIENTATION "Abs MT Orientation" | |
64 #define AXIS_LABEL_ABS_MT_PRESSURE "Abs MT Pressure" | |
65 #define AXIS_LABEL_ABS_MT_TRACKING_ID "Abs MT Tracking ID" | |
66 #define AXIS_LABEL_TOUCH_TIMESTAMP "Touch Timestamp" | |
67 | |
68 // When you add new data types, please make sure the order here is aligned | |
69 // with the order in the DataType enum in the header file because we assume | |
70 // they are in sync when updating the device list (see UpdateDeviceList). | |
71 const char* kCachedAtoms[] = { | |
72 AXIS_LABEL_PROP_REL_HWHEEL, | |
73 AXIS_LABEL_PROP_REL_WHEEL, | |
74 AXIS_LABEL_PROP_ABS_DBL_ORDINAL_X, | |
75 AXIS_LABEL_PROP_ABS_DBL_ORDINAL_Y, | |
76 AXIS_LABEL_PROP_ABS_DBL_START_TIME, | |
77 AXIS_LABEL_PROP_ABS_DBL_END_TIME, | |
78 AXIS_LABEL_PROP_ABS_DBL_FLING_VX, | |
79 AXIS_LABEL_PROP_ABS_DBL_FLING_VY, | |
80 AXIS_LABEL_PROP_ABS_FLING_STATE, | |
81 AXIS_LABEL_PROP_ABS_METRICS_TYPE, | |
82 AXIS_LABEL_PROP_ABS_DBL_METRICS_DATA1, | |
83 AXIS_LABEL_PROP_ABS_DBL_METRICS_DATA2, | |
84 AXIS_LABEL_PROP_ABS_FINGER_COUNT, | |
85 AXIS_LABEL_ABS_MT_TOUCH_MAJOR, | |
86 AXIS_LABEL_ABS_MT_TOUCH_MINOR, | |
87 AXIS_LABEL_ABS_MT_ORIENTATION, | |
88 AXIS_LABEL_ABS_MT_PRESSURE, | |
89 AXIS_LABEL_ABS_MT_TRACKING_ID, | |
90 AXIS_LABEL_TOUCH_TIMESTAMP, | |
91 | |
92 NULL | |
93 }; | |
94 | |
95 // Constants for checking if a data type lies in the range of CMT/Touch data | |
96 // types. | |
97 const int kCMTDataTypeStart = ui::DeviceDataManager::DT_CMT_SCROLL_X; | |
98 const int kCMTDataTypeEnd = ui::DeviceDataManager::DT_CMT_FINGER_COUNT; | |
99 const int kTouchDataTypeStart = ui::DeviceDataManager::DT_TOUCH_MAJOR; | |
100 const int kTouchDataTypeEnd = ui::DeviceDataManager::DT_TOUCH_RAW_TIMESTAMP; | |
101 | |
102 namespace ui { | |
103 | |
104 bool DeviceDataManager::IsCMTDataType(const int type) { | |
105 return (type >= kCMTDataTypeStart) && (type <= kCMTDataTypeEnd); | |
106 } | |
107 | |
108 bool DeviceDataManager::IsTouchDataType(const int type) { | |
109 return (type >= kTouchDataTypeStart) && (type <= kTouchDataTypeEnd); | |
110 } | |
111 | |
112 DeviceDataManager* DeviceDataManager::GetInstance() { | |
113 return Singleton<DeviceDataManager>::get(); | |
114 } | |
115 | |
116 DeviceDataManager::DeviceDataManager() | |
117 : xi_opcode_(-1), | |
118 atom_cache_(gfx::GetXDisplay(), kCachedAtoms), | |
119 button_map_count_(0) { | |
120 CHECK(gfx::GetXDisplay()); | |
121 InitializeXInputInternal(); | |
122 | |
123 // Make sure the sizes of enum and kCachedAtoms are aligned. | |
124 CHECK(arraysize(kCachedAtoms) == static_cast<size_t>(DT_LAST_ENTRY) + 1); | |
125 UpdateDeviceList(gfx::GetXDisplay()); | |
126 UpdateButtonMap(); | |
127 for (int i = 0; i < kMaxDeviceNum; i++) | |
128 touch_device_to_display_map_[i] = gfx::Display::kInvalidDisplayID; | |
129 } | |
130 | |
131 DeviceDataManager::~DeviceDataManager() { | |
132 } | |
133 | |
134 bool DeviceDataManager::InitializeXInputInternal() { | |
135 // Check if XInput is available on the system. | |
136 xi_opcode_ = -1; | |
137 int opcode, event, error; | |
138 if (!XQueryExtension( | |
139 gfx::GetXDisplay(), "XInputExtension", &opcode, &event, &error)) { | |
140 VLOG(1) << "X Input extension not available: error=" << error; | |
141 return false; | |
142 } | |
143 | |
144 // Check the XInput version. | |
145 #if defined(USE_XI2_MT) | |
146 int major = 2, minor = USE_XI2_MT; | |
147 #else | |
148 int major = 2, minor = 0; | |
149 #endif | |
150 if (XIQueryVersion(gfx::GetXDisplay(), &major, &minor) == BadRequest) { | |
151 VLOG(1) << "XInput2 not supported in the server."; | |
152 return false; | |
153 } | |
154 #if defined(USE_XI2_MT) | |
155 if (major < 2 || (major == 2 && minor < USE_XI2_MT)) { | |
156 DVLOG(1) << "XI version on server is " << major << "." << minor << ". " | |
157 << "But 2." << USE_XI2_MT << " is required."; | |
158 return false; | |
159 } | |
160 #endif | |
161 | |
162 xi_opcode_ = opcode; | |
163 CHECK_NE(-1, xi_opcode_); | |
164 | |
165 // Possible XI event types for XIDeviceEvent. See the XI2 protocol | |
166 // specification. | |
167 xi_device_event_types_[XI_KeyPress] = true; | |
168 xi_device_event_types_[XI_KeyRelease] = true; | |
169 xi_device_event_types_[XI_ButtonPress] = true; | |
170 xi_device_event_types_[XI_ButtonRelease] = true; | |
171 xi_device_event_types_[XI_Motion] = true; | |
172 // Multi-touch support was introduced in XI 2.2. | |
173 if (minor >= 2) { | |
174 xi_device_event_types_[XI_TouchBegin] = true; | |
175 xi_device_event_types_[XI_TouchUpdate] = true; | |
176 xi_device_event_types_[XI_TouchEnd] = true; | |
177 } | |
178 return true; | |
179 } | |
180 | |
181 bool DeviceDataManager::IsXInput2Available() const { | |
182 return xi_opcode_ != -1; | |
183 } | |
184 | |
185 void DeviceDataManager::UpdateDeviceList(Display* display) { | |
186 cmt_devices_.reset(); | |
187 touchpads_.reset(); | |
188 for (int i = 0; i < kMaxDeviceNum; ++i) { | |
189 valuator_count_[i] = 0; | |
190 valuator_lookup_[i].clear(); | |
191 data_type_lookup_[i].clear(); | |
192 valuator_min_[i].clear(); | |
193 valuator_max_[i].clear(); | |
194 for (int j = 0; j < kMaxSlotNum; j++) | |
195 last_seen_valuator_[i][j].clear(); | |
196 } | |
197 | |
198 // Find all the touchpad devices. | |
199 XDeviceList dev_list = | |
200 ui::DeviceListCacheX::GetInstance()->GetXDeviceList(display); | |
201 Atom xi_touchpad = XInternAtom(display, XI_TOUCHPAD, false); | |
202 for (int i = 0; i < dev_list.count; ++i) | |
203 if (dev_list[i].type == xi_touchpad) | |
204 touchpads_[dev_list[i].id] = true; | |
205 | |
206 if (!IsXInput2Available()) | |
207 return; | |
208 | |
209 // Update the structs with new valuator information | |
210 XIDeviceList info_list = | |
211 ui::DeviceListCacheX::GetInstance()->GetXI2DeviceList(display); | |
212 Atom atoms[DT_LAST_ENTRY]; | |
213 for (int data_type = 0; data_type < DT_LAST_ENTRY; ++data_type) | |
214 atoms[data_type] = atom_cache_.GetAtom(kCachedAtoms[data_type]); | |
215 | |
216 for (int i = 0; i < info_list.count; ++i) { | |
217 XIDeviceInfo* info = info_list.devices + i; | |
218 | |
219 // We currently handle only slave, non-keyboard devices | |
220 if (info->use != XISlavePointer && info->use != XIFloatingSlave) | |
221 continue; | |
222 | |
223 bool possible_cmt = false; | |
224 bool not_cmt = false; | |
225 const int deviceid = info->deviceid; | |
226 | |
227 for (int j = 0; j < info->num_classes; ++j) { | |
228 if (info->classes[j]->type == XIValuatorClass) | |
229 ++valuator_count_[deviceid]; | |
230 else if (info->classes[j]->type == XIScrollClass) | |
231 not_cmt = true; | |
232 } | |
233 | |
234 // Skip devices that don't use any valuator | |
235 if (!valuator_count_[deviceid]) | |
236 continue; | |
237 | |
238 valuator_lookup_[deviceid].resize(DT_LAST_ENTRY, -1); | |
239 data_type_lookup_[deviceid].resize( | |
240 valuator_count_[deviceid], DT_LAST_ENTRY); | |
241 valuator_min_[deviceid].resize(DT_LAST_ENTRY, 0); | |
242 valuator_max_[deviceid].resize(DT_LAST_ENTRY, 0); | |
243 for (int j = 0; j < kMaxSlotNum; j++) | |
244 last_seen_valuator_[deviceid][j].resize(DT_LAST_ENTRY, 0); | |
245 for (int j = 0; j < info->num_classes; ++j) { | |
246 if (info->classes[j]->type != XIValuatorClass) | |
247 continue; | |
248 | |
249 XIValuatorClassInfo* v = | |
250 reinterpret_cast<XIValuatorClassInfo*>(info->classes[j]); | |
251 for (int data_type = 0; data_type < DT_LAST_ENTRY; ++data_type) { | |
252 if (v->label == atoms[data_type]) { | |
253 valuator_lookup_[deviceid][data_type] = v->number; | |
254 data_type_lookup_[deviceid][v->number] = data_type; | |
255 valuator_min_[deviceid][data_type] = v->min; | |
256 valuator_max_[deviceid][data_type] = v->max; | |
257 if (IsCMTDataType(data_type)) | |
258 possible_cmt = true; | |
259 break; | |
260 } | |
261 } | |
262 } | |
263 | |
264 if (possible_cmt && !not_cmt) | |
265 cmt_devices_[deviceid] = true; | |
266 } | |
267 } | |
268 | |
269 bool DeviceDataManager::GetSlotNumber(const XIDeviceEvent* xiev, int* slot) { | |
270 #if defined(USE_XI2_MT) | |
271 ui::TouchFactory* factory = ui::TouchFactory::GetInstance(); | |
272 if (!factory->IsMultiTouchDevice(xiev->sourceid)) { | |
273 *slot = 0; | |
274 return true; | |
275 } | |
276 return factory->QuerySlotForTrackingID(xiev->detail, slot); | |
277 #else | |
278 *slot = 0; | |
279 return true; | |
280 #endif | |
281 } | |
282 | |
283 void DeviceDataManager::GetEventRawData(const XEvent& xev, EventData* data) { | |
284 if (xev.type != GenericEvent) | |
285 return; | |
286 | |
287 XIDeviceEvent* xiev = static_cast<XIDeviceEvent*>(xev.xcookie.data); | |
288 if (xiev->sourceid >= kMaxDeviceNum || xiev->deviceid >= kMaxDeviceNum) | |
289 return; | |
290 data->clear(); | |
291 const int sourceid = xiev->sourceid; | |
292 double* valuators = xiev->valuators.values; | |
293 for (int i = 0; i <= valuator_count_[sourceid]; ++i) { | |
294 if (XIMaskIsSet(xiev->valuators.mask, i)) { | |
295 int type = data_type_lookup_[sourceid][i]; | |
296 if (type != DT_LAST_ENTRY) { | |
297 (*data)[type] = *valuators; | |
298 if (IsTouchDataType(type)) { | |
299 int slot = -1; | |
300 if (GetSlotNumber(xiev, &slot) && slot >= 0 && slot < kMaxSlotNum) | |
301 last_seen_valuator_[sourceid][slot][type] = *valuators; | |
302 } | |
303 } | |
304 valuators++; | |
305 } | |
306 } | |
307 } | |
308 | |
309 bool DeviceDataManager::GetEventData(const XEvent& xev, | |
310 const DataType type, double* value) { | |
311 if (xev.type != GenericEvent) | |
312 return false; | |
313 | |
314 XIDeviceEvent* xiev = static_cast<XIDeviceEvent*>(xev.xcookie.data); | |
315 if (xiev->sourceid >= kMaxDeviceNum || xiev->deviceid >= kMaxDeviceNum) | |
316 return false; | |
317 const int sourceid = xiev->sourceid; | |
318 if (valuator_lookup_[sourceid].empty()) | |
319 return false; | |
320 | |
321 if (type == DT_TOUCH_TRACKING_ID) { | |
322 // With XInput2 MT, Tracking ID is provided in the detail field for touch | |
323 // events. | |
324 if (xiev->evtype == XI_TouchBegin || | |
325 xiev->evtype == XI_TouchEnd || | |
326 xiev->evtype == XI_TouchUpdate) { | |
327 *value = xiev->detail; | |
328 } else { | |
329 *value = 0; | |
330 } | |
331 return true; | |
332 } | |
333 | |
334 int val_index = valuator_lookup_[sourceid][type]; | |
335 int slot = 0; | |
336 if (val_index >= 0) { | |
337 if (XIMaskIsSet(xiev->valuators.mask, val_index)) { | |
338 double* valuators = xiev->valuators.values; | |
339 while (val_index--) { | |
340 if (XIMaskIsSet(xiev->valuators.mask, val_index)) | |
341 ++valuators; | |
342 } | |
343 *value = *valuators; | |
344 if (IsTouchDataType(type)) { | |
345 if (GetSlotNumber(xiev, &slot) && slot >= 0 && slot < kMaxSlotNum) | |
346 last_seen_valuator_[sourceid][slot][type] = *value; | |
347 } | |
348 return true; | |
349 } else if (IsTouchDataType(type)) { | |
350 if (GetSlotNumber(xiev, &slot) && slot >= 0 && slot < kMaxSlotNum) | |
351 *value = last_seen_valuator_[sourceid][slot][type]; | |
352 } | |
353 } | |
354 | |
355 return false; | |
356 } | |
357 | |
358 bool DeviceDataManager::IsXIDeviceEvent( | |
359 const base::NativeEvent& native_event) const { | |
360 if (native_event->type != GenericEvent || | |
361 native_event->xcookie.extension != xi_opcode_) | |
362 return false; | |
363 return xi_device_event_types_[native_event->xcookie.evtype]; | |
364 } | |
365 | |
366 bool DeviceDataManager::IsTouchpadXInputEvent( | |
367 const base::NativeEvent& native_event) const { | |
368 if (native_event->type != GenericEvent) | |
369 return false; | |
370 | |
371 XIDeviceEvent* xievent = | |
372 static_cast<XIDeviceEvent*>(native_event->xcookie.data); | |
373 if (xievent->sourceid >= kMaxDeviceNum) | |
374 return false; | |
375 return touchpads_[xievent->sourceid]; | |
376 } | |
377 | |
378 bool DeviceDataManager::IsCMTDeviceEvent( | |
379 const base::NativeEvent& native_event) const { | |
380 if (native_event->type != GenericEvent) | |
381 return false; | |
382 | |
383 XIDeviceEvent* xievent = | |
384 static_cast<XIDeviceEvent*>(native_event->xcookie.data); | |
385 if (xievent->sourceid >= kMaxDeviceNum) | |
386 return false; | |
387 return cmt_devices_[xievent->sourceid]; | |
388 } | |
389 | |
390 bool DeviceDataManager::IsCMTGestureEvent( | |
391 const base::NativeEvent& native_event) const { | |
392 return (IsScrollEvent(native_event) || | |
393 IsFlingEvent(native_event) || | |
394 IsCMTMetricsEvent(native_event)); | |
395 } | |
396 | |
397 bool DeviceDataManager::HasEventData( | |
398 const XIDeviceEvent* xiev, const DataType type) const { | |
399 const int idx = valuator_lookup_[xiev->sourceid][type]; | |
400 return (idx >= 0) && XIMaskIsSet(xiev->valuators.mask, idx); | |
401 } | |
402 | |
403 bool DeviceDataManager::IsScrollEvent( | |
404 const base::NativeEvent& native_event) const { | |
405 if (!IsCMTDeviceEvent(native_event)) | |
406 return false; | |
407 | |
408 XIDeviceEvent* xiev = | |
409 static_cast<XIDeviceEvent*>(native_event->xcookie.data); | |
410 return (HasEventData(xiev, DT_CMT_SCROLL_X) || | |
411 HasEventData(xiev, DT_CMT_SCROLL_Y)); | |
412 } | |
413 | |
414 bool DeviceDataManager::IsFlingEvent( | |
415 const base::NativeEvent& native_event) const { | |
416 if (!IsCMTDeviceEvent(native_event)) | |
417 return false; | |
418 | |
419 XIDeviceEvent* xiev = | |
420 static_cast<XIDeviceEvent*>(native_event->xcookie.data); | |
421 return (HasEventData(xiev, DT_CMT_FLING_X) && | |
422 HasEventData(xiev, DT_CMT_FLING_Y) && | |
423 HasEventData(xiev, DT_CMT_FLING_STATE)); | |
424 } | |
425 | |
426 bool DeviceDataManager::IsCMTMetricsEvent( | |
427 const base::NativeEvent& native_event) const { | |
428 if (!IsCMTDeviceEvent(native_event)) | |
429 return false; | |
430 | |
431 XIDeviceEvent* xiev = | |
432 static_cast<XIDeviceEvent*>(native_event->xcookie.data); | |
433 return (HasEventData(xiev, DT_CMT_METRICS_TYPE) && | |
434 HasEventData(xiev, DT_CMT_METRICS_DATA1) && | |
435 HasEventData(xiev, DT_CMT_METRICS_DATA2)); | |
436 } | |
437 | |
438 bool DeviceDataManager::HasGestureTimes( | |
439 const base::NativeEvent& native_event) const { | |
440 if (!IsCMTDeviceEvent(native_event)) | |
441 return false; | |
442 | |
443 XIDeviceEvent* xiev = | |
444 static_cast<XIDeviceEvent*>(native_event->xcookie.data); | |
445 return (HasEventData(xiev, DT_CMT_START_TIME) && | |
446 HasEventData(xiev, DT_CMT_END_TIME)); | |
447 } | |
448 | |
449 void DeviceDataManager::GetScrollOffsets(const base::NativeEvent& native_event, | |
450 float* x_offset, float* y_offset, | |
451 float* x_offset_ordinal, | |
452 float* y_offset_ordinal, | |
453 int* finger_count) { | |
454 *x_offset = 0; | |
455 *y_offset = 0; | |
456 *x_offset_ordinal = 0; | |
457 *y_offset_ordinal = 0; | |
458 *finger_count = 2; | |
459 | |
460 EventData data; | |
461 GetEventRawData(*native_event, &data); | |
462 | |
463 if (data.find(DT_CMT_SCROLL_X) != data.end()) | |
464 *x_offset = data[DT_CMT_SCROLL_X]; | |
465 if (data.find(DT_CMT_SCROLL_Y) != data.end()) | |
466 *y_offset = data[DT_CMT_SCROLL_Y]; | |
467 if (data.find(DT_CMT_ORDINAL_X) != data.end()) | |
468 *x_offset_ordinal = data[DT_CMT_ORDINAL_X]; | |
469 if (data.find(DT_CMT_ORDINAL_Y) != data.end()) | |
470 *y_offset_ordinal = data[DT_CMT_ORDINAL_Y]; | |
471 if (data.find(DT_CMT_FINGER_COUNT) != data.end()) | |
472 *finger_count = static_cast<int>(data[DT_CMT_FINGER_COUNT]); | |
473 } | |
474 | |
475 void DeviceDataManager::GetFlingData(const base::NativeEvent& native_event, | |
476 float* vx, float* vy, | |
477 float* vx_ordinal, float* vy_ordinal, | |
478 bool* is_cancel) { | |
479 *vx = 0; | |
480 *vy = 0; | |
481 *vx_ordinal = 0; | |
482 *vy_ordinal = 0; | |
483 *is_cancel = false; | |
484 | |
485 EventData data; | |
486 GetEventRawData(*native_event, &data); | |
487 | |
488 if (data.find(DT_CMT_FLING_X) != data.end()) | |
489 *vx = data[DT_CMT_FLING_X]; | |
490 if (data.find(DT_CMT_FLING_Y) != data.end()) | |
491 *vy = data[DT_CMT_FLING_Y]; | |
492 if (data.find(DT_CMT_FLING_STATE) != data.end()) | |
493 *is_cancel = !!static_cast<unsigned int>(data[DT_CMT_FLING_STATE]); | |
494 if (data.find(DT_CMT_ORDINAL_X) != data.end()) | |
495 *vx_ordinal = data[DT_CMT_ORDINAL_X]; | |
496 if (data.find(DT_CMT_ORDINAL_Y) != data.end()) | |
497 *vy_ordinal = data[DT_CMT_ORDINAL_Y]; | |
498 } | |
499 | |
500 void DeviceDataManager::GetMetricsData(const base::NativeEvent& native_event, | |
501 GestureMetricsType* type, | |
502 float* data1, float* data2) { | |
503 *type = kGestureMetricsTypeUnknown; | |
504 *data1 = 0; | |
505 *data2 = 0; | |
506 | |
507 EventData data; | |
508 GetEventRawData(*native_event, &data); | |
509 | |
510 if (data.find(DT_CMT_METRICS_TYPE) != data.end()) { | |
511 int val = static_cast<int>(data[DT_CMT_METRICS_TYPE]); | |
512 if (val == 0) | |
513 *type = kGestureMetricsTypeNoisyGround; | |
514 else | |
515 *type = kGestureMetricsTypeUnknown; | |
516 } | |
517 if (data.find(DT_CMT_METRICS_DATA1) != data.end()) | |
518 *data1 = data[DT_CMT_METRICS_DATA1]; | |
519 if (data.find(DT_CMT_METRICS_DATA2) != data.end()) | |
520 *data2 = data[DT_CMT_METRICS_DATA2]; | |
521 } | |
522 | |
523 int DeviceDataManager::GetMappedButton(int button) { | |
524 return button > 0 && button <= button_map_count_ ? button_map_[button - 1] : | |
525 button; | |
526 } | |
527 | |
528 void DeviceDataManager::UpdateButtonMap() { | |
529 button_map_count_ = XGetPointerMapping(gfx::GetXDisplay(), | |
530 button_map_, | |
531 arraysize(button_map_)); | |
532 } | |
533 | |
534 void DeviceDataManager::GetGestureTimes(const base::NativeEvent& native_event, | |
535 double* start_time, | |
536 double* end_time) { | |
537 *start_time = 0; | |
538 *end_time = 0; | |
539 | |
540 EventData data; | |
541 GetEventRawData(*native_event, &data); | |
542 | |
543 if (data.find(DT_CMT_START_TIME) != data.end()) | |
544 *start_time = data[DT_CMT_START_TIME]; | |
545 if (data.find(DT_CMT_END_TIME) != data.end()) | |
546 *end_time = data[DT_CMT_END_TIME]; | |
547 } | |
548 | |
549 bool DeviceDataManager::NormalizeData(unsigned int deviceid, | |
550 const DataType type, | |
551 double* value) { | |
552 double max_value; | |
553 double min_value; | |
554 if (GetDataRange(deviceid, type, &min_value, &max_value)) { | |
555 *value = (*value - min_value) / (max_value - min_value); | |
556 DCHECK(*value >= 0.0 && *value <= 1.0); | |
557 return true; | |
558 } | |
559 return false; | |
560 } | |
561 | |
562 bool DeviceDataManager::GetDataRange(unsigned int deviceid, | |
563 const DataType type, | |
564 double* min, double* max) { | |
565 if (deviceid >= static_cast<unsigned int>(kMaxDeviceNum)) | |
566 return false; | |
567 if (valuator_lookup_[deviceid][type] >= 0) { | |
568 *min = valuator_min_[deviceid][type]; | |
569 *max = valuator_max_[deviceid][type]; | |
570 return true; | |
571 } | |
572 return false; | |
573 } | |
574 | |
575 void DeviceDataManager::SetDeviceListForTest( | |
576 const std::vector<unsigned int>& touchscreen, | |
577 const std::vector<unsigned int>& cmt_devices) { | |
578 for (int i = 0; i < kMaxDeviceNum; ++i) { | |
579 valuator_count_[i] = 0; | |
580 valuator_lookup_[i].clear(); | |
581 data_type_lookup_[i].clear(); | |
582 valuator_min_[i].clear(); | |
583 valuator_max_[i].clear(); | |
584 for (int j = 0; j < kMaxSlotNum; j++) | |
585 last_seen_valuator_[i][j].clear(); | |
586 } | |
587 | |
588 for (size_t i = 0; i < touchscreen.size(); i++) { | |
589 unsigned int deviceid = touchscreen[i]; | |
590 InitializeValuatorsForTest(deviceid, kTouchDataTypeStart, kTouchDataTypeEnd, | |
591 0, 1000); | |
592 } | |
593 | |
594 cmt_devices_.reset(); | |
595 for (size_t i = 0; i < cmt_devices.size(); ++i) { | |
596 unsigned int deviceid = cmt_devices[i]; | |
597 cmt_devices_[deviceid] = true; | |
598 touchpads_[deviceid] = true; | |
599 InitializeValuatorsForTest(deviceid, kCMTDataTypeStart, kCMTDataTypeEnd, | |
600 -1000, 1000); | |
601 } | |
602 } | |
603 | |
604 void DeviceDataManager::SetValuatorDataForTest(XIDeviceEvent* xievent, | |
605 DataType type, | |
606 double value) { | |
607 int index = valuator_lookup_[xievent->deviceid][type]; | |
608 CHECK(!XIMaskIsSet(xievent->valuators.mask, index)); | |
609 CHECK(index >= 0 && index < valuator_count_[xievent->deviceid]); | |
610 XISetMask(xievent->valuators.mask, index); | |
611 | |
612 double* valuators = xievent->valuators.values; | |
613 for (int i = 0; i < index; ++i) { | |
614 if (XIMaskIsSet(xievent->valuators.mask, i)) | |
615 valuators++; | |
616 } | |
617 for (int i = DT_LAST_ENTRY - 1; i > valuators - xievent->valuators.values; | |
618 --i) | |
619 xievent->valuators.values[i] = xievent->valuators.values[i - 1]; | |
620 *valuators = value; | |
621 } | |
622 | |
623 void DeviceDataManager::InitializeValuatorsForTest(int deviceid, | |
624 int start_valuator, | |
625 int end_valuator, | |
626 double min_value, | |
627 double max_value) { | |
628 valuator_lookup_[deviceid].resize(DT_LAST_ENTRY, -1); | |
629 data_type_lookup_[deviceid].resize(DT_LAST_ENTRY, DT_LAST_ENTRY); | |
630 valuator_min_[deviceid].resize(DT_LAST_ENTRY, 0); | |
631 valuator_max_[deviceid].resize(DT_LAST_ENTRY, 0); | |
632 for (int j = 0; j < kMaxSlotNum; j++) | |
633 last_seen_valuator_[deviceid][j].resize(DT_LAST_ENTRY, 0); | |
634 for (int j = start_valuator; j <= end_valuator; ++j) { | |
635 valuator_lookup_[deviceid][j] = valuator_count_[deviceid]; | |
636 data_type_lookup_[deviceid][valuator_count_[deviceid]] = j; | |
637 valuator_min_[deviceid][j] = min_value; | |
638 valuator_max_[deviceid][j] = max_value; | |
639 valuator_count_[deviceid]++; | |
640 } | |
641 } | |
642 | |
643 bool DeviceDataManager::TouchEventNeedsCalibrate(int touch_device_id) const { | |
644 #if defined(OS_CHROMEOS) && defined(USE_XI2_MT) | |
645 int64 touch_display_id = GetDisplayForTouchDevice(touch_device_id); | |
646 if (base::SysInfo::IsRunningOnChromeOS() && | |
647 touch_display_id == gfx::Display::InternalDisplayId()) { | |
648 return true; | |
649 } | |
650 #endif // defined(OS_CHROMEOS) && defined(USE_XI2_MT) | |
651 return false; | |
652 } | |
653 | |
654 void DeviceDataManager::ClearTouchTransformerRecord() { | |
655 for (int i = 0; i < kMaxDeviceNum; i++) { | |
656 touch_device_transformer_map_[i] = gfx::Transform(); | |
657 touch_device_to_display_map_[i] = gfx::Display::kInvalidDisplayID; | |
658 } | |
659 } | |
660 | |
661 bool DeviceDataManager::IsTouchDeviceIdValid(int touch_device_id) const { | |
662 return (touch_device_id > 0 && touch_device_id < kMaxDeviceNum); | |
663 } | |
664 | |
665 void DeviceDataManager::UpdateTouchInfoForDisplay( | |
666 int64 display_id, | |
667 int touch_device_id, | |
668 const gfx::Transform& touch_transformer) { | |
669 if (IsTouchDeviceIdValid(touch_device_id)) { | |
670 touch_device_to_display_map_[touch_device_id] = display_id; | |
671 touch_device_transformer_map_[touch_device_id] = touch_transformer; | |
672 } | |
673 } | |
674 | |
675 void DeviceDataManager::ApplyTouchTransformer(int touch_device_id, | |
676 float* x, float* y) { | |
677 if (IsTouchDeviceIdValid(touch_device_id)) { | |
678 gfx::Point3F point(*x, *y, 0.0); | |
679 const gfx::Transform& trans = | |
680 touch_device_transformer_map_[touch_device_id]; | |
681 trans.TransformPoint(&point); | |
682 *x = point.x(); | |
683 *y = point.y(); | |
684 } | |
685 } | |
686 | |
687 int64 DeviceDataManager::GetDisplayForTouchDevice(int touch_device_id) const { | |
688 if (IsTouchDeviceIdValid(touch_device_id)) | |
689 return touch_device_to_display_map_[touch_device_id]; | |
690 return gfx::Display::kInvalidDisplayID; | |
691 } | |
692 | |
693 } // namespace ui | |
OLD | NEW |