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 <stdint.h> | 7 #include <stdint.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 #include <X11/Xatom.h> | 10 #include <X11/Xatom.h> |
11 | 11 |
12 #include <algorithm> | 12 #include <algorithm> |
13 #include <cmath> | 13 #include <cmath> |
14 #include <set> | 14 #include <set> |
15 #include <string> | 15 #include <string> |
16 #include <vector> | 16 #include <vector> |
17 | 17 |
18 #include "base/bind.h" | 18 #include "base/bind.h" |
19 #include "base/command_line.h" | 19 #include "base/command_line.h" |
20 #include "base/location.h" | 20 #include "base/location.h" |
21 #include "base/logging.h" | 21 #include "base/logging.h" |
22 #include "base/process/launch.h" | 22 #include "base/process/launch.h" |
23 #include "base/single_thread_task_runner.h" | 23 #include "base/single_thread_task_runner.h" |
24 #include "base/strings/string_util.h" | 24 #include "base/strings/string_util.h" |
25 #include "base/sys_info.h" | 25 #include "base/sys_info.h" |
26 #include "base/threading/thread_task_runner_handle.h" | 26 #include "base/threading/thread_task_runner_handle.h" |
27 #include "base/threading/worker_pool.h" | 27 #include "base/threading/worker_pool.h" |
| 28 #include "ui/base/x/x11_util.h" |
28 #include "ui/events/devices/device_data_manager.h" | 29 #include "ui/events/devices/device_data_manager.h" |
29 #include "ui/events/devices/device_hotplug_event_observer.h" | 30 #include "ui/events/devices/device_hotplug_event_observer.h" |
30 #include "ui/events/devices/device_util_linux.h" | 31 #include "ui/events/devices/device_util_linux.h" |
31 #include "ui/events/devices/input_device.h" | 32 #include "ui/events/devices/input_device.h" |
32 #include "ui/events/devices/touchscreen_device.h" | 33 #include "ui/events/devices/touchscreen_device.h" |
| 34 #include "ui/gfx/x/x11_atom_cache.h" |
33 #include "ui/gfx/x/x11_types.h" | 35 #include "ui/gfx/x/x11_types.h" |
34 | 36 |
35 #ifndef XI_PROP_PRODUCT_ID | 37 #ifndef XI_PROP_PRODUCT_ID |
36 #define XI_PROP_PRODUCT_ID "Device Product ID" | 38 #define XI_PROP_PRODUCT_ID "Device Product ID" |
37 #endif | 39 #endif |
38 | 40 |
39 namespace ui { | 41 namespace ui { |
40 | 42 |
41 namespace { | 43 namespace { |
42 | 44 |
43 // Names of all known internal devices that should not be considered as | 45 // Names of all known internal devices that should not be considered as |
44 // keyboards. | 46 // keyboards. |
45 // TODO(rsadam@): Identify these devices using udev rules. (Crbug.com/420728.) | 47 // TODO(rsadam@): Identify these devices using udev rules. (Crbug.com/420728.) |
46 const char* kKnownInvalidKeyboardDeviceNames[] = {"Power Button", | 48 const char* kKnownInvalidKeyboardDeviceNames[] = {"Power Button", |
47 "Sleep Button", | 49 "Sleep Button", |
48 "Video Bus", | 50 "Video Bus", |
49 "gpio-keys.5", | 51 "gpio-keys.5", |
50 "gpio-keys.12", | 52 "gpio-keys.12", |
51 "ROCKCHIP-I2S Headset Jack"}; | 53 "ROCKCHIP-I2S Headset Jack"}; |
52 | 54 |
53 const char* kCachedAtomList[] = { | |
54 "Abs MT Position X", | |
55 "Abs MT Position Y", | |
56 XI_KEYBOARD, | |
57 XI_MOUSE, | |
58 XI_TOUCHPAD, | |
59 XI_TOUCHSCREEN, | |
60 XI_PROP_PRODUCT_ID, | |
61 NULL, | |
62 }; | |
63 | |
64 enum DeviceType { | 55 enum DeviceType { |
65 DEVICE_TYPE_KEYBOARD, | 56 DEVICE_TYPE_KEYBOARD, |
66 DEVICE_TYPE_MOUSE, | 57 DEVICE_TYPE_MOUSE, |
67 DEVICE_TYPE_TOUCHPAD, | 58 DEVICE_TYPE_TOUCHPAD, |
68 DEVICE_TYPE_TOUCHSCREEN, | 59 DEVICE_TYPE_TOUCHSCREEN, |
69 DEVICE_TYPE_OTHER | 60 DEVICE_TYPE_OTHER |
70 }; | 61 }; |
71 | 62 |
72 typedef base::Callback<void(const std::vector<InputDevice>&)> | 63 typedef base::Callback<void(const std::vector<InputDevice>&)> |
73 KeyboardDeviceCallback; | 64 KeyboardDeviceCallback; |
(...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
199 } | 190 } |
200 | 191 |
201 base::FilePath GetDevicePath(XDisplay* dpy, const XIDeviceInfo& device) { | 192 base::FilePath GetDevicePath(XDisplay* dpy, const XIDeviceInfo& device) { |
202 // Skip the main pointer and keyboard since XOpenDevice() generates a | 193 // Skip the main pointer and keyboard since XOpenDevice() generates a |
203 // BadDevice error when passed these devices. | 194 // BadDevice error when passed these devices. |
204 if (device.use == XIMasterPointer || device.use == XIMasterKeyboard) | 195 if (device.use == XIMasterPointer || device.use == XIMasterKeyboard) |
205 return base::FilePath(); | 196 return base::FilePath(); |
206 | 197 |
207 // Input device has a property "Device Node" pointing to its dev input node, | 198 // Input device has a property "Device Node" pointing to its dev input node, |
208 // e.g. Device Node (250): "/dev/input/event8" | 199 // e.g. Device Node (250): "/dev/input/event8" |
209 Atom device_node = XInternAtom(dpy, "Device Node", False); | 200 Atom device_node = ui::X11AtomCache::GetInstance()->GetAtom("Device Node"); |
210 if (device_node == None) | 201 if (device_node == None) |
211 return base::FilePath(); | 202 return base::FilePath(); |
212 | 203 |
213 Atom actual_type; | 204 Atom actual_type; |
214 int actual_format; | 205 int actual_format; |
215 unsigned long nitems, bytes_after; | 206 unsigned long nitems, bytes_after; |
216 unsigned char* data; | 207 unsigned char* data; |
217 XDevice* dev = XOpenDevice(dpy, device.deviceid); | 208 XDevice* dev = XOpenDevice(dpy, device.deviceid); |
218 | 209 |
219 // Sometimes XOpenDevice() doesn't return null but the contents aren't valid. | 210 // Sometimes XOpenDevice() doesn't return null but the contents aren't valid. |
(...skipping 182 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
402 void OnTouchpadDevices(const std::vector<InputDevice>& devices) { | 393 void OnTouchpadDevices(const std::vector<InputDevice>& devices) { |
403 GetHotplugEventObserver()->OnTouchpadDevicesUpdated(devices); | 394 GetHotplugEventObserver()->OnTouchpadDevicesUpdated(devices); |
404 } | 395 } |
405 | 396 |
406 void OnHotplugFinished() { | 397 void OnHotplugFinished() { |
407 GetHotplugEventObserver()->OnDeviceListsComplete(); | 398 GetHotplugEventObserver()->OnDeviceListsComplete(); |
408 } | 399 } |
409 | 400 |
410 } // namespace | 401 } // namespace |
411 | 402 |
412 X11HotplugEventHandler::X11HotplugEventHandler() | 403 X11HotplugEventHandler::X11HotplugEventHandler() {} |
413 : atom_cache_(gfx::GetXDisplay(), kCachedAtomList) { | |
414 } | |
415 | 404 |
416 X11HotplugEventHandler::~X11HotplugEventHandler() { | 405 X11HotplugEventHandler::~X11HotplugEventHandler() { |
417 } | 406 } |
418 | 407 |
419 void X11HotplugEventHandler::OnHotplugEvent() { | 408 void X11HotplugEventHandler::OnHotplugEvent() { |
420 Display* display = gfx::GetXDisplay(); | 409 Display* display = gfx::GetXDisplay(); |
421 const XDeviceList& device_list_xi = | 410 const XDeviceList& device_list_xi = |
422 DeviceListCacheX11::GetInstance()->GetXDeviceList(display); | 411 DeviceListCacheX11::GetInstance()->GetXDeviceList(display); |
423 const XIDeviceList& device_list_xi2 = | 412 const XIDeviceList& device_list_xi2 = |
424 DeviceListCacheX11::GetInstance()->GetXI2DeviceList(display); | 413 DeviceListCacheX11::GetInstance()->GetXI2DeviceList(display); |
425 | 414 |
426 const int kMaxDeviceNum = 128; | 415 const int kMaxDeviceNum = 128; |
427 DeviceType device_types[kMaxDeviceNum]; | 416 DeviceType device_types[kMaxDeviceNum]; |
428 for (int i = 0; i < kMaxDeviceNum; ++i) | 417 for (int i = 0; i < kMaxDeviceNum; ++i) |
429 device_types[i] = DEVICE_TYPE_OTHER; | 418 device_types[i] = DEVICE_TYPE_OTHER; |
430 | 419 |
431 for (int i = 0; i < device_list_xi.count; ++i) { | 420 for (int i = 0; i < device_list_xi.count; ++i) { |
432 int id = device_list_xi[i].id; | 421 int id = device_list_xi[i].id; |
433 if (id < 0 || id >= kMaxDeviceNum) | 422 if (id < 0 || id >= kMaxDeviceNum) |
434 continue; | 423 continue; |
435 | 424 |
436 Atom type = device_list_xi[i].type; | 425 Atom type = device_list_xi[i].type; |
437 if (type == atom_cache_.GetAtom(XI_KEYBOARD)) | 426 if (type == GetAtom(XI_KEYBOARD)) |
438 device_types[id] = DEVICE_TYPE_KEYBOARD; | 427 device_types[id] = DEVICE_TYPE_KEYBOARD; |
439 else if (type == atom_cache_.GetAtom(XI_MOUSE)) | 428 else if (type == GetAtom(XI_MOUSE)) |
440 device_types[id] = DEVICE_TYPE_MOUSE; | 429 device_types[id] = DEVICE_TYPE_MOUSE; |
441 else if (type == atom_cache_.GetAtom(XI_TOUCHPAD)) | 430 else if (type == GetAtom(XI_TOUCHPAD)) |
442 device_types[id] = DEVICE_TYPE_TOUCHPAD; | 431 device_types[id] = DEVICE_TYPE_TOUCHPAD; |
443 else if (type == atom_cache_.GetAtom(XI_TOUCHSCREEN)) | 432 else if (type == GetAtom(XI_TOUCHSCREEN)) |
444 device_types[id] = DEVICE_TYPE_TOUCHSCREEN; | 433 device_types[id] = DEVICE_TYPE_TOUCHSCREEN; |
445 } | 434 } |
446 | 435 |
447 std::vector<DeviceInfo> device_infos; | 436 std::vector<DeviceInfo> device_infos; |
448 for (int i = 0; i < device_list_xi2.count; ++i) { | 437 for (int i = 0; i < device_list_xi2.count; ++i) { |
449 const XIDeviceInfo& device = device_list_xi2[i]; | 438 const XIDeviceInfo& device = device_list_xi2[i]; |
450 if (!device.enabled || IsTestDevice(device.name)) | 439 if (!device.enabled || IsTestDevice(device.name)) |
451 continue; | 440 continue; |
452 | 441 |
453 DeviceType device_type = | 442 DeviceType device_type = |
454 (device.deviceid >= 0 && device.deviceid < kMaxDeviceNum) | 443 (device.deviceid >= 0 && device.deviceid < kMaxDeviceNum) |
455 ? device_types[device.deviceid] | 444 ? device_types[device.deviceid] |
456 : DEVICE_TYPE_OTHER; | 445 : DEVICE_TYPE_OTHER; |
457 | 446 |
458 // Obtain the USB-style vendor and product identifiers. | 447 // Obtain the USB-style vendor and product identifiers. |
459 // (On Linux, XI2 makes this available for all evdev devices. | 448 // (On Linux, XI2 makes this available for all evdev devices. |
460 uint32_t* product_info; | 449 uint32_t* product_info; |
461 Atom type; | 450 Atom type; |
462 int format_return; | 451 int format_return; |
463 unsigned long num_items_return; | 452 unsigned long num_items_return; |
464 unsigned long bytes_after_return; | 453 unsigned long bytes_after_return; |
465 uint16_t vendor = 0; | 454 uint16_t vendor = 0; |
466 uint16_t product = 0; | 455 uint16_t product = 0; |
467 if (XIGetProperty(gfx::GetXDisplay(), device.deviceid, | 456 if (XIGetProperty(gfx::GetXDisplay(), device.deviceid, |
468 atom_cache_.GetAtom(XI_PROP_PRODUCT_ID), 0, 2, 0, | 457 GetAtom(XI_PROP_PRODUCT_ID), 0, 2, 0, XA_INTEGER, &type, |
469 XA_INTEGER, &type, &format_return, &num_items_return, | 458 &format_return, &num_items_return, &bytes_after_return, |
470 &bytes_after_return, | |
471 reinterpret_cast<unsigned char**>(&product_info)) == 0 && | 459 reinterpret_cast<unsigned char**>(&product_info)) == 0 && |
472 product_info) { | 460 product_info) { |
473 if (num_items_return == 2) { | 461 if (num_items_return == 2) { |
474 vendor = product_info[0]; | 462 vendor = product_info[0]; |
475 product = product_info[1]; | 463 product = product_info[1]; |
476 } | 464 } |
477 XFree(product_info); | 465 XFree(product_info); |
478 } | 466 } |
479 | 467 |
480 device_infos.push_back(DeviceInfo( | 468 device_infos.push_back(DeviceInfo( |
481 device, device_type, GetDevicePath(display, device), vendor, product)); | 469 device, device_type, GetDevicePath(display, device), vendor, product)); |
482 } | 470 } |
483 | 471 |
484 // X11 is not thread safe, so first get all the required state. | 472 // X11 is not thread safe, so first get all the required state. |
485 DisplayState display_state; | 473 DisplayState display_state; |
486 display_state.mt_position_x = atom_cache_.GetAtom("Abs MT Position X"); | 474 display_state.mt_position_x = GetAtom("Abs MT Position X"); |
487 display_state.mt_position_y = atom_cache_.GetAtom("Abs MT Position Y"); | 475 display_state.mt_position_y = GetAtom("Abs MT Position Y"); |
488 | 476 |
489 UiCallbacks callbacks; | 477 UiCallbacks callbacks; |
490 callbacks.keyboard_callback = base::Bind(&OnKeyboardDevices); | 478 callbacks.keyboard_callback = base::Bind(&OnKeyboardDevices); |
491 callbacks.touchscreen_callback = base::Bind(&OnTouchscreenDevices); | 479 callbacks.touchscreen_callback = base::Bind(&OnTouchscreenDevices); |
492 callbacks.mouse_callback = base::Bind(&OnMouseDevices); | 480 callbacks.mouse_callback = base::Bind(&OnMouseDevices); |
493 callbacks.touchpad_callback = base::Bind(&OnTouchpadDevices); | 481 callbacks.touchpad_callback = base::Bind(&OnTouchpadDevices); |
494 callbacks.hotplug_finished_callback = base::Bind(&OnHotplugFinished); | 482 callbacks.hotplug_finished_callback = base::Bind(&OnHotplugFinished); |
495 | 483 |
496 // 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 |
497 // worker thread. Once the device information is extracted the parsed devices | 485 // worker thread. Once the device information is extracted the parsed devices |
498 // will be returned via the callbacks. | 486 // will be returned via the callbacks. |
499 base::WorkerPool::PostTask( | 487 base::WorkerPool::PostTask( |
500 FROM_HERE, | 488 FROM_HERE, |
501 base::Bind(&HandleHotplugEventInWorker, device_infos, display_state, | 489 base::Bind(&HandleHotplugEventInWorker, device_infos, display_state, |
502 base::ThreadTaskRunnerHandle::Get(), callbacks), | 490 base::ThreadTaskRunnerHandle::Get(), callbacks), |
503 true /* task_is_slow */); | 491 true /* task_is_slow */); |
504 } | 492 } |
505 | 493 |
506 } // namespace ui | 494 } // namespace ui |
OLD | NEW |