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/logging.h"
10 #include "base/threading/thread_restrictions.h"
12 #if !defined(EVIOCGMTSLOTS)
13 #define EVIOCGMTSLOTS(len) _IOC(_IOC_READ, 'E', 0x0a, len)
20 bool GetEventBits(int fd
, unsigned int type
, void* buf
, unsigned int size
) {
21 if (ioctl(fd
, EVIOCGBIT(type
, size
), buf
) < 0) {
22 DLOG(ERROR
) << "failed EVIOCGBIT(" << type
<< ", " << size
<< ") on fd "
30 bool GetPropBits(int fd
, void* buf
, unsigned int size
) {
31 if (ioctl(fd
, EVIOCGPROP(size
), buf
) < 0) {
32 DLOG(ERROR
) << "failed EVIOCGPROP(" << size
<< ") on fd " << fd
;
39 bool GetAbsInfo(int fd
, int code
, struct input_absinfo
* absinfo
) {
40 if (ioctl(fd
, EVIOCGABS(code
), absinfo
)) {
41 DLOG(ERROR
) << "failed EVIOCGABS(" << code
<< ") on fd " << fd
;
47 // |request| needs to be the equivalent to:
48 // struct input_mt_request_layout {
50 // int32_t values[num_slots];
53 // |size| is num_slots + 1 (for code).
54 bool GetSlotValues(int fd
, int32_t* request
, unsigned int size
) {
56 EVIOCGMTSLOTS(sizeof(int32_t) * size
),
58 DLOG(ERROR
) << "failed EVIOCGMTSLOTS(" << request
[0] << ") on fd " << fd
;
67 EventDeviceInfo::EventDeviceInfo() {
68 memset(ev_bits_
, 0, sizeof(ev_bits_
));
69 memset(key_bits_
, 0, sizeof(key_bits_
));
70 memset(rel_bits_
, 0, sizeof(rel_bits_
));
71 memset(abs_bits_
, 0, sizeof(abs_bits_
));
72 memset(msc_bits_
, 0, sizeof(msc_bits_
));
73 memset(sw_bits_
, 0, sizeof(sw_bits_
));
74 memset(led_bits_
, 0, sizeof(led_bits_
));
75 memset(prop_bits_
, 0, sizeof(prop_bits_
));
76 memset(abs_info_
, 0, sizeof(abs_info_
));
79 EventDeviceInfo::~EventDeviceInfo() {}
81 bool EventDeviceInfo::Initialize(int fd
) {
82 if (!GetEventBits(fd
, 0, ev_bits_
, sizeof(ev_bits_
)))
85 if (!GetEventBits(fd
, EV_KEY
, key_bits_
, sizeof(key_bits_
)))
88 if (!GetEventBits(fd
, EV_REL
, rel_bits_
, sizeof(rel_bits_
)))
91 if (!GetEventBits(fd
, EV_ABS
, abs_bits_
, sizeof(abs_bits_
)))
94 if (!GetEventBits(fd
, EV_MSC
, msc_bits_
, sizeof(msc_bits_
)))
97 if (!GetEventBits(fd
, EV_SW
, sw_bits_
, sizeof(sw_bits_
)))
100 if (!GetEventBits(fd
, EV_LED
, led_bits_
, sizeof(led_bits_
)))
103 if (!GetPropBits(fd
, prop_bits_
, sizeof(prop_bits_
)))
106 for (unsigned int i
= 0; i
< ABS_CNT
; ++i
)
108 if (!GetAbsInfo(fd
, i
, &abs_info_
[i
]))
111 int max_num_slots
= abs_info_
[ABS_MT_SLOT
].maximum
+ 1;
112 // |request| is MT code + slots.
113 int32_t request
[max_num_slots
+ 1];
114 for (unsigned int i
= ABS_MT_SLOT
+ 1; i
< ABS_MAX
; ++i
) {
115 memset(request
, 0, sizeof(request
));
118 if (!GetSlotValues(fd
, request
, max_num_slots
+ 1))
119 LOG(WARNING
) << "Failed to get multitouch values for code " << i
;
121 slot_values_
[i
- ABS_MT_SLOT
- 1].assign(
122 request
+ 1, request
+ max_num_slots
+ 1);
128 bool EventDeviceInfo::HasEventType(unsigned int type
) const {
131 return EvdevBitIsSet(ev_bits_
, type
);
134 bool EventDeviceInfo::HasKeyEvent(unsigned int code
) const {
137 return EvdevBitIsSet(key_bits_
, code
);
140 bool EventDeviceInfo::HasRelEvent(unsigned int code
) const {
143 return EvdevBitIsSet(rel_bits_
, code
);
146 bool EventDeviceInfo::HasAbsEvent(unsigned int code
) const {
149 return EvdevBitIsSet(abs_bits_
, code
);
152 bool EventDeviceInfo::HasMscEvent(unsigned int code
) const {
155 return EvdevBitIsSet(msc_bits_
, code
);
158 bool EventDeviceInfo::HasSwEvent(unsigned int code
) const {
161 return EvdevBitIsSet(sw_bits_
, code
);
164 bool EventDeviceInfo::HasLedEvent(unsigned int code
) const {
167 return EvdevBitIsSet(led_bits_
, code
);
170 bool EventDeviceInfo::HasProp(unsigned int code
) const {
171 if (code
> INPUT_PROP_MAX
)
173 return EvdevBitIsSet(prop_bits_
, code
);
176 int32
EventDeviceInfo::GetAbsMinimum(unsigned int code
) const {
177 return abs_info_
[code
].minimum
;
180 int32
EventDeviceInfo::GetAbsMaximum(unsigned int code
) const {
181 return abs_info_
[code
].maximum
;
184 int32
EventDeviceInfo::GetSlotValue(unsigned int code
,
185 unsigned int slot
) const {
186 const std::vector
<int32_t>& slots
= GetMtSlotsForCode(code
);
187 DCHECK_LE(0u, slot
) << slot
<< " is an invalid slot";
188 DCHECK_LT(slot
, slots
.size()) << slot
<< " is an invalid slot";
192 bool EventDeviceInfo::HasAbsXY() const {
193 return HasAbsEvent(ABS_X
) && HasAbsEvent(ABS_Y
);
196 bool EventDeviceInfo::HasMTAbsXY() const {
197 return HasAbsEvent(ABS_MT_POSITION_X
) && HasAbsEvent(ABS_MT_POSITION_Y
);
200 bool EventDeviceInfo::HasRelXY() const {
201 return HasRelEvent(REL_X
) && HasRelEvent(REL_Y
);
204 bool EventDeviceInfo::IsMappedToScreen() const {
205 // Device position is mapped directly to the screen.
206 if (HasProp(INPUT_PROP_DIRECT
))
209 // Tablets are mapped to the screen.
210 if (HasKeyEvent(BTN_TOOL_PEN
) || HasKeyEvent(BTN_STYLUS
) ||
211 HasKeyEvent(BTN_STYLUS2
))
214 // Device position moves the cursor.
215 if (HasProp(INPUT_PROP_POINTER
))
218 // Touchpads are not mapped to the screen.
219 if (HasKeyEvent(BTN_LEFT
) || HasKeyEvent(BTN_MIDDLE
) ||
220 HasKeyEvent(BTN_RIGHT
) || HasKeyEvent(BTN_TOOL_FINGER
))
223 // Touchscreens are mapped to the screen.
227 bool EventDeviceInfo::HasKeyboard() const {
228 if (!HasEventType(EV_KEY
))
231 // Check first 31 keys: If we have all of them, consider it a full
232 // keyboard. This is exactly what udev does for ID_INPUT_KEYBOARD.
233 for (int key
= KEY_ESC
; key
<= KEY_D
; ++key
)
234 if (!HasKeyEvent(key
))
240 bool EventDeviceInfo::HasMouse() const {
244 bool EventDeviceInfo::HasTouchpad() const {
245 return (HasAbsXY() || HasMTAbsXY()) && !IsMappedToScreen();
248 const std::vector
<int32_t>& EventDeviceInfo::GetMtSlotsForCode(int code
) const {
249 int index
= code
- ABS_MT_SLOT
- 1;
250 DCHECK_LE(0, index
) << code
<< " is not a valid multi-touch code";
251 DCHECK_LT(index
, EVDEV_ABS_MT_COUNT
)
252 << code
<< " is not a valid multi-touch code";
253 return slot_values_
[index
];