Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / ui / events / ozone / evdev / event_device_info.cc
blobdc096b69854c9e0502461ea5eb2dea49cbfb70d7
1 // Copyright 2013 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 "ui/events/ozone/evdev/event_device_info.h"
7 #include <linux/input.h>
9 #include "base/files/file_path.h"
10 #include "base/logging.h"
11 #include "base/threading/thread_restrictions.h"
12 #include "ui/events/devices/device_util_linux.h"
14 #if !defined(EVIOCGMTSLOTS)
15 #define EVIOCGMTSLOTS(len) _IOC(_IOC_READ, 'E', 0x0a, len)
16 #endif
18 namespace ui {
20 namespace {
22 // USB vendor and product strings are pragmatically limited to 126
23 // characters each, so device names more than twice that should be
24 // unusual.
25 const size_t kMaximumDeviceNameLength = 256;
27 bool GetEventBits(int fd,
28 const base::FilePath& path,
29 unsigned int type,
30 void* buf,
31 unsigned int size) {
32 if (ioctl(fd, EVIOCGBIT(type, size), buf) < 0) {
33 PLOG(ERROR) << "Failed EVIOCGBIT (path=" << path.value() << " type=" << type
34 << " size=" << size << ")";
35 return false;
38 return true;
41 bool GetPropBits(int fd,
42 const base::FilePath& path,
43 void* buf,
44 unsigned int size) {
45 if (ioctl(fd, EVIOCGPROP(size), buf) < 0) {
46 PLOG(ERROR) << "Failed EVIOCGPROP (path=" << path.value() << ")";
47 return false;
50 return true;
53 bool GetAbsInfo(int fd,
54 const base::FilePath& path,
55 int code,
56 struct input_absinfo* absinfo) {
57 if (ioctl(fd, EVIOCGABS(code), absinfo)) {
58 PLOG(ERROR) << "Failed EVIOCGABS (path=" << path.value() << " code=" << code
59 << ")";
60 return false;
62 return true;
65 bool GetDeviceName(int fd, const base::FilePath& path, std::string* name) {
66 char device_name[kMaximumDeviceNameLength];
67 if (ioctl(fd, EVIOCGNAME(kMaximumDeviceNameLength - 1), &device_name) < 0) {
68 PLOG(INFO) << "Failed EVIOCGNAME (path=" << path.value() << ")";
69 return false;
71 *name = device_name;
72 return true;
75 bool GetDeviceIdentifiers(int fd,
76 const base::FilePath& path,
77 uint16_t* vendor,
78 uint16_t* product) {
79 struct input_id evdev_id;
80 if (ioctl(fd, EVIOCGID, &evdev_id) < 0) {
81 PLOG(INFO) << "Failed EVIOCGID (path=" << path.value() << ")";
82 return false;
84 *vendor = evdev_id.vendor;
85 *product = evdev_id.product;
86 return true;
89 // |request| needs to be the equivalent to:
90 // struct input_mt_request_layout {
91 // uint32_t code;
92 // int32_t values[num_slots];
93 // };
95 // |size| is num_slots + 1 (for code).
96 void GetSlotValues(int fd,
97 const base::FilePath& path,
98 int32_t* request,
99 unsigned int size) {
100 size_t data_size = size * sizeof(*request);
101 if (ioctl(fd, EVIOCGMTSLOTS(data_size), request) < 0) {
102 PLOG(ERROR) << "Failed EVIOCGMTSLOTS (code=" << request[0]
103 << " path=" << path.value() << ")";
107 void AssignBitset(const unsigned long* src,
108 size_t src_len,
109 unsigned long* dst,
110 size_t dst_len) {
111 memcpy(dst, src, std::min(src_len, dst_len) * sizeof(unsigned long));
112 if (src_len < dst_len)
113 memset(&dst[src_len], 0, (dst_len - src_len) * sizeof(unsigned long));
116 } // namespace
118 EventDeviceInfo::EventDeviceInfo() {
119 memset(ev_bits_, 0, sizeof(ev_bits_));
120 memset(key_bits_, 0, sizeof(key_bits_));
121 memset(rel_bits_, 0, sizeof(rel_bits_));
122 memset(abs_bits_, 0, sizeof(abs_bits_));
123 memset(msc_bits_, 0, sizeof(msc_bits_));
124 memset(sw_bits_, 0, sizeof(sw_bits_));
125 memset(led_bits_, 0, sizeof(led_bits_));
126 memset(prop_bits_, 0, sizeof(prop_bits_));
127 memset(abs_info_, 0, sizeof(abs_info_));
130 EventDeviceInfo::~EventDeviceInfo() {}
132 bool EventDeviceInfo::Initialize(int fd, const base::FilePath& path) {
133 if (!GetEventBits(fd, path, 0, ev_bits_, sizeof(ev_bits_)))
134 return false;
136 if (!GetEventBits(fd, path, EV_KEY, key_bits_, sizeof(key_bits_)))
137 return false;
139 if (!GetEventBits(fd, path, EV_REL, rel_bits_, sizeof(rel_bits_)))
140 return false;
142 if (!GetEventBits(fd, path, EV_ABS, abs_bits_, sizeof(abs_bits_)))
143 return false;
145 if (!GetEventBits(fd, path, EV_MSC, msc_bits_, sizeof(msc_bits_)))
146 return false;
148 if (!GetEventBits(fd, path, EV_SW, sw_bits_, sizeof(sw_bits_)))
149 return false;
151 if (!GetEventBits(fd, path, EV_LED, led_bits_, sizeof(led_bits_)))
152 return false;
154 if (!GetPropBits(fd, path, prop_bits_, sizeof(prop_bits_)))
155 return false;
157 for (unsigned int i = 0; i < ABS_CNT; ++i)
158 if (HasAbsEvent(i))
159 if (!GetAbsInfo(fd, path, i, &abs_info_[i]))
160 return false;
162 int max_num_slots = GetAbsMtSlotCount();
164 // |request| is MT code + slots.
165 int32_t request[max_num_slots + 1];
166 int32_t* request_code = &request[0];
167 int32_t* request_slots = &request[1];
168 for (unsigned int i = EVDEV_ABS_MT_FIRST; i <= EVDEV_ABS_MT_LAST; ++i) {
169 if (!HasAbsEvent(i))
170 continue;
172 memset(request, 0, sizeof(request));
173 *request_code = i;
174 GetSlotValues(fd, path, request, max_num_slots + 1);
176 std::vector<int32_t>* slots = &slot_values_[i - EVDEV_ABS_MT_FIRST];
177 slots->assign(request_slots, request_slots + max_num_slots);
180 if (!GetDeviceName(fd, path, &name_))
181 return false;
183 if (!GetDeviceIdentifiers(fd, path, &vendor_id_, &product_id_))
184 return false;
186 device_type_ = GetInputDeviceTypeFromPath(path);
188 return true;
191 void EventDeviceInfo::SetEventTypes(const unsigned long* ev_bits, size_t len) {
192 AssignBitset(ev_bits, len, ev_bits_, arraysize(ev_bits_));
195 void EventDeviceInfo::SetKeyEvents(const unsigned long* key_bits, size_t len) {
196 AssignBitset(key_bits, len, key_bits_, arraysize(key_bits_));
199 void EventDeviceInfo::SetRelEvents(const unsigned long* rel_bits, size_t len) {
200 AssignBitset(rel_bits, len, rel_bits_, arraysize(rel_bits_));
203 void EventDeviceInfo::SetAbsEvents(const unsigned long* abs_bits, size_t len) {
204 AssignBitset(abs_bits, len, abs_bits_, arraysize(abs_bits_));
207 void EventDeviceInfo::SetMscEvents(const unsigned long* msc_bits, size_t len) {
208 AssignBitset(msc_bits, len, msc_bits_, arraysize(msc_bits_));
211 void EventDeviceInfo::SetSwEvents(const unsigned long* sw_bits, size_t len) {
212 AssignBitset(sw_bits, len, sw_bits_, arraysize(sw_bits_));
215 void EventDeviceInfo::SetLedEvents(const unsigned long* led_bits, size_t len) {
216 AssignBitset(led_bits, len, led_bits_, arraysize(led_bits_));
219 void EventDeviceInfo::SetProps(const unsigned long* prop_bits, size_t len) {
220 AssignBitset(prop_bits, len, prop_bits_, arraysize(prop_bits_));
223 void EventDeviceInfo::SetAbsInfo(unsigned int code,
224 const input_absinfo& abs_info) {
225 if (code > ABS_MAX)
226 return;
228 memcpy(&abs_info_[code], &abs_info, sizeof(abs_info));
231 void EventDeviceInfo::SetAbsMtSlots(unsigned int code,
232 const std::vector<int32_t>& values) {
233 DCHECK_EQ(GetAbsMtSlotCount(), values.size());
234 int index = code - EVDEV_ABS_MT_FIRST;
235 if (index < 0 || index >= EVDEV_ABS_MT_COUNT)
236 return;
237 slot_values_[index] = values;
240 void EventDeviceInfo::SetAbsMtSlot(unsigned int code,
241 unsigned int slot,
242 uint32_t value) {
243 int index = code - EVDEV_ABS_MT_FIRST;
244 if (index < 0 || index >= EVDEV_ABS_MT_COUNT)
245 return;
246 slot_values_[index][slot] = value;
249 void EventDeviceInfo::SetDeviceType(InputDeviceType type) {
250 device_type_ = type;
253 bool EventDeviceInfo::HasEventType(unsigned int type) const {
254 if (type > EV_MAX)
255 return false;
256 return EvdevBitIsSet(ev_bits_, type);
259 bool EventDeviceInfo::HasKeyEvent(unsigned int code) const {
260 if (code > KEY_MAX)
261 return false;
262 return EvdevBitIsSet(key_bits_, code);
265 bool EventDeviceInfo::HasRelEvent(unsigned int code) const {
266 if (code > REL_MAX)
267 return false;
268 return EvdevBitIsSet(rel_bits_, code);
271 bool EventDeviceInfo::HasAbsEvent(unsigned int code) const {
272 if (code > ABS_MAX)
273 return false;
274 return EvdevBitIsSet(abs_bits_, code);
277 bool EventDeviceInfo::HasMscEvent(unsigned int code) const {
278 if (code > MSC_MAX)
279 return false;
280 return EvdevBitIsSet(msc_bits_, code);
283 bool EventDeviceInfo::HasSwEvent(unsigned int code) const {
284 if (code > SW_MAX)
285 return false;
286 return EvdevBitIsSet(sw_bits_, code);
289 bool EventDeviceInfo::HasLedEvent(unsigned int code) const {
290 if (code > LED_MAX)
291 return false;
292 return EvdevBitIsSet(led_bits_, code);
295 bool EventDeviceInfo::HasProp(unsigned int code) const {
296 if (code > INPUT_PROP_MAX)
297 return false;
298 return EvdevBitIsSet(prop_bits_, code);
301 int32_t EventDeviceInfo::GetAbsMinimum(unsigned int code) const {
302 return abs_info_[code].minimum;
305 int32_t EventDeviceInfo::GetAbsMaximum(unsigned int code) const {
306 return abs_info_[code].maximum;
309 int32_t EventDeviceInfo::GetAbsValue(unsigned int code) const {
310 return abs_info_[code].value;
313 input_absinfo EventDeviceInfo::GetAbsInfoByCode(unsigned int code) const {
314 return abs_info_[code];
317 uint32_t EventDeviceInfo::GetAbsMtSlotCount() const {
318 if (!HasAbsEvent(ABS_MT_SLOT))
319 return 0;
320 return GetAbsMaximum(ABS_MT_SLOT) + 1;
323 int32_t EventDeviceInfo::GetAbsMtSlotValue(unsigned int code,
324 unsigned int slot) const {
325 unsigned int index = code - EVDEV_ABS_MT_FIRST;
326 DCHECK(index < EVDEV_ABS_MT_COUNT);
327 return slot_values_[index][slot];
330 int32_t EventDeviceInfo::GetAbsMtSlotValueWithDefault(
331 unsigned int code,
332 unsigned int slot,
333 int32_t default_value) const {
334 if (!HasAbsEvent(code))
335 return default_value;
336 return GetAbsMtSlotValue(code, slot);
339 bool EventDeviceInfo::HasAbsXY() const {
340 return HasAbsEvent(ABS_X) && HasAbsEvent(ABS_Y);
343 bool EventDeviceInfo::HasMTAbsXY() const {
344 return HasAbsEvent(ABS_MT_POSITION_X) && HasAbsEvent(ABS_MT_POSITION_Y);
347 bool EventDeviceInfo::HasRelXY() const {
348 return HasRelEvent(REL_X) && HasRelEvent(REL_Y);
351 bool EventDeviceInfo::HasMultitouch() const {
352 return HasAbsEvent(ABS_MT_SLOT);
355 bool EventDeviceInfo::HasDirect() const {
356 bool has_direct = HasProp(INPUT_PROP_DIRECT);
357 bool has_pointer = HasProp(INPUT_PROP_POINTER);
358 if (has_direct || has_pointer)
359 return has_direct;
361 switch (ProbeLegacyAbsoluteDevice()) {
362 case LegacyAbsoluteDeviceType::LADT_TOUCHSCREEN:
363 return true;
365 case LegacyAbsoluteDeviceType::LADT_TABLET:
366 case LegacyAbsoluteDeviceType::LADT_TOUCHPAD:
367 case LegacyAbsoluteDeviceType::LADT_NONE:
368 return false;
371 NOTREACHED();
372 return false;
375 bool EventDeviceInfo::HasPointer() const {
376 bool has_direct = HasProp(INPUT_PROP_DIRECT);
377 bool has_pointer = HasProp(INPUT_PROP_POINTER);
378 if (has_direct || has_pointer)
379 return has_pointer;
381 switch (ProbeLegacyAbsoluteDevice()) {
382 case LegacyAbsoluteDeviceType::LADT_TOUCHPAD:
383 case LegacyAbsoluteDeviceType::LADT_TABLET:
384 return true;
386 case LegacyAbsoluteDeviceType::LADT_TOUCHSCREEN:
387 case LegacyAbsoluteDeviceType::LADT_NONE:
388 return false;
391 NOTREACHED();
392 return false;
395 bool EventDeviceInfo::HasStylus() const {
396 return HasKeyEvent(BTN_TOOL_PEN) || HasKeyEvent(BTN_STYLUS) ||
397 HasKeyEvent(BTN_STYLUS2);
400 bool EventDeviceInfo::HasKeyboard() const {
401 if (!HasEventType(EV_KEY))
402 return false;
404 // Check first 31 keys: If we have all of them, consider it a full
405 // keyboard. This is exactly what udev does for ID_INPUT_KEYBOARD.
406 for (int key = KEY_ESC; key <= KEY_D; ++key)
407 if (!HasKeyEvent(key))
408 return false;
410 return true;
413 bool EventDeviceInfo::HasMouse() const {
414 return HasRelXY();
417 bool EventDeviceInfo::HasTouchpad() const {
418 return HasAbsXY() && HasPointer() && !HasStylus();
421 bool EventDeviceInfo::HasTablet() const {
422 return HasAbsXY() && HasPointer() && HasStylus();
425 bool EventDeviceInfo::HasTouchscreen() const {
426 return HasAbsXY() && HasDirect();
429 EventDeviceInfo::LegacyAbsoluteDeviceType
430 EventDeviceInfo::ProbeLegacyAbsoluteDevice() const {
431 if (!HasAbsXY())
432 return LegacyAbsoluteDeviceType::LADT_NONE;
434 // Treat internal stylus devices as touchscreens.
435 if (device_type_ == INPUT_DEVICE_INTERNAL && HasStylus())
436 return LegacyAbsoluteDeviceType::LADT_TOUCHSCREEN;
438 if (HasStylus())
439 return LegacyAbsoluteDeviceType::LADT_TABLET;
441 if (HasKeyEvent(BTN_TOOL_FINGER) && HasKeyEvent(BTN_TOUCH))
442 return LegacyAbsoluteDeviceType::LADT_TOUCHPAD;
444 if (HasKeyEvent(BTN_TOUCH))
445 return LegacyAbsoluteDeviceType::LADT_TOUCHSCREEN;
447 // ABS_Z mitigation for extra device on some Elo devices.
448 if (HasKeyEvent(BTN_LEFT) && !HasAbsEvent(ABS_Z))
449 return LegacyAbsoluteDeviceType::LADT_TOUCHSCREEN;
451 return LegacyAbsoluteDeviceType::LADT_NONE;
454 } // namespace ui