1use crate::math::Vec2;
12
13#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
22#[repr(u32)]
23pub enum KeyCode {
24 A, B, C, D, E, F, G, H, I, J, K, L, M,
26 N, O, P, Q, R, S, T, U, V, W, X, Y, Z,
27 Key1, Key2, Key3, Key4, Key5, Key6, Key7, Key8, Key9, Key0,
29 F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12,
31 Space, Enter, Escape, Tab, Backspace, Delete, Insert,
33 Home, End, PageUp, PageDown,
34 Up, Down, Left, Right,
36 LeftShift, RightShift, LeftCtrl, RightCtrl,
38 LeftAlt, RightAlt, LeftSuper, RightSuper,
39 Semicolon, Comma, Period, Slash, Backslash,
41 LeftBracket, RightBracket, Equals, Minus,
42 Apostrophe, Backquote,
43 CapsLock, ScrollLock, NumLock, PrintScreen,
45 Pause, ContextMenu,
46 Unknown,
48}
49
50#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
56pub enum MouseButton {
57 Left,
58 Right,
59 Middle,
60 Button4,
61 Button5,
62}
63
64#[derive(Debug, Clone)]
66pub struct MouseState {
67 pub position: Vec2,
69 pub drag_start: Option<Vec2>,
71 pub delta: Vec2,
73 pub scroll: Vec2,
75 pub held: std::collections::HashSet<MouseButton>,
77 pub pressed_this_frame: Vec<MouseButton>,
79 pub released_this_frame: Vec<MouseButton>,
81 pub cursor_visible: bool,
83 pub cursor_grabbed: bool,
85}
86
87impl Default for MouseState {
88 fn default() -> Self {
89 Self {
90 position: Vec2::ZERO,
91 drag_start: None,
92 delta: Vec2::ZERO,
93 scroll: Vec2::ZERO,
94 held: std::collections::HashSet::new(),
95 pressed_this_frame: Vec::new(),
96 released_this_frame: Vec::new(),
97 cursor_visible: true,
98 cursor_grabbed: false,
99 }
100 }
101}
102
103impl MouseState {
104 pub fn is_down(&self, button: MouseButton) -> bool {
106 self.held.contains(&button)
107 }
108
109 pub fn is_pressed(&self, button: MouseButton) -> bool {
111 self.pressed_this_frame.contains(&button)
112 }
113
114 pub fn is_released(&self, button: MouseButton) -> bool {
116 self.released_this_frame.contains(&button)
117 }
118
119 pub fn is_any_down(&self) -> bool {
121 !self.held.is_empty()
122 }
123
124 pub fn is_dragging(&self) -> bool {
126 self.held.contains(&MouseButton::Left) && self.drag_start.is_some()
127 }
128
129 pub fn drag_vector(&self) -> Option<Vec2> {
131 self.drag_start.map(|start| self.position - start)
132 }
133
134 pub fn set_cursor_visible(&mut self, visible: bool) {
136 self.cursor_visible = visible;
137 }
138
139 pub fn set_cursor_grabbed(&mut self, grabbed: bool) {
141 self.cursor_grabbed = grabbed;
142 }
143}
144
145#[derive(Debug, Clone)]
151pub struct KeyboardState {
152 held: std::collections::HashSet<KeyCode>,
154 pub pressed_this_frame: Vec<KeyCode>,
156 pub released_this_frame: Vec<KeyCode>,
158 text_buffer: String,
160}
161
162impl Default for KeyboardState {
163 fn default() -> Self {
164 Self {
165 held: std::collections::HashSet::new(),
166 pressed_this_frame: Vec::new(),
167 released_this_frame: Vec::new(),
168 text_buffer: String::new(),
169 }
170 }
171}
172
173impl KeyboardState {
174 #[inline]
176 pub fn is_down(&self, key: KeyCode) -> bool {
177 self.held.contains(&key)
178 }
179
180 #[inline]
182 pub fn is_pressed(&self, key: KeyCode) -> bool {
183 self.pressed_this_frame.contains(&key)
184 }
185
186 #[inline]
188 pub fn is_released(&self, key: KeyCode) -> bool {
189 self.released_this_frame.contains(&key)
190 }
191
192 pub fn are_all_down(&self, keys: &[KeyCode]) -> bool {
194 keys.iter().all(|k| self.held.contains(k))
195 }
196
197 pub fn is_any_down(&self, keys: &[KeyCode]) -> bool {
199 keys.iter().any(|k| self.held.contains(k))
200 }
201
202 pub fn take_text(&mut self) -> String {
204 std::mem::take(&mut self.text_buffer)
205 }
206
207 pub fn text(&self) -> &str {
209 &self.text_buffer
210 }
211}
212
213#[derive(Debug, Clone)]
230pub struct InputAction {
231 pub name: String,
233 pub keys: Vec<KeyCode>,
235 pub mouse_buttons: Vec<MouseButton>,
237 pub positive_axis: Vec<(u32, f32)>,
239 pub negative_axis: Vec<(u32, f32)>,
241 pub gamepad_buttons: Vec<u32>,
243}
244
245impl InputAction {
246 pub fn new(name: &str) -> Self {
248 Self {
249 name: name.to_string(),
250 keys: Vec::new(),
251 mouse_buttons: Vec::new(),
252 positive_axis: Vec::new(),
253 negative_axis: Vec::new(),
254 gamepad_buttons: Vec::new(),
255 }
256 }
257
258 pub fn bind_key(&mut self, key: KeyCode) -> &mut Self {
260 self.keys.push(key);
261 self
262 }
263
264 pub fn bind_mouse(&mut self, button: MouseButton) -> &mut Self {
266 self.mouse_buttons.push(button);
267 self
268 }
269
270 pub fn is_down(&self, input: &InputState) -> bool {
272 for key in &self.keys {
273 if input.keyboard.is_down(*key) {
274 return true;
275 }
276 }
277 for btn in &self.mouse_buttons {
278 if input.mouse.is_down(*btn) {
279 return true;
280 }
281 }
282 false
283 }
284
285 pub fn is_pressed(&self, input: &InputState) -> bool {
287 for key in &self.keys {
288 if input.keyboard.is_pressed(*key) {
289 return true;
290 }
291 }
292 for btn in &self.mouse_buttons {
293 if input.mouse.is_pressed(*btn) {
294 return true;
295 }
296 }
297 false
298 }
299}
300
301#[derive(Debug, Clone, Default)]
307pub struct InputState {
308 pub keyboard: KeyboardState,
310 pub mouse: MouseState,
312 actions: Vec<InputAction>,
314}
315
316impl InputState {
317 pub fn register_action(&mut self, action: InputAction) {
319 self.actions.push(action);
320 }
321
322 pub fn action(&self, name: &str) -> Option<&InputAction> {
324 self.actions.iter().find(|a| a.name == name)
325 }
326
327 pub fn is_action_down(&self, name: &str) -> bool {
329 self.actions.iter().any(|a| a.name == name && a.is_down(self))
330 }
331
332 pub fn is_action_pressed(&self, name: &str) -> bool {
334 self.actions.iter().any(|a| a.name == name && a.is_pressed(self))
335 }
336}