1use crate::cardputer;
2use crate::key::{Action, Key, Modifiers};
3
4#[derive(Clone, Copy, Debug, PartialEq, Eq)]
6#[cfg_attr(feature = "defmt", derive(defmt::Format))]
7pub struct KeyEvent {
8 pub key: Key,
10 pub pressed: bool,
12 pub mods: Modifiers,
14}
15
16impl KeyEvent {
17 pub fn action(&self) -> Option<Action> {
24 if !self.pressed {
25 return None;
26 }
27 if self.mods.contains(Modifiers::FN)
28 && let Some(action) = cardputer::fn_layer(self.key)
29 {
30 return Some(action);
31 }
32 match self.key {
33 Key::Enter => Some(Action::Enter),
34 Key::Backspace => Some(Action::Backspace),
35 Key::Tab => Some(Action::Tab),
36 key => {
37 let (base, shifted) = key.legend()?;
38 let shift = self.mods.contains(Modifiers::SHIFT);
39 Some(Action::Char(if shift { shifted } else { base }))
40 }
41 }
42 }
43}
44
45#[derive(Clone, Copy, Debug, Default)]
47pub struct KeyboardState {
48 held: u64,
49 mods: Modifiers,
50}
51
52impl KeyboardState {
53 pub const fn new() -> Self {
55 Self {
56 held: 0,
57 mods: Modifiers::NONE,
58 }
59 }
60
61 pub fn apply(&mut self, key: Key, pressed: bool) -> KeyEvent {
63 if pressed {
64 self.held |= key.bit();
65 } else {
66 self.held &= !key.bit();
67 }
68 if key.modifier().is_some() {
69 self.mods = self.derive_mods();
70 }
71 KeyEvent {
72 key,
73 pressed,
74 mods: self.mods,
75 }
76 }
77
78 pub const fn is_held(&self, key: Key) -> bool {
80 self.held & key.bit() != 0
81 }
82
83 pub const fn modifiers(&self) -> Modifiers {
85 self.mods
86 }
87
88 pub fn clear(&mut self) {
90 *self = Self::new();
91 }
92
93 fn derive_mods(&self) -> Modifiers {
94 [Key::Shift, Key::Ctrl, Key::Alt, Key::Opt, Key::Fn]
95 .into_iter()
96 .filter(|k| self.is_held(*k))
97 .filter_map(Key::modifier)
98 .fold(Modifiers::NONE, Modifiers::union)
99 }
100}
101
102#[cfg(test)]
103mod tests {
104 use super::*;
105
106 fn press(s: &mut KeyboardState, k: Key) -> KeyEvent {
107 s.apply(k, true)
108 }
109
110 #[test]
111 fn plain_and_shifted_characters() {
112 let mut s = KeyboardState::new();
113 assert_eq!(press(&mut s, Key::A).action(), Some(Action::Char('a')));
114 press(&mut s, Key::Shift);
115 assert_eq!(press(&mut s, Key::A).action(), Some(Action::Char('A')));
116 assert_eq!(press(&mut s, Key::Num2).action(), Some(Action::Char('@')));
117 s.apply(Key::Shift, false);
118 assert_eq!(press(&mut s, Key::Num2).action(), Some(Action::Char('2')));
119 }
120
121 #[test]
122 fn fn_layer_beats_shift() {
123 let mut s = KeyboardState::new();
124 press(&mut s, Key::Shift);
125 press(&mut s, Key::Fn);
126 assert_eq!(press(&mut s, Key::Semicolon).action(), Some(Action::Up));
127 assert_eq!(press(&mut s, Key::Equal).action(), Some(Action::F(12)));
128 assert_eq!(press(&mut s, Key::Q).action(), Some(Action::Char('Q')));
130 }
131
132 #[test]
133 fn modifiers_and_releases() {
134 let mut s = KeyboardState::new();
135 let ev = press(&mut s, Key::Ctrl);
136 assert_eq!(ev.action(), None, "modifier keys have no action");
137 let ev = press(&mut s, Key::C);
138 assert!(ev.mods.contains(Modifiers::CTRL));
139 assert_eq!(ev.action(), Some(Action::Char('c')));
140 assert_eq!(s.apply(Key::C, false).action(), None);
141 s.apply(Key::Ctrl, false);
142 assert!(s.modifiers().is_empty());
143 assert!(!s.is_held(Key::Ctrl));
144 }
145}