1use std::collections::HashSet;
4
5#[derive(Debug, Clone)]
7pub enum InputEvent {
8 KeyPressed(KeyCode),
10 KeyReleased(KeyCode),
12 MousePressed(MouseButton),
14 MouseReleased(MouseButton),
16 MouseMoved {
18 x: f64,
20 y: f64,
22 },
23 MouseWheel {
25 delta_x: f64,
27 delta_y: f64,
29 },
30}
31
32#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
34#[allow(missing_docs)]
35pub enum KeyCode {
36 A,
38 B,
39 C,
40 D,
41 E,
42 F,
43 G,
44 H,
45 I,
46 J,
47 K,
48 L,
49 M,
50 N,
51 O,
52 P,
53 Q,
54 R,
55 S,
56 T,
57 U,
58 V,
59 W,
60 X,
61 Y,
62 Z,
63
64 Num0,
66 Num1,
67 Num2,
68 Num3,
69 Num4,
70 Num5,
71 Num6,
72 Num7,
73 Num8,
74 Num9,
75
76 F1,
78 F2,
79 F3,
80 F4,
81 F5,
82 F6,
83 F7,
84 F8,
85 F9,
86 F10,
87 F11,
88 F12,
89
90 Escape,
92 Enter,
93 Space,
94 Tab,
95 Backspace,
96 Shift,
97 Control,
98 Alt,
99
100 Up,
102 Down,
103 Left,
104 Right,
105}
106
107#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
109pub enum MouseButton {
110 Left,
112 Right,
114 Middle,
116 Back,
118 Forward,
120 Other(u16),
122}
123
124#[derive(Debug, Default)]
126pub struct InputState {
127 pressed_keys: HashSet<KeyCode>,
129 pressed_mouse_buttons: HashSet<MouseButton>,
131 mouse_position: (f64, f64),
133 scroll_delta: (f64, f64),
135}
136
137impl InputState {
138 #[must_use]
140 pub fn new() -> Self {
141 Self::default()
142 }
143
144 pub fn process_event(&mut self, event: &InputEvent) {
146 match event {
147 InputEvent::KeyPressed(key) => {
148 self.pressed_keys.insert(*key);
149 }
150 InputEvent::KeyReleased(key) => {
151 self.pressed_keys.remove(key);
152 }
153 InputEvent::MousePressed(button) => {
154 self.pressed_mouse_buttons.insert(*button);
155 }
156 InputEvent::MouseReleased(button) => {
157 self.pressed_mouse_buttons.remove(button);
158 }
159 InputEvent::MouseMoved { x, y } => {
160 self.mouse_position = (*x, *y);
161 }
162 InputEvent::MouseWheel { delta_x, delta_y } => {
163 self.scroll_delta.0 += delta_x;
164 self.scroll_delta.1 += delta_y;
165 }
166 }
167 }
168
169 #[must_use]
171 pub fn is_key_pressed(&self, key: KeyCode) -> bool {
172 self.pressed_keys.contains(&key)
173 }
174
175 #[must_use]
177 pub fn is_mouse_button_pressed(&self, button: MouseButton) -> bool {
178 self.pressed_mouse_buttons.contains(&button)
179 }
180
181 #[must_use]
183 pub fn mouse_position(&self) -> (f64, f64) {
184 self.mouse_position
185 }
186
187 pub fn take_scroll_delta(&mut self) -> (f64, f64) {
189 let delta = self.scroll_delta;
190 self.scroll_delta = (0.0, 0.0);
191 delta
192 }
193
194 pub fn clear(&mut self) {
196 self.pressed_keys.clear();
197 self.pressed_mouse_buttons.clear();
198 self.scroll_delta = (0.0, 0.0);
199 }
200}
201
202#[cfg(test)]
203mod tests {
204 use super::*;
205
206 #[test]
207 fn test_input_state_default() {
208 let state = InputState::new();
209 assert!(!state.is_key_pressed(KeyCode::A));
210 assert!(!state.is_mouse_button_pressed(MouseButton::Left));
211 assert_eq!(state.mouse_position(), (0.0, 0.0));
212 }
213
214 #[test]
215 fn test_key_press_release() {
216 let mut state = InputState::new();
217
218 state.process_event(&InputEvent::KeyPressed(KeyCode::W));
220 assert!(state.is_key_pressed(KeyCode::W));
221 assert!(!state.is_key_pressed(KeyCode::A));
222
223 state.process_event(&InputEvent::KeyPressed(KeyCode::A));
225 assert!(state.is_key_pressed(KeyCode::W));
226 assert!(state.is_key_pressed(KeyCode::A));
227
228 state.process_event(&InputEvent::KeyReleased(KeyCode::W));
230 assert!(!state.is_key_pressed(KeyCode::W));
231 assert!(state.is_key_pressed(KeyCode::A));
232 }
233
234 #[test]
235 fn test_mouse_button_press_release() {
236 let mut state = InputState::new();
237
238 state.process_event(&InputEvent::MousePressed(MouseButton::Left));
239 assert!(state.is_mouse_button_pressed(MouseButton::Left));
240 assert!(!state.is_mouse_button_pressed(MouseButton::Right));
241
242 state.process_event(&InputEvent::MouseReleased(MouseButton::Left));
243 assert!(!state.is_mouse_button_pressed(MouseButton::Left));
244 }
245
246 #[test]
247 fn test_mouse_movement() {
248 let mut state = InputState::new();
249
250 state.process_event(&InputEvent::MouseMoved { x: 100.0, y: 200.0 });
251 assert_eq!(state.mouse_position(), (100.0, 200.0));
252
253 state.process_event(&InputEvent::MouseMoved { x: 150.0, y: 250.0 });
254 assert_eq!(state.mouse_position(), (150.0, 250.0));
255 }
256
257 #[test]
258 fn test_scroll_accumulation() {
259 let mut state = InputState::new();
260
261 state.process_event(&InputEvent::MouseWheel {
262 delta_x: 1.0,
263 delta_y: 2.0,
264 });
265 state.process_event(&InputEvent::MouseWheel {
266 delta_x: 0.5,
267 delta_y: 1.0,
268 });
269
270 let delta = state.take_scroll_delta();
271 assert!((delta.0 - 1.5).abs() < f64::EPSILON);
272 assert!((delta.1 - 3.0).abs() < f64::EPSILON);
273
274 let delta = state.take_scroll_delta();
276 assert!((delta.0).abs() < f64::EPSILON);
277 assert!((delta.1).abs() < f64::EPSILON);
278 }
279
280 #[test]
281 fn test_clear() {
282 let mut state = InputState::new();
283
284 state.process_event(&InputEvent::KeyPressed(KeyCode::Space));
285 state.process_event(&InputEvent::MousePressed(MouseButton::Left));
286 state.process_event(&InputEvent::MouseWheel {
287 delta_x: 1.0,
288 delta_y: 1.0,
289 });
290
291 assert!(state.is_key_pressed(KeyCode::Space));
292 assert!(state.is_mouse_button_pressed(MouseButton::Left));
293
294 state.clear();
295
296 assert!(!state.is_key_pressed(KeyCode::Space));
297 assert!(!state.is_mouse_button_pressed(MouseButton::Left));
298 let delta = state.take_scroll_delta();
299 assert!((delta.0).abs() < f64::EPSILON);
300 }
301
302 #[test]
303 fn test_mouse_button_other() {
304 let mut state = InputState::new();
305
306 state.process_event(&InputEvent::MousePressed(MouseButton::Other(5)));
307 assert!(state.is_mouse_button_pressed(MouseButton::Other(5)));
308 assert!(!state.is_mouse_button_pressed(MouseButton::Other(6)));
309 }
310}
311