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

Side by Side Diff: ui/events/ozone/gamepad/generic_gamepad_mapping.cc

Issue 2899893003: Add generic mapping for gamepad (Closed)
Patch Set: Add generic mapping for gamepad Created 3 years, 6 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 <linux/input.h>
6 #include <algorithm>
7 #include <bitset>
8 #include <cstdint>
9 #include <list>
10 #include <set>
11 #include <vector>
12
13 #include "base/macros.h"
14 #include "base/memory/ptr_util.h"
15 #include "ui/events/ozone/evdev/event_device_info.h"
16 #include "ui/events/ozone/gamepad/generic_gamepad_mapping.h"
17 #include "ui/events/ozone/gamepad/webgamepad_constants.h"
18
19 namespace ui {
20
21 class EVENTS_OZONE_EVDEV_EXPORT GenericGamepadMapper : public GamepadMapper {
22 public:
23 GenericGamepadMapper(std::vector<AbsMapEntry>* axis_mapping,
spang 2017/06/02 23:00:58 Write this as GenericGamepadMapper(std::vector<
jkwang 2017/06/05 18:42:28 Done.
24 std::vector<KeyMapEntry>* button_mapping) {
25 DCHECK(axis_mapping);
26 DCHECK(button_mapping);
27 axis_mapping->swap(axis_mapping_);
28 button_mapping->swap(button_mapping_);
29 }
30
31 bool Map(uint16_t type,
32 uint16_t code,
33 GamepadEventType* mapped_type,
34 uint16_t* mapped_code) const override {
35 if (type == EV_KEY) {
36 for (auto entry : button_mapping_) {
37 if (entry.evdev_code == code) {
38 *mapped_type = GamepadEventType::BUTTON;
39 *mapped_code = entry.mapped_code;
40 return true;
41 }
42 }
43 return false;
44 }
45
46 if (type == EV_ABS) {
47 for (auto entry : axis_mapping_) {
48 if (entry.evdev_code == code) {
49 *mapped_type = entry.mapped_type;
50 *mapped_code = entry.mapped_code;
51 return true;
52 }
53 }
54 return false;
55 }
56 return false;
57 }
58
59 ~GenericGamepadMapper() override {}
60
61 private:
62 std::vector<AbsMapEntry> axis_mapping_;
63 std::vector<KeyMapEntry> button_mapping_;
64 };
65
66 // This helper class will be used to build generic mapping.
67 class GamepadMapperBuilder {
68 public:
69 GamepadMapperBuilder(const EventDeviceInfo& devinfo) : devinfo_(devinfo) {}
spang 2017/06/02 23:00:58 explicit
jkwang 2017/06/05 18:42:28 Done.
70
71 std::unique_ptr<GamepadMapper> ToGamepadMapper() {
72 return base::MakeUnique<GenericGamepadMapper>(&axis_mapping_,
spang 2017/06/02 23:00:58 return base::MakeUnique<GenericGamepadMapper>(std:
jkwang 2017/06/05 18:42:28 Done.
73 &button_mapping_);
74 }
75
76 void MapButton(uint16_t from_button, uint16_t mapped_button) {
77 if (!devinfo_.HasKeyEvent(from_button)) {
78 return;
79 }
80 DCHECK(!IfEvdevButtonMappedFrom(from_button));
81 DCHECK(!IfWebgamepadButtonMappedTo(mapped_button));
82
83 button_mapping_.push_back({from_button, mapped_button});
84 evdev_buttons_.set(from_button);
85 webgamepad_buttons_.set(mapped_button);
86 }
87
88 void MapAxisToButton(uint16_t from_axis, uint16_t mapped_button) {
89 if (!devinfo_.HasAbsEvent(from_axis)) {
90 return;
91 }
92 DCHECK(!IfEvdevAxisMappedFrom(from_axis));
93 evdev_axes_.set(from_axis);
94 axis_mapping_.push_back(TO_BTN(from_axis, mapped_button));
95
96 if (mapped_button == kHAT_X) {
97 DCHECK(!IfWebgamepadButtonMappedTo(WG_BUTTON_DPAD_LEFT));
98 DCHECK(!IfWebgamepadButtonMappedTo(WG_BUTTON_DPAD_RIGHT));
99
100 webgamepad_buttons_.set(WG_BUTTON_DPAD_LEFT);
101 webgamepad_buttons_.set(WG_BUTTON_DPAD_RIGHT);
102 } else if (mapped_button == kHAT_Y) {
103 DCHECK(!IfWebgamepadButtonMappedTo(WG_BUTTON_DPAD_UP));
104 DCHECK(!IfWebgamepadButtonMappedTo(WG_BUTTON_DPAD_DOWN));
105
106 webgamepad_buttons_.set(WG_BUTTON_DPAD_UP);
107 webgamepad_buttons_.set(WG_BUTTON_DPAD_DOWN);
108 } else {
109 DCHECK(!IfWebgamepadButtonMappedTo(mapped_button));
110 webgamepad_buttons_.set(mapped_button);
111 }
112 }
113
114 void MapAxisToAxis(uint16_t from_axis, uint16_t mapped_axis) {
115 if (!devinfo_.HasAbsEvent(from_axis)) {
116 return;
117 }
118 DCHECK(!IfEvdevAxisMappedFrom(from_axis));
119 DCHECK(!IfWebgamepadAxisMappedTo(mapped_axis));
120
121 axis_mapping_.push_back(TO_ABS(from_axis, mapped_axis));
122 evdev_axes_.set(from_axis);
123 webgamepad_axes_.set(mapped_axis);
124 }
125
126 void MapButtonLikeJoydev() {
127 uint16_t next_unmapped_button = 0;
128 // In linux kernel, joydev.c map evdev events in the same way.
129 for (int i = BTN_JOYSTICK - BTN_MISC; i < KEY_MAX - BTN_MISC + 1; i++) {
130 int code = i + BTN_MISC;
131 if (devinfo_.HasKeyEvent(code) && !IfEvdevButtonMappedFrom(code) &&
132 FindNextUnmappedCode(webgamepad_buttons_, &next_unmapped_button)) {
133 MapButton(code, next_unmapped_button);
134 }
135 }
136
137 for (int i = 0; i < BTN_JOYSTICK - BTN_MISC; i++) {
138 int code = i + BTN_MISC;
139 if (devinfo_.HasKeyEvent(code) && !IfEvdevButtonMappedFrom(code) &&
140 FindNextUnmappedCode(webgamepad_buttons_, &next_unmapped_button)) {
141 MapButton(code, next_unmapped_button);
142 }
143 }
144 }
145
146 void MapAxisLikeJoydev() {
147 uint16_t next_unmapped_axis = 0;
148 for (int code = 0; code < ABS_CNT; ++code) {
149 if (devinfo_.HasAbsEvent(code) && !IfEvdevAxisMappedFrom(code) &&
150 FindNextUnmappedCode(webgamepad_axes_, &next_unmapped_axis)) {
151 MapAxisToAxis(code, next_unmapped_axis);
152 }
153 }
154 }
155
156 private:
157 // This function helps to find the next unmapped button or axis. Code is the
158 // last unmapped code and will be the next unmapped code when the function
159 // returns.
160 template <typename T>
161 bool FindNextUnmappedCode(const T& bitset, uint16_t* code) {
162 for (uint16_t i = *code; i < bitset.size(); ++i) {
163 if (!bitset.test(i)) {
164 *code = i;
165 return true;
166 }
167 }
168 return false;
169 }
170
171 bool IfEvdevButtonMappedFrom(uint16_t code) {
172 DCHECK_LT(code, KEY_CNT);
173 return evdev_buttons_.test(code);
174 }
175
176 bool IfEvdevAxisMappedFrom(uint16_t code) {
177 DCHECK_LT(code, ABS_CNT);
178 return evdev_axes_.test(code);
179 }
180
181 bool IfWebgamepadButtonMappedTo(uint16_t code) {
182 DCHECK_LT(code, WG_BUTTON_COUNT);
183 return webgamepad_buttons_.test(code);
184 }
185
186 bool IfWebgamepadAxisMappedTo(uint16_t code) {
187 DCHECK_LT(code, WG_ABS_COUNT);
188 return webgamepad_axes_.test(code);
189 }
190
191 const EventDeviceInfo& devinfo_;
192
193 // Mapped webgamepad buttons and axes will be marked as true.
194 std::bitset<WG_BUTTON_COUNT> webgamepad_buttons_;
195 std::bitset<WG_ABS_COUNT> webgamepad_axes_;
196 // Evdev buttons and axes that are already mapped will be marked as true.
197 std::bitset<KEY_CNT> evdev_buttons_;
198 std::bitset<ABS_CNT> evdev_axes_;
199
200 // Generated Mapping.
201 std::vector<AbsMapEntry> axis_mapping_;
202 std::vector<KeyMapEntry> button_mapping_;
203 };
204
205 static void MapSpecialButtons(GamepadMapperBuilder* builder) {
206 // Map mode seperately.
207 builder->MapButton(BTN_MODE, WG_BUTTON_MODE);
208 // Take care of ADT style back and start.
209 builder->MapButton(KEY_BACK, WG_BUTTON_SELECT);
210 builder->MapButton(KEY_HOMEPAGE, WG_BUTTON_START);
211 }
212
213 static void MapSpecialAxes(const EventDeviceInfo& devinfo,
214 GamepadMapperBuilder* builder) {
215 // HAT0X and HAT0Y always map to DPAD.
216 builder->MapAxisToButton(ABS_HAT0X, kHAT_X);
217 builder->MapAxisToButton(ABS_HAT0Y, kHAT_Y);
218
219 // When ABS_BRAKE and ABS_GAS supported at the same time, they are mapped to
220 // l-trigger and r-trigger.
221 // Otherwise, when x,y,z,rx,ry,rz are all supported, z and rz are mapped to
222 // triggers (As XInput gamepad mapper).
223 if (devinfo.HasAbsEvent(ABS_BRAKE) && devinfo.HasAbsEvent(ABS_GAS)) {
224 builder->MapAxisToButton(ABS_BRAKE, WG_BUTTON_LT);
225 builder->MapAxisToButton(ABS_GAS, WG_BUTTON_RT);
226 } else if (devinfo.HasAbsEvent(ABS_X) && devinfo.HasAbsEvent(ABS_Y) &&
227 devinfo.HasAbsEvent(ABS_Z) && devinfo.HasAbsEvent(ABS_RX) &&
228 devinfo.HasAbsEvent(ABS_RY) && devinfo.HasAbsEvent(ABS_RZ)) {
229 builder->MapAxisToButton(ABS_Z, WG_BUTTON_LT);
230 builder->MapAxisToButton(ABS_RZ, WG_BUTTON_RT);
231 }
232 }
233
spang 2017/06/02 23:00:58 Put everything above in an anonymous namespace (an
jkwang 2017/06/05 18:42:28 Done.
234 std::unique_ptr<GamepadMapper> BuildGenericGamepadMapper(
235 const EventDeviceInfo& info) {
236 GamepadMapperBuilder builder(info);
237 // Must map axes first as axis might be mapped to button and occupy some
238 // webgamepad button slots.
239 MapSpecialAxes(info, &builder);
240 builder.MapAxisLikeJoydev();
241
242 MapSpecialButtons(&builder);
243 builder.MapButtonLikeJoydev();
244
245 return builder.ToGamepadMapper();
246 }
247
248 } // namespace ui
OLDNEW
« no previous file with comments | « ui/events/ozone/gamepad/generic_gamepad_mapping.h ('k') | ui/events/ozone/gamepad/generic_gamepad_mapping_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698