| Index: ui/events/ozone/evdev/event_converter_evdev_impl.cc
|
| diff --git a/ui/events/ozone/evdev/event_converter_evdev_impl.cc b/ui/events/ozone/evdev/event_converter_evdev_impl.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..0c532d5096856f3023eddd57d1dd20f61c208c1c
|
| --- /dev/null
|
| +++ b/ui/events/ozone/evdev/event_converter_evdev_impl.cc
|
| @@ -0,0 +1,247 @@
|
| +// Copyright 2014 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_converter_evdev_impl.h"
|
| +
|
| +#include <errno.h>
|
| +#include <linux/input.h>
|
| +
|
| +#include "base/trace_event/trace_event.h"
|
| +#include "ui/events/event.h"
|
| +#include "ui/events/event_utils.h"
|
| +#include "ui/events/keycodes/dom/keycode_converter.h"
|
| +#include "ui/events/ozone/evdev/device_event_dispatcher_evdev.h"
|
| +#include "ui/events/ozone/evdev/keyboard_util_evdev.h"
|
| +
|
| +namespace ui {
|
| +
|
| +namespace {
|
| +
|
| +// Values for EV_KEY.
|
| +const int kKeyReleaseValue = 0;
|
| +const int kKeyRepeatValue = 2;
|
| +
|
| +} // namespace
|
| +
|
| +EventConverterEvdevImpl::EventConverterEvdevImpl(
|
| + int fd,
|
| + base::FilePath path,
|
| + int id,
|
| + InputDeviceType type,
|
| + const EventDeviceInfo& devinfo,
|
| + CursorDelegateEvdev* cursor,
|
| + DeviceEventDispatcherEvdev* dispatcher)
|
| + : EventConverterEvdev(fd,
|
| + path,
|
| + id,
|
| + type,
|
| + devinfo.name(),
|
| + devinfo.vendor_id(),
|
| + devinfo.product_id()),
|
| + has_keyboard_(devinfo.HasKeyboard()),
|
| + has_touchpad_(devinfo.HasTouchpad()),
|
| + has_caps_lock_led_(devinfo.HasLedEvent(LED_CAPSL)),
|
| + cursor_(cursor),
|
| + dispatcher_(dispatcher) {
|
| +}
|
| +
|
| +EventConverterEvdevImpl::~EventConverterEvdevImpl() {
|
| + DCHECK(!enabled_);
|
| + close(fd_);
|
| +}
|
| +
|
| +void EventConverterEvdevImpl::OnFileCanReadWithoutBlocking(int fd) {
|
| + TRACE_EVENT1("evdev", "EventConverterEvdevImpl::OnFileCanReadWithoutBlocking",
|
| + "fd", fd);
|
| +
|
| + input_event inputs[4];
|
| + ssize_t read_size = read(fd, inputs, sizeof(inputs));
|
| + if (read_size < 0) {
|
| + if (errno == EINTR || errno == EAGAIN)
|
| + return;
|
| + if (errno != ENODEV)
|
| + PLOG(ERROR) << "error reading device " << path_.value();
|
| + Stop();
|
| + return;
|
| + }
|
| +
|
| + if (!enabled_)
|
| + return;
|
| +
|
| + DCHECK_EQ(read_size % sizeof(*inputs), 0u);
|
| + ProcessEvents(inputs, read_size / sizeof(*inputs));
|
| +}
|
| +
|
| +bool EventConverterEvdevImpl::HasKeyboard() const {
|
| + return has_keyboard_;
|
| +}
|
| +
|
| +bool EventConverterEvdevImpl::HasTouchpad() const {
|
| + return has_touchpad_;
|
| +}
|
| +
|
| +bool EventConverterEvdevImpl::HasCapsLockLed() const {
|
| + return has_caps_lock_led_;
|
| +}
|
| +
|
| +void EventConverterEvdevImpl::SetKeyFilter(bool enable_filter,
|
| + std::vector<DomCode> allowed_keys) {
|
| + if (!enable_filter) {
|
| + blocked_keys_.reset();
|
| + return;
|
| + }
|
| +
|
| + blocked_keys_.set();
|
| + for (const DomCode& it : allowed_keys) {
|
| + int evdev_code =
|
| + NativeCodeToEvdevCode(KeycodeConverter::DomCodeToNativeKeycode(it));
|
| + blocked_keys_.reset(evdev_code);
|
| + }
|
| +
|
| + // Release any pressed blocked keys.
|
| + base::TimeDelta timestamp = ui::EventTimeForNow();
|
| + for (int key = 0; key < KEY_CNT; ++key) {
|
| + if (blocked_keys_.test(key))
|
| + OnKeyChange(key, false /* down */, timestamp);
|
| + }
|
| +}
|
| +
|
| +void EventConverterEvdevImpl::OnDisabled() {
|
| + ReleaseKeys();
|
| + ReleaseMouseButtons();
|
| +}
|
| +
|
| +void EventConverterEvdevImpl::ProcessEvents(const input_event* inputs,
|
| + int count) {
|
| + for (int i = 0; i < count; ++i) {
|
| + const input_event& input = inputs[i];
|
| + switch (input.type) {
|
| + case EV_KEY:
|
| + ConvertKeyEvent(input);
|
| + break;
|
| + case EV_REL:
|
| + ConvertMouseMoveEvent(input);
|
| + break;
|
| + case EV_SYN:
|
| + if (input.code == SYN_DROPPED)
|
| + OnLostSync();
|
| + else if (input.code == SYN_REPORT)
|
| + FlushEvents(input);
|
| + break;
|
| + }
|
| + }
|
| +}
|
| +
|
| +void EventConverterEvdevImpl::ConvertKeyEvent(const input_event& input) {
|
| + // Ignore repeat events.
|
| + if (input.value == kKeyRepeatValue)
|
| + return;
|
| +
|
| + // Mouse processing.
|
| + if (input.code >= BTN_MOUSE && input.code < BTN_JOYSTICK) {
|
| + DispatchMouseButton(input);
|
| + return;
|
| + }
|
| +
|
| + // Keyboard processing.
|
| + OnKeyChange(input.code, input.value != kKeyReleaseValue,
|
| + TimeDeltaFromInputEvent(input));
|
| +}
|
| +
|
| +void EventConverterEvdevImpl::ConvertMouseMoveEvent(const input_event& input) {
|
| + if (!cursor_)
|
| + return;
|
| + switch (input.code) {
|
| + case REL_X:
|
| + x_offset_ = input.value;
|
| + break;
|
| + case REL_Y:
|
| + y_offset_ = input.value;
|
| + break;
|
| + }
|
| +}
|
| +
|
| +void EventConverterEvdevImpl::OnKeyChange(unsigned int key,
|
| + bool down,
|
| + const base::TimeDelta& timestamp) {
|
| + if (key > KEY_MAX)
|
| + return;
|
| +
|
| + if (down == key_state_.test(key))
|
| + return;
|
| +
|
| + // Apply key filter (releases for previously pressed keys are excepted).
|
| + if (down && blocked_keys_.test(key))
|
| + return;
|
| +
|
| + // State transition: !(down) -> (down)
|
| + key_state_.set(key, down);
|
| +
|
| + dispatcher_->DispatchKeyEvent(KeyEventParams(input_device_.id, key, down,
|
| + false /* suppress_auto_repeat */,
|
| + timestamp));
|
| +}
|
| +
|
| +void EventConverterEvdevImpl::ReleaseKeys() {
|
| + base::TimeDelta timestamp = ui::EventTimeForNow();
|
| + for (int key = 0; key < KEY_CNT; ++key)
|
| + OnKeyChange(key, false /* down */, timestamp);
|
| +}
|
| +
|
| +void EventConverterEvdevImpl::ReleaseMouseButtons() {
|
| + base::TimeDelta timestamp = ui::EventTimeForNow();
|
| + for (int code = BTN_MOUSE; code < BTN_JOYSTICK; ++code)
|
| + OnButtonChange(code, false /* down */, timestamp);
|
| +}
|
| +
|
| +void EventConverterEvdevImpl::OnLostSync() {
|
| + LOG(WARNING) << "kernel dropped input events";
|
| +
|
| + // We may have missed key releases. Release everything.
|
| + // TODO(spang): Use EVIOCGKEY to avoid releasing keys that are still held.
|
| + ReleaseKeys();
|
| + ReleaseMouseButtons();
|
| +}
|
| +
|
| +void EventConverterEvdevImpl::DispatchMouseButton(const input_event& input) {
|
| + if (!cursor_)
|
| + return;
|
| +
|
| + OnButtonChange(input.code, input.value, TimeDeltaFromInputEvent(input));
|
| +}
|
| +
|
| +void EventConverterEvdevImpl::OnButtonChange(int code,
|
| + bool down,
|
| + const base::TimeDelta& timestamp) {
|
| + if (code == BTN_SIDE)
|
| + code = BTN_BACK;
|
| + else if (code == BTN_EXTRA)
|
| + code = BTN_FORWARD;
|
| +
|
| + int button_offset = code - BTN_MOUSE;
|
| + if (mouse_button_state_.test(button_offset) == down)
|
| + return;
|
| +
|
| + mouse_button_state_.set(button_offset, down);
|
| +
|
| + dispatcher_->DispatchMouseButtonEvent(MouseButtonEventParams(
|
| + input_device_.id, cursor_->GetLocation(), code, down,
|
| + /* allow_remap */ true, timestamp));
|
| +}
|
| +
|
| +void EventConverterEvdevImpl::FlushEvents(const input_event& input) {
|
| + if (!cursor_ || (x_offset_ == 0 && y_offset_ == 0))
|
| + return;
|
| +
|
| + cursor_->MoveCursor(gfx::Vector2dF(x_offset_, y_offset_));
|
| +
|
| + dispatcher_->DispatchMouseMoveEvent(
|
| + MouseMoveEventParams(input_device_.id, cursor_->GetLocation(),
|
| + TimeDeltaFromInputEvent(input)));
|
| +
|
| + x_offset_ = 0;
|
| + y_offset_ = 0;
|
| +}
|
| +
|
| +} // namespace ui
|
|
|