| Index: ui/events/ozone/evdev/event_device_info.cc
|
| diff --git a/ui/events/ozone/evdev/event_device_info.cc b/ui/events/ozone/evdev/event_device_info.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..fba26d3ffbcd2699bd5d3e9febf3709389b510c7
|
| --- /dev/null
|
| +++ b/ui/events/ozone/evdev/event_device_info.cc
|
| @@ -0,0 +1,420 @@
|
| +// Copyright 2013 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +#include "ui/events/ozone/evdev/event_device_info.h"
|
| +
|
| +#include <linux/input.h>
|
| +
|
| +#include "base/logging.h"
|
| +#include "base/threading/thread_restrictions.h"
|
| +
|
| +#if !defined(EVIOCGMTSLOTS)
|
| +#define EVIOCGMTSLOTS(len) _IOC(_IOC_READ, 'E', 0x0a, len)
|
| +#endif
|
| +
|
| +namespace ui {
|
| +
|
| +namespace {
|
| +
|
| +// USB vendor and product strings are pragmatically limited to 126
|
| +// characters each, so device names more than twice that should be
|
| +// unusual.
|
| +const size_t kMaximumDeviceNameLength = 256;
|
| +
|
| +bool GetEventBits(int fd, unsigned int type, void* buf, unsigned int size) {
|
| + if (ioctl(fd, EVIOCGBIT(type, size), buf) < 0) {
|
| + PLOG(ERROR) << "EVIOCGBIT(" << type << ", " << size << ") on fd " << fd;
|
| + return false;
|
| + }
|
| +
|
| + return true;
|
| +}
|
| +
|
| +bool GetPropBits(int fd, void* buf, unsigned int size) {
|
| + if (ioctl(fd, EVIOCGPROP(size), buf) < 0) {
|
| + PLOG(ERROR) << "EVIOCGPROP(" << size << ") on fd " << fd;
|
| + return false;
|
| + }
|
| +
|
| + return true;
|
| +}
|
| +
|
| +bool GetAbsInfo(int fd, int code, struct input_absinfo* absinfo) {
|
| + if (ioctl(fd, EVIOCGABS(code), absinfo)) {
|
| + PLOG(ERROR) << "EVIOCGABS(" << code << ") on fd " << fd;
|
| + return false;
|
| + }
|
| + return true;
|
| +}
|
| +
|
| +bool GetDeviceName(int fd, std::string* name) {
|
| + char device_name[kMaximumDeviceNameLength];
|
| + if (ioctl(fd, EVIOCGNAME(kMaximumDeviceNameLength - 1), &device_name) < 0) {
|
| + PLOG(INFO) << "Can't read device name on fd " << fd;
|
| + return false;
|
| + }
|
| + *name = device_name;
|
| + return true;
|
| +}
|
| +
|
| +bool GetDeviceIdentifiers(int fd, uint16_t* vendor, uint16_t* product) {
|
| + struct input_id evdev_id;
|
| + if (ioctl(fd, EVIOCGID, &evdev_id) < 0) {
|
| + PLOG(INFO) << "Can't read device name on fd " << fd;
|
| + return false;
|
| + }
|
| + *vendor = evdev_id.vendor;
|
| + *product = evdev_id.product;
|
| + return true;
|
| +}
|
| +
|
| +// |request| needs to be the equivalent to:
|
| +// struct input_mt_request_layout {
|
| +// uint32_t code;
|
| +// int32_t values[num_slots];
|
| +// };
|
| +//
|
| +// |size| is num_slots + 1 (for code).
|
| +bool GetSlotValues(int fd, int32_t* request, unsigned int size) {
|
| + size_t data_size = size * sizeof(*request);
|
| +
|
| + if (ioctl(fd, EVIOCGMTSLOTS(data_size), request) < 0) {
|
| + PLOG(ERROR) << "EVIOCGMTSLOTS(" << request[0] << ") on fd " << fd;
|
| + return false;
|
| + }
|
| +
|
| + return true;
|
| +}
|
| +
|
| +void AssignBitset(const unsigned long* src,
|
| + size_t src_len,
|
| + unsigned long* dst,
|
| + size_t dst_len) {
|
| + memcpy(dst, src, std::min(src_len, dst_len) * sizeof(unsigned long));
|
| + if (src_len < dst_len)
|
| + memset(&dst[src_len], 0, (dst_len - src_len) * sizeof(unsigned long));
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| +EventDeviceInfo::EventDeviceInfo() {
|
| + memset(ev_bits_, 0, sizeof(ev_bits_));
|
| + memset(key_bits_, 0, sizeof(key_bits_));
|
| + memset(rel_bits_, 0, sizeof(rel_bits_));
|
| + memset(abs_bits_, 0, sizeof(abs_bits_));
|
| + memset(msc_bits_, 0, sizeof(msc_bits_));
|
| + memset(sw_bits_, 0, sizeof(sw_bits_));
|
| + memset(led_bits_, 0, sizeof(led_bits_));
|
| + memset(prop_bits_, 0, sizeof(prop_bits_));
|
| + memset(abs_info_, 0, sizeof(abs_info_));
|
| +}
|
| +
|
| +EventDeviceInfo::~EventDeviceInfo() {}
|
| +
|
| +bool EventDeviceInfo::Initialize(int fd) {
|
| + if (!GetEventBits(fd, 0, ev_bits_, sizeof(ev_bits_)))
|
| + return false;
|
| +
|
| + if (!GetEventBits(fd, EV_KEY, key_bits_, sizeof(key_bits_)))
|
| + return false;
|
| +
|
| + if (!GetEventBits(fd, EV_REL, rel_bits_, sizeof(rel_bits_)))
|
| + return false;
|
| +
|
| + if (!GetEventBits(fd, EV_ABS, abs_bits_, sizeof(abs_bits_)))
|
| + return false;
|
| +
|
| + if (!GetEventBits(fd, EV_MSC, msc_bits_, sizeof(msc_bits_)))
|
| + return false;
|
| +
|
| + if (!GetEventBits(fd, EV_SW, sw_bits_, sizeof(sw_bits_)))
|
| + return false;
|
| +
|
| + if (!GetEventBits(fd, EV_LED, led_bits_, sizeof(led_bits_)))
|
| + return false;
|
| +
|
| + if (!GetPropBits(fd, prop_bits_, sizeof(prop_bits_)))
|
| + return false;
|
| +
|
| + for (unsigned int i = 0; i < ABS_CNT; ++i)
|
| + if (HasAbsEvent(i))
|
| + if (!GetAbsInfo(fd, i, &abs_info_[i]))
|
| + return false;
|
| +
|
| + int max_num_slots = GetAbsMtSlotCount();
|
| +
|
| + // |request| is MT code + slots.
|
| + int32_t request[max_num_slots + 1];
|
| + int32_t* request_code = &request[0];
|
| + int32_t* request_slots = &request[1];
|
| + for (unsigned int i = EVDEV_ABS_MT_FIRST; i <= EVDEV_ABS_MT_LAST; ++i) {
|
| + if (!HasAbsEvent(i))
|
| + continue;
|
| +
|
| + memset(request, 0, sizeof(request));
|
| + *request_code = i;
|
| + if (!GetSlotValues(fd, request, max_num_slots + 1))
|
| + LOG(WARNING) << "Failed to get multitouch values for code " << i;
|
| +
|
| + std::vector<int32_t>* slots = &slot_values_[i - EVDEV_ABS_MT_FIRST];
|
| + slots->assign(request_slots, request_slots + max_num_slots);
|
| + }
|
| +
|
| + if (!GetDeviceName(fd, &name_))
|
| + return false;
|
| +
|
| + if (!GetDeviceIdentifiers(fd, &vendor_id_, &product_id_))
|
| + return false;
|
| +
|
| + return true;
|
| +}
|
| +
|
| +void EventDeviceInfo::SetEventTypes(const unsigned long* ev_bits, size_t len) {
|
| + AssignBitset(ev_bits, len, ev_bits_, arraysize(ev_bits_));
|
| +}
|
| +
|
| +void EventDeviceInfo::SetKeyEvents(const unsigned long* key_bits, size_t len) {
|
| + AssignBitset(key_bits, len, key_bits_, arraysize(key_bits_));
|
| +}
|
| +
|
| +void EventDeviceInfo::SetRelEvents(const unsigned long* rel_bits, size_t len) {
|
| + AssignBitset(rel_bits, len, rel_bits_, arraysize(rel_bits_));
|
| +}
|
| +
|
| +void EventDeviceInfo::SetAbsEvents(const unsigned long* abs_bits, size_t len) {
|
| + AssignBitset(abs_bits, len, abs_bits_, arraysize(abs_bits_));
|
| +}
|
| +
|
| +void EventDeviceInfo::SetMscEvents(const unsigned long* msc_bits, size_t len) {
|
| + AssignBitset(msc_bits, len, msc_bits_, arraysize(msc_bits_));
|
| +}
|
| +
|
| +void EventDeviceInfo::SetSwEvents(const unsigned long* sw_bits, size_t len) {
|
| + AssignBitset(sw_bits, len, sw_bits_, arraysize(sw_bits_));
|
| +}
|
| +
|
| +void EventDeviceInfo::SetLedEvents(const unsigned long* led_bits, size_t len) {
|
| + AssignBitset(led_bits, len, led_bits_, arraysize(led_bits_));
|
| +}
|
| +
|
| +void EventDeviceInfo::SetProps(const unsigned long* prop_bits, size_t len) {
|
| + AssignBitset(prop_bits, len, prop_bits_, arraysize(prop_bits_));
|
| +}
|
| +
|
| +void EventDeviceInfo::SetAbsInfo(unsigned int code,
|
| + const input_absinfo& abs_info) {
|
| + if (code > ABS_MAX)
|
| + return;
|
| +
|
| + memcpy(&abs_info_[code], &abs_info, sizeof(abs_info));
|
| +}
|
| +
|
| +void EventDeviceInfo::SetAbsMtSlots(unsigned int code,
|
| + const std::vector<int32_t>& values) {
|
| + DCHECK_EQ(GetAbsMtSlotCount(), values.size());
|
| + int index = code - EVDEV_ABS_MT_FIRST;
|
| + if (index < 0 || index >= EVDEV_ABS_MT_COUNT)
|
| + return;
|
| + slot_values_[index] = values;
|
| +}
|
| +
|
| +void EventDeviceInfo::SetAbsMtSlot(unsigned int code,
|
| + unsigned int slot,
|
| + uint32_t value) {
|
| + int index = code - EVDEV_ABS_MT_FIRST;
|
| + if (index < 0 || index >= EVDEV_ABS_MT_COUNT)
|
| + return;
|
| + slot_values_[index][slot] = value;
|
| +}
|
| +
|
| +bool EventDeviceInfo::HasEventType(unsigned int type) const {
|
| + if (type > EV_MAX)
|
| + return false;
|
| + return EvdevBitIsSet(ev_bits_, type);
|
| +}
|
| +
|
| +bool EventDeviceInfo::HasKeyEvent(unsigned int code) const {
|
| + if (code > KEY_MAX)
|
| + return false;
|
| + return EvdevBitIsSet(key_bits_, code);
|
| +}
|
| +
|
| +bool EventDeviceInfo::HasRelEvent(unsigned int code) const {
|
| + if (code > REL_MAX)
|
| + return false;
|
| + return EvdevBitIsSet(rel_bits_, code);
|
| +}
|
| +
|
| +bool EventDeviceInfo::HasAbsEvent(unsigned int code) const {
|
| + if (code > ABS_MAX)
|
| + return false;
|
| + return EvdevBitIsSet(abs_bits_, code);
|
| +}
|
| +
|
| +bool EventDeviceInfo::HasMscEvent(unsigned int code) const {
|
| + if (code > MSC_MAX)
|
| + return false;
|
| + return EvdevBitIsSet(msc_bits_, code);
|
| +}
|
| +
|
| +bool EventDeviceInfo::HasSwEvent(unsigned int code) const {
|
| + if (code > SW_MAX)
|
| + return false;
|
| + return EvdevBitIsSet(sw_bits_, code);
|
| +}
|
| +
|
| +bool EventDeviceInfo::HasLedEvent(unsigned int code) const {
|
| + if (code > LED_MAX)
|
| + return false;
|
| + return EvdevBitIsSet(led_bits_, code);
|
| +}
|
| +
|
| +bool EventDeviceInfo::HasProp(unsigned int code) const {
|
| + if (code > INPUT_PROP_MAX)
|
| + return false;
|
| + return EvdevBitIsSet(prop_bits_, code);
|
| +}
|
| +
|
| +int32_t EventDeviceInfo::GetAbsMinimum(unsigned int code) const {
|
| + return abs_info_[code].minimum;
|
| +}
|
| +
|
| +int32_t EventDeviceInfo::GetAbsMaximum(unsigned int code) const {
|
| + return abs_info_[code].maximum;
|
| +}
|
| +
|
| +int32_t EventDeviceInfo::GetAbsValue(unsigned int code) const {
|
| + return abs_info_[code].value;
|
| +}
|
| +
|
| +uint32_t EventDeviceInfo::GetAbsMtSlotCount() const {
|
| + if (!HasAbsEvent(ABS_MT_SLOT))
|
| + return 0;
|
| + return GetAbsMaximum(ABS_MT_SLOT) + 1;
|
| +}
|
| +
|
| +int32_t EventDeviceInfo::GetAbsMtSlotValue(unsigned int code,
|
| + unsigned int slot) const {
|
| + unsigned int index = code - EVDEV_ABS_MT_FIRST;
|
| + DCHECK(index < EVDEV_ABS_MT_COUNT);
|
| + return slot_values_[index][slot];
|
| +}
|
| +
|
| +int32_t EventDeviceInfo::GetAbsMtSlotValueWithDefault(
|
| + unsigned int code,
|
| + unsigned int slot,
|
| + int32_t default_value) const {
|
| + if (!HasAbsEvent(code))
|
| + return default_value;
|
| + return GetAbsMtSlotValue(code, slot);
|
| +}
|
| +
|
| +bool EventDeviceInfo::HasAbsXY() const {
|
| + return HasAbsEvent(ABS_X) && HasAbsEvent(ABS_Y);
|
| +}
|
| +
|
| +bool EventDeviceInfo::HasMTAbsXY() const {
|
| + return HasAbsEvent(ABS_MT_POSITION_X) && HasAbsEvent(ABS_MT_POSITION_Y);
|
| +}
|
| +
|
| +bool EventDeviceInfo::HasRelXY() const {
|
| + return HasRelEvent(REL_X) && HasRelEvent(REL_Y);
|
| +}
|
| +
|
| +bool EventDeviceInfo::HasMultitouch() const {
|
| + return HasAbsEvent(ABS_MT_SLOT);
|
| +}
|
| +
|
| +bool EventDeviceInfo::HasDirect() const {
|
| + bool has_direct = HasProp(INPUT_PROP_DIRECT);
|
| + bool has_pointer = HasProp(INPUT_PROP_POINTER);
|
| + if (has_direct || has_pointer)
|
| + return has_direct;
|
| +
|
| + switch (ProbeLegacyAbsoluteDevice()) {
|
| + case LegacyAbsoluteDeviceType::LADT_TOUCHSCREEN:
|
| + return true;
|
| +
|
| + case LegacyAbsoluteDeviceType::LADT_TABLET:
|
| + case LegacyAbsoluteDeviceType::LADT_TOUCHPAD:
|
| + case LegacyAbsoluteDeviceType::LADT_NONE:
|
| + return false;
|
| + }
|
| +
|
| + NOTREACHED();
|
| + return false;
|
| +}
|
| +
|
| +bool EventDeviceInfo::HasPointer() const {
|
| + bool has_direct = HasProp(INPUT_PROP_DIRECT);
|
| + bool has_pointer = HasProp(INPUT_PROP_POINTER);
|
| + if (has_direct || has_pointer)
|
| + return has_pointer;
|
| +
|
| + switch (ProbeLegacyAbsoluteDevice()) {
|
| + case LegacyAbsoluteDeviceType::LADT_TOUCHPAD:
|
| + case LegacyAbsoluteDeviceType::LADT_TABLET:
|
| + return true;
|
| +
|
| + case LegacyAbsoluteDeviceType::LADT_TOUCHSCREEN:
|
| + case LegacyAbsoluteDeviceType::LADT_NONE:
|
| + return false;
|
| + }
|
| +
|
| + NOTREACHED();
|
| + return false;
|
| +}
|
| +
|
| +bool EventDeviceInfo::HasStylus() const {
|
| + return HasKeyEvent(BTN_TOOL_PEN) || HasKeyEvent(BTN_STYLUS) ||
|
| + HasKeyEvent(BTN_STYLUS2);
|
| +}
|
| +
|
| +bool EventDeviceInfo::HasKeyboard() const {
|
| + if (!HasEventType(EV_KEY))
|
| + return false;
|
| +
|
| + // Check first 31 keys: If we have all of them, consider it a full
|
| + // keyboard. This is exactly what udev does for ID_INPUT_KEYBOARD.
|
| + for (int key = KEY_ESC; key <= KEY_D; ++key)
|
| + if (!HasKeyEvent(key))
|
| + return false;
|
| +
|
| + return true;
|
| +}
|
| +
|
| +bool EventDeviceInfo::HasMouse() const {
|
| + return HasRelXY();
|
| +}
|
| +
|
| +bool EventDeviceInfo::HasTouchpad() const {
|
| + return HasAbsXY() && HasPointer() && !HasStylus();
|
| +}
|
| +
|
| +bool EventDeviceInfo::HasTablet() const {
|
| + return HasAbsXY() && HasPointer() && HasStylus();
|
| +}
|
| +
|
| +bool EventDeviceInfo::HasTouchscreen() const {
|
| + return HasAbsXY() && HasDirect();
|
| +}
|
| +
|
| +EventDeviceInfo::LegacyAbsoluteDeviceType
|
| +EventDeviceInfo::ProbeLegacyAbsoluteDevice() const {
|
| + if (!HasAbsXY())
|
| + return LegacyAbsoluteDeviceType::LADT_NONE;
|
| +
|
| + if (HasStylus())
|
| + return LegacyAbsoluteDeviceType::LADT_TABLET;
|
| +
|
| + if (HasKeyEvent(BTN_TOOL_FINGER) && HasKeyEvent(BTN_TOUCH))
|
| + return LegacyAbsoluteDeviceType::LADT_TOUCHPAD;
|
| +
|
| + if (HasKeyEvent(BTN_TOUCH) || HasKeyEvent(BTN_LEFT))
|
| + return LegacyAbsoluteDeviceType::LADT_TOUCHSCREEN;
|
| +
|
| + return LegacyAbsoluteDeviceType::LADT_NONE;
|
| +}
|
| +
|
| +} // namespace ui
|
|
|