1use std::{collections::HashSet, sync::OnceLock};
2
3use parking_lot::RwLock;
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
6pub enum Key {
8 Char(char),
10 Up,
12 Down,
14 Left,
16 Right,
18 Space,
20 Enter,
22 Escape,
24 Backspace,
26 Delete,
28 Shift,
30 Control,
32 Alt,
34 Meta,
36 Unknown,
38}
39
40impl From<char> for Key {
41 fn from(value: char) -> Self {
42 if value == ' ' {
43 Self::Space
44 } else {
45 Self::Char(value.to_lowercase().next().unwrap_or(value))
46 }
47 }
48}
49
50impl From<&str> for Key {
51 fn from(value: &str) -> Self {
52 if value.len() == 1 {
53 Self::from(value.chars().next().unwrap())
54 } else {
55 match value.to_lowercase().as_str() {
56 "up" => Self::Up,
57 "down" => Self::Down,
58 "left" => Self::Left,
59 "right" => Self::Right,
60 "space" => Self::Space,
61 "enter" => Self::Enter,
62 "escape" => Self::Escape,
63 "backspace" => Self::Backspace,
64 "delete" => Self::Delete,
65 "shift" => Self::Shift,
66 "control" => Self::Control,
67 "alt" => Self::Alt,
68 "meta" => Self::Meta,
69 _ => Self::Unknown,
70 }
71 }
72 }
73}
74
75impl From<String> for Key {
76 fn from(value: String) -> Self {
77 Key::from(value.as_str())
78 }
79}
80
81#[derive(Debug)]
82struct KeyboardState {
83 pressed: HashSet<Key>,
84 released: HashSet<Key>,
85 held: HashSet<Key>,
86}
87
88impl KeyboardState {
89 fn empty() -> Self {
90 Self {
91 pressed: HashSet::new(),
92 released: HashSet::new(),
93 held: HashSet::new(),
94 }
95 }
96}
97
98static KEYBOARD_STATE: OnceLock<RwLock<KeyboardState>> = OnceLock::new();
99
100fn get_state() -> &'static RwLock<KeyboardState> {
101 KEYBOARD_STATE.get_or_init(|| RwLock::new(KeyboardState::empty()))
102}
103
104pub fn is_down(key: impl Into<Key>) -> bool {
106 get_state().read().held.contains(&key.into())
107}
108
109pub fn is_pressed(key: impl Into<Key>) -> bool {
111 get_state().read().pressed.contains(&key.into())
112}
113
114pub fn is_released(key: impl Into<Key>) -> bool {
116 get_state().read().released.contains(&key.into())
117}
118
119pub fn process_key_event(key: Key, pressed: bool) {
121 let mut state = get_state().write();
122 if pressed {
123 state.held.insert(key);
124 state.pressed.insert(key);
125 } else {
126 state.held.remove(&key);
127 state.released.insert(key);
128 }
129}
130
131pub fn reset() {
133 let mut state = get_state().write();
134 state.pressed.clear();
135 state.released.clear();
136}
137
138pub mod prelude {
140 pub use super::Key;
141}