OLD | NEW |
---|---|
(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 | |
OLD | NEW |