smart_keymap/key/
tap_dance.rs

1use core::fmt::Debug;
2
3use serde::Deserialize;
4
5use crate::input;
6use crate::key;
7use crate::keymap;
8
9pub use crate::init::MAX_TAP_DANCE_DEFINITIONS;
10
11/// Configuration settings for tap dance keys.
12#[derive(Deserialize, Debug, Clone, Copy, PartialEq)]
13pub struct Config {
14    /// The timeout (in number of milliseconds) for the next press of the tap-dance.
15    #[serde(default = "default_timeout")]
16    pub timeout: u16,
17}
18
19fn default_timeout() -> u16 {
20    DEFAULT_CONFIG.timeout
21}
22
23/// Default tap dance config.
24pub const DEFAULT_CONFIG: Config = Config { timeout: 200 };
25
26impl Default for Config {
27    /// Returns the default context.
28    fn default() -> Self {
29        DEFAULT_CONFIG
30    }
31}
32
33/// A key with tap-dance functionality.
34#[derive(Deserialize, Debug, Clone, Copy, PartialEq)]
35pub struct Key<K: key::Key> {
36    /// Tap-Dance definitions.
37    definitions: [Option<K>; MAX_TAP_DANCE_DEFINITIONS],
38}
39
40impl<K: key::Key + Copy> Key<K> {
41    /// Constructs a new tap-dance key.
42    pub const fn new(definitions: [Option<K>; MAX_TAP_DANCE_DEFINITIONS]) -> Key<K> {
43        Key { definitions }
44    }
45
46    /// Construct the tap-dance key from the given slice of keys.
47    pub const fn from_definitions(defs: &[K]) -> Self {
48        let mut definitions: [Option<K>; MAX_TAP_DANCE_DEFINITIONS] =
49            [None; MAX_TAP_DANCE_DEFINITIONS];
50        let mut idx = 0;
51        while idx < definitions.len() && idx < defs.len() {
52            definitions[idx] = Some(defs[idx]);
53            idx += 1;
54        }
55        Self::new(definitions)
56    }
57}
58
59impl<K: key::Key> Key<K> {
60    fn new_pressed_key(
61        &self,
62        context: &K::Context,
63        key_path: key::KeyPath,
64    ) -> (
65        key::PressedKeyResult<K::PendingKeyState, K::KeyState>,
66        key::KeyEvents<K::Event>,
67    )
68    where
69        for<'ctx> &'ctx K::Context: Into<&'ctx Context>,
70        for<'ctx> &'ctx K::Context: Into<&'ctx keymap::KeymapContext>,
71        Event: Into<K::Event>,
72        PendingKeyState: Into<K::PendingKeyState>,
73    {
74        let keymap_index: u16 = key_path.keymap_index();
75
76        let td_pks = PendingKeyState::new();
77        let pk = key::PressedKeyResult::Pending(key_path, td_pks.into());
78
79        let &Context { config, .. } = context.into();
80        let timeout_ev = Event::NextPressTimeout(0);
81        let key_ev = key::Event::Key {
82            keymap_index,
83            key_event: timeout_ev,
84        };
85        let pke =
86            key::KeyEvents::scheduled_event(key::ScheduledEvent::after(config.timeout, key_ev));
87
88        (pk, pke.into_events())
89    }
90}
91
92impl<
93        K: key::Key<
94            Context = crate::init::Context,
95            Event = crate::init::Event,
96            PendingKeyState = crate::init::PendingKeyState,
97            KeyState = crate::init::KeyState,
98        >,
99    > key::Key for Key<K>
100{
101    type Context = crate::init::Context;
102    type Event = crate::init::Event;
103    type PendingKeyState = crate::init::PendingKeyState;
104    type KeyState = crate::init::KeyState;
105
106    fn new_pressed_key(
107        &self,
108        context: &Self::Context,
109        key_path: key::KeyPath,
110    ) -> (
111        key::PressedKeyResult<Self::PendingKeyState, Self::KeyState>,
112        key::KeyEvents<Self::Event>,
113    ) {
114        self.new_pressed_key(context, key_path.clone())
115    }
116
117    fn handle_event(
118        &self,
119        pending_state: &mut Self::PendingKeyState,
120        context: &Self::Context,
121        key_path: key::KeyPath,
122        event: key::Event<Self::Event>,
123    ) -> (Option<key::NewPressedKey>, key::KeyEvents<Self::Event>) {
124        let keymap_index = key_path.keymap_index();
125        let td_pks_res: Result<&mut PendingKeyState, _> = pending_state.try_into();
126        if let Ok(td_pks) = td_pks_res {
127            if let Ok(td_ev) = event.try_into_key_event(|e| e.try_into()) {
128                let (maybe_resolution, pke) =
129                    td_pks.handle_event(context.into(), keymap_index, td_ev);
130
131                if let Some(TapDanceResolution(idx)) = maybe_resolution {
132                    // PRESSED KEY PATH: add Tap Dance item (index for the tap-dance definition)
133                    let new_key_path = key_path.append_path_item(idx as u16);
134
135                    (
136                        Some(key::NewPressedKey::key_path(new_key_path)),
137                        pke.into_events(),
138                    )
139                } else {
140                    // check td_pks press_count against key definitions
141                    let definition_count = self.definitions.iter().filter(|o| o.is_some()).count();
142                    if td_pks.press_count as usize >= definition_count - 1 {
143                        let idx = definition_count - 1;
144                        // PRESSED KEY PATH: add Tap Dance item (index for the tap-dance definition)
145                        let new_key_path = key_path.append_path_item(idx as u16);
146
147                        (
148                            Some(key::NewPressedKey::key_path(new_key_path)),
149                            pke.into_events(),
150                        )
151                    } else {
152                        (None, pke.into_events())
153                    }
154                }
155            } else {
156                (None, key::KeyEvents::no_events())
157            }
158        } else {
159            (None, key::KeyEvents::no_events())
160        }
161    }
162
163    fn lookup(
164        &self,
165        path: &[u16],
166    ) -> &dyn key::Key<
167        Context = Self::Context,
168        Event = Self::Event,
169        PendingKeyState = Self::PendingKeyState,
170        KeyState = Self::KeyState,
171    > {
172        match path {
173            [] => self,
174            // idx = definition index
175            [idx, path @ ..] => match &self.definitions[*idx as usize] {
176                Some(key) => key.lookup(path),
177                None => panic!(),
178            },
179        }
180    }
181}
182
183/// Context for [Key].
184#[derive(Debug, Clone, Copy, PartialEq)]
185pub struct Context {
186    config: Config,
187}
188
189/// Default context.
190pub const DEFAULT_CONTEXT: Context = Context::from_config(DEFAULT_CONFIG);
191
192impl Context {
193    /// Constructs a context from the given config
194    pub const fn from_config(config: Config) -> Context {
195        Context { config }
196    }
197}
198
199/// Resolution of a tap-dance key. (Index of the tap-dance definition).
200#[derive(Debug, Clone, Copy, PartialEq)]
201pub struct TapDanceResolution(u8);
202
203/// Events emitted by a tap-dance key.
204#[derive(Debug, Clone, Copy, PartialEq)]
205pub enum Event {
206    /// Timed out waiting for the next press of the tap-dance key.
207    NextPressTimeout(u8),
208}
209
210/// The state of a pressed tap-dance key.
211#[derive(Debug, Clone, PartialEq)]
212pub struct PendingKeyState {
213    press_count: u8,
214}
215
216impl PendingKeyState {
217    /// Constructs the initial pressed key state
218    fn new() -> PendingKeyState {
219        PendingKeyState { press_count: 0 }
220    }
221
222    fn handle_event(
223        &mut self,
224        context: &Context,
225        keymap_index: u16,
226        event: key::Event<Event>,
227    ) -> (Option<TapDanceResolution>, key::KeyEvents<Event>) {
228        match event {
229            key::Event::Key {
230                key_event: Event::NextPressTimeout(press_timed_out),
231                keymap_index: ev_kmi,
232            } if ev_kmi == keymap_index && press_timed_out == self.press_count => (
233                Some(TapDanceResolution(self.press_count)),
234                key::KeyEvents::no_events(),
235            ),
236
237            key::Event::Input(input::Event::Press {
238                keymap_index: ev_kmi,
239            }) if ev_kmi == keymap_index => {
240                self.press_count += 1;
241
242                let Context { config } = context;
243                let timeout_ev = Event::NextPressTimeout(self.press_count);
244
245                let key_ev = key::Event::Key {
246                    keymap_index,
247                    key_event: timeout_ev,
248                };
249                let pke = key::KeyEvents::scheduled_event(key::ScheduledEvent::after(
250                    config.timeout,
251                    key_ev,
252                ));
253
254                (None, pke)
255            }
256
257            _ => (None, key::KeyEvents::no_events()),
258        }
259    }
260}