| OLD | NEW |
| (Empty) | |
| 1 // Copyright 2017 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/gamepad_event_converter_evdev.h" |
| 6 |
| 7 #include <errno.h> |
| 8 #include <linux/input.h> |
| 9 #include <stddef.h> |
| 10 |
| 11 #include "base/trace_event/trace_event.h" |
| 12 #include "ui/events/event_utils.h" |
| 13 #include "ui/events/ozone/evdev/device_event_dispatcher_evdev.h" |
| 14 #include "ui/events/ozone/evdev/scoped_input_device.h" |
| 15 #include "ui/events/ozone/gamepad/gamepad_event.h" |
| 16 #include "ui/events/ozone/gamepad/gamepad_provider_ozone.h" |
| 17 #include "ui/events/ozone/gamepad/webgamepad_constants.h" |
| 18 |
| 19 namespace { |
| 20 constexpr double kHatThreshold = 0.5; |
| 21 } |
| 22 |
| 23 namespace ui { |
| 24 |
| 25 GamepadEventConverterEvdev::Axis::Axis() |
| 26 : last_value_(0.), |
| 27 scale_(0.), |
| 28 offset_(0.), |
| 29 scaled_fuzz_(0.), |
| 30 scaled_flat_(0.), |
| 31 mapped_type_(GamepadEventType::BUTTON), |
| 32 mapped_code_(0.) {} |
| 33 |
| 34 GamepadEventConverterEvdev::Axis::Axis(const input_absinfo& abs_info, |
| 35 GamepadEventType mapped_type, |
| 36 uint16_t mapped_code) |
| 37 : mapped_type_(mapped_type), mapped_code_(mapped_code) { |
| 38 double mapped_abs_min = kWebGamepadJoystickMin; |
| 39 double mapped_abs_max = kWebGamepadJoystickMax; |
| 40 // If the mapped event is a trigger, we set the min and max to trigger |
| 41 // min/max. |
| 42 if (mapped_code == WG_BUTTON_LT || mapped_code == WG_BUTTON_RT) { |
| 43 mapped_abs_min = kWebGamepadTriggerMin; |
| 44 mapped_abs_max = kWebGamepadTriggerMax; |
| 45 } |
| 46 |
| 47 scale_ = |
| 48 (mapped_abs_max - mapped_abs_min) / (abs_info.maximum - abs_info.minimum); |
| 49 offset_ = (abs_info.maximum + abs_info.minimum) / |
| 50 (mapped_abs_max - mapped_abs_min) * scale_ * mapped_abs_min; |
| 51 |
| 52 scaled_flat_ = abs_info.flat * scale_; |
| 53 scaled_fuzz_ = abs_info.fuzz * scale_; |
| 54 double tmp; |
| 55 // Map the current value and it will be set to value_. |
| 56 MapValue(abs_info.value, &tmp); |
| 57 } |
| 58 |
| 59 bool GamepadEventConverterEvdev::Axis::MapValue(uint16_t value, |
| 60 double* mapped_value) { |
| 61 *mapped_value = value * scale_ + offset_; |
| 62 // As the definition of linux input_absinfo.flat, value within the range of |
| 63 // flat should be seen as zero. |
| 64 if ((*mapped_value < scaled_flat_) && (*mapped_value > -scaled_flat_)) { |
| 65 *mapped_value = 0.0; |
| 66 // We always send out flat. |
| 67 last_value_ = 0.0; |
| 68 return true; |
| 69 } |
| 70 return ValueChangeSignificantly(*mapped_value); |
| 71 } |
| 72 |
| 73 GamepadEventType GamepadEventConverterEvdev::Axis::mapped_type() { |
| 74 return mapped_type_; |
| 75 } |
| 76 |
| 77 uint16_t GamepadEventConverterEvdev::Axis::mapped_code() { |
| 78 return mapped_code_; |
| 79 } |
| 80 |
| 81 bool GamepadEventConverterEvdev::Axis::ValueChangeSignificantly( |
| 82 double new_value) { |
| 83 // To remove noise, the value must change at least by fuzz. |
| 84 if (new_value >= last_value_ - scaled_fuzz_ && |
| 85 new_value <= last_value_ + scaled_fuzz_) { |
| 86 return false; |
| 87 } |
| 88 last_value_ = new_value; |
| 89 return true; |
| 90 } |
| 91 |
| 92 GamepadEventConverterEvdev::GamepadEventConverterEvdev( |
| 93 ScopedInputDevice fd, |
| 94 base::FilePath path, |
| 95 int id, |
| 96 const EventDeviceInfo& devinfo, |
| 97 DeviceEventDispatcherEvdev* dispatcher) |
| 98 : EventConverterEvdev(fd.get(), |
| 99 path, |
| 100 id, |
| 101 devinfo.device_type(), |
| 102 devinfo.name(), |
| 103 devinfo.vendor_id(), |
| 104 devinfo.product_id()), |
| 105 will_send_frame_(false), |
| 106 last_hat_left_press_(false), |
| 107 last_hat_right_press_(false), |
| 108 last_hat_up_press_(false), |
| 109 last_hat_down_press_(false), |
| 110 mapper_(GetGamepadMapper(devinfo.vendor_id(), devinfo.product_id())), |
| 111 input_device_fd_(std::move(fd)), |
| 112 dispatcher_(dispatcher) { |
| 113 input_absinfo abs_info; |
| 114 GamepadEventType mapped_type; |
| 115 uint16_t mapped_code; |
| 116 // In order to map gamepad, we have to save the abs_info from device_info |
| 117 // and get the gamepad_mapping. |
| 118 for (int code = 0; code < ABS_CNT; ++code) { |
| 119 abs_info = devinfo.GetAbsInfoByCode(code); |
| 120 if (devinfo.HasAbsEvent(code)) { |
| 121 // If fuzz was reported as zero, it will be set to flat * 0.25f. It is |
| 122 // the same thing done in Android InputReader.cpp. See: |
| 123 // frameworks/native/services/inputflinger/InputReader.cpp line 6988 for |
| 124 // more details. |
| 125 if (abs_info.fuzz == 0) { |
| 126 abs_info.fuzz = abs_info.flat * 0.25f; |
| 127 } |
| 128 mapper_(EV_ABS, code, &mapped_type, &mapped_code); |
| 129 axes_[code] = Axis(abs_info, mapped_type, mapped_code); |
| 130 } |
| 131 } |
| 132 } |
| 133 |
| 134 GamepadEventConverterEvdev::~GamepadEventConverterEvdev() { |
| 135 DCHECK(!enabled_); |
| 136 } |
| 137 |
| 138 bool GamepadEventConverterEvdev::HasGamepad() const { |
| 139 return true; |
| 140 } |
| 141 |
| 142 void GamepadEventConverterEvdev::OnFileCanReadWithoutBlocking(int fd) { |
| 143 TRACE_EVENT1("evdev", |
| 144 "GamepadEventConverterEvdev::OnFileCanReadWithoutBlocking", "fd", |
| 145 fd); |
| 146 while (true) { |
| 147 input_event input; |
| 148 ssize_t read_size = read(fd, &input, sizeof(input)); |
| 149 if (read_size != sizeof(input)) { |
| 150 if (errno == EINTR || errno == EAGAIN) |
| 151 return; |
| 152 if (errno != ENODEV) |
| 153 PLOG(ERROR) << "error reading device " << path_.value(); |
| 154 Stop(); |
| 155 return; |
| 156 } |
| 157 |
| 158 if (!enabled_) |
| 159 return; |
| 160 |
| 161 ProcessEvent(input); |
| 162 } |
| 163 } |
| 164 void GamepadEventConverterEvdev::OnDisabled() { |
| 165 ResetGamepad(); |
| 166 } |
| 167 |
| 168 void GamepadEventConverterEvdev::ProcessEvent(const input_event& evdev_ev) { |
| 169 base::TimeTicks timestamp = TimeTicksFromInputEvent(evdev_ev); |
| 170 // We may have missed Gamepad releases. Reset everything. |
| 171 // If the event is sync, we send a frame. |
| 172 if (evdev_ev.type == EV_SYN) { |
| 173 if (evdev_ev.code == SYN_DROPPED) { |
| 174 LOG(WARNING) << "kernel dropped input events"; |
| 175 ResyncGamepad(); |
| 176 } else if (evdev_ev.code == SYN_REPORT) { |
| 177 OnSync(timestamp); |
| 178 } |
| 179 } else if (evdev_ev.type == EV_KEY) { |
| 180 ProcessEvdevKey(evdev_ev.code, evdev_ev.value, timestamp); |
| 181 } else if (evdev_ev.type == EV_ABS) { |
| 182 ProcessEvdevAbs(evdev_ev.code, evdev_ev.value, timestamp); |
| 183 } |
| 184 } |
| 185 |
| 186 void GamepadEventConverterEvdev::ProcessEvdevKey( |
| 187 uint16_t code, |
| 188 uint16_t value, |
| 189 const base::TimeTicks& timestamp) { |
| 190 GamepadEventType mapped_type; |
| 191 uint16_t mapped_code; |
| 192 |
| 193 bool found_map = mapper_(EV_KEY, code, &mapped_type, &mapped_code); |
| 194 |
| 195 // If we cannot find a map for this event, it will be discarded. |
| 196 if (!found_map) { |
| 197 return; |
| 198 } |
| 199 |
| 200 // If it's btn -> btn mapping, we can send the event and return now. |
| 201 OnButtonChange(mapped_code, value, timestamp); |
| 202 } |
| 203 |
| 204 void GamepadEventConverterEvdev::ProcessEvdevAbs( |
| 205 uint16_t code, |
| 206 uint16_t value, |
| 207 const base::TimeTicks& timestamp) { |
| 208 GamepadEventType mapped_type; |
| 209 uint16_t mapped_code; |
| 210 |
| 211 double mapped_abs_value; |
| 212 Axis& axis = axes_[code]; |
| 213 mapped_type = axis.mapped_type(); |
| 214 mapped_code = axis.mapped_code(); |
| 215 |
| 216 if (!axis.MapValue(value, &mapped_abs_value)) { |
| 217 return; |
| 218 } |
| 219 |
| 220 // If the mapped type is abs, we can send it now. |
| 221 if (mapped_type == GamepadEventType::AXIS) { |
| 222 OnAbsChange(mapped_code, mapped_abs_value, timestamp); |
| 223 return; |
| 224 } |
| 225 |
| 226 // We need to map HAT to DPAD depend on the state of the axis. |
| 227 if (mapped_code == kHAT_X) { |
| 228 bool hat_left_press = (mapped_abs_value < -kHatThreshold); |
| 229 bool hat_right_press = (mapped_abs_value > kHatThreshold); |
| 230 if (hat_left_press != last_hat_left_press_) { |
| 231 OnButtonChange(WG_BUTTON_DPAD_LEFT, hat_left_press, timestamp); |
| 232 last_hat_left_press_ = hat_left_press; |
| 233 } |
| 234 |
| 235 if (hat_right_press != last_hat_right_press_) { |
| 236 OnButtonChange(WG_BUTTON_DPAD_RIGHT, hat_right_press, timestamp); |
| 237 last_hat_right_press_ = hat_right_press; |
| 238 } |
| 239 } else if (mapped_code == kHAT_Y) { |
| 240 bool hat_up_press = (mapped_abs_value < -kHatThreshold); |
| 241 bool hat_down_press = (mapped_abs_value > kHatThreshold); |
| 242 if (hat_up_press != last_hat_up_press_) { |
| 243 OnButtonChange(WG_BUTTON_DPAD_UP, hat_up_press, timestamp); |
| 244 last_hat_up_press_ = hat_up_press; |
| 245 } |
| 246 |
| 247 if (hat_down_press != last_hat_down_press_) { |
| 248 OnButtonChange(WG_BUTTON_DPAD_DOWN, hat_down_press, timestamp); |
| 249 last_hat_down_press_ = hat_down_press; |
| 250 } |
| 251 } else { |
| 252 OnButtonChange(mapped_code, mapped_abs_value, timestamp); |
| 253 } |
| 254 } |
| 255 |
| 256 void GamepadEventConverterEvdev::ResetGamepad() { |
| 257 base::TimeTicks timestamp = ui::EventTimeForNow(); |
| 258 for (int btn_code = 0; btn_code < WG_BUTTON_COUNT; ++btn_code) { |
| 259 OnButtonChange(btn_code, 0, timestamp); |
| 260 } |
| 261 |
| 262 for (int abs_code = 0; abs_code < WG_ABS_COUNT; ++abs_code) { |
| 263 OnAbsChange(abs_code, 0, timestamp); |
| 264 } |
| 265 OnSync(timestamp); |
| 266 } |
| 267 |
| 268 void GamepadEventConverterEvdev::ResyncGamepad() { |
| 269 base::TimeTicks timestamp = ui::EventTimeForNow(); |
| 270 // Reset all the buttons to 0. |
| 271 for (int btn_code = 0; btn_code < WG_BUTTON_COUNT; ++btn_code) { |
| 272 OnButtonChange(btn_code, 0, timestamp); |
| 273 } |
| 274 // Read the state of all axis. |
| 275 EventDeviceInfo info; |
| 276 if (!info.Initialize(fd_, path_)) { |
| 277 LOG(ERROR) << "Failed to synchronize state for gamepad device: " |
| 278 << path_.value(); |
| 279 Stop(); |
| 280 return; |
| 281 } |
| 282 for (int code = 0; code < ABS_CNT; ++code) { |
| 283 if (info.HasAbsEvent(code)) { |
| 284 ProcessEvdevAbs(code, info.GetAbsValue(code), timestamp); |
| 285 } |
| 286 } |
| 287 OnSync(timestamp); |
| 288 } |
| 289 |
| 290 void GamepadEventConverterEvdev::OnButtonChange( |
| 291 unsigned int code, |
| 292 double value, |
| 293 const base::TimeTicks& timestamp) { |
| 294 GamepadEvent event(input_device_.id, GamepadEventType::BUTTON, code, value, |
| 295 timestamp); |
| 296 dispatcher_->DispatchGamepadEvent(event); |
| 297 will_send_frame_ = true; |
| 298 } |
| 299 |
| 300 void GamepadEventConverterEvdev::OnAbsChange(unsigned int code, |
| 301 double value, |
| 302 const base::TimeTicks& timestamp) { |
| 303 GamepadEvent event(input_device_.id, GamepadEventType::AXIS, code, value, |
| 304 timestamp); |
| 305 dispatcher_->DispatchGamepadEvent(event); |
| 306 will_send_frame_ = true; |
| 307 } |
| 308 |
| 309 void GamepadEventConverterEvdev::OnSync(const base::TimeTicks& timestamp) { |
| 310 if (will_send_frame_) { |
| 311 GamepadEvent event(input_device_.id, GamepadEventType::FRAME, 0, 0, |
| 312 timestamp); |
| 313 dispatcher_->DispatchGamepadEvent(event); |
| 314 will_send_frame_ = false; |
| 315 } |
| 316 } |
| 317 } // namespace ui |
| OLD | NEW |