| 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 |