pawkit_input/
lib.rs

1#![feature(decl_macro)]
2
3use std::{
4    collections::HashMap,
5    fmt::Debug,
6    ops::{Deref, DerefMut},
7    sync::RwLock,
8};
9
10use pawkit_holy_array::HolyArray;
11use serde::{Deserialize, Serialize};
12
13use crate::{
14    binding_map::{BindingList, BindingMap, DefaultBindingMap},
15    bindings::{
16        AnalogBinding, AnalogBindingKind, BoundAxis, BoundButton, DigitalBinding, VectorBinding,
17        VectorBindingKind,
18    },
19    manager::{InputDeviceManager, InputFamily},
20};
21
22pub mod binding_map;
23pub mod bindings;
24pub mod manager;
25
26pub struct InputDeviceManagers {
27    pub keyboard_manager: InputDeviceManager,
28    pub mouse_manager: InputDeviceManager,
29    pub gamepad_manager: InputDeviceManager,
30}
31
32impl InputDeviceManagers {
33    pub fn new() -> Self {
34        return Self {
35            keyboard_manager: InputDeviceManager::new(InputFamily::Keyboard),
36            mouse_manager: InputDeviceManager::new(InputFamily::Mouse),
37            gamepad_manager: InputDeviceManager::new(InputFamily::Gamepad),
38        };
39    }
40}
41
42pub struct InputManager {
43    pub bindings: DefaultBindingMap,
44    pub devices: InputDeviceManagers,
45    handlers: RwLock<HolyArray<InputHandler>>,
46}
47
48impl InputManager {
49    pub fn new() -> Self {
50        return Self {
51            bindings: DefaultBindingMap::new(),
52            devices: InputDeviceManagers::new(),
53            handlers: RwLock::new(HolyArray::new()),
54        };
55    }
56
57    pub fn create_handler(&self) -> Option<usize> {
58        let index = self.bindings.new_instance().ok()?;
59
60        let bindings = self.bindings.get_map(index)?;
61
62        let mut frames = Vec::with_capacity(bindings.values.len());
63
64        for binding in &bindings.values {
65            let frame = match &*binding {
66                BindingList::Analog(_) => InputFrame::Analog {
67                    value: 0f32,
68                    delta: 0f32,
69                },
70
71                BindingList::Digital(_) => InputFrame::Digital {
72                    value: false,
73                    just_pressed: false,
74                    just_released: false,
75                },
76
77                BindingList::Vector(_) => InputFrame::Vector {
78                    value: (0f32, 0f32),
79                    delta: (0f32, 0f32),
80                },
81            };
82
83            frames.push(RwLock::new(frame));
84        }
85
86        let Ok(mut handlers) = self.handlers.write() else {
87            return None;
88        };
89
90        return Some(handlers.acquire(InputHandler {
91            binding_index: index,
92            connected_keyboards: RwLock::new(Vec::new()),
93            connected_mice: RwLock::new(Vec::new()),
94            connected_gamepads: RwLock::new(Vec::new()),
95            frames: frames.into_boxed_slice(),
96        }));
97    }
98
99    pub fn destroy_handler(&self, handler: usize) {
100        let Ok(mut handlers) = self.handlers.write() else {
101            return;
102        };
103
104        handlers.release(handler);
105        let _ = self.bindings.delete_instance(handler);
106    }
107
108    pub fn update(&self) {
109        let Ok(handlers) = self.handlers.read() else {
110            return;
111        };
112
113        for handler in &*handlers {
114            let Some(map) = self.bindings.get_map(handler.binding_index) else {
115                continue;
116            };
117
118            handler.update(&self.devices, &map);
119        }
120    }
121
122    pub fn get_frame(&self, handler: usize, name: &str) -> Option<InputFrame> {
123        let handlers = self.handlers.read().ok()?;
124
125        let handler = handlers.get(handler)?;
126
127        return handler.get_frame(&self.bindings.index, name);
128    }
129
130    pub fn connect_device_to_handler(&self, handler: usize, family: InputFamily, id: usize) {
131        let Ok(handlers) = self.handlers.read() else {
132            return;
133        };
134
135        let Some(handler) = handlers.get(handler) else {
136            return;
137        };
138
139        handler.connect_device(family, id);
140    }
141
142    pub fn connect_device_to_handler_raw(&self, handler: usize, family: InputFamily, id: usize) {
143        let Ok(handlers) = self.handlers.read() else {
144            return;
145        };
146
147        let Some(handler) = handlers.get(handler) else {
148            return;
149        };
150
151        handler.connect_device_raw(&self.devices, family, id);
152    }
153
154    pub fn disconnect_device_from_handler(&self, handler: usize, family: InputFamily, id: usize) {
155        let Ok(handlers) = self.handlers.read() else {
156            return;
157        };
158
159        let Some(handler) = handlers.get(handler) else {
160            return;
161        };
162
163        handler.disconnect_device(family, id);
164    }
165
166    pub fn disconnect_device_from_handler_raw(
167        &self,
168        handler: usize,
169        family: InputFamily,
170        id: usize,
171    ) {
172        let Ok(handlers) = self.handlers.read() else {
173            return;
174        };
175
176        let Some(handler) = handlers.get(handler) else {
177            return;
178        };
179
180        handler.disconnect_device_raw(&self.devices, family, id);
181    }
182}
183
184impl Deref for InputManager {
185    type Target = DefaultBindingMap;
186
187    fn deref(&self) -> &Self::Target {
188        return &self.bindings;
189    }
190}
191
192impl DerefMut for InputManager {
193    fn deref_mut(&mut self) -> &mut Self::Target {
194        return &mut self.bindings;
195    }
196}
197
198#[repr(C, u8)]
199#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Serialize, Deserialize)]
200pub enum InputFrame {
201    Digital {
202        value: bool,
203        just_pressed: bool,
204        just_released: bool,
205    },
206    Analog {
207        value: f32,
208        delta: f32,
209    },
210    Vector {
211        value: (f32, f32),
212        delta: (f32, f32),
213    },
214}
215
216/// An `InputHandler`` represents a single input consumer, typically a player.
217///
218/// It manages its own bindings and keeps track of the devices it's using.
219pub struct InputHandler {
220    binding_index: usize,
221    connected_keyboards: RwLock<Vec<usize>>,
222    connected_mice: RwLock<Vec<usize>>,
223    connected_gamepads: RwLock<Vec<usize>>,
224    frames: Box<[RwLock<InputFrame>]>,
225}
226
227impl InputHandler {
228    fn get_bound_axis<'b, TButton, TAxis>(
229        manager: &InputDeviceManager,
230        axis: &BoundAxis<TButton, TAxis>,
231        connected_devices: &Vec<usize>,
232    ) -> f32
233    where
234        TButton: Sized
235            + Debug
236            + Clone
237            + Copy
238            + PartialEq
239            + PartialOrd
240            + Serialize
241            + Deserialize<'b>
242            + Into<usize>,
243        TAxis: Sized
244            + Debug
245            + Clone
246            + Copy
247            + PartialEq
248            + PartialOrd
249            + Serialize
250            + Deserialize<'b>
251            + Into<usize>,
252    {
253        let mut value = 0f32;
254
255        match axis {
256            BoundAxis::Analog(axis) => {
257                for device in connected_devices {
258                    if let Some(device) = manager.get_state(*device) {
259                        let analog = device.get_analog((*axis).into());
260                        if analog.abs() > value.abs() {
261                            value = analog;
262                        }
263                    }
264                }
265            }
266
267            BoundAxis::Digital(button) => {
268                for device in connected_devices {
269                    if let Some(device) = manager.get_state(*device) {
270                        let analog = if device.get_digital((*button).into()) {
271                            1f32
272                        } else {
273                            0f32
274                        };
275                        if analog.abs() > value.abs() {
276                            value = analog;
277                        }
278                    }
279                }
280            }
281
282            BoundAxis::MultiDigital { negative, positive } => {
283                for device in connected_devices {
284                    if let Some(device) = manager.get_state(*device) {
285                        let pos = if device.get_digital((*positive).into()) {
286                            1f32
287                        } else {
288                            0f32
289                        };
290                        let neg = if device.get_digital((*negative).into()) {
291                            1f32
292                        } else {
293                            0f32
294                        };
295                        let analog = pos - neg;
296                        if analog.abs() > value.abs() {
297                            value = analog;
298                        }
299                    }
300                }
301            }
302        }
303
304        return value;
305    }
306
307    fn get_bound_button<'b, TButton, TAxis>(
308        manager: &InputDeviceManager,
309        button: &BoundButton<TButton, TAxis>,
310        connected_devices: &Vec<usize>,
311    ) -> bool
312    where
313        TButton: Sized
314            + Debug
315            + Clone
316            + Copy
317            + PartialEq
318            + PartialOrd
319            + Serialize
320            + Deserialize<'b>
321            + Into<usize>,
322        TAxis: Sized
323            + Debug
324            + Clone
325            + Copy
326            + PartialEq
327            + PartialOrd
328            + Serialize
329            + Deserialize<'b>
330            + Into<usize>,
331    {
332        match button {
333            BoundButton::Analog { threshold, axis } => {
334                for device in connected_devices {
335                    if let Some(device) = manager.get_state(*device) {
336                        if device.get_analog((*axis).into()) > *threshold {
337                            return true;
338                        }
339                    }
340                }
341            }
342
343            BoundButton::Digital(button) => {
344                for device in connected_devices {
345                    if let Some(device) = manager.get_state(*device) {
346                        if device.get_digital((*button).into()) {
347                            return true;
348                        }
349                    }
350                }
351            }
352        }
353
354        return false;
355    }
356
357    fn get_binding_digital(&self, managers: &InputDeviceManagers, button: &DigitalBinding) -> bool {
358        return match button {
359            DigitalBinding::Gamepad(gamepad) => {
360                let Ok(devices) = self.connected_gamepads.read() else {
361                    return false;
362                };
363
364                Self::get_bound_button(&managers.gamepad_manager, gamepad, &devices)
365            }
366
367            DigitalBinding::Keyboard(keyboard) => {
368                let Ok(devices) = self.connected_keyboards.read() else {
369                    return false;
370                };
371
372                Self::get_bound_button(&managers.keyboard_manager, keyboard, &devices)
373            }
374
375            DigitalBinding::Mouse(mouse) => {
376                let Ok(devices) = self.connected_mice.read() else {
377                    return false;
378                };
379
380                Self::get_bound_button(&managers.mouse_manager, mouse, &devices)
381            }
382        };
383    }
384
385    fn get_binding_analog(&self, managers: &InputDeviceManagers, axis: &AnalogBinding) -> f32 {
386        return match &axis.axis {
387            AnalogBindingKind::Gamepad(gamepad) => {
388                let Ok(devices) = self.connected_gamepads.read() else {
389                    return 0f32;
390                };
391
392                Self::get_bound_axis(&managers.gamepad_manager, gamepad, &devices)
393            }
394
395            AnalogBindingKind::Keyboard(keyboard) => {
396                let Ok(devices) = self.connected_keyboards.read() else {
397                    return 0f32;
398                };
399
400                Self::get_bound_axis(&managers.keyboard_manager, keyboard, &devices)
401            }
402
403            AnalogBindingKind::Mouse(mouse) => {
404                let Ok(devices) = self.connected_mice.read() else {
405                    return 0f32;
406                };
407
408                Self::get_bound_axis(&managers.mouse_manager, mouse, &devices)
409            }
410        };
411    }
412
413    fn get_binding_vector(
414        &self,
415        managers: &InputDeviceManagers,
416        vec: &VectorBinding,
417    ) -> (f32, f32) {
418        return match &vec.axes {
419            VectorBindingKind::Gamepad { x, y } => {
420                let Ok(devices) = self.connected_gamepads.read() else {
421                    return (0f32, 0f32);
422                };
423
424                (
425                    Self::get_bound_axis(&managers.gamepad_manager, x, &devices),
426                    Self::get_bound_axis(&managers.gamepad_manager, y, &devices),
427                )
428            }
429
430            VectorBindingKind::Keyboard { x, y } => {
431                let Ok(devices) = self.connected_keyboards.read() else {
432                    return (0f32, 0f32);
433                };
434
435                (
436                    Self::get_bound_axis(&managers.keyboard_manager, x, &devices),
437                    Self::get_bound_axis(&managers.keyboard_manager, y, &devices),
438                )
439            }
440
441            VectorBindingKind::Mouse { x, y } => {
442                let Ok(devices) = self.connected_mice.read() else {
443                    return (0f32, 0f32);
444                };
445
446                (
447                    Self::get_bound_axis(&managers.mouse_manager, x, &devices),
448                    Self::get_bound_axis(&managers.mouse_manager, y, &devices),
449                )
450            }
451        };
452    }
453
454    fn vec_len_squared(v: (f32, f32)) -> f32 {
455        return v.0 * v.0 + v.1 * v.1;
456    }
457
458    fn vec_sub(a: (f32, f32), b: (f32, f32)) -> (f32, f32) {
459        return (a.0 - b.0, a.1 - b.1);
460    }
461
462    pub fn update(&self, managers: &InputDeviceManagers, bindings: &BindingMap) {
463        for (index, value) in bindings.values.iter().enumerate() {
464            let frame = &self.frames[index];
465
466            match &*value {
467                BindingList::Analog(bindings) => {
468                    let Ok(bindings) = bindings.read() else {
469                        continue;
470                    };
471
472                    let Ok(mut frame) = frame.write() else {
473                        continue;
474                    };
475
476                    let old = if let InputFrame::Analog { value, .. } = &*frame {
477                        *value
478                    } else {
479                        0f32
480                    };
481                    let mut value = 0f32;
482
483                    for binding in &*bindings {
484                        let analog = self.get_binding_analog(managers, binding);
485
486                        if analog.abs() > value.abs() {
487                            value = analog;
488                        }
489                    }
490
491                    *frame = InputFrame::Analog {
492                        value,
493                        delta: value - old,
494                    };
495                }
496
497                BindingList::Digital(bindings) => {
498                    let Ok(bindings) = bindings.read() else {
499                        continue;
500                    };
501
502                    let Ok(mut frame) = frame.write() else {
503                        continue;
504                    };
505
506                    let old = if let InputFrame::Digital { value, .. } = &*frame {
507                        *value
508                    } else {
509                        false
510                    };
511                    let mut value = false;
512
513                    for binding in &*bindings {
514                        if self.get_binding_digital(managers, binding) {
515                            value = true;
516                            break;
517                        }
518                    }
519
520                    *frame = InputFrame::Digital {
521                        value,
522                        just_pressed: value && !old,
523                        just_released: !value && old,
524                    };
525                }
526
527                BindingList::Vector(bindings) => {
528                    let Ok(bindings) = bindings.read() else {
529                        continue;
530                    };
531
532                    let Ok(mut frame) = frame.write() else {
533                        continue;
534                    };
535
536                    let old = if let InputFrame::Vector { value, .. } = &*frame {
537                        *value
538                    } else {
539                        (0f32, 0f32)
540                    };
541                    let mut value = (0f32, 0f32);
542
543                    for binding in &*bindings {
544                        let vec = self.get_binding_vector(managers, binding);
545
546                        if Self::vec_len_squared(vec) > Self::vec_len_squared(value) {
547                            value = vec;
548                        }
549                    }
550
551                    *frame = InputFrame::Vector {
552                        value,
553                        delta: Self::vec_sub(value, old),
554                    };
555                }
556            };
557        }
558    }
559
560    pub fn get_frame(&self, index: &HashMap<String, usize>, name: &str) -> Option<InputFrame> {
561        let index = match index.get(name) {
562            Some(index) => index,
563            None => return None,
564        };
565
566        return Some(self.frames[*index].read().ok()?.clone());
567    }
568
569    pub fn connect_device(&self, family: InputFamily, id: usize) {
570        let Ok(mut devices) = match family {
571            InputFamily::Gamepad => &self.connected_gamepads,
572            InputFamily::Keyboard => &self.connected_keyboards,
573            InputFamily::Mouse => &self.connected_mice,
574        }
575        .write() else {
576            return;
577        };
578
579        devices.push(id);
580    }
581
582    pub fn connect_device_raw(
583        &self,
584        managers: &InputDeviceManagers,
585        family: InputFamily,
586        id: usize,
587    ) {
588        let Some(id) = match family {
589            InputFamily::Gamepad => &managers.gamepad_manager,
590            InputFamily::Keyboard => &managers.keyboard_manager,
591            InputFamily::Mouse => &managers.mouse_manager,
592        }
593        .raw_id_to_id(id) else {
594            return;
595        };
596
597        self.connect_device(family, id);
598    }
599
600    pub fn disconnect_device(&self, family: InputFamily, id: usize) {
601        let Ok(mut devices) = match family {
602            InputFamily::Gamepad => &self.connected_gamepads,
603            InputFamily::Keyboard => &self.connected_keyboards,
604            InputFamily::Mouse => &self.connected_mice,
605        }
606        .write() else {
607            return;
608        };
609
610        devices
611            .iter()
612            .position(|it| *it == id)
613            .map(|it| devices.remove(it));
614    }
615
616    pub fn disconnect_device_raw(
617        &self,
618        managers: &InputDeviceManagers,
619        family: InputFamily,
620        id: usize,
621    ) {
622        let Some(id) = match family {
623            InputFamily::Gamepad => &managers.gamepad_manager,
624            InputFamily::Keyboard => &managers.keyboard_manager,
625            InputFamily::Mouse => &managers.mouse_manager,
626        }
627        .raw_id_to_id(id) else {
628            return;
629        };
630
631        self.disconnect_device(family, id);
632    }
633}