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