1use std::collections::HashSet;
7use bevy_ecs::prelude::*;
8use glam::Vec2;
9
10#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
22pub enum KeyCode {
23 A, B, C, D, E, F, G, H, I, J, K, L, M,
25 N, O, P, Q, R, S, T, U, V, W, X, Y, Z,
26 Key0, Key1, Key2, Key3, Key4,
28 Key5, Key6, Key7, Key8, Key9,
29 F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12,
31 Space, Enter, Escape, Tab, Backspace, Delete,
33 Left, Right, Up, Down,
34 LShift, RShift, LControl, RControl, LAlt, RAlt,
35}
36
37impl KeyCode {
38 pub fn from_winit(key: winit::keyboard::KeyCode) -> Option<KeyCode> {
40 use winit::keyboard::KeyCode as WK;
41 match key {
42 WK::KeyA => Some(KeyCode::A), WK::KeyB => Some(KeyCode::B),
43 WK::KeyC => Some(KeyCode::C), WK::KeyD => Some(KeyCode::D),
44 WK::KeyE => Some(KeyCode::E), WK::KeyF => Some(KeyCode::F),
45 WK::KeyG => Some(KeyCode::G), WK::KeyH => Some(KeyCode::H),
46 WK::KeyI => Some(KeyCode::I), WK::KeyJ => Some(KeyCode::J),
47 WK::KeyK => Some(KeyCode::K), WK::KeyL => Some(KeyCode::L),
48 WK::KeyM => Some(KeyCode::M), WK::KeyN => Some(KeyCode::N),
49 WK::KeyO => Some(KeyCode::O), WK::KeyP => Some(KeyCode::P),
50 WK::KeyQ => Some(KeyCode::Q), WK::KeyR => Some(KeyCode::R),
51 WK::KeyS => Some(KeyCode::S), WK::KeyT => Some(KeyCode::T),
52 WK::KeyU => Some(KeyCode::U), WK::KeyV => Some(KeyCode::V),
53 WK::KeyW => Some(KeyCode::W), WK::KeyX => Some(KeyCode::X),
54 WK::KeyY => Some(KeyCode::Y), WK::KeyZ => Some(KeyCode::Z),
55 WK::Digit0 => Some(KeyCode::Key0), WK::Digit1 => Some(KeyCode::Key1),
56 WK::Digit2 => Some(KeyCode::Key2), WK::Digit3 => Some(KeyCode::Key3),
57 WK::Digit4 => Some(KeyCode::Key4), WK::Digit5 => Some(KeyCode::Key5),
58 WK::Digit6 => Some(KeyCode::Key6), WK::Digit7 => Some(KeyCode::Key7),
59 WK::Digit8 => Some(KeyCode::Key8), WK::Digit9 => Some(KeyCode::Key9),
60 WK::F1 => Some(KeyCode::F1), WK::F2 => Some(KeyCode::F2),
61 WK::F3 => Some(KeyCode::F3), WK::F4 => Some(KeyCode::F4),
62 WK::F5 => Some(KeyCode::F5), WK::F6 => Some(KeyCode::F6),
63 WK::F7 => Some(KeyCode::F7), WK::F8 => Some(KeyCode::F8),
64 WK::F9 => Some(KeyCode::F9), WK::F10 => Some(KeyCode::F10),
65 WK::F11 => Some(KeyCode::F11), WK::F12 => Some(KeyCode::F12),
66 WK::Space => Some(KeyCode::Space), WK::Enter => Some(KeyCode::Enter),
67 WK::Escape => Some(KeyCode::Escape), WK::Tab => Some(KeyCode::Tab),
68 WK::Backspace => Some(KeyCode::Backspace), WK::Delete => Some(KeyCode::Delete),
69 WK::ArrowLeft => Some(KeyCode::Left), WK::ArrowRight => Some(KeyCode::Right),
70 WK::ArrowUp => Some(KeyCode::Up), WK::ArrowDown => Some(KeyCode::Down),
71 WK::ShiftLeft => Some(KeyCode::LShift), WK::ShiftRight => Some(KeyCode::RShift),
72 WK::ControlLeft => Some(KeyCode::LControl), WK::ControlRight => Some(KeyCode::RControl),
73 WK::AltLeft => Some(KeyCode::LAlt), WK::AltRight => Some(KeyCode::RAlt),
74 _ => None,
75 }
76 }
77}
78
79#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
89pub enum MouseButton {
90 Left,
91 Right,
92 Middle,
93}
94
95impl MouseButton {
96 pub fn from_winit(button: winit::event::MouseButton) -> Option<MouseButton> {
98 match button {
99 winit::event::MouseButton::Left => Some(MouseButton::Left),
100 winit::event::MouseButton::Right => Some(MouseButton::Right),
101 winit::event::MouseButton::Middle => Some(MouseButton::Middle),
102 _ => None,
103 }
104 }
105}
106
107#[derive(Resource)]
135pub struct InputState {
136 keys_pressed: HashSet<KeyCode>,
138 keys_just_pressed: HashSet<KeyCode>,
140 keys_just_released: HashSet<KeyCode>,
142
143 mouse_pressed: HashSet<MouseButton>,
145 mouse_just_pressed: HashSet<MouseButton>,
147 mouse_just_released: HashSet<MouseButton>,
149
150 mouse_position: Vec2,
152 mouse_delta: Vec2,
154 scroll_delta: f32,
156}
157
158impl InputState {
159 pub fn new() -> Self {
161 Self {
162 keys_pressed: HashSet::new(),
163 keys_just_pressed: HashSet::new(),
164 keys_just_released: HashSet::new(),
165 mouse_pressed: HashSet::new(),
166 mouse_just_pressed: HashSet::new(),
167 mouse_just_released: HashSet::new(),
168 mouse_position: Vec2::ZERO,
169 mouse_delta: Vec2::ZERO,
170 scroll_delta: 0.0,
171 }
172 }
173
174 pub fn press_key(&mut self, key: KeyCode) {
178 if self.keys_pressed.insert(key) {
179 self.keys_just_pressed.insert(key);
180 }
181 }
182
183 pub fn release_key(&mut self, key: KeyCode) {
185 if self.keys_pressed.remove(&key) {
186 self.keys_just_released.insert(key);
187 }
188 }
189
190 pub fn is_key_pressed(&self, key: KeyCode) -> bool {
192 self.keys_pressed.contains(&key)
193 }
194
195 pub fn is_key_just_pressed(&self, key: KeyCode) -> bool {
197 self.keys_just_pressed.contains(&key)
198 }
199
200 pub fn is_key_just_released(&self, key: KeyCode) -> bool {
202 self.keys_just_released.contains(&key)
203 }
204
205 pub fn press_mouse(&mut self, button: MouseButton) {
209 if self.mouse_pressed.insert(button) {
210 self.mouse_just_pressed.insert(button);
211 }
212 }
213
214 pub fn release_mouse(&mut self, button: MouseButton) {
216 if self.mouse_pressed.remove(&button) {
217 self.mouse_just_released.insert(button);
218 }
219 }
220
221 pub fn is_mouse_pressed(&self, button: MouseButton) -> bool {
223 self.mouse_pressed.contains(&button)
224 }
225
226 pub fn is_mouse_just_pressed(&self, button: MouseButton) -> bool {
228 self.mouse_just_pressed.contains(&button)
229 }
230
231 pub fn is_mouse_just_released(&self, button: MouseButton) -> bool {
233 self.mouse_just_released.contains(&button)
234 }
235
236 pub fn set_mouse_position(&mut self, position: Vec2) {
240 self.mouse_position = position;
241 }
242
243 pub fn add_mouse_delta(&mut self, delta: Vec2) {
245 self.mouse_delta += delta;
246 }
247
248 pub fn mouse_position(&self) -> Vec2 {
250 self.mouse_position
251 }
252
253 pub fn mouse_delta(&self) -> Vec2 {
255 self.mouse_delta
256 }
257
258 pub fn add_scroll_delta(&mut self, delta: f32) {
260 self.scroll_delta += delta;
261 }
262
263 pub fn scroll_delta(&self) -> f32 {
265 self.scroll_delta
266 }
267
268 pub fn end_frame(&mut self) {
272 self.keys_just_pressed.clear();
273 self.keys_just_released.clear();
274 self.mouse_just_pressed.clear();
275 self.mouse_just_released.clear();
276 self.mouse_delta = Vec2::ZERO;
277 self.scroll_delta = 0.0;
278 }
279
280 pub fn pressed_keys(&self) -> &HashSet<KeyCode> {
282 &self.keys_pressed
283 }
284}
285
286impl Default for InputState {
287 fn default() -> Self {
288 Self::new()
289 }
290}
291
292#[cfg(test)]
293mod tests {
294 use super::*;
295
296 #[test]
297 fn test_key_press_release() {
298 let mut input = InputState::new();
299
300 input.press_key(KeyCode::W);
301 assert!(input.is_key_pressed(KeyCode::W));
302 assert!(input.is_key_just_pressed(KeyCode::W));
303 assert!(!input.is_key_just_released(KeyCode::W));
304
305 input.end_frame();
306 assert!(input.is_key_pressed(KeyCode::W));
307 assert!(!input.is_key_just_pressed(KeyCode::W));
308
309 input.release_key(KeyCode::W);
310 assert!(!input.is_key_pressed(KeyCode::W));
311 assert!(input.is_key_just_released(KeyCode::W));
312
313 input.end_frame();
314 assert!(!input.is_key_just_released(KeyCode::W));
315 }
316
317 #[test]
318 fn test_mouse_buttons() {
319 let mut input = InputState::new();
320
321 input.press_mouse(MouseButton::Left);
322 assert!(input.is_mouse_pressed(MouseButton::Left));
323 assert!(input.is_mouse_just_pressed(MouseButton::Left));
324
325 input.end_frame();
326 assert!(input.is_mouse_pressed(MouseButton::Left));
327 assert!(!input.is_mouse_just_pressed(MouseButton::Left));
328 }
329
330 #[test]
331 fn test_mouse_delta() {
332 let mut input = InputState::new();
333 input.add_mouse_delta(Vec2::new(5.0, 3.0));
334 input.add_mouse_delta(Vec2::new(2.0, -1.0));
335 assert_eq!(input.mouse_delta(), Vec2::new(7.0, 2.0));
336
337 input.end_frame();
338 assert_eq!(input.mouse_delta(), Vec2::ZERO);
339 }
340
341 #[test]
342 fn test_scroll_delta() {
343 let mut input = InputState::new();
344 input.add_scroll_delta(1.5);
345 input.add_scroll_delta(-0.5);
346 assert_eq!(input.scroll_delta(), 1.0);
347
348 input.end_frame();
349 assert_eq!(input.scroll_delta(), 0.0);
350 }
351
352 #[test]
353 fn test_duplicate_press() {
354 let mut input = InputState::new();
355 input.press_key(KeyCode::A);
356 input.press_key(KeyCode::A); assert_eq!(input.pressed_keys().len(), 1);
358 }
359}