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