styleguide: Move Rvalue References to the Blacklist with Exceptions.
[chromium-blink-merge.git] / device / hid / input_service_linux.cc
blob90132e91af24b78e7afa9ff0da84ec1af8fd93b2
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
3 // found in the LICENSE file.
5 #include <libudev.h>
7 #include "base/bind.h"
8 #include "base/lazy_instance.h"
9 #include "base/logging.h"
10 #include "base/strings/string_number_conversions.h"
11 #include "base/strings/string_util.h"
12 #include "base/threading/thread_restrictions.h"
13 #include "device/hid/input_service_linux.h"
15 namespace device {
17 namespace {
19 const char kSubsystemHid[] = "hid";
20 const char kSubsystemInput[] = "input";
21 const char kTypeBluetooth[] = "bluetooth";
22 const char kTypeUsb[] = "usb";
23 const char kTypeSerio[] = "serio";
24 const char kIdInputAccelerometer[] = "ID_INPUT_ACCELEROMETER";
25 const char kIdInputJoystick[] = "ID_INPUT_JOYSTICK";
26 const char kIdInputKey[] = "ID_INPUT_KEY";
27 const char kIdInputKeyboard[] = "ID_INPUT_KEYBOARD";
28 const char kIdInputMouse[] = "ID_INPUT_MOUSE";
29 const char kIdInputTablet[] = "ID_INPUT_TABLET";
30 const char kIdInputTouchpad[] = "ID_INPUT_TOUCHPAD";
31 const char kIdInputTouchscreen[] = "ID_INPUT_TOUCHSCREEN";
33 // The instance will be reset when message loop destroys.
34 base::LazyInstance<scoped_ptr<InputServiceLinux> >::Leaky
35 g_input_service_linux_ptr = LAZY_INSTANCE_INITIALIZER;
37 bool GetBoolProperty(udev_device* device, const char* key) {
38 CHECK(device);
39 CHECK(key);
40 const char* property = udev_device_get_property_value(device, key);
41 if (!property)
42 return false;
43 int value;
44 if (!base::StringToInt(property, &value)) {
45 LOG(ERROR) << "Not an integer value for " << key << " property";
46 return false;
48 return (value != 0);
51 InputServiceLinux::InputDeviceInfo::Type GetDeviceType(udev_device* device) {
52 if (udev_device_get_parent_with_subsystem_devtype(
53 device, kTypeBluetooth, NULL)) {
54 return InputServiceLinux::InputDeviceInfo::TYPE_BLUETOOTH;
56 if (udev_device_get_parent_with_subsystem_devtype(device, kTypeUsb, NULL))
57 return InputServiceLinux::InputDeviceInfo::TYPE_USB;
58 if (udev_device_get_parent_with_subsystem_devtype(device, kTypeSerio, NULL))
59 return InputServiceLinux::InputDeviceInfo::TYPE_SERIO;
60 return InputServiceLinux::InputDeviceInfo::TYPE_UNKNOWN;
63 std::string GetParentDeviceName(udev_device* device, const char* subsystem) {
64 udev_device* parent =
65 udev_device_get_parent_with_subsystem_devtype(device, subsystem, NULL);
66 if (!parent)
67 return std::string();
68 const char* name = udev_device_get_property_value(parent, "NAME");
69 if (!name)
70 return std::string();
71 std::string result;
72 base::TrimString(name, "\"", &result);
73 return result;
76 class InputServiceLinuxImpl : public InputServiceLinux,
77 public DeviceMonitorLinux::Observer {
78 public:
79 // Implements DeviceMonitorLinux::Observer:
80 virtual void OnDeviceAdded(udev_device* device) OVERRIDE;
81 virtual void OnDeviceRemoved(udev_device* device) OVERRIDE;
83 private:
84 friend class InputServiceLinux;
86 InputServiceLinuxImpl();
87 virtual ~InputServiceLinuxImpl();
89 DISALLOW_COPY_AND_ASSIGN(InputServiceLinuxImpl);
92 InputServiceLinuxImpl::InputServiceLinuxImpl() {
93 DeviceMonitorLinux::GetInstance()->AddObserver(this);
94 DeviceMonitorLinux::GetInstance()->Enumerate(base::Bind(
95 &InputServiceLinuxImpl::OnDeviceAdded, base::Unretained(this)));
98 InputServiceLinuxImpl::~InputServiceLinuxImpl() {
99 if (DeviceMonitorLinux::HasInstance())
100 DeviceMonitorLinux::GetInstance()->RemoveObserver(this);
103 void InputServiceLinuxImpl::OnDeviceAdded(udev_device* device) {
104 DCHECK(CalledOnValidThread());
105 if (!device)
106 return;
107 const char* devnode = udev_device_get_devnode(device);
108 if (!devnode)
109 return;
111 InputDeviceInfo info;
112 info.id = devnode;
114 const char* subsystem = udev_device_get_subsystem(device);
115 if (!subsystem)
116 return;
117 if (strcmp(subsystem, kSubsystemHid) == 0) {
118 info.subsystem = InputServiceLinux::InputDeviceInfo::SUBSYSTEM_HID;
119 info.name = GetParentDeviceName(device, kSubsystemHid);
120 } else if (strcmp(subsystem, kSubsystemInput) == 0) {
121 info.subsystem = InputServiceLinux::InputDeviceInfo::SUBSYSTEM_INPUT;
122 info.name = GetParentDeviceName(device, kSubsystemInput);
123 } else {
124 return;
127 info.type = GetDeviceType(device);
129 info.is_accelerometer = GetBoolProperty(device, kIdInputAccelerometer);
130 info.is_joystick = GetBoolProperty(device, kIdInputJoystick);
131 info.is_key = GetBoolProperty(device, kIdInputKey);
132 info.is_keyboard = GetBoolProperty(device, kIdInputKeyboard);
133 info.is_mouse = GetBoolProperty(device, kIdInputMouse);
134 info.is_tablet = GetBoolProperty(device, kIdInputTablet);
135 info.is_touchpad = GetBoolProperty(device, kIdInputTouchpad);
136 info.is_touchscreen = GetBoolProperty(device, kIdInputTouchscreen);
138 AddDevice(info);
141 void InputServiceLinuxImpl::OnDeviceRemoved(udev_device* device) {
142 DCHECK(CalledOnValidThread());
143 if (!device)
144 return;
145 const char* devnode = udev_device_get_devnode(device);
146 if (devnode)
147 RemoveDevice(devnode);
150 } // namespace
152 InputServiceLinux::InputDeviceInfo::InputDeviceInfo()
153 : subsystem(SUBSYSTEM_UNKNOWN),
154 type(TYPE_UNKNOWN),
155 is_accelerometer(false),
156 is_joystick(false),
157 is_key(false),
158 is_keyboard(false),
159 is_mouse(false),
160 is_tablet(false),
161 is_touchpad(false),
162 is_touchscreen(false) {}
164 InputServiceLinux::InputServiceLinux() {
165 base::ThreadRestrictions::AssertIOAllowed();
166 base::MessageLoop::current()->AddDestructionObserver(this);
169 InputServiceLinux::~InputServiceLinux() {
170 DCHECK(CalledOnValidThread());
171 base::MessageLoop::current()->RemoveDestructionObserver(this);
174 // static
175 InputServiceLinux* InputServiceLinux::GetInstance() {
176 if (!HasInstance())
177 g_input_service_linux_ptr.Get().reset(new InputServiceLinuxImpl());
178 return g_input_service_linux_ptr.Get().get();
181 // static
182 bool InputServiceLinux::HasInstance() {
183 return g_input_service_linux_ptr.Get().get();
186 // static
187 void InputServiceLinux::SetForTesting(InputServiceLinux* service) {
188 g_input_service_linux_ptr.Get().reset(service);
191 void InputServiceLinux::AddObserver(Observer* observer) {
192 DCHECK(CalledOnValidThread());
193 if (observer)
194 observers_.AddObserver(observer);
197 void InputServiceLinux::RemoveObserver(Observer* observer) {
198 DCHECK(CalledOnValidThread());
199 if (observer)
200 observers_.RemoveObserver(observer);
203 void InputServiceLinux::GetDevices(std::vector<InputDeviceInfo>* devices) {
204 DCHECK(CalledOnValidThread());
205 for (DeviceMap::iterator it = devices_.begin(), ie = devices_.end(); it != ie;
206 ++it) {
207 devices->push_back(it->second);
211 bool InputServiceLinux::GetDeviceInfo(const std::string& id,
212 InputDeviceInfo* info) const {
213 DCHECK(CalledOnValidThread());
214 DeviceMap::const_iterator it = devices_.find(id);
215 if (it == devices_.end())
216 return false;
217 *info = it->second;
218 return true;
221 void InputServiceLinux::WillDestroyCurrentMessageLoop() {
222 DCHECK(CalledOnValidThread());
223 g_input_service_linux_ptr.Get().reset(NULL);
226 void InputServiceLinux::AddDevice(const InputDeviceInfo& info) {
227 devices_[info.id] = info;
228 FOR_EACH_OBSERVER(Observer, observers_, OnInputDeviceAdded(info));
231 void InputServiceLinux::RemoveDevice(const std::string& id) {
232 devices_.erase(id);
233 FOR_EACH_OBSERVER(Observer, observers_, OnInputDeviceRemoved(id));
236 bool InputServiceLinux::CalledOnValidThread() const {
237 return thread_checker_.CalledOnValidThread();
240 } // namespace device