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

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

Issue 2805793002: ozone: evdev: Add gamepad support (Closed)
Patch Set: Created 3 years, 8 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 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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698