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.
4 
5 #include "ui/events/ozone/evdev/event_device_info.h"
6 
7 #include <linux/input.h>
8 
9 #include "base/files/file_path.h"
10 #include "base/logging.h"
11 #include "base/stl_util.h"
12 #include "base/threading/thread_restrictions.h"
13 #include "ui/events/devices/device_util_linux.h"
14 
15 #if !defined(EVIOCGMTSLOTS)
16 #define EVIOCGMTSLOTS(len) _IOC(_IOC_READ, 'E', 0x0a, len)
17 #endif
18 
19 namespace ui {
20 
21 namespace {
22 
23 // USB vendor and product strings are pragmatically limited to 126
24 // characters each, so device names more than twice that should be
25 // unusual.
26 const size_t kMaximumDeviceNameLength = 256;
27 
28 constexpr struct {
29   uint16_t vendor;
30   uint16_t product_id;
31 } kKeyboardBlocklist[] = {
32   {0x045e, 0x0b05},  // Xbox One Elite Series 2 gamepad
33 };
34 
35 constexpr struct {
36   uint16_t vendor;
37   uint16_t product_id;
38 } kStylusButtonDevices[] = {
39     {0x413c, 0x81d5},  // Dell Active Pen PN579X
40 };
41 
GetEventBits(int fd,const base::FilePath & path,unsigned int type,void * buf,unsigned int size)42 bool GetEventBits(int fd,
43                   const base::FilePath& path,
44                   unsigned int type,
45                   void* buf,
46                   unsigned int size) {
47   if (ioctl(fd, EVIOCGBIT(type, size), buf) < 0) {
48     PLOG(ERROR) << "Failed EVIOCGBIT (path=" << path.value() << " type=" << type
49                 << " size=" << size << ")";
50     return false;
51   }
52 
53   return true;
54 }
55 
GetPropBits(int fd,const base::FilePath & path,void * buf,unsigned int size)56 bool GetPropBits(int fd,
57                  const base::FilePath& path,
58                  void* buf,
59                  unsigned int size) {
60   if (ioctl(fd, EVIOCGPROP(size), buf) < 0) {
61     PLOG(ERROR) << "Failed EVIOCGPROP (path=" << path.value() << ")";
62     return false;
63   }
64 
65   return true;
66 }
67 
GetAbsInfo(int fd,const base::FilePath & path,int code,struct input_absinfo * absinfo)68 bool GetAbsInfo(int fd,
69                 const base::FilePath& path,
70                 int code,
71                 struct input_absinfo* absinfo) {
72   if (ioctl(fd, EVIOCGABS(code), absinfo)) {
73     PLOG(ERROR) << "Failed EVIOCGABS (path=" << path.value() << " code=" << code
74                 << ")";
75     return false;
76   }
77   return true;
78 }
79 
GetDeviceName(int fd,const base::FilePath & path,std::string * name)80 bool GetDeviceName(int fd, const base::FilePath& path, std::string* name) {
81   char device_name[kMaximumDeviceNameLength];
82   if (ioctl(fd, EVIOCGNAME(kMaximumDeviceNameLength - 1), &device_name) < 0) {
83     PLOG(INFO) << "Failed EVIOCGNAME (path=" << path.value() << ")";
84     return false;
85   }
86   *name = device_name;
87   return true;
88 }
89 
GetDeviceIdentifiers(int fd,const base::FilePath & path,input_id * id)90 bool GetDeviceIdentifiers(int fd, const base::FilePath& path, input_id* id) {
91   *id = {};
92   if (ioctl(fd, EVIOCGID, id) < 0) {
93     PLOG(INFO) << "Failed EVIOCGID (path=" << path.value() << ")";
94     return false;
95   }
96   return true;
97 }
98 
GetDevicePhysInfo(int fd,const base::FilePath & path,std::string * phys)99 void GetDevicePhysInfo(int fd, const base::FilePath& path, std::string* phys) {
100   char device_phys[kMaximumDeviceNameLength];
101   if (ioctl(fd, EVIOCGPHYS(kMaximumDeviceNameLength - 1), &device_phys) < 0) {
102     PLOG(INFO) << "Failed EVIOCGPHYS (path=" << path.value() << ")";
103     return;
104   }
105   *phys = device_phys;
106 }
107 
108 // |request| needs to be the equivalent to:
109 // struct input_mt_request_layout {
110 //   uint32_t code;
111 //   int32_t values[num_slots];
112 // };
113 //
114 // |size| is num_slots + 1 (for code).
GetSlotValues(int fd,const base::FilePath & path,int32_t * request,unsigned int size)115 void GetSlotValues(int fd,
116                    const base::FilePath& path,
117                    int32_t* request,
118                    unsigned int size) {
119   size_t data_size = size * sizeof(*request);
120   if (ioctl(fd, EVIOCGMTSLOTS(data_size), request) < 0) {
121     PLOG(ERROR) << "Failed EVIOCGMTSLOTS (code=" << request[0]
122                 << " path=" << path.value() << ")";
123   }
124 }
125 
AssignBitset(const unsigned long * src,size_t src_len,unsigned long * dst,size_t dst_len)126 void AssignBitset(const unsigned long* src,
127                   size_t src_len,
128                   unsigned long* dst,
129                   size_t dst_len) {
130   memcpy(dst, src, std::min(src_len, dst_len) * sizeof(unsigned long));
131   if (src_len < dst_len)
132     memset(&dst[src_len], 0, (dst_len - src_len) * sizeof(unsigned long));
133 }
134 
IsBlacklistedAbsoluteMouseDevice(const input_id & id)135 bool IsBlacklistedAbsoluteMouseDevice(const input_id& id) {
136   static constexpr struct {
137     uint16_t vid;
138     uint16_t pid;
139   } kUSBLegacyBlackListedDevices[] = {
140       {0x222a, 0x0001},  // ILITEK ILITEK-TP
141   };
142 
143   for (size_t i = 0; i < base::size(kUSBLegacyBlackListedDevices); ++i) {
144     if (id.vendor == kUSBLegacyBlackListedDevices[i].vid &&
145         id.product == kUSBLegacyBlackListedDevices[i].pid) {
146       return true;
147     }
148   }
149 
150   return false;
151 }
152 
153 }  // namespace
154 
EventDeviceInfo()155 EventDeviceInfo::EventDeviceInfo() {
156   memset(ev_bits_, 0, sizeof(ev_bits_));
157   memset(key_bits_, 0, sizeof(key_bits_));
158   memset(rel_bits_, 0, sizeof(rel_bits_));
159   memset(abs_bits_, 0, sizeof(abs_bits_));
160   memset(msc_bits_, 0, sizeof(msc_bits_));
161   memset(sw_bits_, 0, sizeof(sw_bits_));
162   memset(led_bits_, 0, sizeof(led_bits_));
163   memset(prop_bits_, 0, sizeof(prop_bits_));
164   memset(abs_info_, 0, sizeof(abs_info_));
165 }
166 
~EventDeviceInfo()167 EventDeviceInfo::~EventDeviceInfo() {}
168 
Initialize(int fd,const base::FilePath & path)169 bool EventDeviceInfo::Initialize(int fd, const base::FilePath& path) {
170   if (!GetEventBits(fd, path, 0, ev_bits_, sizeof(ev_bits_)))
171     return false;
172 
173   if (!GetEventBits(fd, path, EV_KEY, key_bits_, sizeof(key_bits_)))
174     return false;
175 
176   if (!GetEventBits(fd, path, EV_REL, rel_bits_, sizeof(rel_bits_)))
177     return false;
178 
179   if (!GetEventBits(fd, path, EV_ABS, abs_bits_, sizeof(abs_bits_)))
180     return false;
181 
182   if (!GetEventBits(fd, path, EV_MSC, msc_bits_, sizeof(msc_bits_)))
183     return false;
184 
185   if (!GetEventBits(fd, path, EV_SW, sw_bits_, sizeof(sw_bits_)))
186     return false;
187 
188   if (!GetEventBits(fd, path, EV_LED, led_bits_, sizeof(led_bits_)))
189     return false;
190 
191   if (!GetPropBits(fd, path, prop_bits_, sizeof(prop_bits_)))
192     return false;
193 
194   for (unsigned int i = 0; i < ABS_CNT; ++i)
195     if (HasAbsEvent(i))
196       if (!GetAbsInfo(fd, path, i, &abs_info_[i]))
197         return false;
198 
199   int max_num_slots = GetAbsMtSlotCount();
200 
201   // |request| is MT code + slots.
202   int32_t request[max_num_slots + 1];
203   int32_t* request_code = &request[0];
204   int32_t* request_slots = &request[1];
205   for (unsigned int i = EVDEV_ABS_MT_FIRST; i <= EVDEV_ABS_MT_LAST; ++i) {
206     if (!HasAbsEvent(i))
207       continue;
208 
209     memset(request, 0, sizeof(request));
210     *request_code = i;
211     GetSlotValues(fd, path, request, max_num_slots + 1);
212 
213     std::vector<int32_t>* slots = &slot_values_[i - EVDEV_ABS_MT_FIRST];
214     slots->assign(request_slots, request_slots + max_num_slots);
215   }
216 
217   if (!GetDeviceName(fd, path, &name_))
218     return false;
219 
220   if (!GetDeviceIdentifiers(fd, path, &input_id_))
221     return false;
222 
223   GetDevicePhysInfo(fd, path, &phys_);
224 
225   device_type_ = GetInputDeviceTypeFromId(input_id_);
226   if (device_type_ == InputDeviceType::INPUT_DEVICE_UNKNOWN)
227     device_type_ = GetInputDeviceTypeFromPath(path);
228 
229   return true;
230 }
231 
SetEventTypes(const unsigned long * ev_bits,size_t len)232 void EventDeviceInfo::SetEventTypes(const unsigned long* ev_bits, size_t len) {
233   AssignBitset(ev_bits, len, ev_bits_, base::size(ev_bits_));
234 }
235 
SetKeyEvents(const unsigned long * key_bits,size_t len)236 void EventDeviceInfo::SetKeyEvents(const unsigned long* key_bits, size_t len) {
237   AssignBitset(key_bits, len, key_bits_, base::size(key_bits_));
238 }
239 
SetRelEvents(const unsigned long * rel_bits,size_t len)240 void EventDeviceInfo::SetRelEvents(const unsigned long* rel_bits, size_t len) {
241   AssignBitset(rel_bits, len, rel_bits_, base::size(rel_bits_));
242 }
243 
SetAbsEvents(const unsigned long * abs_bits,size_t len)244 void EventDeviceInfo::SetAbsEvents(const unsigned long* abs_bits, size_t len) {
245   AssignBitset(abs_bits, len, abs_bits_, base::size(abs_bits_));
246 }
247 
SetMscEvents(const unsigned long * msc_bits,size_t len)248 void EventDeviceInfo::SetMscEvents(const unsigned long* msc_bits, size_t len) {
249   AssignBitset(msc_bits, len, msc_bits_, base::size(msc_bits_));
250 }
251 
SetSwEvents(const unsigned long * sw_bits,size_t len)252 void EventDeviceInfo::SetSwEvents(const unsigned long* sw_bits, size_t len) {
253   AssignBitset(sw_bits, len, sw_bits_, base::size(sw_bits_));
254 }
255 
SetLedEvents(const unsigned long * led_bits,size_t len)256 void EventDeviceInfo::SetLedEvents(const unsigned long* led_bits, size_t len) {
257   AssignBitset(led_bits, len, led_bits_, base::size(led_bits_));
258 }
259 
SetProps(const unsigned long * prop_bits,size_t len)260 void EventDeviceInfo::SetProps(const unsigned long* prop_bits, size_t len) {
261   AssignBitset(prop_bits, len, prop_bits_, base::size(prop_bits_));
262 }
263 
SetAbsInfo(unsigned int code,const input_absinfo & abs_info)264 void EventDeviceInfo::SetAbsInfo(unsigned int code,
265                                  const input_absinfo& abs_info) {
266   if (code > ABS_MAX)
267     return;
268 
269   memcpy(&abs_info_[code], &abs_info, sizeof(abs_info));
270 }
271 
SetAbsMtSlots(unsigned int code,const std::vector<int32_t> & values)272 void EventDeviceInfo::SetAbsMtSlots(unsigned int code,
273                                     const std::vector<int32_t>& values) {
274   DCHECK_EQ(GetAbsMtSlotCount(), values.size());
275   int index = code - EVDEV_ABS_MT_FIRST;
276   if (index < 0 || index >= EVDEV_ABS_MT_COUNT)
277     return;
278   slot_values_[index] = values;
279 }
280 
SetAbsMtSlot(unsigned int code,unsigned int slot,uint32_t value)281 void EventDeviceInfo::SetAbsMtSlot(unsigned int code,
282                                    unsigned int slot,
283                                    uint32_t value) {
284   int index = code - EVDEV_ABS_MT_FIRST;
285   if (index < 0 || index >= EVDEV_ABS_MT_COUNT)
286     return;
287   slot_values_[index][slot] = value;
288 }
289 
SetDeviceType(InputDeviceType type)290 void EventDeviceInfo::SetDeviceType(InputDeviceType type) {
291   device_type_ = type;
292 }
293 
SetId(input_id id)294 void EventDeviceInfo::SetId(input_id id) {
295   input_id_ = id;
296 }
SetName(const std::string & name)297 void EventDeviceInfo::SetName(const std::string& name) {
298   name_ = name;
299 }
300 
HasEventType(unsigned int type) const301 bool EventDeviceInfo::HasEventType(unsigned int type) const {
302   if (type > EV_MAX)
303     return false;
304   return EvdevBitIsSet(ev_bits_, type);
305 }
306 
HasKeyEvent(unsigned int code) const307 bool EventDeviceInfo::HasKeyEvent(unsigned int code) const {
308   if (code > KEY_MAX)
309     return false;
310   return EvdevBitIsSet(key_bits_, code);
311 }
312 
HasRelEvent(unsigned int code) const313 bool EventDeviceInfo::HasRelEvent(unsigned int code) const {
314   if (code > REL_MAX)
315     return false;
316   return EvdevBitIsSet(rel_bits_, code);
317 }
318 
HasAbsEvent(unsigned int code) const319 bool EventDeviceInfo::HasAbsEvent(unsigned int code) const {
320   if (code > ABS_MAX)
321     return false;
322   return EvdevBitIsSet(abs_bits_, code);
323 }
324 
HasMscEvent(unsigned int code) const325 bool EventDeviceInfo::HasMscEvent(unsigned int code) const {
326   if (code > MSC_MAX)
327     return false;
328   return EvdevBitIsSet(msc_bits_, code);
329 }
330 
HasSwEvent(unsigned int code) const331 bool EventDeviceInfo::HasSwEvent(unsigned int code) const {
332   if (code > SW_MAX)
333     return false;
334   return EvdevBitIsSet(sw_bits_, code);
335 }
336 
HasLedEvent(unsigned int code) const337 bool EventDeviceInfo::HasLedEvent(unsigned int code) const {
338   if (code > LED_MAX)
339     return false;
340   return EvdevBitIsSet(led_bits_, code);
341 }
342 
HasProp(unsigned int code) const343 bool EventDeviceInfo::HasProp(unsigned int code) const {
344   if (code > INPUT_PROP_MAX)
345     return false;
346   return EvdevBitIsSet(prop_bits_, code);
347 }
348 
GetAbsMinimum(unsigned int code) const349 int32_t EventDeviceInfo::GetAbsMinimum(unsigned int code) const {
350   return abs_info_[code].minimum;
351 }
352 
GetAbsMaximum(unsigned int code) const353 int32_t EventDeviceInfo::GetAbsMaximum(unsigned int code) const {
354   return abs_info_[code].maximum;
355 }
356 
GetAbsResolution(unsigned int code) const357 int32_t EventDeviceInfo::GetAbsResolution(unsigned int code) const {
358   return abs_info_[code].resolution;
359 }
360 
GetAbsValue(unsigned int code) const361 int32_t EventDeviceInfo::GetAbsValue(unsigned int code) const {
362   return abs_info_[code].value;
363 }
364 
GetAbsInfoByCode(unsigned int code) const365 input_absinfo EventDeviceInfo::GetAbsInfoByCode(unsigned int code) const {
366   return abs_info_[code];
367 }
368 
GetAbsMtSlotCount() const369 uint32_t EventDeviceInfo::GetAbsMtSlotCount() const {
370   if (!HasAbsEvent(ABS_MT_SLOT))
371     return 0;
372   return GetAbsMaximum(ABS_MT_SLOT) + 1;
373 }
374 
GetAbsMtSlotValue(unsigned int code,unsigned int slot) const375 int32_t EventDeviceInfo::GetAbsMtSlotValue(unsigned int code,
376                                            unsigned int slot) const {
377   unsigned int index = code - EVDEV_ABS_MT_FIRST;
378   DCHECK(index < EVDEV_ABS_MT_COUNT);
379   return slot_values_[index][slot];
380 }
381 
GetAbsMtSlotValueWithDefault(unsigned int code,unsigned int slot,int32_t default_value) const382 int32_t EventDeviceInfo::GetAbsMtSlotValueWithDefault(
383     unsigned int code,
384     unsigned int slot,
385     int32_t default_value) const {
386   if (!HasAbsEvent(code))
387     return default_value;
388   return GetAbsMtSlotValue(code, slot);
389 }
390 
HasAbsXY() const391 bool EventDeviceInfo::HasAbsXY() const {
392   return HasAbsEvent(ABS_X) && HasAbsEvent(ABS_Y);
393 }
394 
HasMTAbsXY() const395 bool EventDeviceInfo::HasMTAbsXY() const {
396   return HasAbsEvent(ABS_MT_POSITION_X) && HasAbsEvent(ABS_MT_POSITION_Y);
397 }
398 
HasRelXY() const399 bool EventDeviceInfo::HasRelXY() const {
400   return HasRelEvent(REL_X) && HasRelEvent(REL_Y);
401 }
402 
HasMultitouch() const403 bool EventDeviceInfo::HasMultitouch() const {
404   return HasAbsEvent(ABS_MT_SLOT);
405 }
406 
HasDirect() const407 bool EventDeviceInfo::HasDirect() const {
408   bool has_direct = HasProp(INPUT_PROP_DIRECT);
409   bool has_pointer = HasProp(INPUT_PROP_POINTER);
410   if (has_direct || has_pointer)
411     return has_direct;
412 
413   switch (ProbeLegacyAbsoluteDevice()) {
414     case LegacyAbsoluteDeviceType::TOUCHSCREEN:
415       return true;
416 
417     case LegacyAbsoluteDeviceType::TABLET:
418     case LegacyAbsoluteDeviceType::TOUCHPAD:
419     case LegacyAbsoluteDeviceType::NONE:
420       return false;
421   }
422 
423   NOTREACHED();
424   return false;
425 }
426 
HasPointer() const427 bool EventDeviceInfo::HasPointer() const {
428   bool has_direct = HasProp(INPUT_PROP_DIRECT);
429   bool has_pointer = HasProp(INPUT_PROP_POINTER);
430   if (has_direct || has_pointer)
431     return has_pointer;
432 
433   switch (ProbeLegacyAbsoluteDevice()) {
434     case LegacyAbsoluteDeviceType::TOUCHPAD:
435     case LegacyAbsoluteDeviceType::TABLET:
436       return true;
437 
438     case LegacyAbsoluteDeviceType::TOUCHSCREEN:
439     case LegacyAbsoluteDeviceType::NONE:
440       return false;
441   }
442 
443   NOTREACHED();
444   return false;
445 }
446 
HasStylus() const447 bool EventDeviceInfo::HasStylus() const {
448   return HasKeyEvent(BTN_TOOL_PEN) || HasKeyEvent(BTN_STYLUS) ||
449          HasKeyEvent(BTN_STYLUS2);
450 }
451 
IsStylusButtonDevice() const452 bool EventDeviceInfo::IsStylusButtonDevice() const {
453   for (const auto& device_id : kStylusButtonDevices) {
454     if (input_id_.vendor == device_id.vendor &&
455         input_id_.product == device_id.product_id)
456       return true;
457   }
458 
459   return false;
460 }
461 
IsInKeyboardBlockList(input_id input_id_)462 bool IsInKeyboardBlockList(input_id input_id_) {
463   for (const auto& blocklist_id : kKeyboardBlocklist) {
464     if (input_id_.vendor == blocklist_id.vendor &&
465         input_id_.product == blocklist_id.product_id)
466       return true;
467   }
468 
469   return false;
470 }
471 
HasKeyboard() const472 bool EventDeviceInfo::HasKeyboard() const {
473   if (!HasEventType(EV_KEY))
474     return false;
475   if (IsInKeyboardBlockList(input_id_))
476     return false;
477   if (IsStylusButtonDevice())
478     return false;
479 
480   // Check first 31 keys: If we have all of them, consider it a full
481   // keyboard. This is exactly what udev does for ID_INPUT_KEYBOARD.
482   for (int key = KEY_ESC; key <= KEY_D; ++key)
483     if (!HasKeyEvent(key))
484       return false;
485 
486   return true;
487 }
488 
HasMouse() const489 bool EventDeviceInfo::HasMouse() const {
490   return HasRelXY();
491 }
492 
HasTouchpad() const493 bool EventDeviceInfo::HasTouchpad() const {
494   return HasAbsXY() && HasPointer() && !HasStylus();
495 }
496 
HasTablet() const497 bool EventDeviceInfo::HasTablet() const {
498   return HasAbsXY() && HasPointer() && HasStylus();
499 }
500 
HasTouchscreen() const501 bool EventDeviceInfo::HasTouchscreen() const {
502   return HasAbsXY() && HasDirect();
503 }
504 
HasGamepad() const505 bool EventDeviceInfo::HasGamepad() const {
506   if (!HasEventType(EV_KEY))
507     return false;
508 
509   // If the device has gamepad button, and it's not keyboard or tablet, it will
510   // be considered to be a gamepad. Note: this WILL have false positives and
511   // false negatives. A concrete solution will use ID_INPUT_JOYSTICK with some
512   // patch removing false positives.
513   bool support_gamepad_btn = false;
514   for (int key = BTN_JOYSTICK; key <= BTN_THUMBR; ++key) {
515     if (HasKeyEvent(key))
516       support_gamepad_btn = true;
517   }
518 
519   return support_gamepad_btn && !HasTablet() && !HasKeyboard();
520 }
521 
522 // static
GetInputDeviceTypeFromId(input_id id)523 ui::InputDeviceType EventDeviceInfo::GetInputDeviceTypeFromId(input_id id) {
524   static constexpr struct {
525     uint16_t vid;
526     uint16_t pid;
527   } kUSBInternalDevices[] = {
528       {0x18d1, 0x502b},  // Google, Hammer PID (soraka)
529       {0x18d1, 0x5030},  // Google, Whiskers PID (nocturne)
530       {0x18d1, 0x503c},  // Google, Masterball PID (krane)
531       {0x18d1, 0x503d},  // Google, Magnemite PID (kodama)
532       {0x18d1, 0x5044},  // Google, Moonball PID (kakadu)
533       {0x1fd2, 0x8103},  // LG, Internal TouchScreen PID
534   };
535 
536   if (id.bustype == BUS_USB) {
537     for (size_t i = 0; i < base::size(kUSBInternalDevices); ++i) {
538       if (id.vendor == kUSBInternalDevices[i].vid &&
539           id.product == kUSBInternalDevices[i].pid)
540         return InputDeviceType::INPUT_DEVICE_INTERNAL;
541     }
542   }
543 
544   switch (id.bustype) {
545     case BUS_I2C:
546     case BUS_I8042:
547       return ui::InputDeviceType::INPUT_DEVICE_INTERNAL;
548     case BUS_USB:
549       return ui::InputDeviceType::INPUT_DEVICE_USB;
550     case BUS_BLUETOOTH:
551       return ui::InputDeviceType::INPUT_DEVICE_BLUETOOTH;
552     default:
553       return ui::InputDeviceType::INPUT_DEVICE_UNKNOWN;
554   }
555 }
556 
557 EventDeviceInfo::LegacyAbsoluteDeviceType
ProbeLegacyAbsoluteDevice() const558 EventDeviceInfo::ProbeLegacyAbsoluteDevice() const {
559   if (!HasAbsXY())
560     return LegacyAbsoluteDeviceType::NONE;
561 
562   // Treat internal stylus devices as touchscreens.
563   if (device_type_ == INPUT_DEVICE_INTERNAL && HasStylus())
564     return LegacyAbsoluteDeviceType::TOUCHSCREEN;
565 
566   if (HasStylus())
567     return LegacyAbsoluteDeviceType::TABLET;
568 
569   if (HasKeyEvent(BTN_TOOL_FINGER) && HasKeyEvent(BTN_TOUCH))
570     return LegacyAbsoluteDeviceType::TOUCHPAD;
571 
572   if (HasKeyEvent(BTN_TOUCH))
573     return LegacyAbsoluteDeviceType::TOUCHSCREEN;
574 
575   // ABS_Z mitigation for extra device on some Elo devices.
576   if (HasKeyEvent(BTN_LEFT) && !HasAbsEvent(ABS_Z) &&
577       !IsBlacklistedAbsoluteMouseDevice(input_id_))
578     return LegacyAbsoluteDeviceType::TOUCHSCREEN;
579 
580   return LegacyAbsoluteDeviceType::NONE;
581 }
582 
583 }  // namespace ui
584