1use ui_events::keyboard::{Code, Key, KeyState, KeyboardEvent, Location, Modifiers};
5
6extern crate alloc;
7use alloc::vec::Vec;
8
9#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Debug)]
10struct KeyInfo(Key, Location, Code);
11
12#[derive(Clone, Debug, Default)]
14pub struct KeyboardState {
15 just_pressed: Vec<KeyInfo>,
17 just_released: Vec<KeyInfo>,
19 down: Vec<KeyInfo>,
21 pub modifiers: Modifiers,
23}
24
25impl KeyboardState {
26 pub fn key_just_pressed(&self, key: Key) -> bool {
29 self.just_pressed.iter().any(|KeyInfo(k, ..)| k == &key)
30 }
31
32 pub fn key_str_just_pressed(&self, s: &str) -> bool {
41 self.just_pressed
42 .iter()
43 .any(|KeyInfo(k, ..)| matches!(k, Key::Character(c) if c == s))
44 }
45
46 pub fn key_just_pressed_location(&self, key: Key, location: Location) -> bool {
48 self.just_pressed
49 .iter()
50 .any(|KeyInfo(k, l, _)| k == &key && l == &location)
51 }
52
53 pub fn key_str_just_pressed_location(&self, s: &str, location: Location) -> bool {
62 self.just_pressed
63 .iter()
64 .any(|KeyInfo(k, l, ..)| l == &location && matches!(k, Key::Character(c) if c == s))
65 }
66
67 pub fn code_just_pressed(&self, code: Code) -> bool {
69 self.just_pressed.iter().any(|KeyInfo(_, _, c)| c == &code)
70 }
71
72 pub fn key_just_released(&self, key: Key) -> bool {
75 self.just_released.iter().any(|KeyInfo(k, ..)| k == &key)
76 }
77
78 pub fn key_str_just_released(&self, s: &str) -> bool {
87 self.just_released
88 .iter()
89 .any(|KeyInfo(k, ..)| matches!(k, Key::Character(c) if c == s))
90 }
91
92 pub fn key_just_released_location(&self, key: Key, location: Location) -> bool {
94 self.just_released
95 .iter()
96 .any(|KeyInfo(k, l, _)| k == &key && l == &location)
97 }
98
99 pub fn key_str_just_released_location(&self, s: &str, location: Location) -> bool {
108 self.just_released
109 .iter()
110 .any(|KeyInfo(k, l, ..)| l == &location && matches!(k, Key::Character(c) if c == s))
111 }
112
113 pub fn code_just_released(&self, code: Code) -> bool {
115 self.just_released.iter().any(|KeyInfo(_, _, c)| c == &code)
116 }
117
118 pub fn is_any_down(&self) -> bool {
120 !self.down.is_empty()
121 }
122
123 pub fn key_down(&self, key: Key) -> bool {
131 self.down.iter().any(|KeyInfo(k, ..)| k == &key)
132 }
133
134 pub fn key_str_down(&self, s: &str) -> bool {
142 self.down
143 .iter()
144 .any(|KeyInfo(k, ..)| matches!(k, Key::Character(c) if c == s))
145 }
146
147 pub fn key_down_location(&self, key: Key, location: Location) -> bool {
155 self.down
156 .iter()
157 .any(|KeyInfo(k, l, _)| k == &key && l == &location)
158 }
159
160 pub fn key_str_down_location(&self, s: &str, location: Location) -> bool {
168 self.down
169 .iter()
170 .any(|KeyInfo(k, l, ..)| l == &location && matches!(k, Key::Character(c) if c == s))
171 }
172
173 pub fn code_down(&self, code: Code) -> bool {
175 self.down.iter().any(|KeyInfo(_, _, c)| c == &code)
176 }
177
178 pub fn clear_frame(&mut self) {
180 self.just_pressed.clear();
181 self.just_released.clear();
182 }
183
184 pub fn process_keyboard_event(&mut self, event: KeyboardEvent) {
189 self.modifiers = event.modifiers;
190 let info = KeyInfo(event.key, event.location, event.code);
191 match event.state {
192 KeyState::Down => {
193 self.just_pressed.push(info.clone());
194 self.down.push(info.clone());
195 }
196 KeyState::Up => {
197 self.just_released.push(info.clone());
198 self.down.retain(|other| other != &info);
199 }
200 }
201 }
202}
203
204#[cfg(test)]
205mod tests {
206 use super::*;
207 use ui_events::keyboard::{Code, NamedKey};
208
209 fn make_key_down_event(key: Key) -> KeyboardEvent {
210 KeyboardEvent {
211 state: KeyState::Down,
212 key,
213 location: Location::Standard,
214 code: Code::Unidentified,
215 modifiers: Default::default(),
216 is_composing: false,
217 repeat: false,
218 }
219 }
220
221 fn make_key_up_event(key: Key) -> KeyboardEvent {
222 KeyboardEvent {
223 state: KeyState::Up,
224 key,
225 location: Location::Standard,
226 code: Code::Unidentified,
227 modifiers: Default::default(),
228 is_composing: false,
229 repeat: false,
230 }
231 }
232
233 #[test]
234 fn press_and_hold_a() {
235 let mut state = KeyboardState::default();
236 state.process_keyboard_event(make_key_down_event(Key::Character("A".into())));
237
238 assert!(state.key_just_pressed(Key::Character("A".into())));
239 assert!(state.key_str_just_pressed("A"));
240 assert!(state.key_str_just_pressed_location("A", Location::Standard));
241 assert!(!state.key_str_just_pressed_location("A", Location::Left));
242 assert!(state.key_down(Key::Character("A".into())));
243 assert!(state.key_str_down("A"));
244 assert!(state.key_str_down_location("A", Location::Standard));
245 assert!(!state.key_str_down_location("A", Location::Left));
246 assert!(!state.key_just_released(Key::Character("A".into())));
247 assert!(!state.key_str_just_released("A"));
248 assert!(!state.key_str_just_released_location("A", Location::Standard));
249 assert!(!state.key_str_just_released_location("A", Location::Left));
250
251 state.clear_frame();
252
253 assert!(!state.key_just_pressed(Key::Character("A".into())));
254 assert!(!state.key_str_just_pressed("A"));
255 assert!(!state.key_str_just_pressed_location("A", Location::Standard));
256 assert!(!state.key_str_just_pressed_location("A", Location::Left));
257 assert!(state.key_down(Key::Character("A".into())));
258 assert!(state.key_str_down("A"));
259 assert!(state.key_str_down_location("A", Location::Standard));
260 assert!(!state.key_str_down_location("A", Location::Left));
261 }
262
263 #[test]
264 fn press_and_release_a() {
265 let mut state = KeyboardState::default();
266 state.process_keyboard_event(make_key_down_event(Key::Character("A".into())));
267 state.process_keyboard_event(make_key_up_event(Key::Character("A".into())));
268
269 assert!(state.key_just_pressed(Key::Character("A".into())));
270 assert!(state.key_str_just_pressed("A"));
271 assert!(state.key_str_just_pressed_location("A", Location::Standard));
272 assert!(!state.key_str_just_pressed_location("A", Location::Left));
273 assert!(state.key_just_released(Key::Character("A".into())));
274 assert!(state.key_str_just_released("A"));
275 assert!(state.key_str_just_released_location("A", Location::Standard));
276 assert!(!state.key_str_just_released_location("A", Location::Left));
277 assert!(!state.key_down(Key::Character("A".into())));
278 assert!(!state.key_str_down("A"));
279 assert!(!state.key_str_down_location("A", Location::Standard));
280 assert!(!state.key_str_down_location("A", Location::Left));
281 }
282
283 #[test]
284 fn release_after_hold() {
285 let mut state = KeyboardState::default();
286 state.process_keyboard_event(make_key_down_event(Key::Character("A".into())));
287 state.clear_frame();
288 state.process_keyboard_event(make_key_up_event(Key::Character("A".into())));
289
290 assert!(!state.key_just_pressed(Key::Character("A".into())));
291 assert!(!state.key_str_just_pressed("A"));
292 assert!(!state.key_str_just_pressed_location("A", Location::Standard));
293 assert!(!state.key_str_just_pressed_location("A", Location::Left));
294 assert!(state.key_just_released(Key::Character("A".into())));
295 assert!(state.key_str_just_released("A"));
296 assert!(state.key_str_just_released_location("A", Location::Standard));
297 assert!(!state.key_str_just_released_location("A", Location::Left));
298 assert!(!state.key_down(Key::Character("A".into())));
299 assert!(!state.key_str_down("A"));
300 assert!(!state.key_str_down_location("A", Location::Standard));
301 assert!(!state.key_str_down_location("A", Location::Left));
302 }
303
304 fn make_code_down_event(code: Code) -> KeyboardEvent {
305 KeyboardEvent {
306 state: KeyState::Down,
307 key: Key::Named(NamedKey::Unidentified),
308 location: Location::Standard,
309 code,
310 modifiers: Default::default(),
311 is_composing: false,
312 repeat: false,
313 }
314 }
315
316 fn make_code_up_event(code: Code) -> KeyboardEvent {
317 KeyboardEvent {
318 state: KeyState::Up,
319 key: Key::Named(NamedKey::Unidentified),
320 location: Location::Standard,
321 code,
322 modifiers: Default::default(),
323 is_composing: false,
324 repeat: false,
325 }
326 }
327
328 #[test]
329 fn press_and_hold_a_code() {
330 let mut state = KeyboardState::default();
331 state.process_keyboard_event(make_code_down_event(Code::KeyA));
332
333 assert!(state.code_just_pressed(Code::KeyA));
334 assert!(state.code_down(Code::KeyA));
335 assert!(!state.code_just_released(Code::KeyA));
336
337 state.clear_frame();
338
339 assert!(!state.code_just_pressed(Code::KeyA));
340 assert!(state.code_down(Code::KeyA));
341 }
342
343 #[test]
344 fn press_and_release_a_code() {
345 let mut state = KeyboardState::default();
346 state.process_keyboard_event(make_code_down_event(Code::KeyA));
347 state.process_keyboard_event(make_code_up_event(Code::KeyA));
348
349 assert!(state.code_just_pressed(Code::KeyA));
350 assert!(state.code_just_released(Code::KeyA));
351 assert!(!state.code_down(Code::KeyA));
352 }
353
354 #[test]
355 fn release_after_hold_code() {
356 let mut state = KeyboardState::default();
357 state.process_keyboard_event(make_code_down_event(Code::KeyA));
358 state.clear_frame();
359 state.process_keyboard_event(make_code_up_event(Code::KeyA));
360
361 assert!(!state.code_just_pressed(Code::KeyA));
362 assert!(state.code_just_released(Code::KeyA));
363 assert!(!state.code_down(Code::KeyA));
364 }
365}