1use core::fmt::Debug;
12use core::marker::PhantomData;
13
14use serde::Deserialize;
15
16use crate::input;
17use crate::key;
18use crate::keymap;
19
20#[derive(Deserialize, Debug, Clone, Copy, PartialEq)]
22pub struct Ref(pub Key);
23
24pub fn is_lockable(key_output: &key::KeyOutput) -> bool {
28 *key_output != key::KeyOutput::NO_OUTPUT
29 && matches!(key_output.key_code(), key::KeyUsage::Keyboard(_))
30}
31
32#[derive(Debug, Clone, Copy, PartialEq)]
34struct PendingLock {
35 keymap_index: u16,
36 key_output: key::KeyOutput,
37}
38
39#[derive(Debug, Clone, Copy, PartialEq)]
41pub struct Context {
42 watching: bool,
43 pending_lock: Option<PendingLock>,
45 locked: Option<key::KeyOutput>,
46}
47
48impl Default for Context {
49 fn default() -> Self {
50 Self::new()
51 }
52}
53
54impl Context {
55 pub const fn new() -> Self {
57 Context {
58 watching: false,
59 pending_lock: None,
60 locked: None,
61 }
62 }
63
64 pub fn reset(&mut self) {
66 *self = Self::new();
67 }
68
69 pub fn is_watching(&self) -> bool {
71 self.watching
72 }
73
74 pub fn is_locked(&self, key_output: &key::KeyOutput) -> bool {
76 self.locked.as_ref() == Some(key_output)
77 }
78
79 fn commit_lock(&mut self, key_output: key::KeyOutput) -> key::KeyEvents<Event> {
83 match self.locked {
84 Some(existing) if existing == key_output => key::KeyEvents::no_events(),
85 Some(existing) => {
86 self.locked = Some(key_output);
87 let mut pke =
88 key::KeyEvents::event(key::Event::Input(input::Event::VirtualKeyRelease {
89 key_output: existing,
90 }));
91 pke.add_event(key::Event::Input(input::Event::VirtualKeyPress {
92 key_output,
93 }));
94 pke
95 }
96 None => {
97 self.locked = Some(key_output);
98 key::KeyEvents::event(key::Event::Input(input::Event::VirtualKeyPress {
99 key_output,
100 }))
101 }
102 }
103 }
104
105 fn unlock_if_matches(&mut self, key_output: &key::KeyOutput) -> bool {
107 match self.locked {
108 Some(locked) if locked == *key_output => {
109 self.locked = None;
110 true
111 }
112 _ => false,
113 }
114 }
115
116 fn handle_event(&mut self, event: key::Event<Event>) -> key::KeyEvents<Event> {
117 match event {
118 key::Event::Key {
119 key_event: Event::ToggleWatching,
120 ..
121 } => {
122 self.watching = !self.watching;
123 if !self.watching {
125 self.pending_lock = None;
126 }
127 key::KeyEvents::no_events()
128 }
129 key::Event::Keymap(keymap::KeymapEvent::ResolvedKeyOutput {
130 keymap_index,
131 key_output,
132 }) => match (self.watching, is_lockable(&key_output)) {
133 (true, true) => {
134 self.watching = false;
137 self.pending_lock = Some(PendingLock {
138 keymap_index,
139 key_output,
140 });
141 key::KeyEvents::no_events()
142 }
143 (true, false) => {
144 self.watching = false;
146 key::KeyEvents::no_events()
147 }
148 (false, true) if self.unlock_if_matches(&key_output) => {
149 key::KeyEvents::event(key::Event::Input(input::Event::VirtualKeyRelease {
150 key_output,
151 }))
152 }
153 (false, _) => key::KeyEvents::no_events(),
154 },
155 key::Event::Input(input::Event::Release { keymap_index }) => match self.pending_lock {
156 Some(PendingLock {
157 keymap_index: pending_index,
158 key_output,
159 }) if pending_index == keymap_index => {
160 self.pending_lock = None;
161 self.commit_lock(key_output)
162 }
163 _ => key::KeyEvents::no_events(),
164 },
165 _ => key::KeyEvents::no_events(),
166 }
167 }
168}
169
170impl key::Context for Context {
171 type Event = Event;
172
173 fn handle_event(&mut self, event: key::Event<Self::Event>) -> key::KeyEvents<Self::Event> {
174 self.handle_event(event)
175 }
176
177 fn reset(&mut self) {
178 Context::reset(self);
179 }
180}
181
182#[derive(Debug, Clone, Copy, PartialEq)]
184pub enum Event {
185 ToggleWatching,
187}
188
189#[derive(Deserialize, Debug, Clone, Copy, PartialEq)]
191pub enum Key {
192 KeyLock,
194}
195
196impl Key {
197 pub const fn new() -> Self {
199 Key::KeyLock
200 }
201
202 pub fn new_pressed_key(&self, keymap_index: u16) -> key::KeyEvents<Event> {
204 match self {
205 Key::KeyLock => {
206 key::KeyEvents::event(key::Event::key_event(keymap_index, Event::ToggleWatching))
207 }
208 }
209 }
210}
211
212impl Default for Key {
213 fn default() -> Self {
214 Self::new()
215 }
216}
217
218#[derive(Debug, Clone, Copy, PartialEq)]
220pub struct PendingKeyState;
221
222#[derive(Debug, Clone, Copy, PartialEq)]
224pub struct KeyState;
225
226#[derive(Debug, Clone, Copy, PartialEq)]
228pub struct System<R>(PhantomData<R>);
229
230impl<R> System<R> {
231 pub const fn new() -> Self {
233 Self(PhantomData)
234 }
235}
236
237impl<R> Default for System<R> {
238 fn default() -> Self {
239 Self::new()
240 }
241}
242
243impl<R: Debug> key::System<R> for System<R> {
244 type Ref = Ref;
245 type Context = Context;
246 type Event = Event;
247 type PendingKeyState = PendingKeyState;
248 type KeyState = KeyState;
249
250 fn new_pressed_key(
251 &self,
252 keymap_index: u16,
253 _context: &Self::Context,
254 Ref(key): Ref,
255 ) -> (
256 key::PressedKeyResult<R, Self::PendingKeyState, Self::KeyState>,
257 key::KeyEvents<Self::Event>,
258 ) {
259 let pke = key.new_pressed_key(keymap_index);
260 let pkr = key::PressedKeyResult::NewPressedKey(key::NewPressedKey::NoOp);
261 (pkr, pke.into_events())
262 }
263
264 fn update_pending_state(
265 &self,
266 _pending_state: &mut Self::PendingKeyState,
267 _keymap_index: u16,
268 _context: &Self::Context,
269 _key_ref: Ref,
270 _event: key::Event<Self::Event>,
271 ) -> (Option<key::NewPressedKey<R>>, key::KeyEvents<Self::Event>) {
272 panic!()
273 }
274
275 fn update_state(
276 &self,
277 _key_state: &mut Self::KeyState,
278 _ref: &Self::Ref,
279 _context: &Self::Context,
280 _keymap_index: u16,
281 _event: key::Event<Self::Event>,
282 ) -> key::KeyEvents<Self::Event> {
283 panic!()
284 }
285
286 fn key_output(
287 &self,
288 _key_ref: &Self::Ref,
289 _key_state: &Self::KeyState,
290 ) -> Option<key::KeyOutput> {
291 panic!()
292 }
293}
294
295#[cfg(test)]
296mod tests {
297 use super::*;
298
299 #[test]
300 fn test_sizeof_ref() {
301 assert_eq!(0, core::mem::size_of::<Ref>());
302 }
303
304 #[test]
305 fn test_sizeof_event() {
306 assert_eq!(0, core::mem::size_of::<Event>());
307 }
308
309 #[test]
310 fn is_lockable_accepts_keyboard_keycode() {
311 assert!(is_lockable(&key::KeyOutput::from_key_code(0x04)));
312 }
313
314 #[test]
315 fn is_lockable_accepts_modifier() {
316 assert!(is_lockable(&key::KeyOutput::from_key_code(0xE1)));
317 }
318
319 #[test]
320 fn is_lockable_rejects_no_output() {
321 assert!(!is_lockable(&key::KeyOutput::NO_OUTPUT));
322 }
323
324 #[test]
325 fn is_lockable_rejects_consumer() {
326 assert!(!is_lockable(&key::KeyOutput::from_consumer_code(1)));
327 }
328
329 #[test]
330 fn toggle_watching_arms() {
331 let mut ctx = Context::new();
332 let _ =
333 key::Context::handle_event(&mut ctx, key::Event::key_event(0, Event::ToggleWatching));
334 assert!(ctx.is_watching());
335 }
336
337 #[test]
338 fn toggle_watching_twice_disarms() {
339 let mut ctx = Context::new();
340 let _ =
341 key::Context::handle_event(&mut ctx, key::Event::key_event(0, Event::ToggleWatching));
342 let _ =
343 key::Context::handle_event(&mut ctx, key::Event::key_event(0, Event::ToggleWatching));
344 assert!(!ctx.is_watching());
345 }
346
347 #[test]
348 fn non_lockable_cancels_watching() {
349 let mut ctx = Context::new();
350 let _ =
351 key::Context::handle_event(&mut ctx, key::Event::key_event(0, Event::ToggleWatching));
352 let _ = key::Context::handle_event(
353 &mut ctx,
354 key::Event::Keymap(keymap::KeymapEvent::ResolvedKeyOutput {
355 keymap_index: 1,
356 key_output: key::KeyOutput::from_consumer_code(0x01),
357 }),
358 );
359 assert!(!ctx.is_watching());
360 }
361}