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

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, 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 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 // Set the minimum fuzz. For example, if min is 0 and max is 255, we can't
43 // determine if 127 is 0.0 or 128 is 0.0. We will just fuzz by one percent
spang 2017/04/21 05:38:46 This seems dubious to me. Why is 1% the right mini
jkwang 2017/04/25 21:16:41 I am doing this because I am concerned that some g
44 // to make them both zero. If (max - min) is less than zero, we won't do
45 // this override because we don't want to cause too much error.
46 if (abs_info_[code].fuzz == 0) {
47 abs_info_[code].fuzz =
48 (abs_info_[code].maximum - abs_info_[code].minimum) / 100;
49 }
50
51 // Some gamepad report garbage flat value. To map approprate value to
52 // exactly 0.0, we need the flat value to be fixed. We assume the flat is
53 // in the middle of minimum and maximum if it's not min.
54 if (abs_info_[code].flat != abs_info_[code].minimum) {
55 abs_info_[code].flat =
56 (abs_info_[code].maximum + abs_info_[code].minimum) / 2;
57 }
58 }
59 }
60 mapper_ = GetGamepadMapper(devinfo.vendor_id(), devinfo.product_id());
61 }
62
63 GamepadEventConverterEvdev::~GamepadEventConverterEvdev() {
64 DCHECK(!enabled_);
65 }
66
67 bool GamepadEventConverterEvdev::HasGamepad() const {
68 return true;
69 }
70
71 void GamepadEventConverterEvdev::OnFileCanReadWithoutBlocking(int fd) {
72 TRACE_EVENT1("evdev",
73 "GamepadEventConverterEvdev::OnFileCanReadWithoutBlocking", "fd",
74 fd);
75 while (true) {
76 input_event input;
77 ssize_t read_size = read(fd, &input, sizeof(input));
78 if (read_size != sizeof(input)) {
79 if (errno == EINTR || errno == EAGAIN)
80 return;
81 if (errno != ENODEV)
82 PLOG(ERROR) << "error reading device " << path_.value();
83 Stop();
84 return;
85 }
86
87 if (!enabled_)
88 return;
89
90 ProcessEvent(input);
91 }
92 }
93 void GamepadEventConverterEvdev::OnDisabled() {
94 ResetGamepad();
95 }
96
97 void GamepadEventConverterEvdev::ProcessEvent(const input_event& evdev_ev) {
98 // We may have missed Gamepad releases. Reset everything.
99 // If the event is sync, we send a frame.
100 if (evdev_ev.type == EV_SYN) {
101 if (evdev_ev.code == SYN_DROPPED) {
102 LOG(WARNING) << "kernel dropped input events";
103 ResetGamepad();
104 } else if (evdev_ev.code == SYN_REPORT) {
105 OnSync(TimeTicksFromInputEvent(evdev_ev));
106 }
107 return;
108 }
109
110 GamepadEventType mapped_type;
111 uint16_t mapped_code;
112
113 bool found_map =
114 mapper_(evdev_ev.type, evdev_ev.code, &mapped_type, &mapped_code);
115
116 // If we cannot find a map for this event, it will be discarded.
117 if (!found_map) {
118 return;
119 }
120
121 // If it's btn -> btn mapping, we can send the event and return now.
122 if (mapped_type == GamepadEventType::BUTTON && evdev_ev.type == EV_KEY) {
123 OnButtonChange(mapped_code, evdev_ev.value,
124 TimeTicksFromInputEvent(evdev_ev));
125 return;
126 }
127
128 double mapped_abs_value;
129 double mapped_abs_min = kWebGamepadJoystickMin;
130 double mapped_abs_max = kWebGamepadJoystickMax;
131 // If the mapped event is a trigger, we set the min and max to trigger
132 // min/max.
133 if (mapped_code == WG_BUTTON_L2 || mapped_code == WG_BUTTON_R2) {
134 mapped_abs_min = kWebGamepadTriggerMin;
135 mapped_abs_max = kWebGamepadTriggerMax;
136 }
137
138 // Code is out of ABS_MAX. This should not happen, but we don't want a gamepad
139 // reporting wrong values break the code.
140 if (evdev_ev.code < 0 || evdev_ev.code > ABS_MAX) {
141 return;
142 }
143
144 struct input_absinfo& abs_info = abs_info_[evdev_ev.code];
145 // To remove noise, the value must change at least by fuzz.
146 if (evdev_ev.value > abs_info.value - abs_info.fuzz &&
147 evdev_ev.value < abs_info.value + abs_info.fuzz) {
148 return;
149 }
150
151 // Save the old value for later use.
152 int old_value = abs_info.value;
153 // If the value of input is within the range of [flat - fuzz, flat + fuzz],
154 // the value is discarded and we are going to use 0.
155 if (evdev_ev.value >= abs_info.flat - abs_info.fuzz &&
156 evdev_ev.value <= abs_info.flat + abs_info.fuzz) {
157 abs_info.value = abs_info.flat;
158 mapped_abs_value = 0.0;
159 } else if (evdev_ev.value <= abs_info.minimum + abs_info.fuzz) {
160 // We are manually set min and max to ensure double value equals.
161 abs_info.value = abs_info.minimum;
162 mapped_abs_value = mapped_abs_min;
163 } else if (evdev_ev.value >= abs_info.maximum - abs_info.fuzz) {
164 abs_info.value = abs_info.maximum;
165 mapped_abs_value = mapped_abs_max;
166 } else {
167 abs_info.value = evdev_ev.value;
168 // Check if the min == max to avoid divide by zero. If min == max, we are
169 // going to discard this event.
170 if (abs_info.minimum == abs_info.maximum) {
171 return;
172 }
173 mapped_abs_value =
174 mapped_abs_min +
175 (mapped_abs_max - mapped_abs_min) *
176 static_cast<double>(evdev_ev.value - abs_info.minimum) /
177 static_cast<double>(abs_info.maximum - abs_info.minimum);
178 }
179
180 // If the mapped type is abs, we can send it now.
181 if (mapped_type == GamepadEventType::AXIS) {
182 OnAbsChange(mapped_code, mapped_abs_value,
183 TimeTicksFromInputEvent(evdev_ev));
184 return;
185 }
186
187 // We need to map HAT to DPAD depend on the state of the axis.
188 if (mapped_code == kHAT_X) {
189 if (mapped_abs_value < 0.0 ||
190 (mapped_abs_value == 0.0 && old_value < abs_info.flat)) {
191 // If current HAT_X is < 0 or it was <0 before it's dpad left.
192 mapped_code = WG_BUTTON_DPAD_LEFT;
193 } else {
194 mapped_code = WG_BUTTON_DPAD_RIGHT;
195 }
196 } else if (mapped_code == kHAT_Y) {
197 if (mapped_abs_value < 0 ||
198 (mapped_abs_value == 0.0 && old_value < abs_info.flat)) {
199 mapped_code = WG_BUTTON_DPAD_UP;
200 } else {
201 mapped_code = WG_BUTTON_DPAD_DOWN;
202 }
203 }
204 OnButtonChange(mapped_code, mapped_abs_value,
205 TimeTicksFromInputEvent(evdev_ev));
206 }
207
208 void GamepadEventConverterEvdev::ResetGamepad() {
209 base::TimeTicks timestamp = ui::EventTimeForNow();
210 for (int btn_code = 0; btn_code < kWebGamepadBtnCnt; ++btn_code) {
211 OnButtonChange(btn_code, 0, timestamp);
212 }
213
214 for (int abs_code = 0; abs_code < kWebGamepadAbsCnt; ++abs_code) {
215 OnAbsChange(abs_code, 0, timestamp);
216 }
217 OnSync(timestamp);
218 }
219
220 void GamepadEventConverterEvdev::OnButtonChange(
221 unsigned int code,
222 double value,
223 const base::TimeTicks& timestamp) {
224 GamepadEvent event(input_device_.id, GamepadEventType::BUTTON, code, value,
225 timestamp);
226 dispatcher_->DispatchGamepadEvent(event);
227 will_send_frame_ = true;
228 }
229
230 void GamepadEventConverterEvdev::OnAbsChange(unsigned int code,
231 double value,
232 const base::TimeTicks& timestamp) {
233 GamepadEvent event(input_device_.id, GamepadEventType::AXIS, code, value,
234 timestamp);
235 dispatcher_->DispatchGamepadEvent(event);
236 will_send_frame_ = true;
237 }
238
239 void GamepadEventConverterEvdev::OnSync(const base::TimeTicks& timestamp) {
240 if (will_send_frame_) {
241 GamepadEvent event(input_device_.id, GamepadEventType::FRAME, 0, 0,
242 timestamp);
243 dispatcher_->DispatchGamepadEvent(event);
244 will_send_frame_ = false;
245 }
246 }
247
248 } // namespace ui
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698