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

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 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
OLDNEW
« no previous file with comments | « ui/events/ozone/evdev/gamepad_event_converter_evdev.h ('k') | ui/events/ozone/evdev/gamepad_event_converter_evdev_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698