Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / ui / events / ozone / evdev / event_converter_evdev_impl.cc
blobebc77fa2771cda1cd8dcf772e870f4817dd6c788
1 // Copyright 2014 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_converter_evdev_impl.h"
7 #include <errno.h>
8 #include <linux/input.h>
10 #include "base/trace_event/trace_event.h"
11 #include "ui/events/event.h"
12 #include "ui/events/event_utils.h"
13 #include "ui/events/keycodes/dom/keycode_converter.h"
14 #include "ui/events/ozone/evdev/device_event_dispatcher_evdev.h"
15 #include "ui/events/ozone/evdev/keyboard_util_evdev.h"
17 namespace ui {
19 namespace {
21 // Values for EV_KEY.
22 const int kKeyReleaseValue = 0;
23 const int kKeyRepeatValue = 2;
25 } // namespace
27 EventConverterEvdevImpl::EventConverterEvdevImpl(
28 int fd,
29 base::FilePath path,
30 int id,
31 const EventDeviceInfo& devinfo,
32 CursorDelegateEvdev* cursor,
33 DeviceEventDispatcherEvdev* dispatcher)
34 : EventConverterEvdev(fd,
35 path,
36 id,
37 devinfo.device_type(),
38 devinfo.name(),
39 devinfo.vendor_id(),
40 devinfo.product_id()),
41 has_keyboard_(devinfo.HasKeyboard()),
42 has_touchpad_(devinfo.HasTouchpad()),
43 has_caps_lock_led_(devinfo.HasLedEvent(LED_CAPSL)),
44 cursor_(cursor),
45 dispatcher_(dispatcher) {
48 EventConverterEvdevImpl::~EventConverterEvdevImpl() {
49 DCHECK(!enabled_);
50 close(fd_);
53 void EventConverterEvdevImpl::OnFileCanReadWithoutBlocking(int fd) {
54 TRACE_EVENT1("evdev", "EventConverterEvdevImpl::OnFileCanReadWithoutBlocking",
55 "fd", fd);
57 input_event inputs[4];
58 ssize_t read_size = read(fd, inputs, sizeof(inputs));
59 if (read_size < 0) {
60 if (errno == EINTR || errno == EAGAIN)
61 return;
62 if (errno != ENODEV)
63 PLOG(ERROR) << "error reading device " << path_.value();
64 Stop();
65 return;
68 if (!enabled_)
69 return;
71 DCHECK_EQ(read_size % sizeof(*inputs), 0u);
72 ProcessEvents(inputs, read_size / sizeof(*inputs));
75 bool EventConverterEvdevImpl::HasKeyboard() const {
76 return has_keyboard_;
79 bool EventConverterEvdevImpl::HasTouchpad() const {
80 return has_touchpad_;
83 bool EventConverterEvdevImpl::HasCapsLockLed() const {
84 return has_caps_lock_led_;
87 void EventConverterEvdevImpl::SetKeyFilter(bool enable_filter,
88 std::vector<DomCode> allowed_keys) {
89 if (!enable_filter) {
90 blocked_keys_.reset();
91 return;
94 blocked_keys_.set();
95 for (const DomCode& it : allowed_keys) {
96 int evdev_code =
97 NativeCodeToEvdevCode(KeycodeConverter::DomCodeToNativeKeycode(it));
98 blocked_keys_.reset(evdev_code);
101 // Release any pressed blocked keys.
102 base::TimeDelta timestamp = ui::EventTimeForNow();
103 for (int key = 0; key < KEY_CNT; ++key) {
104 if (blocked_keys_.test(key))
105 OnKeyChange(key, false /* down */, timestamp);
109 void EventConverterEvdevImpl::OnDisabled() {
110 ReleaseKeys();
111 ReleaseMouseButtons();
114 void EventConverterEvdevImpl::ProcessEvents(const input_event* inputs,
115 int count) {
116 for (int i = 0; i < count; ++i) {
117 const input_event& input = inputs[i];
118 switch (input.type) {
119 case EV_KEY:
120 ConvertKeyEvent(input);
121 break;
122 case EV_REL:
123 ConvertMouseMoveEvent(input);
124 break;
125 case EV_SYN:
126 if (input.code == SYN_DROPPED)
127 OnLostSync();
128 else if (input.code == SYN_REPORT)
129 FlushEvents(input);
130 break;
135 void EventConverterEvdevImpl::ConvertKeyEvent(const input_event& input) {
136 // Ignore repeat events.
137 if (input.value == kKeyRepeatValue)
138 return;
140 // Mouse processing.
141 if (input.code >= BTN_MOUSE && input.code < BTN_JOYSTICK) {
142 DispatchMouseButton(input);
143 return;
146 // Keyboard processing.
147 OnKeyChange(input.code, input.value != kKeyReleaseValue,
148 TimeDeltaFromInputEvent(input));
151 void EventConverterEvdevImpl::ConvertMouseMoveEvent(const input_event& input) {
152 if (!cursor_)
153 return;
154 switch (input.code) {
155 case REL_X:
156 x_offset_ = input.value;
157 break;
158 case REL_Y:
159 y_offset_ = input.value;
160 break;
164 void EventConverterEvdevImpl::OnKeyChange(unsigned int key,
165 bool down,
166 const base::TimeDelta& timestamp) {
167 if (key > KEY_MAX)
168 return;
170 if (down == key_state_.test(key))
171 return;
173 // Apply key filter (releases for previously pressed keys are excepted).
174 if (down && blocked_keys_.test(key))
175 return;
177 // State transition: !(down) -> (down)
178 key_state_.set(key, down);
180 dispatcher_->DispatchKeyEvent(KeyEventParams(input_device_.id, key, down,
181 false /* suppress_auto_repeat */,
182 timestamp));
185 void EventConverterEvdevImpl::ReleaseKeys() {
186 base::TimeDelta timestamp = ui::EventTimeForNow();
187 for (int key = 0; key < KEY_CNT; ++key)
188 OnKeyChange(key, false /* down */, timestamp);
191 void EventConverterEvdevImpl::ReleaseMouseButtons() {
192 base::TimeDelta timestamp = ui::EventTimeForNow();
193 for (int code = BTN_MOUSE; code < BTN_JOYSTICK; ++code)
194 OnButtonChange(code, false /* down */, timestamp);
197 void EventConverterEvdevImpl::OnLostSync() {
198 LOG(WARNING) << "kernel dropped input events";
200 // We may have missed key releases. Release everything.
201 // TODO(spang): Use EVIOCGKEY to avoid releasing keys that are still held.
202 ReleaseKeys();
203 ReleaseMouseButtons();
206 void EventConverterEvdevImpl::DispatchMouseButton(const input_event& input) {
207 if (!cursor_)
208 return;
210 OnButtonChange(input.code, input.value, TimeDeltaFromInputEvent(input));
213 void EventConverterEvdevImpl::OnButtonChange(int code,
214 bool down,
215 const base::TimeDelta& timestamp) {
216 if (code == BTN_SIDE)
217 code = BTN_BACK;
218 else if (code == BTN_EXTRA)
219 code = BTN_FORWARD;
221 int button_offset = code - BTN_MOUSE;
222 if (mouse_button_state_.test(button_offset) == down)
223 return;
225 mouse_button_state_.set(button_offset, down);
227 dispatcher_->DispatchMouseButtonEvent(MouseButtonEventParams(
228 input_device_.id, cursor_->GetLocation(), code, down,
229 /* allow_remap */ true, timestamp));
232 void EventConverterEvdevImpl::FlushEvents(const input_event& input) {
233 if (!cursor_ || (x_offset_ == 0 && y_offset_ == 0))
234 return;
236 cursor_->MoveCursor(gfx::Vector2dF(x_offset_, y_offset_));
238 dispatcher_->DispatchMouseMoveEvent(
239 MouseMoveEventParams(input_device_.id, cursor_->GetLocation(),
240 TimeDeltaFromInputEvent(input)));
242 x_offset_ = 0;
243 y_offset_ = 0;
246 } // namespace ui