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

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 ui {
20
21 GamepadEventConverterEvdev::GamepadEventConverterEvdev(
22 ScopedInputDevice fd,
23 base::FilePath path,
24 int id,
25 const EventDeviceInfo& devinfo,
26 DeviceEventDispatcherEvdev* dispatcher)
27 : EventConverterEvdev(fd.get(),
28 path,
29 id,
30 devinfo.device_type(),
31 devinfo.name(),
32 devinfo.vendor_id(),
33 devinfo.product_id()),
34 will_send_frame_(false),
35 input_device_fd_(std::move(fd)),
36 dispatcher_(dispatcher) {
37 // In order to map gamepad, we have to save the abs_info from device_info
38 // and get the gamepad_mapping.
39 for (int code = 0; code < ABS_CNT; ++code) {
40 abs_info_[code] = devinfo.GetAbsInfoByCode(code);
41 if (devinfo.HasAbsEvent(code)) {
42 // If fuzz was reported as zero, it will be set to flat * 0.25f. It is the
43 // same thing done in Android InputReader.cpp. See:
44 // frameworks/native/services/inputflinger/InputReader.cpp line 6988 for
45 // more details.
46 if (abs_info_[code].fuzz == 0) {
47 abs_info_[code].fuzz = abs_info_[code].flat * 0.25f;
48 }
49 }
50 }
51 mapper_ = GetGamepadMapper(devinfo.vendor_id(), devinfo.product_id());
52 }
53
54 GamepadEventConverterEvdev::~GamepadEventConverterEvdev() {
55 DCHECK(!enabled_);
56 }
57
58 bool GamepadEventConverterEvdev::HasGamepad() const {
59 return true;
60 }
61
62 void GamepadEventConverterEvdev::OnFileCanReadWithoutBlocking(int fd) {
63 TRACE_EVENT1("evdev",
64 "GamepadEventConverterEvdev::OnFileCanReadWithoutBlocking", "fd",
65 fd);
66 while (true) {
67 input_event input;
68 ssize_t read_size = read(fd, &input, sizeof(input));
69 if (read_size != sizeof(input)) {
70 if (errno == EINTR || errno == EAGAIN)
71 return;
72 if (errno != ENODEV)
73 PLOG(ERROR) << "error reading device " << path_.value();
74 Stop();
75 return;
76 }
77
78 if (!enabled_)
79 return;
80
81 ProcessEvent(input);
82 }
83 }
84 void GamepadEventConverterEvdev::OnDisabled() {
85 ResetGamepad();
86 }
87
88 void GamepadEventConverterEvdev::ProcessEvent(const input_event& evdev_ev) {
89 // We may have missed Gamepad releases. Reset everything.
90 // If the event is sync, we send a frame.
91 if (evdev_ev.type == EV_SYN) {
92 if (evdev_ev.code == SYN_DROPPED) {
93 LOG(WARNING) << "kernel dropped input events";
94 ResyncGamepad();
95 } else if (evdev_ev.code == SYN_REPORT) {
96 OnSync(TimeTicksFromInputEvent(evdev_ev));
97 }
98 return;
99 }
100
101 GamepadEventType mapped_type;
102 uint16_t mapped_code;
103
104 bool found_map =
105 mapper_(evdev_ev.type, evdev_ev.code, &mapped_type, &mapped_code);
106
107 // If we cannot find a map for this event, it will be discarded.
108 if (!found_map) {
109 return;
110 }
111
112 // If it's btn -> btn mapping, we can send the event and return now.
113 if (mapped_type == GamepadEventType::BUTTON && evdev_ev.type == EV_KEY) {
114 OnButtonChange(mapped_code, evdev_ev.value,
115 TimeTicksFromInputEvent(evdev_ev));
116 return;
117 }
118
119 double mapped_abs_value;
120
121 double mapped_abs_min = kWebGamepadJoystickMin;
122 double mapped_abs_max = kWebGamepadJoystickMax;
123 // If the mapped event is a trigger, we set the min and max to trigger
124 // min/max.
125 if (mapped_code == WG_BUTTON_LT || mapped_code == WG_BUTTON_RT) {
126 mapped_abs_min = kWebGamepadTriggerMin;
127 mapped_abs_max = kWebGamepadTriggerMax;
128 }
129
130 // Code is out of ABS_MAX. This should not happen, but we don't want a gamepad
131 // reporting wrong values break the code.
132 if (evdev_ev.code < 0 || evdev_ev.code > ABS_MAX) {
133 return;
134 }
135
136 struct input_absinfo& abs_info = abs_info_[evdev_ev.code];
137 // To remove noise, the value must change at least by fuzz.
138 if (evdev_ev.value > abs_info.value - abs_info.fuzz &&
spang 2017/05/03 22:00:37 Can't this fuzzing prevent the value from returnin
jkwang 2017/05/05 00:07:45 Done.
139 evdev_ev.value < abs_info.value + abs_info.fuzz) {
140 return;
141 }
142
143 // Save the old value for later use.
144 int old_value = abs_info.value;
145 abs_info.value = evdev_ev.value;
146
147 double scale =
148 (mapped_abs_max - mapped_abs_min) / (abs_info.maximum - abs_info.minimum);
149 double offset = (abs_info.maximum + abs_info.minimum) /
spang 2017/05/03 22:00:38 offset and scale can be pre-calculated. If you do
jkwang 2017/05/05 00:07:45 Done.
150 (mapped_abs_max - mapped_abs_min) * scale * mapped_abs_min;
151
152 double scaled_flat = abs_info.flat * scale;
153
154 mapped_abs_value = evdev_ev.value * scale + offset;
155
156 // As the definition of linux input_absinfo.flat, value within the range of
157 // flat should be seen as zero.
158 if (mapped_abs_value < scaled_flat && mapped_abs_value > -scaled_flat) {
159 mapped_abs_value = 0.0;
160 }
161
162 // If the mapped type is abs, we can send it now.
163 if (mapped_type == GamepadEventType::AXIS) {
164 OnAbsChange(mapped_code, mapped_abs_value,
165 TimeTicksFromInputEvent(evdev_ev));
166 return;
167 }
168
169 // We need to map HAT to DPAD depend on the state of the axis.
170 if (mapped_code == kHAT_X) {
171 if (mapped_abs_value < 0.0 ||
172 (mapped_abs_value == 0.0 && old_value < abs_info.flat)) {
spang 2017/05/03 22:00:37 It's hard to follow this because it mixes use of t
jkwang 2017/05/05 00:07:45 Done.
173 // If current HAT_X is < 0 or it was < 0 before, it's dpad left.
174 mapped_code = WG_BUTTON_DPAD_LEFT;
175 } else {
176 mapped_code = WG_BUTTON_DPAD_RIGHT;
177 }
178 } else if (mapped_code == kHAT_Y) {
179 if (mapped_abs_value < 0 ||
180 (mapped_abs_value == 0.0 && old_value < abs_info.flat)) {
181 mapped_code = WG_BUTTON_DPAD_UP;
182 } else {
183 mapped_code = WG_BUTTON_DPAD_DOWN;
184 }
185 }
186 OnButtonChange(mapped_code, mapped_abs_value,
187 TimeTicksFromInputEvent(evdev_ev));
188 }
189
190 void GamepadEventConverterEvdev::ResetGamepad() {
191 base::TimeTicks timestamp = ui::EventTimeForNow();
192 for (int btn_code = 0; btn_code < WG_BUTTON_COUNT; ++btn_code) {
193 OnButtonChange(btn_code, 0, timestamp);
194 }
195
196 for (int abs_code = 0; abs_code < WG_ABS_COUNT; ++abs_code) {
197 OnAbsChange(abs_code, 0, timestamp);
198 }
199 OnSync(timestamp);
200 }
201
202 void GamepadEventConverterEvdev::ResyncGamepad() {
spang 2017/05/03 22:00:37 Please either sync buttons or release them (or you
jkwang 2017/05/05 00:07:45 Done.
203 EventDeviceInfo info;
204 if (!info.Initialize(fd_, path_)) {
205 LOG(ERROR) << "Failed to synchronize state for gamepad device: "
206 << path_.value();
207 Stop();
208 return;
209 }
210 for (int code = 0; code < ABS_CNT; ++code) {
211 abs_info_[code] = info.GetAbsInfoByCode(code);
212 if (info.HasAbsEvent(code) &&
213 abs_info_[code].value != info.GetAbsValue(code)) {
214 input_event event;
215 event.time = base::Time::UnixEpoch().ToTimeVal();
spang 2017/05/03 22:00:38 Unix epoch is for the real time clock. Input uses
jkwang 2017/05/05 00:07:45 Done.
216 event.type = EV_ABS;
217 event.code = code;
218 event.value = info.GetAbsValue(code);
219 ProcessEvent(event);
220 }
221 }
222 OnSync(ui::EventTimeForNow());
223 }
224
225 void GamepadEventConverterEvdev::OnButtonChange(
226 unsigned int code,
227 double value,
228 const base::TimeTicks& timestamp) {
229 GamepadEvent event(input_device_.id, GamepadEventType::BUTTON, code, value,
230 timestamp);
231 dispatcher_->DispatchGamepadEvent(event);
232 will_send_frame_ = true;
233 }
234
235 void GamepadEventConverterEvdev::OnAbsChange(unsigned int code,
236 double value,
237 const base::TimeTicks& timestamp) {
238 GamepadEvent event(input_device_.id, GamepadEventType::AXIS, code, value,
239 timestamp);
240 dispatcher_->DispatchGamepadEvent(event);
241 will_send_frame_ = true;
242 }
243
244 void GamepadEventConverterEvdev::OnSync(const base::TimeTicks& timestamp) {
245 if (will_send_frame_) {
246 GamepadEvent event(input_device_.id, GamepadEventType::FRAME, 0, 0,
247 timestamp);
248 dispatcher_->DispatchGamepadEvent(event);
249 will_send_frame_ = false;
250 }
251 }
252 } // namespace ui
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698