smart_keymap/key/
composite.rs

1//! This module implements the `keymap::Key` for a 'composite' key,
2//!  which can be any of the other key definitions,
3//!  and is the default Key for the `keymap::KeyMap` implementation.
4#![doc = include_str!("doc_de_composite.md")]
5
6use core::fmt::Debug;
7
8#[cfg(feature = "std")]
9use serde::Deserialize;
10
11use crate::{key, keymap};
12
13mod base;
14mod chorded;
15mod layered;
16mod tap_hold;
17
18pub use base::BaseKey;
19pub use chorded::{Chorded, ChordedKey, ChordedNestable};
20pub use layered::{Layered, LayeredKey, LayeredNestable};
21pub use tap_hold::{TapHold, TapHoldKey, TapHoldNestable};
22
23/// Type alias for composite key types.
24///
25/// Composite key is defined as a tree of key nodes:
26///
27///   ```text
28///   Base    := LayerModifier | Keyboard
29///
30///   TapHold := TapHold<Base> | Base
31///
32///   Layered := Layered<TapHold> | TapHold
33///
34///   Chorded := Chorded<Layered> | AuxChorded<Layered> | Layered
35///   ```
36pub type Key = ChordedKey<LayeredKey<TapHoldKey<BaseKey>>>;
37
38/// Type alias for result from new_pressed_key.
39pub type PressedKeyResult = key::PressedKeyResult<PendingKeyState, KeyState>;
40
41/// Config used for constructing initial context
42#[derive(Debug, Clone, Copy, PartialEq)]
43#[cfg_attr(feature = "std", derive(Deserialize))]
44pub struct Config {
45    /// The chorded configuration.
46    #[cfg_attr(feature = "std", serde(default))]
47    pub chorded: key::chorded::Config,
48    /// The sticky modifier configuration
49    #[cfg_attr(feature = "std", serde(default))]
50    pub sticky: key::sticky::Config,
51    /// The tap dance configuration.
52    #[cfg_attr(feature = "std", serde(default))]
53    pub tap_dance: key::tap_dance::Config,
54    /// The tap hold configuration.
55    #[cfg_attr(feature = "std", serde(default))]
56    pub tap_hold: key::tap_hold::Config,
57}
58
59/// The default config.
60pub const DEFAULT_CONFIG: Config = Config {
61    chorded: key::chorded::DEFAULT_CONFIG,
62    sticky: key::sticky::DEFAULT_CONFIG,
63    tap_dance: key::tap_dance::DEFAULT_CONFIG,
64    tap_hold: key::tap_hold::DEFAULT_CONFIG,
65};
66
67/// An aggregate context for [key::Context]s.
68#[derive(Debug, Clone, Copy)]
69pub struct Context {
70    keymap_context: keymap::KeymapContext,
71    caps_word_context: key::caps_word::Context,
72    chorded_context: key::chorded::Context,
73    layer_context: key::layered::Context,
74    tap_dance_context: key::tap_dance::Context,
75    tap_hold_context: key::tap_hold::Context,
76    sticky_context: key::sticky::Context,
77}
78
79/// The default context.
80pub const DEFAULT_CONTEXT: Context = Context {
81    keymap_context: keymap::DEFAULT_KEYMAP_CONTEXT,
82    caps_word_context: key::caps_word::DEFAULT_CONTEXT,
83    chorded_context: key::chorded::DEFAULT_CONTEXT,
84    layer_context: key::layered::DEFAULT_CONTEXT,
85    sticky_context: key::sticky::DEFAULT_CONTEXT,
86    tap_dance_context: key::tap_dance::DEFAULT_CONTEXT,
87    tap_hold_context: key::tap_hold::DEFAULT_CONTEXT,
88};
89
90impl Context {
91    /// Constructs a [Context] from the given [Config].
92    pub const fn from_config(config: Config) -> Self {
93        Self {
94            chorded_context: key::chorded::Context::from_config(config.chorded),
95            sticky_context: key::sticky::Context::from_config(config.sticky),
96            tap_dance_context: key::tap_dance::Context::from_config(config.tap_dance),
97            tap_hold_context: key::tap_hold::Context::from_config(config.tap_hold),
98            ..DEFAULT_CONTEXT
99        }
100    }
101}
102
103impl Default for Context {
104    /// Returns the default context.
105    fn default() -> Self {
106        DEFAULT_CONTEXT
107    }
108}
109
110impl key::Context for Context {
111    type Event = Event;
112    fn handle_event(&mut self, event: key::Event<Self::Event>) -> key::KeyEvents<Self::Event> {
113        let mut pke = key::KeyEvents::no_events();
114
115        let caps_word_ev = self.caps_word_context.handle_event(event);
116        pke.extend(caps_word_ev);
117
118        if let Ok(e) = event.try_into_key_event(|e| e.try_into()) {
119            let sticky_ev = self.sticky_context.handle_event(e);
120            pke.extend(sticky_ev.into_events());
121        }
122
123        if let Ok(e) = event.try_into_key_event(|e| e.try_into()) {
124            self.chorded_context.handle_event(e);
125        }
126
127        if let key::Event::Key {
128            key_event: Event::LayerModification(ev),
129            ..
130        } = event
131        {
132            self.layer_context.handle_event(ev);
133        }
134
135        pke
136    }
137}
138
139impl keymap::SetKeymapContext for Context {
140    fn set_keymap_context(&mut self, context: keymap::KeymapContext) {
141        self.keymap_context = context;
142    }
143}
144
145impl<'c> From<&'c Context> for &'c keymap::KeymapContext {
146    fn from(ctx: &'c Context) -> Self {
147        &ctx.keymap_context
148    }
149}
150
151impl<'c> From<&'c Context> for &'c key::caps_word::Context {
152    fn from(ctx: &'c Context) -> Self {
153        &ctx.caps_word_context
154    }
155}
156
157impl<'c> From<&'c Context> for &'c key::chorded::Context {
158    fn from(ctx: &'c Context) -> Self {
159        &ctx.chorded_context
160    }
161}
162
163impl<'c> From<&'c Context> for &'c key::layered::Context {
164    fn from(ctx: &'c Context) -> Self {
165        &ctx.layer_context
166    }
167}
168
169impl<'c> From<&'c Context> for &'c key::sticky::Context {
170    fn from(ctx: &'c Context) -> Self {
171        &ctx.sticky_context
172    }
173}
174
175impl<'c> From<&'c Context> for &'c key::tap_dance::Context {
176    fn from(ctx: &'c Context) -> Self {
177        &ctx.tap_dance_context
178    }
179}
180
181impl<'c> From<&'c Context> for &'c key::tap_hold::Context {
182    fn from(ctx: &'c Context) -> Self {
183        &ctx.tap_hold_context
184    }
185}
186
187/// Sum type aggregating the [key::Event] types.
188#[derive(Debug, Clone, Copy, PartialEq)]
189pub enum Event {
190    /// A caps word event.
191    CapsWord(key::caps_word::Event),
192    /// A chorded event.
193    Chorded(key::chorded::Event),
194    /// A sticky modifier event.
195    Sticky(key::sticky::Event),
196    /// A tap-dance event.
197    TapDance(key::tap_dance::Event),
198    /// A tap-hold event.
199    TapHold(key::tap_hold::Event),
200    /// A layer modification event.
201    LayerModification(key::layered::LayerEvent),
202}
203
204impl From<key::caps_word::Event> for Event {
205    fn from(ev: key::caps_word::Event) -> Self {
206        Event::CapsWord(ev)
207    }
208}
209
210impl From<key::chorded::Event> for Event {
211    fn from(ev: key::chorded::Event) -> Self {
212        Event::Chorded(ev)
213    }
214}
215
216impl From<key::layered::LayerEvent> for Event {
217    fn from(ev: key::layered::LayerEvent) -> Self {
218        Event::LayerModification(ev)
219    }
220}
221
222impl From<key::sticky::Event> for Event {
223    fn from(ev: key::sticky::Event) -> Self {
224        Event::Sticky(ev)
225    }
226}
227
228impl From<key::tap_dance::Event> for Event {
229    fn from(ev: key::tap_dance::Event) -> Self {
230        Event::TapDance(ev)
231    }
232}
233
234impl From<key::tap_hold::Event> for Event {
235    fn from(ev: key::tap_hold::Event) -> Self {
236        Event::TapHold(ev)
237    }
238}
239
240impl TryFrom<Event> for key::caps_word::Event {
241    type Error = key::EventError;
242
243    fn try_from(ev: Event) -> Result<Self, Self::Error> {
244        match ev {
245            Event::CapsWord(ev) => Ok(ev),
246            _ => Err(key::EventError::UnmappableEvent),
247        }
248    }
249}
250
251impl TryFrom<Event> for key::chorded::Event {
252    type Error = key::EventError;
253
254    fn try_from(ev: Event) -> Result<Self, Self::Error> {
255        match ev {
256            Event::Chorded(ev) => Ok(ev),
257            _ => Err(key::EventError::UnmappableEvent),
258        }
259    }
260}
261
262impl TryFrom<Event> for key::layered::LayerEvent {
263    type Error = key::EventError;
264
265    fn try_from(ev: Event) -> Result<Self, Self::Error> {
266        match ev {
267            Event::LayerModification(ev) => Ok(ev),
268            _ => Err(key::EventError::UnmappableEvent),
269        }
270    }
271}
272
273impl TryFrom<Event> for key::sticky::Event {
274    type Error = key::EventError;
275
276    fn try_from(ev: Event) -> Result<Self, Self::Error> {
277        match ev {
278            Event::Sticky(ev) => Ok(ev),
279            _ => Err(key::EventError::UnmappableEvent),
280        }
281    }
282}
283
284impl TryFrom<Event> for key::tap_dance::Event {
285    type Error = key::EventError;
286
287    fn try_from(ev: Event) -> Result<Self, Self::Error> {
288        match ev {
289            Event::TapDance(ev) => Ok(ev),
290            _ => Err(key::EventError::UnmappableEvent),
291        }
292    }
293}
294
295impl TryFrom<Event> for key::tap_hold::Event {
296    type Error = key::EventError;
297
298    fn try_from(ev: Event) -> Result<Self, Self::Error> {
299        match ev {
300            Event::TapHold(ev) => Ok(ev),
301            _ => Err(key::EventError::UnmappableEvent),
302        }
303    }
304}
305
306/// Aggregate enum for key state. (i.e. pressed key data).
307#[derive(Debug, Clone, PartialEq)]
308pub enum PendingKeyState {
309    /// Pending key state for [key::tap_dance::PendingKeyState].
310    TapDance(key::tap_dance::PendingKeyState),
311    /// Pending key state for [key::tap_hold::PendingKeyState].
312    TapHold(key::tap_hold::PendingKeyState),
313    /// Pending key state for [key::chorded::PendingKeyState].
314    Chorded(key::chorded::PendingKeyState),
315}
316
317impl From<key::tap_dance::PendingKeyState> for PendingKeyState {
318    fn from(pks: key::tap_dance::PendingKeyState) -> Self {
319        PendingKeyState::TapDance(pks)
320    }
321}
322
323impl From<key::tap_hold::PendingKeyState> for PendingKeyState {
324    fn from(pks: key::tap_hold::PendingKeyState) -> Self {
325        PendingKeyState::TapHold(pks)
326    }
327}
328
329impl From<key::chorded::PendingKeyState> for PendingKeyState {
330    fn from(pks: key::chorded::PendingKeyState) -> Self {
331        PendingKeyState::Chorded(pks)
332    }
333}
334
335impl<'pks> TryFrom<&'pks mut PendingKeyState> for &'pks mut key::tap_dance::PendingKeyState {
336    type Error = ();
337
338    fn try_from(pks: &'pks mut PendingKeyState) -> Result<Self, Self::Error> {
339        match pks {
340            PendingKeyState::TapDance(pks) => Ok(pks),
341            _ => Err(()),
342        }
343    }
344}
345
346impl<'pks> TryFrom<&'pks mut PendingKeyState> for &'pks mut key::tap_hold::PendingKeyState {
347    type Error = ();
348
349    fn try_from(pks: &'pks mut PendingKeyState) -> Result<Self, Self::Error> {
350        match pks {
351            PendingKeyState::TapHold(pks) => Ok(pks),
352            _ => Err(()),
353        }
354    }
355}
356
357impl<'pks> TryFrom<&'pks mut PendingKeyState> for &'pks mut key::chorded::PendingKeyState {
358    type Error = ();
359
360    fn try_from(pks: &'pks mut PendingKeyState) -> Result<Self, Self::Error> {
361        match pks {
362            PendingKeyState::Chorded(pks) => Ok(pks),
363            _ => Err(()),
364        }
365    }
366}
367
368/// Aggregate enum for key state. (i.e. pressed key data).
369#[derive(Debug, Clone, Copy, PartialEq)]
370pub enum KeyState {
371    /// No-op key state.
372    NoOp, // e.g. chorded::AuxiliaryKey's state is a no-op
373    /// Key state for [key::keyboard::KeyState].
374    Keyboard(key::keyboard::KeyState),
375    /// Key state for [key::layered::ModifierKeyState].
376    LayerModifier(key::layered::ModifierKeyState),
377    /// Key state for [key::sticky::KeyState].
378    Sticky(key::sticky::KeyState),
379    /// Key state for [key::custom::KeyState].
380    Custom(key::custom::KeyState),
381}
382
383impl From<key::NoOpKeyState<Context, Event>> for KeyState {
384    fn from(_: key::NoOpKeyState<Context, Event>) -> Self {
385        KeyState::NoOp
386    }
387}
388
389impl From<key::keyboard::KeyState> for KeyState {
390    fn from(ks: key::keyboard::KeyState) -> Self {
391        KeyState::Keyboard(ks)
392    }
393}
394
395impl From<key::layered::ModifierKeyState> for KeyState {
396    fn from(ks: key::layered::ModifierKeyState) -> Self {
397        KeyState::LayerModifier(ks)
398    }
399}
400
401impl From<key::sticky::KeyState> for KeyState {
402    fn from(ks: key::sticky::KeyState) -> Self {
403        KeyState::Sticky(ks)
404    }
405}
406
407impl From<key::custom::KeyState> for KeyState {
408    fn from(ks: key::custom::KeyState) -> Self {
409        KeyState::Custom(ks)
410    }
411}
412
413impl key::KeyState for KeyState {
414    type Context = Context;
415    type Event = Event;
416
417    fn handle_event(
418        &mut self,
419        context: &Self::Context,
420        keymap_index: u16,
421        event: key::Event<Self::Event>,
422    ) -> key::KeyEvents<Self::Event> {
423        match self {
424            KeyState::Keyboard(_) => key::KeyEvents::no_events(),
425            KeyState::LayerModifier(ks) => {
426                if let Ok(ev) = event.try_into_key_event(|e| e.try_into()) {
427                    let l_ev = ks.handle_event(keymap_index, ev);
428                    if let Some(l_ev) = l_ev {
429                        let c_ev = Event::LayerModification(l_ev);
430                        key::KeyEvents::event(key::Event::key_event(keymap_index, c_ev))
431                    } else {
432                        key::KeyEvents::no_events()
433                    }
434                } else {
435                    key::KeyEvents::no_events()
436                }
437            }
438            KeyState::Sticky(ks) => {
439                if let Ok(ev) = event.try_into_key_event(|e| e.try_into()) {
440                    let ctx = context.into();
441                    let ke = ks.handle_event(ctx, keymap_index, ev);
442                    ke.into_events()
443                } else {
444                    key::KeyEvents::no_events()
445                }
446            }
447            KeyState::NoOp => key::KeyEvents::no_events(),
448            KeyState::Custom(_) => key::KeyEvents::no_events(),
449        }
450    }
451
452    fn key_output(&self) -> Option<key::KeyOutput> {
453        match self {
454            KeyState::Keyboard(ks) => Some(ks.key_output()),
455            KeyState::LayerModifier(_) => None,
456            KeyState::Sticky(ks) => ks.key_output(),
457            KeyState::NoOp => None,
458            KeyState::Custom(ks) => Some(ks.key_output()),
459        }
460    }
461}
462
463#[cfg(test)]
464mod tests {
465    use super::*;
466
467    #[test]
468    fn test_composite_pressedkey_layerpressedmodifier_handles_release_event() {
469        use crate::input;
470        use key::{composite, Key, KeyState};
471
472        // Assemble
473        type Ctx = composite::Context;
474        type K = composite::Key;
475        let keymap_index: u16 = 0;
476        let key_path = key::key_path(keymap_index);
477        let key = K::layer_modifier(key::layered::ModifierKey::Hold(1));
478        let context: Ctx = DEFAULT_CONTEXT;
479        let (pressed_lmod_key, _) = key.new_pressed_key(&context, key_path);
480
481        // Act
482        let events = pressed_lmod_key.unwrap_resolved().handle_event(
483            &context,
484            keymap_index,
485            key::Event::Input(input::Event::Release { keymap_index }),
486        );
487
488        // Assert
489        let _key_ev = match events.into_iter().next().map(|sch_ev| sch_ev.event) {
490            Some(key::Event::Key {
491                key_event:
492                    Event::LayerModification(key::layered::LayerEvent::LayerDeactivated(layer_index)),
493                ..
494            }) => {
495                assert_eq!(1, layer_index);
496            }
497            _ => panic!("Expected an Event::Key(LayerModification(LayerDeactivated(layer)))"),
498        };
499    }
500
501    #[test]
502    fn test_composite_context_updates_with_composite_layermodifier_press_event() {
503        use key::{composite, Context, Key};
504
505        // Assemble
506        type Ctx = composite::Context;
507        type K = composite::Key;
508        let keys: [K; 2] = [
509            K::layer_modifier(key::layered::ModifierKey::Hold(1)),
510            K::layered(key::layered::LayeredKey::new(
511                key::keyboard::Key::new(0x04).into(),
512                [Some(key::keyboard::Key::new(0x05).into())],
513            )),
514        ];
515        let mut context: Ctx = DEFAULT_CONTEXT;
516        let keymap_index: u16 = 0;
517        let key_path = key::key_path(keymap_index);
518        let (_pressed_key, pressed_key_events) =
519            keys[keymap_index as usize].new_pressed_key(&context, key_path);
520        let maybe_ev = pressed_key_events.into_iter().next();
521
522        // Act
523        let event = match maybe_ev {
524            Some(key::ScheduledEvent { event, .. }) => event,
525            _ => panic!("Expected Some(ScheduledEvent(Event::Key(_)))"),
526        };
527        context.handle_event(event);
528        let actual_active_layers = context.layer_context.layer_state();
529
530        // Assert
531        let expected_active_layers = &[true];
532        assert_eq!(expected_active_layers[0..1], actual_active_layers[0..1]);
533    }
534
535    #[test]
536    fn test_composite_context_updates_with_composite_layerpressedmodifier_release_event() {
537        use crate::input;
538        use key::{composite, Context, Key, KeyState};
539
540        // Assemble
541        type Ctx = composite::Context;
542        type K = composite::Key;
543        let keys: [K; 2] = [
544            K::layer_modifier(key::layered::ModifierKey::Hold(1)),
545            K::layered(key::layered::LayeredKey::new(
546                key::keyboard::Key::new(0x04).into(),
547                [Some(key::keyboard::Key::new(0x05).into())],
548            )),
549        ];
550        let mut context: Ctx = DEFAULT_CONTEXT;
551        let keymap_index: u16 = 0;
552        let key_path = key::key_path(keymap_index);
553        let (pressed_lmod_key, _) = keys[keymap_index as usize].new_pressed_key(&context, key_path);
554        context.layer_context.activate_layer(1);
555        let events = pressed_lmod_key.unwrap_resolved().handle_event(
556            &context,
557            0,
558            key::Event::Input(input::Event::Release { keymap_index: 0 }),
559        );
560        let key_ev = match events.into_iter().next().map(|sch_ev| sch_ev.event) {
561            Some(key_event) => key_event,
562            _ => panic!("Expected an Event::Key(_)"),
563        };
564
565        // Act
566        context.handle_event(key_ev);
567        let actual_active_layers = context.layer_context.layer_state();
568
569        // Assert
570        let expected_active_layers = &[false];
571        assert_eq!(expected_active_layers[0..1], actual_active_layers[0..1]);
572    }
573
574    #[test]
575    fn test_composite_keyboard_pressed_key_has_key_code_for_composite_keyboard_key_def() {
576        use key::{composite, Key, KeyState};
577
578        // Assemble
579        type Ctx = composite::Context;
580        type K = composite::Key;
581        let keys: [K; 3] = [
582            K::layer_modifier(key::layered::ModifierKey::Hold(1)),
583            K::layered(key::layered::LayeredKey::new(
584                key::keyboard::Key::new(0x04).into(),
585                [Some(key::keyboard::Key::new(0x05).into())],
586            )),
587            K::keyboard(key::keyboard::Key::new(0x06)),
588        ];
589        let context: Ctx = DEFAULT_CONTEXT;
590
591        // Act
592        let keymap_index: u16 = 2;
593        let key_path = key::key_path(keymap_index);
594        let (pressed_key, _) = keys[keymap_index as usize].new_pressed_key(&context, key_path);
595        let actual_keycode = pressed_key.unwrap_resolved().key_output();
596
597        // Assert
598        let expected_keycode = Some(key::KeyOutput::from_key_code(0x06));
599        assert_eq!(expected_keycode, actual_keycode);
600    }
601
602    #[test]
603    fn test_composite_keyboard_pressed_key_has_key_code_for_composite_layered_key_def() {
604        use key::{composite, Key, KeyState};
605
606        // Assemble
607        type Ctx = composite::Context;
608        type K = composite::Key;
609        let keys: [K; 3] = [
610            K::layer_modifier(key::layered::ModifierKey::Hold(1)),
611            K::layered(key::layered::LayeredKey::new(
612                key::keyboard::Key::new(0x04).into(),
613                [Some(key::keyboard::Key::new(0x05).into())],
614            )),
615            K::keyboard(key::keyboard::Key::new(0x06)),
616        ];
617        let context: Ctx = DEFAULT_CONTEXT;
618
619        // Act
620        let keymap_index: u16 = 1;
621        let key_path = key::key_path(keymap_index);
622        let (pressed_key, _) = keys[keymap_index as usize].new_pressed_key(&context, key_path);
623        let actual_keycode = pressed_key.unwrap_resolved().key_output();
624
625        // Assert
626        let expected_keycode = Some(key::KeyOutput::from_key_code(0x04));
627        assert_eq!(expected_keycode, actual_keycode);
628    }
629}