Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(78)

Side by Side Diff: ui/events/ozone/evdev/gamepad_event_converter_evdev.cc

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

Powered by Google App Engine
This is Rietveld 408576698