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