arcane_engine/platform/
input.rs1use std::collections::HashSet;
2
3#[derive(Debug, Default)]
5pub struct InputState {
6 pub keys_down: HashSet<String>,
8 pub keys_pressed: HashSet<String>,
10 pub keys_released: HashSet<String>,
12 pub mouse_x: f32,
14 pub mouse_y: f32,
15 pub mouse_buttons: HashSet<u8>,
17 pub mouse_buttons_pressed: HashSet<u8>,
19 pub mouse_buttons_released: HashSet<u8>,
21}
22
23impl InputState {
24 pub fn begin_frame(&mut self) {
26 self.keys_pressed.clear();
27 self.keys_released.clear();
28 self.mouse_buttons_pressed.clear();
29 self.mouse_buttons_released.clear();
30 }
31
32 pub fn key_down(&mut self, key: &str) {
34 if self.keys_down.insert(key.to_string()) {
35 self.keys_pressed.insert(key.to_string());
36 }
37 }
38
39 pub fn key_up(&mut self, key: &str) {
41 if self.keys_down.remove(key) {
42 self.keys_released.insert(key.to_string());
43 }
44 }
45
46 pub fn mouse_move(&mut self, x: f32, y: f32) {
48 self.mouse_x = x;
49 self.mouse_y = y;
50 }
51
52 pub fn mouse_button_down(&mut self, button: u8) {
54 if self.mouse_buttons.insert(button) {
55 self.mouse_buttons_pressed.insert(button);
56 }
57 }
58
59 pub fn mouse_button_up(&mut self, button: u8) {
61 if self.mouse_buttons.remove(&button) {
62 self.mouse_buttons_released.insert(button);
63 }
64 }
65
66 pub fn is_key_down(&self, key: &str) -> bool {
68 self.keys_down.contains(key)
69 }
70
71 pub fn is_key_pressed(&self, key: &str) -> bool {
73 self.keys_pressed.contains(key)
74 }
75}
76
77#[cfg(test)]
78mod tests {
79 use super::*;
80
81 #[test]
82 fn key_pressed_survives_until_read() {
83 let mut input = InputState::default();
88
89 input.key_down("ArrowUp");
91 assert!(input.is_key_pressed("ArrowUp"));
92 assert!(input.is_key_down("ArrowUp"));
93
94 assert!(input.is_key_pressed("ArrowUp"));
96
97 input.begin_frame();
99 assert!(!input.is_key_pressed("ArrowUp"));
100 assert!(input.is_key_down("ArrowUp")); }
102
103 #[test]
104 fn begin_frame_before_read_loses_input() {
105 let mut input = InputState::default();
108
109 input.key_down("w");
110 assert!(input.is_key_pressed("w"));
111
112 input.begin_frame();
114 assert!(!input.is_key_pressed("w")); }
116
117 #[test]
118 fn held_key_does_not_re_trigger_pressed() {
119 let mut input = InputState::default();
120
121 input.key_down("a");
122 assert!(input.is_key_pressed("a"));
123
124 input.begin_frame();
125
126 input.key_down("a");
128 assert!(!input.is_key_pressed("a"));
129 assert!(input.is_key_down("a"));
130 }
131
132 #[test]
133 fn key_release_tracked() {
134 let mut input = InputState::default();
135
136 input.key_down("Space");
137 input.begin_frame();
138 input.key_up("Space");
139
140 assert!(!input.is_key_down("Space"));
141 assert!(input.keys_released.contains("Space"));
142
143 input.begin_frame();
144 assert!(!input.keys_released.contains("Space"));
145 }
146
147 #[test]
148 fn mouse_position_is_tracked() {
149 let mut input = InputState::default();
150 assert_eq!(input.mouse_x, 0.0);
151 assert_eq!(input.mouse_y, 0.0);
152
153 input.mouse_x = 100.5;
154 input.mouse_y = 200.75;
155
156 assert_eq!(input.mouse_x, 100.5);
157 assert_eq!(input.mouse_y, 200.75);
158 }
159
160 #[test]
161 fn multiple_keys_can_be_down_simultaneously() {
162 let mut input = InputState::default();
163
164 input.key_down("w");
165 input.key_down("a");
166 input.key_down("d");
167
168 assert!(input.is_key_down("w"));
169 assert!(input.is_key_down("a"));
170 assert!(input.is_key_down("d"));
171 assert!(input.is_key_pressed("w"));
172 assert!(input.is_key_pressed("a"));
173 assert!(input.is_key_pressed("d"));
174 }
175
176 #[test]
177 fn releasing_one_key_does_not_affect_others() {
178 let mut input = InputState::default();
179
180 input.key_down("w");
181 input.key_down("a");
182 input.begin_frame();
183
184 input.key_up("w");
185
186 assert!(!input.is_key_down("w"));
187 assert!(input.is_key_down("a"));
188 }
189
190 #[test]
191 fn key_pressed_works_with_special_keys() {
192 let mut input = InputState::default();
193
194 input.key_down("Escape");
195 input.key_down("Return");
196 input.key_down("ArrowLeft");
197
198 assert!(input.is_key_pressed("Escape"));
199 assert!(input.is_key_pressed("Return"));
200 assert!(input.is_key_pressed("ArrowLeft"));
201 }
202
203 #[test]
204 fn default_input_state_has_no_keys_down() {
205 let input = InputState::default();
206
207 assert!(!input.is_key_down("a"));
208 assert!(!input.is_key_down("Space"));
209 assert!(!input.is_key_pressed("w"));
210 assert_eq!(input.keys_down.len(), 0);
211 assert_eq!(input.keys_pressed.len(), 0);
212 }
213}