1use std::collections::{HashMap, HashSet};
2
3use crate::buttons::{Axis1d, Axis2d, Button, MouseAxis1d};
4
5pub struct InputState {
6 buttons: HashMap<Button, ButtonState>,
7
8 mouse_motion: (f32, f32),
9 cursor_position: (f32, f32),
10}
11
12#[derive(Debug, Clone, Copy)]
13pub enum ButtonState {
14 Pressed,
15 Released,
16 JustPressed,
17 JustReleased,
18}
19
20impl InputState {
21 pub fn new() -> Self {
22 Self {
23 buttons: HashMap::new(),
24
25 mouse_motion: (0.0, 0.0),
26 cursor_position: (0.0, 0.0),
27 }
28 }
29
30 pub fn button_state(&self, button: Button) -> ButtonState {
31 self.buttons
32 .get(&button)
33 .copied()
34 .unwrap_or(ButtonState::Released)
35 }
36
37 pub fn is_button_just_down(&self, button: Button) -> bool {
38 matches!(self.buttons.get(&button), Some(ButtonState::JustPressed))
39 }
40
41 pub fn is_button_down(&self, button: Button) -> bool {
42 matches!(
43 self.buttons.get(&button),
44 Some(ButtonState::Pressed | ButtonState::JustPressed)
45 )
46 }
47
48 pub fn get_axis1d(&self, axis: Axis1d) -> f32 {
49 match axis {
50 Axis1d::Mouse(mouse) => match mouse {
51 MouseAxis1d::X => self.mouse_motion.0,
52 MouseAxis1d::Y => self.mouse_motion.1,
53 },
54 Axis1d::Gamepad(_) => todo!(),
55 }
56 }
57
58 pub fn get_axis2d(&self, axis: Axis2d) -> (f32, f32) {
59 match axis {
60 Axis2d::Mouse(_) => self.mouse_motion,
61 Axis2d::Gamepad(_) => todo!(),
62 }
63 }
64
65 pub fn cursor_position(&self) -> (f32, f32) {
66 self.cursor_position
67 }
68
69 pub fn end_update(&mut self) {
70 self.mouse_motion = (0.0, 0.0);
71
72 let mut to_remove = HashSet::new();
73
74 for (button, state) in self.buttons.iter_mut() {
75 match state {
76 ButtonState::JustPressed => *state = ButtonState::Pressed,
77 ButtonState::JustReleased => {
78 to_remove.insert(*button);
79 }
80 _ => {}
81 }
82 }
83
84 for button in to_remove {
85 self.buttons.remove(&button);
86 }
87 }
88
89 #[cfg(feature = "gilrs")]
90 pub fn handle_gilrs_event(&mut self, event: &gilrs::Event) {
91 use crate::GamepadButton;
92 use gilrs::EventType;
93
94 match &event.event {
95 EventType::ButtonPressed(button, _) => {
96 if let Ok(button) = GamepadButton::try_from(*button) {
97 self.buttons
98 .insert(Button::Gamepad(button), ButtonState::JustPressed);
99 }
100 }
101
102 EventType::ButtonReleased(button, _) => {
103 if let Ok(button) = GamepadButton::try_from(*button) {
104 self.buttons
105 .insert(Button::Gamepad(button), ButtonState::JustReleased);
106 }
107 }
108
109 _ => {}
110 }
111 }
112
113 #[cfg(feature = "winit")]
114 pub fn handle_winit_event<T>(&mut self, event: &winit::event::Event<T>) {
115 use crate::{KeyboardKey, MouseButton};
116 use winit::event::{DeviceEvent, ElementState, Event, WindowEvent};
117
118 match event {
119 Event::WindowEvent {
120 event: WindowEvent::KeyboardInput { input, .. },
121 ..
122 } => match input.virtual_keycode {
123 Some(keycode) => {
124 if let Ok(key) = KeyboardKey::try_from(keycode) {
125 match input.state {
126 ElementState::Pressed => {
127 self.buttons
128 .insert(Button::Keyboard(key), ButtonState::JustPressed);
129 }
130 ElementState::Released => {
131 self.buttons
132 .insert(Button::Keyboard(key), ButtonState::JustReleased);
133 }
134 }
135 }
136 }
137 None => {}
138 },
139
140 Event::WindowEvent {
141 event: WindowEvent::MouseInput { state, button, .. },
142 ..
143 } => {
144 if let Ok(button) = MouseButton::try_from(*button) {
145 match state {
146 ElementState::Pressed => {
147 self.buttons
148 .insert(Button::Mouse(button), ButtonState::JustPressed);
149 }
150 ElementState::Released => {
151 self.buttons
152 .insert(Button::Mouse(button), ButtonState::JustReleased);
153 }
154 }
155 }
156 }
157
158 Event::WindowEvent {
159 event: WindowEvent::CursorMoved { position, .. },
160 ..
161 } => {
162 self.cursor_position = (position.x as f32, position.y as f32);
163 }
164
165 Event::DeviceEvent {
166 event: DeviceEvent::MouseMotion { delta },
167 ..
168 } => {
169 self.mouse_motion.0 += delta.0 as f32;
170 self.mouse_motion.1 += delta.1 as f32;
171 }
172
173 _ => {}
174 }
175 }
176}