1#[cfg(not(target_arch = "wasm32"))]
5use gilrs::{Axis, Button, Event, EventType, Gilrs};
6use std::collections::HashMap;
7use std::fmt::Debug;
8use winit::event::{ElementState, KeyEvent, MouseButton};
9use winit::keyboard::{KeyCode, PhysicalKey};
10
11pub trait GameAction: Copy + Eq + Debug + 'static {
13 fn count() -> usize;
15
16 fn index(&self) -> usize;
18
19 fn from_index(index: usize) -> Option<Self>;
21
22 fn move_negative_x() -> Option<Self> {
23 None
24 }
25
26 fn move_positive_x() -> Option<Self> {
27 None
28 }
29
30 fn move_negative_y() -> Option<Self> {
31 None
32 }
33
34 fn move_positive_y() -> Option<Self> {
35 None
36 }
37}
38
39#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
41pub enum MouseBinding {
42 Left,
43 Right,
44 Middle,
45}
46
47#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
49pub enum Key {
50 W,
51 A,
52 S,
53 D,
54 Space,
55 Shift,
56 Alt,
57 Up,
58 Down,
59 Left,
60 Right,
61 F12,
62 Escape,
63}
64
65impl Key {
66 fn from_keycode(code: KeyCode) -> Option<Self> {
67 match code {
68 KeyCode::KeyW => Some(Key::W),
69 KeyCode::KeyA => Some(Key::A),
70 KeyCode::KeyS => Some(Key::S),
71 KeyCode::KeyD => Some(Key::D),
72 KeyCode::Space => Some(Key::Space),
73 KeyCode::ShiftLeft => Some(Key::Shift),
74 KeyCode::AltLeft => Some(Key::Alt),
75 KeyCode::ArrowUp => Some(Key::Up),
76 KeyCode::ArrowDown => Some(Key::Down),
77 KeyCode::ArrowLeft => Some(Key::Left),
78 KeyCode::ArrowRight => Some(Key::Right),
79 KeyCode::F12 => Some(Key::F12),
80 KeyCode::Escape => Some(Key::Escape),
81 _ => None,
82 }
83 }
84}
85
86pub struct InputMap<A: GameAction> {
88 keyboard_map: HashMap<Key, A>,
89 mouse_map: HashMap<MouseBinding, A>,
90 #[cfg(not(target_arch = "wasm32"))]
91 gamepad_map: HashMap<Button, A>,
92}
93
94impl<A: GameAction> InputMap<A> {
95 pub fn new() -> Self {
96 Self {
97 keyboard_map: HashMap::new(),
98 mouse_map: HashMap::new(),
99 #[cfg(not(target_arch = "wasm32"))]
100 gamepad_map: HashMap::new(),
101 }
102 }
103
104 pub fn bind_key(&mut self, key: Key, action: A) {
105 self.keyboard_map.insert(key, action);
106 }
107
108 pub fn bind_mouse(&mut self, button: MouseBinding, action: A) {
109 self.mouse_map.insert(button, action);
110 }
111
112 #[cfg(not(target_arch = "wasm32"))]
113 pub fn bind_button(&mut self, button: Button, action: A) {
114 self.gamepad_map.insert(button, action);
115 }
116
117 #[cfg(not(target_arch = "wasm32"))]
118 fn get_action_for_button(&self, button: Button) -> Option<A> {
119 self.gamepad_map.get(&button).copied()
120 }
121}
122
123impl<A: GameAction> Default for InputMap<A> {
124 fn default() -> Self {
125 Self::new()
126 }
127}
128
129#[derive(Debug, Clone, Copy)]
131struct BufferedInput<A: GameAction> {
132 action: A,
133 time_pressed: f32,
134}
135
136pub struct InputState<A: GameAction> {
138 keys: [bool; 13],
139 keys_prev: [bool; 13],
140 actions: Vec<bool>,
141 actions_prev: Vec<bool>,
142 mouse_buttons: [bool; 3],
143 gamepad_axes: [f32; 2],
144
145 #[cfg(not(target_arch = "wasm32"))]
146 gamepad_buttons: Vec<bool>,
147 input_map: InputMap<A>,
148
149 #[cfg(not(target_arch = "wasm32"))]
150 gilrs: Option<Gilrs>,
151 input_buffer: Vec<BufferedInput<A>>,
152 current_time: f32,
153}
154
155impl<A: GameAction> InputState<A> {
156 pub fn new() -> Self {
157 let action_count = A::count();
158 Self {
159 keys: [false; 13],
160 keys_prev: [false; 13],
161 actions: vec![false; action_count],
162 actions_prev: vec![false; action_count],
163 mouse_buttons: [false; 3],
164 gamepad_axes: [0.0; 2],
165 #[cfg(not(target_arch = "wasm32"))]
166 gamepad_buttons: vec![false; action_count],
167 input_map: InputMap::new(),
168
169 #[cfg(not(target_arch = "wasm32"))]
170 gilrs: match Gilrs::new() {
171 Ok(g) => Some(g),
172 Err(e) => {
173 log::warn!("Failed to initialize gamepad support: {e}");
174 None
175 }
176 },
177 input_buffer: Vec::with_capacity(8),
178 current_time: 0.0,
179 }
180 }
181
182 pub fn is_action_pressed(&self, action: A) -> bool {
183 self.actions[action.index()]
184 }
185
186 pub fn is_action_just_pressed(&self, action: A) -> bool {
187 let idx = action.index();
188 self.actions[idx] && !self.actions_prev[idx]
189 }
190
191 pub fn was_action_pressed_buffered(&self, action: A, buffer_window: f32) -> bool {
192 if self.is_action_just_pressed(action) {
193 return true;
194 }
195
196 for buffered in &self.input_buffer {
197 if buffered.action == action {
198 let elapsed = self.current_time - buffered.time_pressed;
199 if elapsed <= buffer_window {
200 return true;
201 }
202 }
203 }
204
205 false
206 }
207
208 #[allow(dead_code)]
210 pub fn is_key_pressed(&self, key: Key) -> bool {
211 self.keys[key as usize]
212 }
213
214 #[allow(dead_code)]
216 pub fn is_key_just_pressed(&self, key: Key) -> bool {
217 let idx = key as usize;
218 self.keys[idx] && !self.keys_prev[idx]
219 }
220
221 pub fn is_mouse_pressed(&self, button: MouseButton) -> bool {
222 match button {
223 MouseButton::Left => self.mouse_buttons[0],
224 MouseButton::Right => self.mouse_buttons[1],
225 MouseButton::Middle => self.mouse_buttons[2],
226 _ => false,
227 }
228 }
229
230 pub fn get_move_x(&self) -> f32 {
232 let mut value = 0.0;
233
234 if let Some(left) = A::move_negative_x()
235 && self.is_action_pressed(left)
236 {
237 value -= 1.0;
238 }
239 if let Some(right) = A::move_positive_x()
240 && self.is_action_pressed(right)
241 {
242 value += 1.0;
243 }
244
245 if self.gamepad_axes[0].abs() > 0.1 {
246 value = self.gamepad_axes[0];
247 }
248
249 value
250 }
251
252 pub fn get_move_y(&self) -> f32 {
254 let mut value = 0.0;
255
256 if let Some(up) = A::move_negative_y()
257 && self.is_action_pressed(up)
258 {
259 value -= 1.0;
260 }
261 if let Some(down) = A::move_positive_y()
262 && self.is_action_pressed(down)
263 {
264 value += 1.0;
265 }
266
267 if self.gamepad_axes[1].abs() > 0.1 {
268 value = self.gamepad_axes[1];
269 }
270
271 value
272 }
273
274 pub fn any_keyboard_or_mouse(&self) -> bool {
275 self.keys.iter().any(|&k| k) || self.mouse_buttons.iter().any(|&b| b)
276 }
277
278 pub fn any_gamepad(&self) -> bool {
279 if self.gamepad_axes.iter().any(|&a| a.abs() > 0.1) {
280 return true;
281 }
282 #[cfg(not(target_arch = "wasm32"))]
283 {
284 if self.gamepad_buttons.iter().any(|&b| b) {
285 return true;
286 }
287 }
288 false
289 }
290
291 pub fn begin_frame(&mut self, delta_time: f32) {
295 self.actions_prev.clone_from(&self.actions);
296 self.current_time += delta_time;
297
298 self.actions.fill(false);
300 for (&key, &action) in &self.input_map.keyboard_map {
301 if self.keys[key as usize] {
302 self.actions[action.index()] = true;
303 }
304 }
305
306 for (&binding, &action) in &self.input_map.mouse_map {
308 let idx = match binding {
309 MouseBinding::Left => 0,
310 MouseBinding::Right => 1,
311 MouseBinding::Middle => 2,
312 };
313 if self.mouse_buttons[idx] {
314 self.actions[action.index()] = true;
315 }
316 }
317
318 #[cfg(not(target_arch = "wasm32"))]
320 {
321 if let Some(ref mut gilrs) = self.gilrs {
322 while let Some(Event { event, .. }) = gilrs.next_event() {
323 match event {
324 EventType::ButtonPressed(button, _) => {
325 if let Some(action) = self.input_map.get_action_for_button(button) {
326 self.gamepad_buttons[action.index()] = true;
327 }
328 }
329 EventType::ButtonReleased(button, _) => {
330 if let Some(action) = self.input_map.get_action_for_button(button) {
331 self.gamepad_buttons[action.index()] = false;
332 }
333 }
334 EventType::AxisChanged(Axis::LeftStickX, value, _) => {
335 self.gamepad_axes[0] = value;
336 }
337 EventType::AxisChanged(Axis::LeftStickY, value, _) => {
338 self.gamepad_axes[1] = -value;
339 }
340 _ => {}
341 }
342 }
343 }
344
345 let action_count = A::count();
347 for i in 0..action_count {
348 if self.gamepad_buttons[i] {
349 self.actions[i] = true;
350 }
351 }
352 }
353
354 let action_count = A::count();
356 for i in 0..action_count {
357 if self.actions[i] && !self.actions_prev[i]
358 && let Some(action) = A::from_index(i)
359 {
360 self.input_buffer.push(BufferedInput {
361 action,
362 time_pressed: self.current_time,
363 });
364 }
365 }
366
367 self.input_buffer
369 .retain(|buffered| self.current_time - buffered.time_pressed < 1.0);
370 }
371
372 pub fn end_frame(&mut self) {
373 self.keys_prev = self.keys;
374 }
375
376 pub(crate) fn handle_key_event(&mut self, event: &KeyEvent) {
378 let pressed = event.state == ElementState::Pressed;
379
380 if let PhysicalKey::Code(keycode) = event.physical_key
381 && let Some(key) = Key::from_keycode(keycode)
382 {
383 self.keys[key as usize] = pressed;
384 }
385 }
386
387 pub(crate) fn handle_mouse_button(&mut self, button: MouseButton, pressed: bool) {
389 match button {
390 MouseButton::Left => self.mouse_buttons[0] = pressed,
391 MouseButton::Right => self.mouse_buttons[1] = pressed,
392 MouseButton::Middle => self.mouse_buttons[2] = pressed,
393 _ => {}
394 }
395 }
396
397 pub fn input_map_mut(&mut self) -> &mut InputMap<A> {
398 &mut self.input_map
399 }
400}
401
402impl<A: GameAction> Default for InputState<A> {
403 fn default() -> Self {
404 Self::new()
405 }
406}