1use std::collections::HashSet;
3use std::sync::{LazyLock, RwLock};
4
5static INPUT: LazyLock<RwLock<InputState>> = LazyLock::new(|| RwLock::new(InputState::default()));
6
7#[derive(Debug, Default)]
8pub struct InputState {
9 held: HashSet<String>,
10 pressed: HashSet<String>,
11 released: HashSet<String>,
12 mouse: (f64, f64),
13}
14
15pub fn input_begin_frame() {
16 let mut state = INPUT.write().unwrap();
17 state.pressed.clear();
18 state.released.clear();
19}
20
21pub fn input_clear() {
24 let mut state = INPUT.write().unwrap();
25 state.held.clear();
26 state.pressed.clear();
27 state.released.clear();
28}
29
30pub fn input_set_key(name: &str, held: bool) {
31 let mut state = INPUT.write().unwrap();
32 if held && state.held.insert(name.to_string()) {
33 state.pressed.insert(name.to_string());
34 } else if !held && state.held.remove(name) {
35 state.released.insert(name.to_string());
36 }
37}
38
39pub fn input_set_mouse(x: f64, y: f64) {
40 INPUT.write().unwrap().mouse = (x, y);
41}
42
43pub fn input_held(key: &str) -> bool {
44 INPUT.read().unwrap().held.contains(key)
45}
46
47pub fn input_pressed(key: &str) -> bool {
48 INPUT.read().unwrap().pressed.contains(key)
49}
50
51pub fn input_released(key: &str) -> bool {
52 INPUT.read().unwrap().released.contains(key)
53}
54
55pub fn input_mouse() -> (f64, f64) {
56 INPUT.read().unwrap().mouse
57}
58
59#[cfg(test)]
60mod tests {
61 use super::*;
62
63 #[test]
64 fn key_edges_last_one_frame() {
65 let _guard = crate::host::HOST_SERIAL.lock().unwrap();
66 input_begin_frame();
67 input_set_key("T-KeyEdgesLastOneFrame", false);
68 input_begin_frame();
69 assert!(!input_held("T-KeyEdgesLastOneFrame"));
70 input_set_key("T-KeyEdgesLastOneFrame", true);
71 assert!(input_held("T-KeyEdgesLastOneFrame"));
72 assert!(input_pressed("T-KeyEdgesLastOneFrame"));
73 input_begin_frame();
74 assert!(input_held("T-KeyEdgesLastOneFrame"));
75 assert!(!input_pressed("T-KeyEdgesLastOneFrame"));
76 input_set_key("T-KeyEdgesLastOneFrame", false);
77 assert!(!input_held("T-KeyEdgesLastOneFrame"));
78 assert!(input_released("T-KeyEdgesLastOneFrame"));
79 input_begin_frame();
80 assert!(!input_released("T-KeyEdgesLastOneFrame"));
81 }
82
83 #[test]
84 fn clear_drops_held_and_edges() {
85 let _guard = crate::host::HOST_SERIAL.lock().unwrap();
86 input_begin_frame();
87 input_set_key("T-ClearDropsState", true);
88 assert!(input_held("T-ClearDropsState"));
89 assert!(input_pressed("T-ClearDropsState"));
90 input_clear();
91 assert!(!input_held("T-ClearDropsState"));
92 assert!(!input_pressed("T-ClearDropsState"));
93 assert!(!input_released("T-ClearDropsState"));
94 input_set_key("T-ClearDropsState", false);
96 assert!(!input_released("T-ClearDropsState"));
97 input_begin_frame();
98 }
99}