smart_keymap/key/
sticky.rs

1use core::fmt::Debug;
2use core::marker::Copy;
3use core::ops::Index;
4
5use serde::Deserialize;
6
7use crate::input;
8use crate::key;
9use crate::keymap;
10
11/// Reference for a sticky modifier key.
12#[derive(Deserialize, Debug, Clone, Copy, PartialEq)]
13pub struct Ref(pub u8);
14
15/// When the sticky modifiers activate.
16#[derive(Deserialize, Debug, Clone, Copy, PartialEq)]
17pub enum StickyKeyActivation {
18    /// Sticky modifiers activate when the sticky key is released.
19    OnStickyKeyRelease,
20    // TODO: add another config option for "on next key press"
21    // /// Sticky modifiers activate when the next key is pressed.
22    // OnNextKeyPress,
23}
24
25/// When the sticky modifiers release.
26#[derive(Deserialize, Debug, Clone, Copy, PartialEq)]
27pub enum StickyKeyRelease {
28    /// Sticky modifiers release when the modified key is released.
29    OnModifiedKeyRelease,
30    /// Sticky modifiers release when a key is pressed after the modified key.
31    OnNextKeyPress,
32}
33
34/// Sticky Key configuration.
35#[derive(Deserialize, Debug, Clone, Copy, PartialEq)]
36pub struct Config {
37    /// The sticky key activation mode.
38    #[serde(default = "default_activation")]
39    pub activation: StickyKeyActivation,
40    /// When the sticky modifiers release.
41    #[serde(default = "default_release")]
42    pub release: StickyKeyRelease,
43}
44
45fn default_activation() -> StickyKeyActivation {
46    DEFAULT_CONFIG.activation
47}
48
49fn default_release() -> StickyKeyRelease {
50    DEFAULT_CONFIG.release
51}
52
53/// The default [Config].
54pub const DEFAULT_CONFIG: Config = Config {
55    activation: StickyKeyActivation::OnStickyKeyRelease,
56    release: StickyKeyRelease::OnModifiedKeyRelease,
57};
58
59impl Default for Config {
60    /// Returns the default context.
61    fn default() -> Self {
62        DEFAULT_CONFIG
63    }
64}
65
66const MAX_STICKY_MODIFIERS: u8 = 4;
67
68/// Sticky Modifiers context.
69#[derive(Debug, Clone, Copy)]
70pub struct Context {
71    /// The sticky modifier key configuration.
72    pub config: Config,
73    /// Sticky modifiers.
74    pub active_modifiers: [key::KeyboardModifiers; MAX_STICKY_MODIFIERS as usize],
75    /// Number af active sticky modifiers.
76    pub active_modifier_count: u8,
77    /// Index of the next output resolved once a sticky key has been released.
78    pub pressed_keymap_index: Option<u16>,
79}
80
81/// The default [Context].
82pub const DEFAULT_CONTEXT: Context = Context {
83    config: DEFAULT_CONFIG,
84    active_modifiers: [key::KeyboardModifiers::NONE; MAX_STICKY_MODIFIERS as usize],
85    active_modifier_count: 0,
86    pressed_keymap_index: None,
87};
88
89impl Context {
90    /// Constructs a context from the given config
91    pub const fn from_config(config: Config) -> Context {
92        Context {
93            config,
94            ..DEFAULT_CONTEXT
95        }
96    }
97
98    /// Updates the context with the given event.
99    pub fn handle_event(&mut self, event: key::Event<Event>) -> key::KeyEvents<Event> {
100        // Cases:
101        //
102        // - No sticky key has been pressed.
103        //   - Event: any, when active_modifiers is None.
104        //   - Ctx same as default.
105        // - Sticky key has been tapped,
106        //    (pressed, released, without interruption),
107        //   - Event: Event::ActivateModifiers
108        //   - Ctx has sticky key active.
109        //     - Virtual Key modifier is pressed (if config StickyKeyActivation::OnStickyKeyRelease)
110        //   - add the activated modifiers to self.activated_modifiers
111        // - Next key has been pressed
112        //   ("modified key")
113        //   - Event: Keymap::ResolvedKeyOutput (active modifiers is Some(), pressed_keymap_index is None)
114        //   - Virtual Key modifier is pressed  (if config StickyKeyActivation::OnNextKeyPress)
115        //   - Ctx still has the sticky key active.
116        // - Same next key has been released
117        //   ("modified key")
118        //   - Event: input::Event::KeyRelease, with the same keymap index.
119        //   - Ctx deactivates the sticky key.
120        //     - Virtual Key modifier is released.
121        // - Another key has been pressed,
122        //    after sticky modifiers are pressed.
123        //   - Event: Keymap::ResolvedKeyOutput (active modifiers is Some(), pressed_keymap_index is Some())
124        //   - c.f. ZMK's quick-release.
125
126        match (self.active_modifier_count, event) {
127            // Case:
128            //  - a sticky key has been released.
129            (
130                0,
131                key::Event::Key {
132                    key_event: Event::ActivateModifiers(mods),
133                    ..
134                },
135            ) => {
136                self.active_modifiers[0] = mods;
137                self.active_modifier_count = 1;
138
139                key::KeyEvents::no_events()
140            }
141            // Case:
142            //  - another sticky key has been released.
143            (
144                active_modifier_count,
145                key::Event::Key {
146                    key_event: Event::ActivateModifiers(mods),
147                    ..
148                },
149            ) => {
150                if active_modifier_count < MAX_STICKY_MODIFIERS {
151                    self.active_modifiers[active_modifier_count as usize] = mods;
152                    self.active_modifier_count += 1;
153                }
154
155                key::KeyEvents::no_events()
156            }
157            // Case:
158            //  - Next key has been pressed, this is the "modified key";
159            //     this key gets modified until it is released.
160            (
161                active_modifier_count,
162                key::Event::Keymap(keymap::KeymapEvent::ResolvedKeyOutput { keymap_index, .. }),
163            ) if active_modifier_count > 0 => {
164                let pke = key::KeyEvents::no_events();
165
166                // The sticky key deactivates (releases)
167                //  once the modified key releases.
168                //
169                // Track the keymap index that resolved the key state.
170                self.pressed_keymap_index = Some(keymap_index);
171
172                // if matches!(self.config.activation, StickyKeyActivation::OnNextKeyPress) {
173                //     // TODO: if the config is to activate on key press, send the VK here
174                // }
175
176                pke
177            }
178            // Case:
179            //  - Modified key is released.
180            (
181                active_modifier_count,
182                key::Event::Input(input::Event::Release {
183                    keymap_index: ev_kmi,
184                }),
185            ) if Some(ev_kmi) == self.pressed_keymap_index && active_modifier_count > 0 => {
186                // Modified key has been released; release the VK.
187                let mut pke = key::KeyEvents::no_events();
188
189                self.active_modifiers[..active_modifier_count as usize]
190                    .iter()
191                    .for_each(|&m| {
192                        let sticky_key_output = key::KeyOutput::from_key_modifiers(m);
193                        let vk_ev = key::Event::Input(input::Event::VirtualKeyRelease {
194                            key_output: sticky_key_output,
195                        });
196                        pke.add_event(key::ScheduledEvent::immediate(vk_ev));
197                    });
198
199                self.active_modifier_count = 0;
200                self.pressed_keymap_index = None;
201
202                pke
203            }
204            // Case: after the sticky key modifiers are modifying a key,
205            //        another key is pressed,
206            //        & the config.release is OnNextKeyPress.
207            //  - Modified key is released.
208            (active_modifier_count, key::Event::Input(input::Event::Press { .. }))
209                if self.pressed_keymap_index.is_some()
210                    && self.config.release == StickyKeyRelease::OnNextKeyPress =>
211            {
212                // Another key has been pressed (& config is to release sticky modifiers);
213                //  release the VK.
214                let mut pke = key::KeyEvents::no_events();
215
216                self.active_modifiers[..active_modifier_count as usize]
217                    .iter()
218                    .for_each(|&m| {
219                        let sticky_key_output = key::KeyOutput::from_key_modifiers(m);
220                        let vk_ev = key::Event::Input(input::Event::VirtualKeyRelease {
221                            key_output: sticky_key_output,
222                        });
223                        pke.add_event(key::ScheduledEvent::immediate(vk_ev));
224                    });
225
226                self.active_modifier_count = 0;
227                self.pressed_keymap_index = None;
228
229                pke
230            }
231            _ => key::KeyEvents::no_events(),
232        }
233    }
234}
235
236/// Sticky Modifier key events.
237#[derive(Debug, Clone, Copy, PartialEq)]
238pub enum Event {
239    /// Activates the given modifier(s) as "sticky"
240    ActivateModifiers(key::KeyboardModifiers),
241}
242
243/// A key for HID Keyboard usage codes.
244#[derive(Deserialize, Debug, Clone, Copy, PartialEq)]
245pub struct Key {
246    /// The sticky key modifiers.
247    pub sticky_modifiers: key::KeyboardModifiers,
248}
249
250impl Key {
251    /// Constructs a key with the given key_code.
252    pub const fn new(sticky_modifiers: key::KeyboardModifiers) -> Self {
253        Key { sticky_modifiers }
254    }
255
256    /// Constructs a pressed key state
257    pub fn new_pressed_key(&self) -> KeyState {
258        KeyState::new()
259    }
260}
261
262/// The pending key state type for sticky modifier keys. (No pending state).
263#[derive(Debug, Clone, Copy, PartialEq)]
264pub struct PendingKeyState;
265
266/// Whether the pressed Sticky modifier key is "sticky" or "regular".
267#[derive(Debug, Clone, Copy, Eq, PartialEq)]
268pub enum Behavior {
269    /// Key state is "sticky". (Will activate sticky modifier when released).
270    Sticky,
271    /// Key state is "regular". (No sticky modifiers activated when released).
272    Regular,
273}
274
275/// Key state for sticky modifier keys.
276#[derive(Debug, Clone, Copy, PartialEq)]
277pub struct KeyState {
278    behavior: Behavior,
279}
280
281impl KeyState {
282    /// Constructs a new key state with the given sticky modifiers.
283    pub fn new() -> Self {
284        KeyState {
285            behavior: Behavior::Sticky,
286        }
287    }
288}
289
290impl Default for KeyState {
291    /// Returns the default key state.
292    fn default() -> Self {
293        Self::new()
294    }
295}
296
297impl KeyState {
298    /// Handle the given event.
299    pub fn update_state(
300        &mut self,
301        key: &Key,
302        context: &Context,
303        keymap_index: u16,
304        event: key::Event<Event>,
305    ) -> key::KeyEvents<Event> {
306        //  - If another key is *pressed*, then we're no longer a sticky key.
307        //  - If this key is released & it's a sticky key
308        //     (& the config is for "eager sticky mod"),
309        //     then emit a VK with the mods; emit event "activate".
310        match self.behavior {
311            Behavior::Sticky => match event {
312                key::Event::Keymap(keymap::KeymapEvent::ResolvedKeyOutput { .. }) => {
313                    // Another key has been pressed.
314                    // The sticky modifier key acts as a regular key.
315                    self.behavior = Behavior::Regular;
316
317                    key::KeyEvents::no_events()
318                }
319                key::Event::Input(input::Event::Release {
320                    keymap_index: released_index,
321                }) if released_index == keymap_index => {
322                    // The sticky key has been released.
323                    match context.config.activation {
324                        StickyKeyActivation::OnStickyKeyRelease => {
325                            let sticky_ev = Event::ActivateModifiers(key.sticky_modifiers);
326                            let k_ev = key::Event::key_event(keymap_index, sticky_ev);
327
328                            let sticky_key_output =
329                                key::KeyOutput::from_key_modifiers(key.sticky_modifiers);
330                            let vk_ev = key::Event::Input(input::Event::VirtualKeyPress {
331                                key_output: sticky_key_output,
332                            });
333
334                            let mut pke = key::KeyEvents::event(k_ev);
335                            pke.add_event(key::ScheduledEvent::immediate(vk_ev));
336                            pke
337                        }
338                    }
339                }
340                _ => key::KeyEvents::no_events(),
341            },
342            Behavior::Regular => key::KeyEvents::no_events(),
343        }
344    }
345
346    /// Key output for the pressed key state.
347    pub fn key_output(&self, key: &Key) -> Option<key::KeyOutput> {
348        match self.behavior {
349            Behavior::Sticky => None,
350            Behavior::Regular => Some(key::KeyOutput::from_key_modifiers(key.sticky_modifiers)),
351        }
352    }
353}
354
355/// The [key::System] implementation for keyboard keys.
356#[derive(Debug, Clone, Copy, PartialEq)]
357pub struct System<Keys: Index<usize, Output = Key>> {
358    keys: Keys,
359}
360
361impl<Keys: Index<usize, Output = Key>> System<Keys> {
362    /// Constructs a new [System] with the given key data.
363    pub const fn new(key_data: Keys) -> Self {
364        Self { keys: key_data }
365    }
366}
367
368impl<R, Keys: Debug + Index<usize, Output = Key>> key::System<R> for System<Keys> {
369    type Ref = Ref;
370    type Context = Context;
371    type Event = Event;
372    type PendingKeyState = PendingKeyState;
373    type KeyState = KeyState;
374
375    fn new_pressed_key(
376        &self,
377        _keymap_index: u16,
378        _context: &Self::Context,
379        Ref(key_index): Ref,
380    ) -> (
381        key::PressedKeyResult<R, Self::PendingKeyState, Self::KeyState>,
382        key::KeyEvents<Self::Event>,
383    ) {
384        let key = &self.keys[key_index as usize];
385        let ks = key.new_pressed_key();
386        let pks = key::PressedKeyResult::Resolved(ks);
387        let pke = key::KeyEvents::no_events();
388        (pks, pke)
389    }
390
391    fn update_pending_state(
392        &self,
393        _pending_state: &mut Self::PendingKeyState,
394        _keymap_index: u16,
395        _context: &Self::Context,
396        _key_ref: Ref,
397        _event: key::Event<Self::Event>,
398    ) -> (Option<key::NewPressedKey<R>>, key::KeyEvents<Self::Event>) {
399        panic!()
400    }
401
402    fn update_state(
403        &self,
404        key_state: &mut Self::KeyState,
405        Ref(key_index): &Self::Ref,
406        context: &Self::Context,
407        keymap_index: u16,
408        event: key::Event<Self::Event>,
409    ) -> key::KeyEvents<Self::Event> {
410        let key = &self.keys[*key_index as usize];
411        key_state.update_state(key, context, keymap_index, event)
412    }
413
414    fn key_output(
415        &self,
416        Ref(key_index): &Self::Ref,
417        key_state: &Self::KeyState,
418    ) -> Option<key::KeyOutput> {
419        let key = &self.keys[*key_index as usize];
420        key_state.key_output(key)
421    }
422}