OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "ui/events/platform/x11/x11_hotplug_event_handler.h" | 5 #include "ui/events/platform/x11/x11_hotplug_event_handler.h" |
6 | 6 |
7 #include <X11/Xatom.h> | 7 #include <X11/Xatom.h> |
8 #include <X11/extensions/XInput.h> | 8 #include <X11/extensions/XInput.h> |
9 #include <X11/extensions/XInput2.h> | 9 #include <X11/extensions/XInput2.h> |
10 | 10 |
(...skipping 14 matching lines...) Expand all Loading... |
25 #include "base/thread_task_runner_handle.h" | 25 #include "base/thread_task_runner_handle.h" |
26 #include "base/threading/worker_pool.h" | 26 #include "base/threading/worker_pool.h" |
27 #include "ui/events/devices/device_data_manager.h" | 27 #include "ui/events/devices/device_data_manager.h" |
28 #include "ui/events/devices/device_hotplug_event_observer.h" | 28 #include "ui/events/devices/device_hotplug_event_observer.h" |
29 #include "ui/events/devices/device_util_linux.h" | 29 #include "ui/events/devices/device_util_linux.h" |
30 #include "ui/events/devices/input_device.h" | 30 #include "ui/events/devices/input_device.h" |
31 #include "ui/events/devices/keyboard_device.h" | 31 #include "ui/events/devices/keyboard_device.h" |
32 #include "ui/events/devices/touchscreen_device.h" | 32 #include "ui/events/devices/touchscreen_device.h" |
33 #include "ui/gfx/x/x11_types.h" | 33 #include "ui/gfx/x/x11_types.h" |
34 | 34 |
35 #ifndef XI_PROP_PRODUCT_ID | |
36 #define XI_PROP_PRODUCT_ID "Device Product ID" | |
37 #endif | |
38 | |
39 namespace ui { | 35 namespace ui { |
40 | 36 |
41 namespace { | 37 namespace { |
42 | 38 |
43 // Names of all known internal devices that should not be considered as | 39 // Names of all known internal devices that should not be considered as |
44 // keyboards. | 40 // keyboards. |
45 // TODO(rsadam@): Identify these devices using udev rules. (Crbug.com/420728.) | 41 // TODO(rsadam@): Identify these devices using udev rules. (Crbug.com/420728.) |
46 const char* kKnownInvalidKeyboardDeviceNames[] = {"Power Button", | 42 const char* kKnownInvalidKeyboardDeviceNames[] = {"Power Button", |
47 "Sleep Button", | 43 "Sleep Button", |
48 "Video Bus", | 44 "Video Bus", |
49 "gpio-keys.12", | 45 "gpio-keys.12", |
50 "ROCKCHIP-I2S Headset Jack"}; | 46 "ROCKCHIP-I2S Headset Jack"}; |
51 | 47 |
52 const char* kCachedAtomList[] = { | 48 const char* kCachedAtomList[] = { |
53 "Abs MT Position X", | 49 "Abs MT Position X", |
54 "Abs MT Position Y", | 50 "Abs MT Position Y", |
55 XI_KEYBOARD, | 51 XI_KEYBOARD, |
56 XI_MOUSE, | 52 XI_MOUSE, |
57 XI_TOUCHPAD, | 53 XI_TOUCHPAD, |
58 XI_TOUCHSCREEN, | 54 XI_TOUCHSCREEN, |
59 XI_PROP_PRODUCT_ID, | |
60 NULL, | 55 NULL, |
61 }; | 56 }; |
62 | 57 |
63 enum DeviceType { | 58 enum DeviceType { |
64 DEVICE_TYPE_KEYBOARD, | 59 DEVICE_TYPE_KEYBOARD, |
65 DEVICE_TYPE_MOUSE, | 60 DEVICE_TYPE_MOUSE, |
66 DEVICE_TYPE_TOUCHPAD, | 61 DEVICE_TYPE_TOUCHPAD, |
67 DEVICE_TYPE_TOUCHSCREEN, | 62 DEVICE_TYPE_TOUCHSCREEN, |
68 DEVICE_TYPE_OTHER | 63 DEVICE_TYPE_OTHER |
69 }; | 64 }; |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
111 explicit TouchClassInfo(const XITouchClassInfo& info) | 106 explicit TouchClassInfo(const XITouchClassInfo& info) |
112 : mode(info.mode), num_touches(info.num_touches) {} | 107 : mode(info.mode), num_touches(info.num_touches) {} |
113 | 108 |
114 int mode; | 109 int mode; |
115 int num_touches; | 110 int num_touches; |
116 }; | 111 }; |
117 | 112 |
118 struct DeviceInfo { | 113 struct DeviceInfo { |
119 DeviceInfo(const XIDeviceInfo& device, | 114 DeviceInfo(const XIDeviceInfo& device, |
120 DeviceType type, | 115 DeviceType type, |
121 const base::FilePath& path, | 116 const base::FilePath& path) |
122 uint16_t vendor, | |
123 uint16_t product) | |
124 : id(device.deviceid), | 117 : id(device.deviceid), |
125 name(device.name), | 118 name(device.name), |
126 vendor_id(vendor), | |
127 product_id(product), | |
128 use(device.use), | 119 use(device.use), |
129 type(type), | 120 type(type), |
130 path(path) { | 121 path(path) { |
131 for (int i = 0; i < device.num_classes; ++i) { | 122 for (int i = 0; i < device.num_classes; ++i) { |
132 switch (device.classes[i]->type) { | 123 switch (device.classes[i]->type) { |
133 case XIValuatorClass: | 124 case XIValuatorClass: |
134 valuator_class_infos.push_back(ValuatorClassInfo( | 125 valuator_class_infos.push_back(ValuatorClassInfo( |
135 *reinterpret_cast<XIValuatorClassInfo*>(device.classes[i]))); | 126 *reinterpret_cast<XIValuatorClassInfo*>(device.classes[i]))); |
136 break; | 127 break; |
137 case XITouchClass: | 128 case XITouchClass: |
138 // A device can have at most one XITouchClassInfo. Ref: | 129 // A device can have at most one XITouchClassInfo. Ref: |
139 // http://manpages.ubuntu.com/manpages/saucy/man3/XIQueryDevice.3.html | 130 // http://manpages.ubuntu.com/manpages/saucy/man3/XIQueryDevice.3.html |
140 DCHECK(!touch_class_info.mode); | 131 DCHECK(!touch_class_info.mode); |
141 touch_class_info = TouchClassInfo( | 132 touch_class_info = TouchClassInfo( |
142 *reinterpret_cast<XITouchClassInfo*>(device.classes[i])); | 133 *reinterpret_cast<XITouchClassInfo*>(device.classes[i])); |
143 break; | 134 break; |
144 default: | 135 default: |
145 break; | 136 break; |
146 } | 137 } |
147 } | 138 } |
148 } | 139 } |
149 | 140 |
150 // Unique device identifier. | 141 // Unique device identifier. |
151 int id; | 142 int id; |
152 | 143 |
153 // Internal device name. | 144 // Internal device name. |
154 std::string name; | 145 std::string name; |
155 | 146 |
156 // USB-style device identifiers. | |
157 uint16_t vendor_id; | |
158 uint16_t product_id; | |
159 | |
160 // Device type (ie: XIMasterPointer) | 147 // Device type (ie: XIMasterPointer) |
161 int use; | 148 int use; |
162 | 149 |
163 // Specifies the type of the device. | 150 // Specifies the type of the device. |
164 DeviceType type; | 151 DeviceType type; |
165 | 152 |
166 // Path to the actual device (ie: /dev/input/eventXX) | 153 // Path to the actual device (ie: /dev/input/eventXX) |
167 base::FilePath path; | 154 base::FilePath path; |
168 | 155 |
169 std::vector<ValuatorClassInfo> valuator_class_infos; | 156 std::vector<ValuatorClassInfo> valuator_class_infos; |
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
252 std::vector<KeyboardDevice> devices; | 239 std::vector<KeyboardDevice> devices; |
253 | 240 |
254 for (const DeviceInfo& device_info : device_infos) { | 241 for (const DeviceInfo& device_info : device_infos) { |
255 if (device_info.type != DEVICE_TYPE_KEYBOARD) | 242 if (device_info.type != DEVICE_TYPE_KEYBOARD) |
256 continue; | 243 continue; |
257 if (device_info.use != XISlaveKeyboard) | 244 if (device_info.use != XISlaveKeyboard) |
258 continue; // Assume all keyboards are keyboard slaves | 245 continue; // Assume all keyboards are keyboard slaves |
259 if (IsKnownInvalidKeyboardDevice(device_info.name)) | 246 if (IsKnownInvalidKeyboardDevice(device_info.name)) |
260 continue; // Skip invalid devices. | 247 continue; // Skip invalid devices. |
261 InputDeviceType type = GetInputDeviceTypeFromPath(device_info.path); | 248 InputDeviceType type = GetInputDeviceTypeFromPath(device_info.path); |
262 KeyboardDevice keyboard(device_info.id, type, device_info.name); | 249 devices.push_back(KeyboardDevice(device_info.id, type)); |
263 devices.push_back(keyboard); | |
264 } | 250 } |
265 | 251 |
266 reply_runner->PostTask(FROM_HERE, base::Bind(callback, devices)); | 252 reply_runner->PostTask(FROM_HERE, base::Bind(callback, devices)); |
267 } | 253 } |
268 | 254 |
269 // Helper used to parse mouse information. When it is done it uses | 255 // Helper used to parse mouse information. When it is done it uses |
270 // |reply_runner| and |callback| to update the state on the UI thread. | 256 // |reply_runner| and |callback| to update the state on the UI thread. |
271 void HandleMouseDevicesInWorker(const std::vector<DeviceInfo>& device_infos, | 257 void HandleMouseDevicesInWorker(const std::vector<DeviceInfo>& device_infos, |
272 scoped_refptr<base::TaskRunner> reply_runner, | 258 scoped_refptr<base::TaskRunner> reply_runner, |
273 const InputDeviceCallback& callback) { | 259 const InputDeviceCallback& callback) { |
274 std::vector<InputDevice> devices; | 260 std::vector<InputDevice> devices; |
275 for (const DeviceInfo& device_info : device_infos) { | 261 for (const DeviceInfo& device_info : device_infos) { |
276 if (device_info.type != DEVICE_TYPE_MOUSE || | 262 if (device_info.type != DEVICE_TYPE_MOUSE || |
277 device_info.use != XISlavePointer) { | 263 device_info.use != XISlavePointer) { |
278 continue; | 264 continue; |
279 } | 265 } |
280 | 266 |
281 InputDeviceType type = GetInputDeviceTypeFromPath(device_info.path); | 267 InputDeviceType type = GetInputDeviceTypeFromPath(device_info.path); |
282 devices.push_back(InputDevice(device_info.id, type, device_info.name)); | 268 devices.push_back(InputDevice(device_info.id, type)); |
283 } | 269 } |
284 | 270 |
285 reply_runner->PostTask(FROM_HERE, base::Bind(callback, devices)); | 271 reply_runner->PostTask(FROM_HERE, base::Bind(callback, devices)); |
286 } | 272 } |
287 | 273 |
288 // Helper used to parse touchpad information. When it is done it uses | 274 // Helper used to parse touchpad information. When it is done it uses |
289 // |reply_runner| and |callback| to update the state on the UI thread. | 275 // |reply_runner| and |callback| to update the state on the UI thread. |
290 void HandleTouchpadDevicesInWorker(const std::vector<DeviceInfo>& device_infos, | 276 void HandleTouchpadDevicesInWorker(const std::vector<DeviceInfo>& device_infos, |
291 scoped_refptr<base::TaskRunner> reply_runner, | 277 scoped_refptr<base::TaskRunner> reply_runner, |
292 const InputDeviceCallback& callback) { | 278 const InputDeviceCallback& callback) { |
293 std::vector<InputDevice> devices; | 279 std::vector<InputDevice> devices; |
294 for (const DeviceInfo& device_info : device_infos) { | 280 for (const DeviceInfo& device_info : device_infos) { |
295 if (device_info.type != DEVICE_TYPE_TOUCHPAD || | 281 if (device_info.type != DEVICE_TYPE_TOUCHPAD || |
296 device_info.use != XISlavePointer) { | 282 device_info.use != XISlavePointer) { |
297 continue; | 283 continue; |
298 } | 284 } |
299 | 285 |
300 InputDeviceType type = GetInputDeviceTypeFromPath(device_info.path); | 286 InputDeviceType type = GetInputDeviceTypeFromPath(device_info.path); |
301 devices.push_back(InputDevice(device_info.id, type, device_info.name)); | 287 devices.push_back(InputDevice(device_info.id, type)); |
302 } | 288 } |
303 | 289 |
304 reply_runner->PostTask(FROM_HERE, base::Bind(callback, devices)); | 290 reply_runner->PostTask(FROM_HERE, base::Bind(callback, devices)); |
305 } | 291 } |
306 | 292 |
307 // Helper used to parse touchscreen information. When it is done it uses | 293 // Helper used to parse touchscreen information. When it is done it uses |
308 // |reply_runner| and |callback| to update the state on the UI thread. | 294 // |reply_runner| and |callback| to update the state on the UI thread. |
309 void HandleTouchscreenDevicesInWorker( | 295 void HandleTouchscreenDevicesInWorker( |
310 const std::vector<DeviceInfo>& device_infos, | 296 const std::vector<DeviceInfo>& device_infos, |
311 const DisplayState& display_state, | 297 const DisplayState& display_state, |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
344 max_y = valuator.max; | 330 max_y = valuator.max; |
345 } | 331 } |
346 } | 332 } |
347 } | 333 } |
348 | 334 |
349 // Touchscreens should have absolute X and Y axes. | 335 // Touchscreens should have absolute X and Y axes. |
350 if (max_x > 0.0 && max_y > 0.0) { | 336 if (max_x > 0.0 && max_y > 0.0) { |
351 InputDeviceType type = GetInputDeviceTypeFromPath(device_info.path); | 337 InputDeviceType type = GetInputDeviceTypeFromPath(device_info.path); |
352 // |max_x| and |max_y| are inclusive values, so we need to add 1 to get | 338 // |max_x| and |max_y| are inclusive values, so we need to add 1 to get |
353 // the size. | 339 // the size. |
354 devices.push_back( | 340 devices.push_back(TouchscreenDevice( |
355 TouchscreenDevice(device_info.id, type, device_info.name, | 341 device_info.id, type, gfx::Size(max_x + 1, max_y + 1), |
356 gfx::Size(max_x + 1, max_y + 1), | 342 device_info.touch_class_info.num_touches)); |
357 device_info.touch_class_info.num_touches)); | |
358 } | 343 } |
359 } | 344 } |
360 | 345 |
361 reply_runner->PostTask(FROM_HERE, base::Bind(callback, devices)); | 346 reply_runner->PostTask(FROM_HERE, base::Bind(callback, devices)); |
362 } | 347 } |
363 | 348 |
364 // Called on a worker thread to parse the device information. | 349 // Called on a worker thread to parse the device information. |
365 void HandleHotplugEventInWorker( | 350 void HandleHotplugEventInWorker( |
366 const std::vector<DeviceInfo>& devices, | 351 const std::vector<DeviceInfo>& devices, |
367 const DisplayState& display_state, | 352 const DisplayState& display_state, |
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
436 std::vector<DeviceInfo> device_infos; | 421 std::vector<DeviceInfo> device_infos; |
437 for (int i = 0; i < device_list_xi2.count; ++i) { | 422 for (int i = 0; i < device_list_xi2.count; ++i) { |
438 const XIDeviceInfo& device = device_list_xi2[i]; | 423 const XIDeviceInfo& device = device_list_xi2[i]; |
439 if (!device.enabled || IsTestDevice(device.name)) | 424 if (!device.enabled || IsTestDevice(device.name)) |
440 continue; | 425 continue; |
441 | 426 |
442 DeviceType device_type = | 427 DeviceType device_type = |
443 (device.deviceid >= 0 && device.deviceid < kMaxDeviceNum) | 428 (device.deviceid >= 0 && device.deviceid < kMaxDeviceNum) |
444 ? device_types[device.deviceid] | 429 ? device_types[device.deviceid] |
445 : DEVICE_TYPE_OTHER; | 430 : DEVICE_TYPE_OTHER; |
446 | 431 device_infos.push_back( |
447 // Obtain the USB-style vendor and product identifiers. | 432 DeviceInfo(device, device_type, GetDevicePath(display, device))); |
448 // (On Linux, XI2 makes this available for all evdev devices. | |
449 uint32_t* product_info; | |
450 Atom type; | |
451 int format_return; | |
452 unsigned long num_items_return; | |
453 unsigned long bytes_after_return; | |
454 uint16_t vendor = 0; | |
455 uint16_t product = 0; | |
456 if (XIGetProperty(gfx::GetXDisplay(), device.deviceid, | |
457 atom_cache_.GetAtom(XI_PROP_PRODUCT_ID), 0, 2, 0, | |
458 XA_INTEGER, &type, &format_return, &num_items_return, | |
459 &bytes_after_return, | |
460 reinterpret_cast<unsigned char**>(&product_info)) == 0 && | |
461 product_info) { | |
462 vendor = product_info[0]; | |
463 product = product_info[1]; | |
464 XFree(product_info); | |
465 } | |
466 | |
467 device_infos.push_back(DeviceInfo( | |
468 device, device_type, GetDevicePath(display, device), vendor, product)); | |
469 } | 433 } |
470 | 434 |
471 // X11 is not thread safe, so first get all the required state. | 435 // X11 is not thread safe, so first get all the required state. |
472 DisplayState display_state; | 436 DisplayState display_state; |
473 display_state.mt_position_x = atom_cache_.GetAtom("Abs MT Position X"); | 437 display_state.mt_position_x = atom_cache_.GetAtom("Abs MT Position X"); |
474 display_state.mt_position_y = atom_cache_.GetAtom("Abs MT Position Y"); | 438 display_state.mt_position_y = atom_cache_.GetAtom("Abs MT Position Y"); |
475 | 439 |
476 UiCallbacks callbacks; | 440 UiCallbacks callbacks; |
477 callbacks.keyboard_callback = base::Bind(&OnKeyboardDevices); | 441 callbacks.keyboard_callback = base::Bind(&OnKeyboardDevices); |
478 callbacks.touchscreen_callback = base::Bind(&OnTouchscreenDevices); | 442 callbacks.touchscreen_callback = base::Bind(&OnTouchscreenDevices); |
479 callbacks.mouse_callback = base::Bind(&OnMouseDevices); | 443 callbacks.mouse_callback = base::Bind(&OnMouseDevices); |
480 callbacks.touchpad_callback = base::Bind(&OnTouchpadDevices); | 444 callbacks.touchpad_callback = base::Bind(&OnTouchpadDevices); |
481 | 445 |
482 // Parsing the device information may block, so delegate the operation to a | 446 // Parsing the device information may block, so delegate the operation to a |
483 // worker thread. Once the device information is extracted the parsed devices | 447 // worker thread. Once the device information is extracted the parsed devices |
484 // will be returned via the callbacks. | 448 // will be returned via the callbacks. |
485 base::WorkerPool::PostTask( | 449 base::WorkerPool::PostTask(FROM_HERE, |
486 FROM_HERE, | 450 base::Bind(&HandleHotplugEventInWorker, |
487 base::Bind(&HandleHotplugEventInWorker, device_infos, display_state, | 451 device_infos, |
488 base::ThreadTaskRunnerHandle::Get(), callbacks), | 452 display_state, |
489 true /* task_is_slow */); | 453 base::ThreadTaskRunnerHandle::Get(), |
| 454 callbacks), |
| 455 true /* task_is_slow */); |
490 } | 456 } |
491 | 457 |
492 } // namespace ui | 458 } // namespace ui |
OLD | NEW |