123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248 |
- // Copyright 2014 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "services/device/hid/input_service_linux.h"
- #include <memory>
- #include "base/bind.h"
- #include "base/logging.h"
- #include "base/scoped_observation.h"
- #include "base/strings/string_number_conversions.h"
- #include "base/strings/string_util.h"
- #include "base/threading/scoped_blocking_call.h"
- #include "device/base/device_monitor_linux.h"
- #include "device/udev_linux/udev.h"
- namespace device {
- namespace {
- const char kSubsystemHid[] = "hid";
- const char kSubsystemInput[] = "input";
- const char kSubsystemMisc[] = "misc";
- const char kTypeBluetooth[] = "bluetooth";
- const char kTypeUsb[] = "usb";
- const char kTypeSerio[] = "serio";
- const char kIdInputAccelerometer[] = "ID_INPUT_ACCELEROMETER";
- const char kIdInputJoystick[] = "ID_INPUT_JOYSTICK";
- const char kIdInputKey[] = "ID_INPUT_KEY";
- const char kIdInputKeyboard[] = "ID_INPUT_KEYBOARD";
- const char kIdInputMouse[] = "ID_INPUT_MOUSE";
- const char kIdInputTablet[] = "ID_INPUT_TABLET";
- const char kIdInputTouchpad[] = "ID_INPUT_TOUCHPAD";
- const char kIdInputTouchscreen[] = "ID_INPUT_TOUCHSCREEN";
- InputServiceLinux* g_input_service_linux = nullptr;
- bool GetBoolProperty(udev_device* device, const char* key) {
- CHECK(device);
- CHECK(key);
- const char* property = udev_device_get_property_value(device, key);
- if (!property)
- return false;
- int value;
- if (!base::StringToInt(property, &value)) {
- LOG(ERROR) << "Not an integer value for " << key << " property";
- return false;
- }
- return (value != 0);
- }
- mojom::InputDeviceType GetDeviceType(udev_device* device) {
- // Bluetooth classic hid devices are registered under bluetooth subsystem.
- // Bluetooth LE hid devices are registered under virtual misc/hid subsystems.
- if (udev_device_get_parent_with_subsystem_devtype(device, kTypeBluetooth,
- NULL) ||
- (udev_device_get_parent_with_subsystem_devtype(device, kSubsystemHid,
- NULL) &&
- udev_device_get_parent_with_subsystem_devtype(device, kSubsystemMisc,
- NULL))) {
- return mojom::InputDeviceType::TYPE_BLUETOOTH;
- }
- if (udev_device_get_parent_with_subsystem_devtype(device, kTypeUsb, NULL))
- return mojom::InputDeviceType::TYPE_USB;
- if (udev_device_get_parent_with_subsystem_devtype(device, kTypeSerio, NULL))
- return mojom::InputDeviceType::TYPE_SERIO;
- return mojom::InputDeviceType::TYPE_UNKNOWN;
- }
- std::string GetParentDeviceName(udev_device* device, const char* subsystem) {
- udev_device* parent =
- udev_device_get_parent_with_subsystem_devtype(device, subsystem, NULL);
- if (!parent)
- return std::string();
- const char* name = udev_device_get_property_value(parent, "NAME");
- if (!name)
- return std::string();
- std::string result;
- base::TrimString(name, "\"", &result);
- return result;
- }
- class InputServiceLinuxImpl : public InputServiceLinux,
- public DeviceMonitorLinux::Observer {
- public:
- InputServiceLinuxImpl(const InputServiceLinuxImpl&) = delete;
- InputServiceLinuxImpl& operator=(const InputServiceLinuxImpl&) = delete;
- // Implements DeviceMonitorLinux::Observer:
- void OnDeviceAdded(udev_device* device) override;
- void OnDeviceRemoved(udev_device* device) override;
- private:
- friend class InputServiceLinux;
- InputServiceLinuxImpl();
- ~InputServiceLinuxImpl() override;
- base::ScopedObservation<DeviceMonitorLinux, DeviceMonitorLinux::Observer>
- observation_{this};
- };
- InputServiceLinuxImpl::InputServiceLinuxImpl() {
- DeviceMonitorLinux* monitor = DeviceMonitorLinux::GetInstance();
- observation_.Observe(monitor);
- monitor->Enumerate(base::BindRepeating(&InputServiceLinuxImpl::OnDeviceAdded,
- base::Unretained(this)));
- }
- InputServiceLinuxImpl::~InputServiceLinuxImpl() {
- // Never destroyed.
- NOTREACHED();
- }
- void InputServiceLinuxImpl::OnDeviceAdded(udev_device* device) {
- DCHECK(CalledOnValidThread());
- base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
- base::BlockingType::MAY_BLOCK);
- if (!device)
- return;
- const char* devnode = udev_device_get_devnode(device);
- if (!devnode)
- return;
- auto info = mojom::InputDeviceInfo::New();
- info->id = devnode;
- const char* subsystem = udev_device_get_subsystem(device);
- if (!subsystem)
- return;
- if (strcmp(subsystem, kSubsystemHid) == 0) {
- info->subsystem = mojom::InputDeviceSubsystem::SUBSYSTEM_HID;
- info->name = GetParentDeviceName(device, kSubsystemHid);
- } else if (strcmp(subsystem, kSubsystemInput) == 0) {
- info->subsystem = mojom::InputDeviceSubsystem::SUBSYSTEM_INPUT;
- info->name = GetParentDeviceName(device, kSubsystemInput);
- } else {
- return;
- }
- info->type = GetDeviceType(device);
- info->is_accelerometer = GetBoolProperty(device, kIdInputAccelerometer);
- info->is_joystick = GetBoolProperty(device, kIdInputJoystick);
- info->is_key = GetBoolProperty(device, kIdInputKey);
- info->is_keyboard = GetBoolProperty(device, kIdInputKeyboard);
- info->is_mouse = GetBoolProperty(device, kIdInputMouse);
- info->is_tablet = GetBoolProperty(device, kIdInputTablet);
- info->is_touchpad = GetBoolProperty(device, kIdInputTouchpad);
- info->is_touchscreen = GetBoolProperty(device, kIdInputTouchscreen);
- AddDevice(std::move(info));
- }
- void InputServiceLinuxImpl::OnDeviceRemoved(udev_device* device) {
- DCHECK(CalledOnValidThread());
- if (!device)
- return;
- base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
- base::BlockingType::MAY_BLOCK);
- const char* devnode = udev_device_get_devnode(device);
- if (devnode)
- RemoveDevice(devnode);
- }
- } // namespace
- InputServiceLinux::InputServiceLinux() {}
- InputServiceLinux::~InputServiceLinux() {
- DCHECK(CalledOnValidThread());
- }
- // static
- void InputServiceLinux::BindReceiver(
- mojo::PendingReceiver<mojom::InputDeviceManager> receiver) {
- GetInstance()->AddReceiver(std::move(receiver));
- }
- // static
- InputServiceLinux* InputServiceLinux::GetInstance() {
- if (!HasInstance())
- g_input_service_linux = new InputServiceLinuxImpl();
- return g_input_service_linux;
- }
- // static
- bool InputServiceLinux::HasInstance() {
- return !!g_input_service_linux;
- }
- // static
- void InputServiceLinux::SetForTesting(
- std::unique_ptr<InputServiceLinux> service) {
- DCHECK(!HasInstance());
- DCHECK(service);
- // |service| will never be destroyed.
- g_input_service_linux = service.release();
- }
- void InputServiceLinux::AddReceiver(
- mojo::PendingReceiver<mojom::InputDeviceManager> receiver) {
- receivers_.Add(this, std::move(receiver));
- }
- void InputServiceLinux::GetDevicesAndSetClient(
- mojo::PendingAssociatedRemote<mojom::InputDeviceManagerClient> client,
- GetDevicesCallback callback) {
- GetDevices(std::move(callback));
- if (!client.is_valid())
- return;
- clients_.Add(std::move(client));
- }
- void InputServiceLinux::GetDevices(GetDevicesCallback callback) {
- DCHECK(CalledOnValidThread());
- std::vector<mojom::InputDeviceInfoPtr> devices;
- for (auto& device : devices_)
- devices.push_back(device.second->Clone());
- std::move(callback).Run(std::move(devices));
- }
- void InputServiceLinux::AddDevice(mojom::InputDeviceInfoPtr info) {
- auto* device_info = info.get();
- for (auto& client : clients_)
- client->InputDeviceAdded(device_info->Clone());
- devices_[info->id] = std::move(info);
- }
- void InputServiceLinux::RemoveDevice(const std::string& id) {
- devices_.erase(id);
- for (auto& client : clients_)
- client->InputDeviceRemoved(id);
- }
- bool InputServiceLinux::CalledOnValidThread() const {
- return thread_checker_.CalledOnValidThread();
- }
- } // namespace device
|