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

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 {
20 using ui::GamepadEventType;
21
22 class GenericGamepadMapper : public ui::GamepadMapper {
23 public:
24 GenericGamepadMapper(std::vector<ui::AbsMapEntry> axis_mapping,
25 std::vector<ui::KeyMapEntry> button_mapping) {
26 axis_mapping.swap(axis_mapping_);
27 button_mapping.swap(button_mapping_);
28 }
29
30 bool Map(uint16_t type,
31 uint16_t code,
32 ui::GamepadEventType* mapped_type,
33 uint16_t* mapped_code) const override {
34 if (type == EV_KEY) {
35 for (auto entry : button_mapping_) {
36 if (entry.evdev_code == code) {
37 *mapped_type = ui::GamepadEventType::BUTTON;
38 *mapped_code = entry.mapped_code;
39 return true;
40 }
41 }
42 return false;
43 }
44
45 if (type == EV_ABS) {
46 for (auto entry : axis_mapping_) {
47 if (entry.evdev_code == code) {
48 *mapped_type = entry.mapped_type;
49 *mapped_code = entry.mapped_code;
50 return true;
51 }
52 }
53 return false;
54 }
55 return false;
56 }
57
58 ~GenericGamepadMapper() override {}
59
60 private:
61 std::vector<ui::AbsMapEntry> axis_mapping_;
62 std::vector<ui::KeyMapEntry> button_mapping_;
63 };
64
65 // This helper class will be used to build generic mapping.
66 class GamepadMapperBuilder {
67 public:
68 explicit GamepadMapperBuilder(const ui::EventDeviceInfo& devinfo)
69 : devinfo_(devinfo) {}
70
71 std::unique_ptr<ui::GamepadMapper> ToGamepadMapper() {
72 return base::MakeUnique<GenericGamepadMapper>(std::move(axis_mapping_),
73 std::move(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 == ui::kHAT_X) {
97 DCHECK(!IfWebgamepadButtonMappedTo(ui::WG_BUTTON_DPAD_LEFT));
98 DCHECK(!IfWebgamepadButtonMappedTo(ui::WG_BUTTON_DPAD_RIGHT));
99
100 webgamepad_buttons_.set(ui::WG_BUTTON_DPAD_LEFT);
101 webgamepad_buttons_.set(ui::WG_BUTTON_DPAD_RIGHT);
102 } else if (mapped_button == ui::kHAT_Y) {
103 DCHECK(!IfWebgamepadButtonMappedTo(ui::WG_BUTTON_DPAD_UP));
104 DCHECK(!IfWebgamepadButtonMappedTo(ui::WG_BUTTON_DPAD_DOWN));
105
106 webgamepad_buttons_.set(ui::WG_BUTTON_DPAD_UP);
107 webgamepad_buttons_.set(ui::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, ui::WG_BUTTON_COUNT);
183 return webgamepad_buttons_.test(code);
184 }
185
186 bool IfWebgamepadAxisMappedTo(uint16_t code) {
187 DCHECK_LT(code, ui::WG_ABS_COUNT);
188 return webgamepad_axes_.test(code);
189 }
190
191 const ui::EventDeviceInfo& devinfo_;
192
193 // Mapped webgamepad buttons and axes will be marked as true.
194 std::bitset<ui::WG_BUTTON_COUNT> webgamepad_buttons_;
195 std::bitset<ui::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<ui::AbsMapEntry> axis_mapping_;
202 std::vector<ui::KeyMapEntry> button_mapping_;
203 };
204
205 void MapSpecialButtons(GamepadMapperBuilder* builder) {
206 // Map mode seperately.
207 builder->MapButton(BTN_MODE, ui::WG_BUTTON_MODE);
208 // Take care of ADT style back and start.
209 builder->MapButton(KEY_BACK, ui::WG_BUTTON_SELECT);
210 builder->MapButton(KEY_HOMEPAGE, ui::WG_BUTTON_START);
211 }
212
213 void MapSpecialAxes(const ui::EventDeviceInfo& devinfo,
214 GamepadMapperBuilder* builder) {
215 // HAT0X and HAT0Y always map to DPAD.
216 builder->MapAxisToButton(ABS_HAT0X, ui::kHAT_X);
217 builder->MapAxisToButton(ABS_HAT0Y, ui::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, ui::WG_BUTTON_LT);
225 builder->MapAxisToButton(ABS_GAS, ui::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, ui::WG_BUTTON_LT);
230 builder->MapAxisToButton(ABS_RZ, ui::WG_BUTTON_RT);
231 }
232 }
233 } // namespace
234
235 namespace ui {
236 std::unique_ptr<GamepadMapper> BuildGenericGamepadMapper(
237 const EventDeviceInfo& info) {
238 GamepadMapperBuilder builder(info);
239 // Must map axes first as axis might be mapped to button and occupy some
240 // webgamepad button slots.
241 MapSpecialAxes(info, &builder);
242 builder.MapAxisLikeJoydev();
243
244 MapSpecialButtons(&builder);
245 builder.MapButtonLikeJoydev();
246
247 return builder.ToGamepadMapper();
248 }
249
250 } // 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