OLD | NEW |
(Empty) | |
| 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. |
| 4 |
| 5 #include "ui/events/ozone/evdev/event_converter_evdev_impl.h" |
| 6 |
| 7 #include <errno.h> |
| 8 #include <linux/input.h> |
| 9 |
| 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" |
| 16 |
| 17 namespace ui { |
| 18 |
| 19 namespace { |
| 20 |
| 21 // Values for EV_KEY. |
| 22 const int kKeyReleaseValue = 0; |
| 23 const int kKeyRepeatValue = 2; |
| 24 |
| 25 } // namespace |
| 26 |
| 27 EventConverterEvdevImpl::EventConverterEvdevImpl( |
| 28 int fd, |
| 29 base::FilePath path, |
| 30 int id, |
| 31 InputDeviceType type, |
| 32 const EventDeviceInfo& devinfo, |
| 33 CursorDelegateEvdev* cursor, |
| 34 DeviceEventDispatcherEvdev* dispatcher) |
| 35 : EventConverterEvdev(fd, |
| 36 path, |
| 37 id, |
| 38 type, |
| 39 devinfo.name(), |
| 40 devinfo.vendor_id(), |
| 41 devinfo.product_id()), |
| 42 has_keyboard_(devinfo.HasKeyboard()), |
| 43 has_touchpad_(devinfo.HasTouchpad()), |
| 44 has_caps_lock_led_(devinfo.HasLedEvent(LED_CAPSL)), |
| 45 cursor_(cursor), |
| 46 dispatcher_(dispatcher) { |
| 47 } |
| 48 |
| 49 EventConverterEvdevImpl::~EventConverterEvdevImpl() { |
| 50 DCHECK(!enabled_); |
| 51 close(fd_); |
| 52 } |
| 53 |
| 54 void EventConverterEvdevImpl::OnFileCanReadWithoutBlocking(int fd) { |
| 55 TRACE_EVENT1("evdev", "EventConverterEvdevImpl::OnFileCanReadWithoutBlocking", |
| 56 "fd", fd); |
| 57 |
| 58 input_event inputs[4]; |
| 59 ssize_t read_size = read(fd, inputs, sizeof(inputs)); |
| 60 if (read_size < 0) { |
| 61 if (errno == EINTR || errno == EAGAIN) |
| 62 return; |
| 63 if (errno != ENODEV) |
| 64 PLOG(ERROR) << "error reading device " << path_.value(); |
| 65 Stop(); |
| 66 return; |
| 67 } |
| 68 |
| 69 if (!enabled_) |
| 70 return; |
| 71 |
| 72 DCHECK_EQ(read_size % sizeof(*inputs), 0u); |
| 73 ProcessEvents(inputs, read_size / sizeof(*inputs)); |
| 74 } |
| 75 |
| 76 bool EventConverterEvdevImpl::HasKeyboard() const { |
| 77 return has_keyboard_; |
| 78 } |
| 79 |
| 80 bool EventConverterEvdevImpl::HasTouchpad() const { |
| 81 return has_touchpad_; |
| 82 } |
| 83 |
| 84 bool EventConverterEvdevImpl::HasCapsLockLed() const { |
| 85 return has_caps_lock_led_; |
| 86 } |
| 87 |
| 88 void EventConverterEvdevImpl::SetKeyFilter(bool enable_filter, |
| 89 std::vector<DomCode> allowed_keys) { |
| 90 if (!enable_filter) { |
| 91 blocked_keys_.reset(); |
| 92 return; |
| 93 } |
| 94 |
| 95 blocked_keys_.set(); |
| 96 for (const DomCode& it : allowed_keys) { |
| 97 int evdev_code = |
| 98 NativeCodeToEvdevCode(KeycodeConverter::DomCodeToNativeKeycode(it)); |
| 99 blocked_keys_.reset(evdev_code); |
| 100 } |
| 101 |
| 102 // Release any pressed blocked keys. |
| 103 base::TimeDelta timestamp = ui::EventTimeForNow(); |
| 104 for (int key = 0; key < KEY_CNT; ++key) { |
| 105 if (blocked_keys_.test(key)) |
| 106 OnKeyChange(key, false /* down */, timestamp); |
| 107 } |
| 108 } |
| 109 |
| 110 void EventConverterEvdevImpl::OnDisabled() { |
| 111 ReleaseKeys(); |
| 112 ReleaseMouseButtons(); |
| 113 } |
| 114 |
| 115 void EventConverterEvdevImpl::ProcessEvents(const input_event* inputs, |
| 116 int count) { |
| 117 for (int i = 0; i < count; ++i) { |
| 118 const input_event& input = inputs[i]; |
| 119 switch (input.type) { |
| 120 case EV_KEY: |
| 121 ConvertKeyEvent(input); |
| 122 break; |
| 123 case EV_REL: |
| 124 ConvertMouseMoveEvent(input); |
| 125 break; |
| 126 case EV_SYN: |
| 127 if (input.code == SYN_DROPPED) |
| 128 OnLostSync(); |
| 129 else if (input.code == SYN_REPORT) |
| 130 FlushEvents(input); |
| 131 break; |
| 132 } |
| 133 } |
| 134 } |
| 135 |
| 136 void EventConverterEvdevImpl::ConvertKeyEvent(const input_event& input) { |
| 137 // Ignore repeat events. |
| 138 if (input.value == kKeyRepeatValue) |
| 139 return; |
| 140 |
| 141 // Mouse processing. |
| 142 if (input.code >= BTN_MOUSE && input.code < BTN_JOYSTICK) { |
| 143 DispatchMouseButton(input); |
| 144 return; |
| 145 } |
| 146 |
| 147 // Keyboard processing. |
| 148 OnKeyChange(input.code, input.value != kKeyReleaseValue, |
| 149 TimeDeltaFromInputEvent(input)); |
| 150 } |
| 151 |
| 152 void EventConverterEvdevImpl::ConvertMouseMoveEvent(const input_event& input) { |
| 153 if (!cursor_) |
| 154 return; |
| 155 switch (input.code) { |
| 156 case REL_X: |
| 157 x_offset_ = input.value; |
| 158 break; |
| 159 case REL_Y: |
| 160 y_offset_ = input.value; |
| 161 break; |
| 162 } |
| 163 } |
| 164 |
| 165 void EventConverterEvdevImpl::OnKeyChange(unsigned int key, |
| 166 bool down, |
| 167 const base::TimeDelta& timestamp) { |
| 168 if (key > KEY_MAX) |
| 169 return; |
| 170 |
| 171 if (down == key_state_.test(key)) |
| 172 return; |
| 173 |
| 174 // Apply key filter (releases for previously pressed keys are excepted). |
| 175 if (down && blocked_keys_.test(key)) |
| 176 return; |
| 177 |
| 178 // State transition: !(down) -> (down) |
| 179 key_state_.set(key, down); |
| 180 |
| 181 dispatcher_->DispatchKeyEvent(KeyEventParams(input_device_.id, key, down, |
| 182 false /* suppress_auto_repeat */, |
| 183 timestamp)); |
| 184 } |
| 185 |
| 186 void EventConverterEvdevImpl::ReleaseKeys() { |
| 187 base::TimeDelta timestamp = ui::EventTimeForNow(); |
| 188 for (int key = 0; key < KEY_CNT; ++key) |
| 189 OnKeyChange(key, false /* down */, timestamp); |
| 190 } |
| 191 |
| 192 void EventConverterEvdevImpl::ReleaseMouseButtons() { |
| 193 base::TimeDelta timestamp = ui::EventTimeForNow(); |
| 194 for (int code = BTN_MOUSE; code < BTN_JOYSTICK; ++code) |
| 195 OnButtonChange(code, false /* down */, timestamp); |
| 196 } |
| 197 |
| 198 void EventConverterEvdevImpl::OnLostSync() { |
| 199 LOG(WARNING) << "kernel dropped input events"; |
| 200 |
| 201 // We may have missed key releases. Release everything. |
| 202 // TODO(spang): Use EVIOCGKEY to avoid releasing keys that are still held. |
| 203 ReleaseKeys(); |
| 204 ReleaseMouseButtons(); |
| 205 } |
| 206 |
| 207 void EventConverterEvdevImpl::DispatchMouseButton(const input_event& input) { |
| 208 if (!cursor_) |
| 209 return; |
| 210 |
| 211 OnButtonChange(input.code, input.value, TimeDeltaFromInputEvent(input)); |
| 212 } |
| 213 |
| 214 void EventConverterEvdevImpl::OnButtonChange(int code, |
| 215 bool down, |
| 216 const base::TimeDelta& timestamp) { |
| 217 if (code == BTN_SIDE) |
| 218 code = BTN_BACK; |
| 219 else if (code == BTN_EXTRA) |
| 220 code = BTN_FORWARD; |
| 221 |
| 222 int button_offset = code - BTN_MOUSE; |
| 223 if (mouse_button_state_.test(button_offset) == down) |
| 224 return; |
| 225 |
| 226 mouse_button_state_.set(button_offset, down); |
| 227 |
| 228 dispatcher_->DispatchMouseButtonEvent(MouseButtonEventParams( |
| 229 input_device_.id, cursor_->GetLocation(), code, down, |
| 230 /* allow_remap */ true, timestamp)); |
| 231 } |
| 232 |
| 233 void EventConverterEvdevImpl::FlushEvents(const input_event& input) { |
| 234 if (!cursor_ || (x_offset_ == 0 && y_offset_ == 0)) |
| 235 return; |
| 236 |
| 237 cursor_->MoveCursor(gfx::Vector2dF(x_offset_, y_offset_)); |
| 238 |
| 239 dispatcher_->DispatchMouseMoveEvent( |
| 240 MouseMoveEventParams(input_device_.id, cursor_->GetLocation(), |
| 241 TimeDeltaFromInputEvent(input))); |
| 242 |
| 243 x_offset_ = 0; |
| 244 y_offset_ = 0; |
| 245 } |
| 246 |
| 247 } // namespace ui |
OLD | NEW |