oxygengine_input/resources/
controller.rs1use crate::device::InputDevice;
2use core::{ecs::Universe, Scalar};
3use serde::{Deserialize, Serialize};
4use std::collections::HashMap;
5
6#[derive(Debug, Default, Clone, Serialize, Deserialize)]
7pub struct InputMappings {
8 #[serde(default)]
10 pub axes: HashMap<String, HashMap<String, String>>,
11 #[serde(default)]
13 pub triggers: HashMap<String, HashMap<String, String>>,
14}
15
16#[derive(Debug, Clone, Copy, Eq, PartialEq, Serialize, Deserialize)]
17pub enum TriggerState {
18 Idle,
19 Pressed,
20 Hold,
21 Released,
22}
23
24impl Default for TriggerState {
25 fn default() -> Self {
26 Self::Idle
27 }
28}
29
30impl TriggerState {
31 #[inline]
32 pub fn is_on(self) -> bool {
33 self == TriggerState::Pressed || self == TriggerState::Hold
34 }
35
36 #[inline]
37 pub fn is_off(self) -> bool {
38 !self.is_on()
39 }
40
41 #[inline]
42 pub fn is_idle(self) -> bool {
43 self == TriggerState::Idle
44 }
45
46 #[inline]
47 pub fn is_pressed(self) -> bool {
48 self == TriggerState::Pressed
49 }
50
51 #[inline]
52 pub fn is_hold(self) -> bool {
53 self == TriggerState::Hold
54 }
55
56 #[inline]
57 pub fn is_released(self) -> bool {
58 self == TriggerState::Released
59 }
60
61 #[inline]
62 pub fn press(self) -> Self {
63 match self {
64 Self::Idle => Self::Pressed,
65 Self::Pressed => Self::Hold,
66 Self::Hold => Self::Hold,
67 Self::Released => Self::Pressed,
68 }
69 }
70
71 #[inline]
72 pub fn release(self) -> Self {
73 match self {
74 Self::Idle => Self::Idle,
75 Self::Pressed => Self::Released,
76 Self::Hold => Self::Released,
77 Self::Released => Self::Idle,
78 }
79 }
80
81 #[inline]
82 pub fn progress(self, press: bool) -> Self {
83 if press {
84 self.press()
85 } else {
86 self.release()
87 }
88 }
89
90 #[inline]
91 pub fn priority(self) -> u8 {
92 match self {
93 Self::Idle => 0,
94 Self::Pressed => 1,
95 Self::Hold => 2,
96 Self::Released => 1,
97 }
98 }
99}
100
101#[derive(Default)]
102pub struct InputController {
103 devices: HashMap<String, Box<dyn InputDevice>>,
104 mapping_axes: HashMap<String, (String, String)>,
105 mapping_triggers: HashMap<String, (String, String)>,
106 axes: HashMap<String, Scalar>,
107 triggers: HashMap<String, TriggerState>,
108 text: String,
109}
110
111impl InputController {
112 pub fn register<D>(&mut self, mut device: D)
113 where
114 D: InputDevice + 'static,
115 {
116 device.on_register();
117 self.devices
118 .insert(device.name().to_owned(), Box::new(device));
119 }
120
121 pub fn unregister(&mut self, name: &str) -> Option<Box<dyn InputDevice>> {
122 if let Some(mut device) = self.devices.remove(name) {
123 device.on_unregister();
124 Some(device)
125 } else {
126 None
127 }
128 }
129
130 pub fn device(&self, id: &str) -> Option<&dyn InputDevice> {
131 self.devices.get(id).map(|device| device.as_ref())
132 }
133
134 pub fn as_device<T>(&self, id: &str) -> Option<&T>
135 where
136 T: InputDevice,
137 {
138 if let Some(device) = self.devices.get(id) {
139 device.as_any().downcast_ref::<T>()
140 } else {
141 None
142 }
143 }
144
145 pub fn mapping_axes(&self) -> impl Iterator<Item = (&str, (&str, &str))> {
146 self.mapping_axes
147 .iter()
148 .map(|(k, (a, b))| (k.as_str(), (a.as_str(), b.as_str())))
149 }
150
151 pub fn mapping_triggers(&self) -> impl Iterator<Item = (&str, (&str, &str))> {
152 self.mapping_triggers
153 .iter()
154 .map(|(k, (a, b))| (k.as_str(), (a.as_str(), b.as_str())))
155 }
156
157 pub fn map_config(&mut self, config: InputMappings) {
158 for (device, mappings) in config.axes {
159 for (name_from, name_to) in mappings {
160 self.map_axis(&name_from, &device, &name_to);
161 }
162 }
163 for (device, mappings) in config.triggers {
164 for (name_from, name_to) in mappings {
165 self.map_trigger(&name_from, &device, &name_to);
166 }
167 }
168 }
169
170 pub fn map_axis(&mut self, name_from: &str, device: &str, name_to: &str) {
171 self.mapping_axes.insert(
172 name_from.to_owned(),
173 (device.to_owned(), name_to.to_owned()),
174 );
175 }
176
177 pub fn unmap_axis(&mut self, name: &str) {
178 self.mapping_axes.remove(name);
179 }
180
181 pub fn map_trigger(&mut self, name_from: &str, device: &str, name_to: &str) {
182 self.mapping_triggers.insert(
183 name_from.to_owned(),
184 (device.to_owned(), name_to.to_owned()),
185 );
186 }
187
188 pub fn unmap_trigger(&mut self, name: &str) {
189 self.mapping_triggers.remove(name);
190 }
191
192 pub fn axes(&self) -> impl Iterator<Item = (&str, Scalar)> {
193 self.axes.iter().map(|(k, v)| (k.as_str(), *v))
194 }
195
196 pub fn triggers(&self) -> impl Iterator<Item = (&str, TriggerState)> {
197 self.triggers.iter().map(|(k, v)| (k.as_str(), *v))
198 }
199
200 pub fn axis(&self, name: &str) -> Option<Scalar> {
201 self.axes.get(name).cloned()
202 }
203
204 pub fn multi_axis<const N: usize>(&self, names: [&str; N]) -> [Option<Scalar>; N] {
205 let mut result = [None; N];
206 for i in 0..N {
207 result[i] = self.axis(names[i]);
208 }
209 result
210 }
211
212 pub fn mirror_multi_axis<const N: usize>(
213 &self,
214 names: [(&str, &str); N],
215 ) -> [Option<Scalar>; N] {
216 let mut result = [None; N];
217 for i in 0..N {
218 let name = names[i];
219 result[i] = match (self.axis(name.0), self.axis(name.1)) {
220 (None, None) => None,
221 (Some(v), None) => Some(-v),
222 (None, Some(v)) => Some(v),
223 (Some(a), Some(b)) => Some(b - a),
224 };
225 }
226 result
227 }
228
229 pub fn axis_or_default(&self, name: &str) -> Scalar {
230 self.axis(name).unwrap_or(0.0)
231 }
232
233 pub fn multi_axis_or_default<const N: usize>(&self, names: [&str; N]) -> [Scalar; N] {
234 let mut result = [Default::default(); N];
235 for i in 0..N {
236 result[i] = self.axis_or_default(names[i]);
237 }
238 result
239 }
240
241 pub fn mirror_multi_axis_or_default<const N: usize>(
242 &self,
243 names: [(&str, &str); N],
244 ) -> [Scalar; N] {
245 let mut result = [Default::default(); N];
246 for i in 0..N {
247 let name = names[i];
248 result[i] = self.axis_or_default(name.0) - self.axis_or_default(name.1);
249 }
250 result
251 }
252
253 pub fn set_axis(&mut self, name: &str, value: Scalar) {
254 self.axes.insert(name.to_owned(), value);
255 }
256
257 pub fn trigger(&self, name: &str) -> Option<TriggerState> {
258 self.triggers.get(name).cloned()
259 }
260
261 pub fn multi_trigger<const N: usize>(&self, names: [&str; N]) -> [Option<TriggerState>; N] {
262 let mut result = [None; N];
263 for i in 0..N {
264 result[i] = self.trigger(names[i]);
265 }
266 result
267 }
268
269 pub fn priority_trigger<const N: usize>(&self, names: [&str; N]) -> Option<TriggerState> {
270 let mut result = None;
271 for name in names.iter() {
272 result = match (result, self.trigger(name)) {
273 (None, v) => v,
274 (Some(a), Some(b)) => {
275 if b.priority() > a.priority() {
276 Some(b)
277 } else {
278 Some(a)
279 }
280 }
281 _ => result,
282 };
283 }
284 result
285 }
286
287 pub fn trigger_or_default(&self, name: &str) -> TriggerState {
288 self.trigger(name).unwrap_or(TriggerState::Idle)
289 }
290
291 pub fn multi_trigger_or_default<const N: usize>(&self, names: [&str; N]) -> [TriggerState; N] {
292 let mut result = [Default::default(); N];
293 for i in 0..N {
294 result[i] = self.trigger_or_default(names[i]);
295 }
296 result
297 }
298
299 pub fn priority_trigger_or_default<const N: usize>(&self, names: [&str; N]) -> TriggerState {
300 let mut result = TriggerState::Idle;
301 for name in names.iter() {
302 let state = self.trigger_or_default(name);
303 if state.priority() > result.priority() {
304 result = state;
305 }
306 }
307 result
308 }
309
310 pub fn set_trigger(&mut self, name: &str, value: TriggerState) {
311 self.triggers.insert(name.to_owned(), value);
312 }
313
314 pub fn text(&self) -> &str {
315 &self.text
316 }
317
318 pub fn process(&mut self, universe: &mut Universe) {
319 for device in self.devices.values_mut() {
320 device.process(universe);
321 }
322 self.text.clear();
323 for device in self.devices.values() {
324 if let Some(text) = device.query_text() {
325 self.text.push_str(&text);
326 }
327 }
328 self.axes.clear();
329 for (name_from, (dev, name_to)) in &self.mapping_axes {
330 if let Some(device) = self.devices.get(dev) {
331 if let Some(value) = device.query_axis(name_to) {
332 self.axes.insert(name_from.to_owned(), value);
333 }
334 }
335 }
336 for (name_from, (dev, name_to)) in &self.mapping_triggers {
337 if let Some(device) = self.devices.get(dev) {
338 if let Some(value) = device.query_trigger(name_to) {
339 let prev = self.triggers.get(name_from).unwrap_or(&TriggerState::Idle);
340 let next = prev.progress(value);
341 self.triggers.insert(name_from.to_owned(), next);
342 }
343 }
344 }
345 }
346}