summaryrefslogtreecommitdiff
path: root/chromium/ui/events/platform/x11/x11_hotplug_event_handler.cc
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@theqtcompany.com>2015-06-18 14:10:49 +0200
committerOswald Buddenhagen <oswald.buddenhagen@theqtcompany.com>2015-06-18 13:53:24 +0000
commit813fbf95af77a531c57a8c497345ad2c61d475b3 (patch)
tree821b2c8de8365f21b6c9ba17a236fb3006a1d506 /chromium/ui/events/platform/x11/x11_hotplug_event_handler.cc
parentaf6588f8d723931a298c995fa97259bb7f7deb55 (diff)
downloadqtwebengine-chromium-813fbf95af77a531c57a8c497345ad2c61d475b3.tar.gz
BASELINE: Update chromium to 44.0.2403.47
Change-Id: Ie056fedba95cf5e5c76b30c4b2c80fca4764aa2f Reviewed-by: Oswald Buddenhagen <oswald.buddenhagen@theqtcompany.com>
Diffstat (limited to 'chromium/ui/events/platform/x11/x11_hotplug_event_handler.cc')
-rw-r--r--chromium/ui/events/platform/x11/x11_hotplug_event_handler.cc514
1 files changed, 394 insertions, 120 deletions
diff --git a/chromium/ui/events/platform/x11/x11_hotplug_event_handler.cc b/chromium/ui/events/platform/x11/x11_hotplug_event_handler.cc
index 3ce944efc3e..20428977e5d 100644
--- a/chromium/ui/events/platform/x11/x11_hotplug_event_handler.cc
+++ b/chromium/ui/events/platform/x11/x11_hotplug_event_handler.cc
@@ -4,6 +4,7 @@
#include "ui/events/platform/x11/x11_hotplug_event_handler.h"
+#include <X11/Xatom.h>
#include <X11/extensions/XInput.h>
#include <X11/extensions/XInput2.h>
@@ -13,11 +14,17 @@
#include <string>
#include <vector>
+#include "base/bind.h"
#include "base/command_line.h"
+#include "base/location.h"
#include "base/logging.h"
#include "base/process/launch.h"
+#include "base/single_thread_task_runner.h"
#include "base/strings/string_util.h"
#include "base/sys_info.h"
+#include "base/thread_task_runner_handle.h"
+#include "base/threading/worker_pool.h"
+#include "ui/events/devices/device_data_manager.h"
#include "ui/events/devices/device_hotplug_event_observer.h"
#include "ui/events/devices/device_util_linux.h"
#include "ui/events/devices/input_device.h"
@@ -25,65 +32,190 @@
#include "ui/events/devices/touchscreen_device.h"
#include "ui/gfx/x/x11_types.h"
+#ifndef XI_PROP_PRODUCT_ID
+#define XI_PROP_PRODUCT_ID "Device Product ID"
+#endif
+
namespace ui {
namespace {
-// The name of the xinput device corresponding to the AT internal keyboard.
-const char kATKeyboardName[] = "AT Translated Set 2 keyboard";
+// Names of all known internal devices that should not be considered as
+// keyboards.
+// TODO(rsadam@): Identify these devices using udev rules. (Crbug.com/420728.)
+const char* kKnownInvalidKeyboardDeviceNames[] = {"Power Button",
+ "Sleep Button",
+ "Video Bus",
+ "gpio-keys.5",
+ "gpio-keys.12",
+ "ROCKCHIP-I2S Headset Jack"};
-// The prefix of xinput devices corresponding to CrOS EC internal keyboards.
-const char kCrosEcKeyboardPrefix[] = "cros-ec";
+const char* kCachedAtomList[] = {
+ "Abs MT Position X",
+ "Abs MT Position Y",
+ XI_KEYBOARD,
+ XI_MOUSE,
+ XI_TOUCHPAD,
+ XI_TOUCHSCREEN,
+ XI_PROP_PRODUCT_ID,
+ NULL,
+};
-// Returns true if |name| is the name of a known keyboard device. Note, this may
-// return false negatives.
-bool IsKnownKeyboard(const std::string& name) {
- std::string lower = base::StringToLowerASCII(name);
- return lower.find("keyboard") != std::string::npos;
-}
+enum DeviceType {
+ DEVICE_TYPE_KEYBOARD,
+ DEVICE_TYPE_MOUSE,
+ DEVICE_TYPE_TOUCHPAD,
+ DEVICE_TYPE_TOUCHSCREEN,
+ DEVICE_TYPE_OTHER
+};
+
+typedef base::Callback<void(const std::vector<KeyboardDevice>&)>
+ KeyboardDeviceCallback;
+
+typedef base::Callback<void(const std::vector<TouchscreenDevice>&)>
+ TouchscreenDeviceCallback;
+
+typedef base::Callback<void(const std::vector<InputDevice>&)>
+ InputDeviceCallback;
+
+// Used for updating the state on the UI thread once device information is
+// parsed on helper threads.
+struct UiCallbacks {
+ KeyboardDeviceCallback keyboard_callback;
+ TouchscreenDeviceCallback touchscreen_callback;
+ InputDeviceCallback mouse_callback;
+ InputDeviceCallback touchpad_callback;
+};
+
+// Stores a copy of the XIValuatorClassInfo values so X11 device processing can
+// happen on a worker thread. This is needed since X11 structs are not copyable.
+struct ValuatorClassInfo {
+ ValuatorClassInfo(const XIValuatorClassInfo& info)
+ : label(info.label),
+ max(info.max),
+ min(info.min),
+ mode(info.mode),
+ number(info.number) {}
+
+ Atom label;
+ double max;
+ double min;
+ int mode;
+ int number;
+};
+
+// Stores a copy of the XITouchClassInfo values so X11 device processing can
+// happen on a worker thread. This is needed since X11 structs are not copyable.
+struct TouchClassInfo {
+ TouchClassInfo() : mode(0), num_touches(0) {}
+
+ explicit TouchClassInfo(const XITouchClassInfo& info)
+ : mode(info.mode), num_touches(info.num_touches) {}
+
+ int mode;
+ int num_touches;
+};
+
+struct DeviceInfo {
+ DeviceInfo(const XIDeviceInfo& device,
+ DeviceType type,
+ const base::FilePath& path,
+ uint16_t vendor,
+ uint16_t product)
+ : id(device.deviceid),
+ name(device.name),
+ vendor_id(vendor),
+ product_id(product),
+ use(device.use),
+ type(type),
+ path(path) {
+ for (int i = 0; i < device.num_classes; ++i) {
+ switch (device.classes[i]->type) {
+ case XIValuatorClass:
+ valuator_class_infos.push_back(ValuatorClassInfo(
+ *reinterpret_cast<XIValuatorClassInfo*>(device.classes[i])));
+ break;
+ case XITouchClass:
+ // A device can have at most one XITouchClassInfo. Ref:
+ // http://manpages.ubuntu.com/manpages/saucy/man3/XIQueryDevice.3.html
+ DCHECK(!touch_class_info.mode);
+ touch_class_info = TouchClassInfo(
+ *reinterpret_cast<XITouchClassInfo*>(device.classes[i]));
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ // Unique device identifier.
+ int id;
+
+ // Internal device name.
+ std::string name;
+
+ // USB-style device identifiers.
+ uint16_t vendor_id;
+ uint16_t product_id;
+
+ // Device type (ie: XIMasterPointer)
+ int use;
+
+ // Specifies the type of the device.
+ DeviceType type;
+
+ // Path to the actual device (ie: /dev/input/eventXX)
+ base::FilePath path;
-// Returns true if |name| is the name of a known internal keyboard device. Note,
+ std::vector<ValuatorClassInfo> valuator_class_infos;
+
+ TouchClassInfo touch_class_info;
+};
+
+// X11 display cache used on worker threads. This is filled on the UI thread and
+// passed in to the worker threads.
+struct DisplayState {
+ Atom mt_position_x;
+ Atom mt_position_y;
+};
+
+// Returns true if |name| is the name of a known invalid keyboard device. Note,
// this may return false negatives.
-bool IsInternalKeyboard(const std::string& name) {
- // TODO(rsadam@): Come up with a more generic way of identifying internal
- // keyboards. See crbug.com/420728.
- if (name == kATKeyboardName)
- return true;
- return name.compare(
- 0u, strlen(kCrosEcKeyboardPrefix), kCrosEcKeyboardPrefix) == 0;
+bool IsKnownInvalidKeyboardDevice(const std::string& name) {
+ std::string trimmed(name);
+ base::TrimWhitespaceASCII(name, base::TRIM_TRAILING, &trimmed);
+ for (const char* device_name : kKnownInvalidKeyboardDeviceNames) {
+ if (trimmed == device_name)
+ return true;
+ }
+ return false;
}
// Returns true if |name| is the name of a known XTEST device. Note, this may
// return false negatives.
-bool IsTestKeyboard(const std::string& name) {
+bool IsTestDevice(const std::string& name) {
return name.find("XTEST") != std::string::npos;
}
-// We consider the touchscreen to be internal if it is an I2c device.
-// With the device id, we can query X to get the device's dev input
-// node eventXXX. Then we search all the dev input nodes registered
-// by I2C devices to see if we can find eventXXX.
-bool IsTouchscreenInternal(XDisplay* dpy, int device_id) {
-#if !defined(CHROMEOS)
- return false;
-#else
- if (!base::SysInfo::IsRunningOnChromeOS())
- return false;
-#endif
+base::FilePath GetDevicePath(XDisplay* dpy, const XIDeviceInfo& device) {
+ // Skip the main pointer and keyboard since XOpenDevice() generates a
+ // BadDevice error when passed these devices.
+ if (device.use == XIMasterPointer || device.use == XIMasterKeyboard)
+ return base::FilePath();
// Input device has a property "Device Node" pointing to its dev input node,
// e.g. Device Node (250): "/dev/input/event8"
Atom device_node = XInternAtom(dpy, "Device Node", False);
if (device_node == None)
- return false;
+ return base::FilePath();
Atom actual_type;
int actual_format;
unsigned long nitems, bytes_after;
unsigned char* data;
- XDevice* dev = XOpenDevice(dpy, device_id);
+ XDevice* dev = XOpenDevice(dpy, device.deviceid);
if (!dev)
- return false;
+ return base::FilePath();
if (XGetDeviceProperty(dpy,
dev,
@@ -98,124 +230,266 @@ bool IsTouchscreenInternal(XDisplay* dpy, int device_id) {
&bytes_after,
&data) != Success) {
XCloseDevice(dpy, dev);
- return false;
+ return base::FilePath();
}
- base::FilePath dev_node_path(reinterpret_cast<char*>(data));
+
+ std::string path;
+ // Make sure the returned value is a string.
+ if (actual_type == XA_STRING && actual_format == 8)
+ path = reinterpret_cast<char*>(data);
+
XFree(data);
XCloseDevice(dpy, dev);
- return ui::IsTouchscreenInternal(dev_node_path);
+ return base::FilePath(path);
}
-} // namespace
+// Helper used to parse keyboard information. When it is done it uses
+// |reply_runner| and |callback| to update the state on the UI thread.
+void HandleKeyboardDevicesInWorker(
+ const std::vector<DeviceInfo>& device_infos,
+ scoped_refptr<base::TaskRunner> reply_runner,
+ const KeyboardDeviceCallback& callback) {
+ std::vector<KeyboardDevice> devices;
-X11HotplugEventHandler::X11HotplugEventHandler(
- DeviceHotplugEventObserver* delegate)
- : delegate_(delegate) {
-}
+ for (const DeviceInfo& device_info : device_infos) {
+ if (device_info.type != DEVICE_TYPE_KEYBOARD)
+ continue;
+ if (device_info.use != XISlaveKeyboard)
+ continue; // Assume all keyboards are keyboard slaves
+ if (IsKnownInvalidKeyboardDevice(device_info.name))
+ continue; // Skip invalid devices.
+ InputDeviceType type = GetInputDeviceTypeFromPath(device_info.path);
+ KeyboardDevice keyboard(device_info.id, type, device_info.name);
+ devices.push_back(keyboard);
+ }
-X11HotplugEventHandler::~X11HotplugEventHandler() {
+ reply_runner->PostTask(FROM_HERE, base::Bind(callback, devices));
}
-void X11HotplugEventHandler::OnHotplugEvent() {
- const XIDeviceList& device_list =
- DeviceListCacheX11::GetInstance()->GetXI2DeviceList(gfx::GetXDisplay());
- HandleTouchscreenDevices(device_list);
- HandleKeyboardDevices(device_list);
-}
+// Helper used to parse mouse information. When it is done it uses
+// |reply_runner| and |callback| to update the state on the UI thread.
+void HandleMouseDevicesInWorker(const std::vector<DeviceInfo>& device_infos,
+ scoped_refptr<base::TaskRunner> reply_runner,
+ const InputDeviceCallback& callback) {
+ std::vector<InputDevice> devices;
+ for (const DeviceInfo& device_info : device_infos) {
+ if (device_info.type != DEVICE_TYPE_MOUSE ||
+ device_info.use != XISlavePointer) {
+ continue;
+ }
-void X11HotplugEventHandler::HandleKeyboardDevices(
- const XIDeviceList& x11_devices) {
- std::vector<KeyboardDevice> devices;
+ InputDeviceType type = GetInputDeviceTypeFromPath(device_info.path);
+ devices.push_back(InputDevice(device_info.id, type, device_info.name));
+ }
- for (int i = 0; i < x11_devices.count; i++) {
- if (!x11_devices[i].enabled || x11_devices[i].use != XISlaveKeyboard)
- continue; // Assume all keyboards are keyboard slaves
- std::string device_name(x11_devices[i].name);
- base::TrimWhitespaceASCII(device_name, base::TRIM_TRAILING, &device_name);
- if (IsTestKeyboard(device_name))
- continue; // Skip test devices.
- InputDeviceType type;
- if (IsInternalKeyboard(device_name)) {
- type = InputDeviceType::INPUT_DEVICE_INTERNAL;
- } else if (IsKnownKeyboard(device_name)) {
- type = InputDeviceType::INPUT_DEVICE_EXTERNAL;
- } else {
- type = InputDeviceType::INPUT_DEVICE_UNKNOWN;
+ reply_runner->PostTask(FROM_HERE, base::Bind(callback, devices));
+}
+
+// Helper used to parse touchpad information. When it is done it uses
+// |reply_runner| and |callback| to update the state on the UI thread.
+void HandleTouchpadDevicesInWorker(const std::vector<DeviceInfo>& device_infos,
+ scoped_refptr<base::TaskRunner> reply_runner,
+ const InputDeviceCallback& callback) {
+ std::vector<InputDevice> devices;
+ for (const DeviceInfo& device_info : device_infos) {
+ if (device_info.type != DEVICE_TYPE_TOUCHPAD ||
+ device_info.use != XISlavePointer) {
+ continue;
}
- devices.push_back(
- KeyboardDevice(x11_devices[i].deviceid, type, device_name));
+
+ InputDeviceType type = GetInputDeviceTypeFromPath(device_info.path);
+ devices.push_back(InputDevice(device_info.id, type, device_info.name));
}
- delegate_->OnKeyboardDevicesUpdated(devices);
+
+ reply_runner->PostTask(FROM_HERE, base::Bind(callback, devices));
}
-void X11HotplugEventHandler::HandleTouchscreenDevices(
- const XIDeviceList& x11_devices) {
+// Helper used to parse touchscreen information. When it is done it uses
+// |reply_runner| and |callback| to update the state on the UI thread.
+void HandleTouchscreenDevicesInWorker(
+ const std::vector<DeviceInfo>& device_infos,
+ const DisplayState& display_state,
+ scoped_refptr<base::TaskRunner> reply_runner,
+ const TouchscreenDeviceCallback& callback) {
std::vector<TouchscreenDevice> devices;
- Display* display = gfx::GetXDisplay();
- Atom valuator_x = XInternAtom(display, "Abs MT Position X", False);
- Atom valuator_y = XInternAtom(display, "Abs MT Position Y", False);
- if (valuator_x == None || valuator_y == None)
+ if (display_state.mt_position_x == None ||
+ display_state.mt_position_y == None)
return;
- std::set<int> no_match_touchscreen;
- for (int i = 0; i < x11_devices.count; i++) {
- if (!x11_devices[i].enabled || x11_devices[i].use != XIFloatingSlave)
- continue; // Assume all touchscreens are floating slaves
+ for (const DeviceInfo& device_info : device_infos) {
+ if (device_info.type != DEVICE_TYPE_TOUCHSCREEN ||
+ (device_info.use != XIFloatingSlave &&
+ device_info.use != XISlavePointer)) {
+ continue;
+ }
+
+ // Touchscreens should be direct touch devices.
+ if (device_info.touch_class_info.mode != XIDirectTouch)
+ continue;
double max_x = -1.0;
double max_y = -1.0;
- bool is_direct_touch = false;
-
- for (int j = 0; j < x11_devices[i].num_classes; j++) {
- XIAnyClassInfo* class_info = x11_devices[i].classes[j];
-
- if (class_info->type == XIValuatorClass) {
- XIValuatorClassInfo* valuator_info =
- reinterpret_cast<XIValuatorClassInfo*>(class_info);
-
- if (valuator_x == valuator_info->label) {
- // Ignore X axis valuator with unexpected properties
- if (valuator_info->number == 0 && valuator_info->mode == Absolute &&
- valuator_info->min == 0.0) {
- max_x = valuator_info->max;
- }
- } else if (valuator_y == valuator_info->label) {
- // Ignore Y axis valuator with unexpected properties
- if (valuator_info->number == 1 && valuator_info->mode == Absolute &&
- valuator_info->min == 0.0) {
- max_y = valuator_info->max;
- }
+
+ for (const ValuatorClassInfo& valuator : device_info.valuator_class_infos) {
+ if (display_state.mt_position_x == valuator.label) {
+ // Ignore X axis valuator with unexpected properties
+ if (valuator.number == 0 && valuator.mode == Absolute &&
+ valuator.min == 0.0) {
+ max_x = valuator.max;
+ }
+ } else if (display_state.mt_position_y == valuator.label) {
+ // Ignore Y axis valuator with unexpected properties
+ if (valuator.number == 1 && valuator.mode == Absolute &&
+ valuator.min == 0.0) {
+ max_y = valuator.max;
}
}
-#if defined(USE_XI2_MT)
- if (class_info->type == XITouchClass) {
- XITouchClassInfo* touch_info =
- reinterpret_cast<XITouchClassInfo*>(class_info);
- is_direct_touch = touch_info->mode == XIDirectTouch;
- }
-#endif
}
- // Touchscreens should have absolute X and Y axes, and be direct touch
- // devices.
- if (max_x > 0.0 && max_y > 0.0 && is_direct_touch) {
- InputDeviceType type =
- IsTouchscreenInternal(display, x11_devices[i].deviceid)
- ? InputDeviceType::INPUT_DEVICE_INTERNAL
- : InputDeviceType::INPUT_DEVICE_EXTERNAL;
- std::string name(x11_devices[i].name);
+ // Touchscreens should have absolute X and Y axes.
+ if (max_x > 0.0 && max_y > 0.0) {
+ InputDeviceType type = GetInputDeviceTypeFromPath(device_info.path);
// |max_x| and |max_y| are inclusive values, so we need to add 1 to get
// the size.
- devices.push_back(TouchscreenDevice(
- x11_devices[i].deviceid,
- type,
- name,
- gfx::Size(max_x + 1, max_y + 1)));
+ devices.push_back(
+ TouchscreenDevice(device_info.id, type, device_info.name,
+ gfx::Size(max_x + 1, max_y + 1),
+ device_info.touch_class_info.num_touches));
+ }
+ }
+
+ reply_runner->PostTask(FROM_HERE, base::Bind(callback, devices));
+}
+
+// Called on a worker thread to parse the device information.
+void HandleHotplugEventInWorker(
+ const std::vector<DeviceInfo>& devices,
+ const DisplayState& display_state,
+ scoped_refptr<base::TaskRunner> reply_runner,
+ const UiCallbacks& callbacks) {
+ HandleTouchscreenDevicesInWorker(
+ devices, display_state, reply_runner, callbacks.touchscreen_callback);
+ HandleKeyboardDevicesInWorker(
+ devices, reply_runner, callbacks.keyboard_callback);
+ HandleMouseDevicesInWorker(devices, reply_runner, callbacks.mouse_callback);
+ HandleTouchpadDevicesInWorker(devices, reply_runner,
+ callbacks.touchpad_callback);
+}
+
+DeviceHotplugEventObserver* GetHotplugEventObserver() {
+ return DeviceDataManager::GetInstance();
+}
+
+void OnKeyboardDevices(const std::vector<KeyboardDevice>& devices) {
+ GetHotplugEventObserver()->OnKeyboardDevicesUpdated(devices);
+}
+
+void OnTouchscreenDevices(const std::vector<TouchscreenDevice>& devices) {
+ GetHotplugEventObserver()->OnTouchscreenDevicesUpdated(devices);
+}
+
+void OnMouseDevices(const std::vector<InputDevice>& devices) {
+ GetHotplugEventObserver()->OnMouseDevicesUpdated(devices);
+}
+
+void OnTouchpadDevices(const std::vector<InputDevice>& devices) {
+ GetHotplugEventObserver()->OnTouchpadDevicesUpdated(devices);
+}
+
+} // namespace
+
+X11HotplugEventHandler::X11HotplugEventHandler()
+ : atom_cache_(gfx::GetXDisplay(), kCachedAtomList) {
+}
+
+X11HotplugEventHandler::~X11HotplugEventHandler() {
+}
+
+void X11HotplugEventHandler::OnHotplugEvent() {
+ Display* display = gfx::GetXDisplay();
+ const XDeviceList& device_list_xi =
+ DeviceListCacheX11::GetInstance()->GetXDeviceList(display);
+ const XIDeviceList& device_list_xi2 =
+ DeviceListCacheX11::GetInstance()->GetXI2DeviceList(display);
+
+ const int kMaxDeviceNum = 128;
+ DeviceType device_types[kMaxDeviceNum];
+ for (int i = 0; i < kMaxDeviceNum; ++i)
+ device_types[i] = DEVICE_TYPE_OTHER;
+
+ for (int i = 0; i < device_list_xi.count; ++i) {
+ int id = device_list_xi[i].id;
+ if (id < 0 || id >= kMaxDeviceNum)
+ continue;
+
+ Atom type = device_list_xi[i].type;
+ if (type == atom_cache_.GetAtom(XI_KEYBOARD))
+ device_types[id] = DEVICE_TYPE_KEYBOARD;
+ else if (type == atom_cache_.GetAtom(XI_MOUSE))
+ device_types[id] = DEVICE_TYPE_MOUSE;
+ else if (type == atom_cache_.GetAtom(XI_TOUCHPAD))
+ device_types[id] = DEVICE_TYPE_TOUCHPAD;
+ else if (type == atom_cache_.GetAtom(XI_TOUCHSCREEN))
+ device_types[id] = DEVICE_TYPE_TOUCHSCREEN;
+ }
+
+ std::vector<DeviceInfo> device_infos;
+ for (int i = 0; i < device_list_xi2.count; ++i) {
+ const XIDeviceInfo& device = device_list_xi2[i];
+ if (!device.enabled || IsTestDevice(device.name))
+ continue;
+
+ DeviceType device_type =
+ (device.deviceid >= 0 && device.deviceid < kMaxDeviceNum)
+ ? device_types[device.deviceid]
+ : DEVICE_TYPE_OTHER;
+
+ // Obtain the USB-style vendor and product identifiers.
+ // (On Linux, XI2 makes this available for all evdev devices.
+ uint32_t* product_info;
+ Atom type;
+ int format_return;
+ unsigned long num_items_return;
+ unsigned long bytes_after_return;
+ uint16_t vendor = 0;
+ uint16_t product = 0;
+ if (XIGetProperty(gfx::GetXDisplay(), device.deviceid,
+ atom_cache_.GetAtom(XI_PROP_PRODUCT_ID), 0, 2, 0,
+ XA_INTEGER, &type, &format_return, &num_items_return,
+ &bytes_after_return,
+ reinterpret_cast<unsigned char**>(&product_info)) == 0 &&
+ product_info) {
+ if (num_items_return == 2) {
+ vendor = product_info[0];
+ product = product_info[1];
+ }
+ XFree(product_info);
}
+
+ device_infos.push_back(DeviceInfo(
+ device, device_type, GetDevicePath(display, device), vendor, product));
}
- delegate_->OnTouchscreenDevicesUpdated(devices);
+ // X11 is not thread safe, so first get all the required state.
+ DisplayState display_state;
+ display_state.mt_position_x = atom_cache_.GetAtom("Abs MT Position X");
+ display_state.mt_position_y = atom_cache_.GetAtom("Abs MT Position Y");
+
+ UiCallbacks callbacks;
+ callbacks.keyboard_callback = base::Bind(&OnKeyboardDevices);
+ callbacks.touchscreen_callback = base::Bind(&OnTouchscreenDevices);
+ callbacks.mouse_callback = base::Bind(&OnMouseDevices);
+ callbacks.touchpad_callback = base::Bind(&OnTouchpadDevices);
+
+ // Parsing the device information may block, so delegate the operation to a
+ // worker thread. Once the device information is extracted the parsed devices
+ // will be returned via the callbacks.
+ base::WorkerPool::PostTask(
+ FROM_HERE,
+ base::Bind(&HandleHotplugEventInWorker, device_infos, display_state,
+ base::ThreadTaskRunnerHandle::Get(), callbacks),
+ true /* task_is_slow */);
}
} // namespace ui