Chromium Code Reviews| 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/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/devices/stylus_state.h" | |
| 13 #include "ui/events/event.h" | |
| 14 #include "ui/events/event_utils.h" | |
| 15 #include "ui/events/keycodes/dom/keycode_converter.h" | |
| 16 #include "ui/events/ozone/evdev/device_event_dispatcher_evdev.h" | |
| 17 #include "ui/events/ozone/evdev/scoped_input_device.h" | |
| 18 #include "ui/events/webgamepad_constants.h" | |
| 19 | |
| 20 namespace ui { | |
| 21 | |
| 22 GamepadEventConverterEvdev::GamepadEventConverterEvdev( | |
| 23 ScopedInputDevice fd, | |
| 24 base::FilePath path, | |
| 25 int id, | |
| 26 const EventDeviceInfo& devinfo, | |
| 27 DeviceEventDispatcherEvdev* dispatcher) | |
| 28 : EventConverterEvdev(fd.get(), | |
| 29 path, | |
| 30 id, | |
| 31 devinfo.device_type(), | |
| 32 devinfo.name(), | |
| 33 devinfo.vendor_id(), | |
| 34 devinfo.product_id()), | |
| 35 will_send_frame_(false), | |
| 36 input_device_fd_(std::move(fd)), | |
| 37 dispatcher_(dispatcher) { | |
| 38 // In order to map gamepad, we have to save the abs_info from device_info | |
| 39 // and get the gamepad_mapping. | |
| 40 for (int code = 0; code < ABS_CNT; ++code) { | |
| 41 abs_info_[code] = devinfo.GetAbsInfoByCode(code); | |
| 42 if (devinfo.HasAbsEvent(code)) { | |
| 43 // Set the minimum fuzz. For example, if min is 0 and max is 255, we can't | |
| 44 // determine if 127 is 0.0 or 128 is 0.0. We will just fuzz by one percent | |
| 45 // to make them both zero. If (max - min) is less than zero, we won't do | |
| 46 // this override because we don't want to cause too much error. | |
| 47 if (abs_info_[code].fuzz == 0) { | |
| 48 abs_info_[code].fuzz = | |
| 49 (abs_info_[code].maximum - abs_info_[code].minimum) / 100; | |
| 50 } | |
| 51 | |
| 52 // Some gamepad report garbage flat value. To map approprate value to | |
| 53 // exactly 0.0, we need the flat value to be fixed. We assume the flat is | |
| 54 // in the middle of minimum and maximum if it's not min. | |
| 55 if (abs_info_[code].flat != abs_info_[code].minimum) { | |
| 56 abs_info_[code].flat = | |
| 57 (abs_info_[code].maximum + abs_info_[code].minimum) / 2; | |
| 58 } | |
| 59 } | |
| 60 } | |
| 61 gamepad_mapping_ = | |
| 62 GetGamepadMapping(devinfo.vendor_id(), devinfo.product_id()); | |
| 63 } | |
| 64 | |
| 65 GamepadEventConverterEvdev::~GamepadEventConverterEvdev() { | |
| 66 DCHECK(!enabled_); | |
| 67 } | |
| 68 | |
| 69 bool GamepadEventConverterEvdev::HasGamepad() const { | |
| 70 return true; | |
| 71 } | |
| 72 | |
| 73 void GamepadEventConverterEvdev::OnFileCanReadWithoutBlocking(int fd) { | |
| 74 TRACE_EVENT1("evdev", | |
| 75 "GamepadEventConverterEvdev::OnFileCanReadWithoutBlocking", "fd", | |
| 76 fd); | |
| 77 while (true) { | |
| 78 input_event input; | |
| 79 ssize_t read_size = read(fd, &input, sizeof(input)); | |
| 80 if (read_size != sizeof(input)) { | |
| 81 if (errno == EINTR || errno == EAGAIN) | |
| 82 return; | |
| 83 if (errno != ENODEV) | |
| 84 PLOG(ERROR) << "error reading device " << path_.value(); | |
| 85 Stop(); | |
| 86 return; | |
| 87 } | |
| 88 | |
| 89 if (!enabled_) | |
| 90 return; | |
| 91 | |
| 92 ProcessEvent(input); | |
| 93 } | |
| 94 } | |
| 95 void GamepadEventConverterEvdev::OnDisabled() { | |
| 96 ResetGamepad(); | |
| 97 } | |
| 98 | |
| 99 void GamepadEventConverterEvdev::ProcessEvent(const input_event& evdev_ev) { | |
| 100 // We may have missed Gamepad releases. Reset everything. | |
| 101 // If the event is sync, we send a frame. | |
| 102 if (evdev_ev.type == EV_SYN) { | |
| 103 if (evdev_ev.code == SYN_DROPPED) { | |
| 104 LOG(WARNING) << "kernel dropped input events"; | |
| 105 ResetGamepad(); | |
|
spang
2017/04/13 00:52:19
Should sync using EVIOCGABS and EVIOCGKEY here.
jkwang
2017/04/19 19:42:23
Sounds reasonable. But this will be a rare corner
spang
2017/04/21 05:38:46
I still think we should do this right for absolute
jkwang
2017/04/25 21:16:41
Done.
| |
| 106 } else if (evdev_ev.code == SYN_REPORT) { | |
| 107 OnSync(TimeTicksFromInputEvent(evdev_ev)); | |
| 108 } | |
| 109 return; | |
| 110 } | |
| 111 | |
| 112 GamepadEventType mapped_type; | |
| 113 uint16_t mapped_code; | |
| 114 | |
| 115 // We are going to search the event in the mapping. | |
| 116 bool found_map = false; | |
| 117 for (size_t i = 0; i < gamepad_mapping_->size(); ++i) { | |
|
spang
2017/04/13 00:52:19
Can you do do the mapping once at startup so that
jkwang
2017/04/19 19:42:23
Done.
| |
| 118 const GamepadMappingEntry& map_entry_ = (*gamepad_mapping_)[i]; | |
| 119 if (evdev_ev.type == map_entry_.evdev_type && | |
| 120 evdev_ev.code == map_entry_.evdev_code) { | |
| 121 found_map = true; | |
| 122 mapped_type = map_entry_.mapped_type; | |
| 123 mapped_code = map_entry_.mapped_code; | |
| 124 } | |
| 125 } | |
| 126 | |
| 127 // If we cannot find a map for this event, it will be discarded. | |
| 128 if (!found_map) { | |
| 129 return; | |
| 130 } | |
| 131 | |
| 132 // If it's btn -> btn mapping, we can send the event and return now. | |
| 133 if (mapped_type == GamepadEventType::BUTTON && evdev_ev.type == EV_KEY) { | |
| 134 OnButtonChange(mapped_code, evdev_ev.value, | |
| 135 TimeTicksFromInputEvent(evdev_ev)); | |
| 136 return; | |
| 137 } | |
| 138 | |
| 139 double mapped_abs_value; | |
| 140 double mapped_abs_min = kWebGamepadJoystickMin; | |
| 141 double mapped_abs_max = kWebGamepadJoystickMax; | |
| 142 // If the mapped event is a trigger, we set the min and max to trigger | |
| 143 // min/max. | |
| 144 if (mapped_code == WG_BUTTON_L2 || mapped_code == WG_BUTTON_R2) { | |
|
spang
2017/04/21 05:38:46
Shouldn't this kind of stuff go in the mapping?
jkwang
2017/04/25 21:16:41
This is fixed, when the mapped axis is L2 or R2 th
| |
| 145 mapped_abs_min = kWebGamepadTriggerMin; | |
| 146 mapped_abs_max = kWebGamepadTriggerMax; | |
| 147 } | |
| 148 | |
| 149 // Code is out of ABS_MAX. This should not happen, but we don't want a gamepad | |
| 150 // reporting wrong values break the code. | |
| 151 if (evdev_ev.code < 0 || evdev_ev.code > ABS_MAX) { | |
| 152 return; | |
| 153 } | |
| 154 | |
| 155 struct input_absinfo& abs_info = abs_info_[evdev_ev.code]; | |
| 156 // To remove noise, the value must change at least by fuzz. | |
|
spang
2017/04/13 00:52:19
This is kinda odd, why do we get values within |fu
jkwang
2017/04/19 19:42:23
We have to read in the values and decide whether w
| |
| 157 if (evdev_ev.value > abs_info.value - abs_info.fuzz && | |
| 158 evdev_ev.value < abs_info.value + abs_info.fuzz) { | |
| 159 return; | |
| 160 } | |
| 161 | |
| 162 // Save the old value for later use. | |
| 163 int old_value = abs_info.value; | |
| 164 // If the value of input is within the range of [flat - fuzz, flat + fuzz], | |
| 165 // the value is discarded and we are going to use 0. | |
| 166 if (evdev_ev.value >= abs_info.flat - abs_info.fuzz && | |
| 167 evdev_ev.value <= abs_info.flat + abs_info.fuzz) { | |
| 168 abs_info.value = abs_info.flat; | |
| 169 mapped_abs_value = 0.0; | |
| 170 } else if (evdev_ev.value <= abs_info.minimum + abs_info.fuzz) { | |
| 171 // We are manually set min and max to ensure double value equals. | |
| 172 abs_info.value = abs_info.minimum; | |
| 173 mapped_abs_value = mapped_abs_min; | |
| 174 } else if (evdev_ev.value >= abs_info.maximum - abs_info.fuzz) { | |
| 175 abs_info.value = abs_info.maximum; | |
| 176 mapped_abs_value = mapped_abs_max; | |
| 177 } else { | |
| 178 abs_info.value = evdev_ev.value; | |
| 179 // Check if the min == max to avoid divide by zero. If min == max, we are | |
| 180 // going to discard this event. | |
| 181 if (abs_info.minimum == abs_info.maximum) { | |
| 182 return; | |
| 183 } | |
| 184 mapped_abs_value = | |
| 185 mapped_abs_min + | |
| 186 (mapped_abs_max - mapped_abs_min) * | |
| 187 static_cast<double>(evdev_ev.value - abs_info.minimum) / | |
| 188 static_cast<double>(abs_info.maximum - abs_info.minimum); | |
| 189 } | |
| 190 | |
| 191 // If the mapped type is abs, we can send it now. | |
| 192 if (mapped_type == GamepadEventType::AXIS) { | |
| 193 OnAbsChange(mapped_code, mapped_abs_value, | |
| 194 TimeTicksFromInputEvent(evdev_ev)); | |
| 195 return; | |
| 196 } | |
| 197 | |
| 198 // We need to map HAT to DPAD depend on the state of the axis. | |
| 199 if (mapped_code == kHAT_X) { | |
| 200 if (mapped_abs_value < 0.0 || | |
| 201 (mapped_abs_value == 0.0 && old_value < abs_info.flat)) { | |
| 202 // If current HAT_X is < 0 or it was <0 before it's dpad left. | |
| 203 mapped_code = WG_BUTTON_DPAD_LEFT; | |
| 204 } else { | |
| 205 mapped_code = WG_BUTTON_DPAD_RIGHT; | |
| 206 } | |
| 207 } else if (mapped_code == kHAT_Y) { | |
| 208 if (mapped_abs_value < 0 || | |
| 209 (mapped_abs_value == 0.0 && old_value < abs_info.flat)) { | |
| 210 mapped_code = WG_BUTTON_DPAD_UP; | |
| 211 } else { | |
| 212 mapped_code = WG_BUTTON_DPAD_DOWN; | |
| 213 } | |
| 214 } | |
| 215 OnButtonChange(mapped_code, mapped_abs_value, | |
| 216 TimeTicksFromInputEvent(evdev_ev)); | |
| 217 } | |
| 218 | |
| 219 void GamepadEventConverterEvdev::ResetGamepad() { | |
| 220 base::TimeTicks timestamp = ui::EventTimeForNow(); | |
| 221 for (int btn_code = 0; btn_code < kWebGamepadBtnCnt; ++btn_code) { | |
| 222 OnButtonChange(btn_code, 0, timestamp); | |
| 223 } | |
| 224 | |
| 225 for (int abs_code = 0; abs_code < kWebGamepadAbsCnt; ++abs_code) { | |
| 226 OnAbsChange(abs_code, 0, timestamp); | |
| 227 } | |
| 228 OnSync(timestamp); | |
| 229 } | |
| 230 | |
| 231 void GamepadEventConverterEvdev::OnButtonChange( | |
| 232 unsigned int code, | |
| 233 double value, | |
| 234 const base::TimeTicks& timestamp) { | |
| 235 EventType type; | |
| 236 if (value == 0.0) { | |
| 237 type = ET_GAMEPAD_BTN_RELEASED; | |
| 238 } else { | |
| 239 type = ET_GAMEPAD_BTN_PRESSED; | |
| 240 } | |
| 241 | |
| 242 dispatcher_->DispatchGamepadEvent( | |
| 243 GamepadEventParams(input_device_.id, type, value, code, timestamp)); | |
| 244 will_send_frame_ = true; | |
| 245 } | |
| 246 | |
| 247 void GamepadEventConverterEvdev::OnAbsChange(unsigned int code, | |
| 248 double value, | |
| 249 const base::TimeTicks& timestamp) { | |
| 250 dispatcher_->DispatchGamepadEvent(GamepadEventParams( | |
| 251 input_device_.id, ET_GAMEPAD_ABS_MOVED, value, code, timestamp)); | |
| 252 will_send_frame_ = true; | |
| 253 } | |
| 254 | |
| 255 void GamepadEventConverterEvdev::OnSync(const base::TimeTicks& timestamp) { | |
| 256 if (will_send_frame_) { | |
| 257 // Dispatch gamepad frame. | |
| 258 dispatcher_->DispatchGamepadEvent(GamepadEventParams( | |
| 259 input_device_.id, ET_GAMEPAD_FRAME, 0.0, 0, timestamp)); | |
| 260 | |
| 261 will_send_frame_ = false; | |
| 262 } | |
| 263 } | |
| 264 | |
| 265 } // namespace ui | |
| OLD | NEW |