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)
22 // USB vendor and product strings are pragmatically limited to 126
23 // characters each, so device names more than twice that should be
25 const size_t kMaximumDeviceNameLength
= 256;
27 bool GetEventBits(int fd
,
28 const base::FilePath
& path
,
32 if (ioctl(fd
, EVIOCGBIT(type
, size
), buf
) < 0) {
33 PLOG(ERROR
) << "Failed EVIOCGBIT (path=" << path
.value() << " type=" << type
34 << " size=" << size
<< ")";
41 bool GetPropBits(int fd
,
42 const base::FilePath
& path
,
45 if (ioctl(fd
, EVIOCGPROP(size
), buf
) < 0) {
46 PLOG(ERROR
) << "Failed EVIOCGPROP (path=" << path
.value() << ")";
53 bool GetAbsInfo(int fd
,
54 const base::FilePath
& path
,
56 struct input_absinfo
* absinfo
) {
57 if (ioctl(fd
, EVIOCGABS(code
), absinfo
)) {
58 PLOG(ERROR
) << "Failed EVIOCGABS (path=" << path
.value() << " code=" << code
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() << ")";
75 bool GetDeviceIdentifiers(int fd
,
76 const base::FilePath
& path
,
79 struct input_id evdev_id
;
80 if (ioctl(fd
, EVIOCGID
, &evdev_id
) < 0) {
81 PLOG(INFO
) << "Failed EVIOCGID (path=" << path
.value() << ")";
84 *vendor
= evdev_id
.vendor
;
85 *product
= evdev_id
.product
;
89 // |request| needs to be the equivalent to:
90 // struct input_mt_request_layout {
92 // int32_t values[num_slots];
95 // |size| is num_slots + 1 (for code).
96 void GetSlotValues(int fd
,
97 const base::FilePath
& path
,
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
,
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));
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_
)))
136 if (!GetEventBits(fd
, path
, EV_KEY
, key_bits_
, sizeof(key_bits_
)))
139 if (!GetEventBits(fd
, path
, EV_REL
, rel_bits_
, sizeof(rel_bits_
)))
142 if (!GetEventBits(fd
, path
, EV_ABS
, abs_bits_
, sizeof(abs_bits_
)))
145 if (!GetEventBits(fd
, path
, EV_MSC
, msc_bits_
, sizeof(msc_bits_
)))
148 if (!GetEventBits(fd
, path
, EV_SW
, sw_bits_
, sizeof(sw_bits_
)))
151 if (!GetEventBits(fd
, path
, EV_LED
, led_bits_
, sizeof(led_bits_
)))
154 if (!GetPropBits(fd
, path
, prop_bits_
, sizeof(prop_bits_
)))
157 for (unsigned int i
= 0; i
< ABS_CNT
; ++i
)
159 if (!GetAbsInfo(fd
, path
, i
, &abs_info_
[i
]))
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
) {
172 memset(request
, 0, sizeof(request
));
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_
))
183 if (!GetDeviceIdentifiers(fd
, path
, &vendor_id_
, &product_id_
))
186 device_type_
= GetInputDeviceTypeFromPath(path
);
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
) {
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
)
237 slot_values_
[index
] = values
;
240 void EventDeviceInfo::SetAbsMtSlot(unsigned int code
,
243 int index
= code
- EVDEV_ABS_MT_FIRST
;
244 if (index
< 0 || index
>= EVDEV_ABS_MT_COUNT
)
246 slot_values_
[index
][slot
] = value
;
249 void EventDeviceInfo::SetDeviceType(InputDeviceType type
) {
253 bool EventDeviceInfo::HasEventType(unsigned int type
) const {
256 return EvdevBitIsSet(ev_bits_
, type
);
259 bool EventDeviceInfo::HasKeyEvent(unsigned int code
) const {
262 return EvdevBitIsSet(key_bits_
, code
);
265 bool EventDeviceInfo::HasRelEvent(unsigned int code
) const {
268 return EvdevBitIsSet(rel_bits_
, code
);
271 bool EventDeviceInfo::HasAbsEvent(unsigned int code
) const {
274 return EvdevBitIsSet(abs_bits_
, code
);
277 bool EventDeviceInfo::HasMscEvent(unsigned int code
) const {
280 return EvdevBitIsSet(msc_bits_
, code
);
283 bool EventDeviceInfo::HasSwEvent(unsigned int code
) const {
286 return EvdevBitIsSet(sw_bits_
, code
);
289 bool EventDeviceInfo::HasLedEvent(unsigned int code
) const {
292 return EvdevBitIsSet(led_bits_
, code
);
295 bool EventDeviceInfo::HasProp(unsigned int code
) const {
296 if (code
> INPUT_PROP_MAX
)
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
))
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(
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
)
361 switch (ProbeLegacyAbsoluteDevice()) {
362 case LegacyAbsoluteDeviceType::LADT_TOUCHSCREEN
:
365 case LegacyAbsoluteDeviceType::LADT_TABLET
:
366 case LegacyAbsoluteDeviceType::LADT_TOUCHPAD
:
367 case LegacyAbsoluteDeviceType::LADT_NONE
:
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
)
381 switch (ProbeLegacyAbsoluteDevice()) {
382 case LegacyAbsoluteDeviceType::LADT_TOUCHPAD
:
383 case LegacyAbsoluteDeviceType::LADT_TABLET
:
386 case LegacyAbsoluteDeviceType::LADT_TOUCHSCREEN
:
387 case LegacyAbsoluteDeviceType::LADT_NONE
:
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
))
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
))
413 bool EventDeviceInfo::HasMouse() const {
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 {
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
;
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
;