cloudiful_bevy_input/
bindings.rs1use bevy::input::gamepad::{GamepadAxis, GamepadButton};
2use bevy::input::keyboard::KeyCode;
3use bevy::prelude::Resource;
4use std::collections::HashMap;
5use std::hash::Hash;
6
7pub trait InputAction: Copy + Eq + Hash + Send + Sync + 'static {}
8
9impl<T> InputAction for T where T: Copy + Eq + Hash + Send + Sync + 'static {}
10
11#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
12pub enum InputButton {
13 Key(KeyCode),
14 Gamepad(GamepadButton),
15}
16
17#[derive(Debug, Clone, Copy, PartialEq)]
18pub enum InputBinding {
19 Button(InputButton),
20 GamepadAxis(GamepadAxis),
21 ButtonAxis {
22 negative: InputButton,
23 positive: InputButton,
24 },
25}
26
27#[derive(Resource, Debug, Clone)]
28pub struct InputMap<A: InputAction> {
29 bindings: HashMap<A, Vec<InputBinding>>,
30}
31
32impl<A: InputAction> Default for InputMap<A> {
33 fn default() -> Self {
34 Self {
35 bindings: HashMap::new(),
36 }
37 }
38}
39
40impl<A: InputAction> InputMap<A> {
41 pub fn bindings(&self, action: A) -> &[InputBinding] {
42 self.bindings.get(&action).map(Vec::as_slice).unwrap_or(&[])
43 }
44
45 pub fn actions(&self) -> impl Iterator<Item = A> + '_ {
46 self.bindings.keys().copied()
47 }
48
49 pub fn clear_action(&mut self, action: A) {
50 self.bindings.remove(&action);
51 }
52
53 pub fn set_bindings(
54 &mut self,
55 action: A,
56 bindings: impl IntoIterator<Item = InputBinding>,
57 ) -> &mut Self {
58 self.bindings.insert(action, bindings.into_iter().collect());
59 self
60 }
61
62 pub fn bind_key(&mut self, action: A, key: KeyCode) -> &mut Self {
63 self.push(action, InputBinding::Button(InputButton::Key(key)))
64 }
65
66 pub fn bind_gamepad_button(&mut self, action: A, button: GamepadButton) -> &mut Self {
67 self.push(action, InputBinding::Button(InputButton::Gamepad(button)))
68 }
69
70 pub fn bind_gamepad_axis(&mut self, action: A, axis: GamepadAxis) -> &mut Self {
71 self.push(action, InputBinding::GamepadAxis(axis))
72 }
73
74 pub fn bind_button_axis(
75 &mut self,
76 action: A,
77 negative: InputButton,
78 positive: InputButton,
79 ) -> &mut Self {
80 self.push(action, InputBinding::ButtonAxis { negative, positive })
81 }
82
83 pub fn rebind_button(&mut self, action: A, old: InputButton, new: InputButton) -> bool {
84 self.replace(action, |binding| match binding {
85 InputBinding::Button(button) if *button == old => {
86 *binding = InputBinding::Button(new);
87 true
88 }
89 InputBinding::ButtonAxis { negative, positive } if *negative == old => {
90 *binding = InputBinding::ButtonAxis {
91 negative: new,
92 positive: *positive,
93 };
94 true
95 }
96 InputBinding::ButtonAxis { negative, positive } if *positive == old => {
97 *binding = InputBinding::ButtonAxis {
98 negative: *negative,
99 positive: new,
100 };
101 true
102 }
103 _ => false,
104 })
105 }
106
107 pub fn rebind_gamepad_axis(&mut self, action: A, old: GamepadAxis, new: GamepadAxis) -> bool {
108 self.replace(action, |binding| match binding {
109 InputBinding::GamepadAxis(axis) if *axis == old => {
110 *binding = InputBinding::GamepadAxis(new);
111 true
112 }
113 _ => false,
114 })
115 }
116
117 fn push(&mut self, action: A, binding: InputBinding) -> &mut Self {
118 self.bindings.entry(action).or_default().push(binding);
119 self
120 }
121
122 fn replace(&mut self, action: A, mut replace: impl FnMut(&mut InputBinding) -> bool) -> bool {
123 let Some(bindings) = self.bindings.get_mut(&action) else {
124 return false;
125 };
126
127 for binding in bindings.iter_mut() {
128 if replace(binding) {
129 return true;
130 }
131 }
132
133 false
134 }
135}