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[0];
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    ) -> (
124        Option<key::PressedKeyResult<Self::PendingKeyState, Self::KeyState>>,
125        key::KeyEvents<Self::Event>,
126    ) {
127        let keymap_index = key_path[0];
128        let td_pks_res: Result<&mut PendingKeyState, _> = pending_state.try_into();
129        if let Ok(td_pks) = td_pks_res {
130            if let Ok(td_ev) = event.try_into_key_event(|e| e.try_into()) {
131                let (maybe_resolution, pke) =
132                    td_pks.handle_event(context.into(), keymap_index, td_ev);
133
134                if let Some(TapDanceResolution(idx)) = maybe_resolution {
135                    let nk = (&self.definitions[idx as usize]).as_ref().unwrap();
136
137                    let (pkr, pke) = nk.new_pressed_key(context, key_path);
138                    // PRESSED KEY PATH: add Tap Dance item (index for the tap-dance definition)
139                    let pkr = pkr.add_path_item(idx as u16);
140
141                    (Some(pkr), pke)
142                } else {
143                    // check td_pks press_count against key definitions
144                    let definition_count = self.definitions.iter().filter(|o| o.is_some()).count();
145                    if td_pks.press_count as usize >= definition_count - 1 {
146                        let idx = definition_count - 1;
147                        let nk = (&self.definitions[idx]).as_ref().unwrap();
148                        let (pkr, pke) = nk.new_pressed_key(context, key_path);
149                        // PRESSED KEY PATH: add Tap Dance item (index for the tap-dance definition)
150                        let pkr = pkr.add_path_item(idx as u16);
151
152                        (Some(pkr), pke)
153                    } else {
154                        (None, pke.into_events())
155                    }
156                }
157            } else {
158                (None, key::KeyEvents::no_events())
159            }
160        } else {
161            (None, key::KeyEvents::no_events())
162        }
163    }
164
165    fn lookup(
166        &self,
167        path: &[u16],
168    ) -> &dyn key::Key<
169        Context = Self::Context,
170        Event = Self::Event,
171        PendingKeyState = Self::PendingKeyState,
172        KeyState = Self::KeyState,
173    > {
174        match path {
175            [] => self,
176            // idx = definition index
177            [idx, path @ ..] => match &self.definitions[*idx as usize] {
178                Some(key) => key.lookup(path),
179                None => panic!(),
180            },
181        }
182    }
183}
184
185/// Context for [Key].
186#[derive(Debug, Clone, Copy, PartialEq)]
187pub struct Context {
188    config: Config,
189}
190
191/// Default context.
192pub const DEFAULT_CONTEXT: Context = Context::from_config(DEFAULT_CONFIG);
193
194impl Context {
195    /// Constructs a context from the given config
196    pub const fn from_config(config: Config) -> Context {
197        Context { config }
198    }
199}
200
201/// Resolution of a tap-dance key. (Index of the tap-dance definition).
202#[derive(Debug, Clone, Copy, PartialEq)]
203pub struct TapDanceResolution(u8);
204
205/// Events emitted by a tap-dance key.
206#[derive(Debug, Clone, Copy, PartialEq)]
207pub enum Event {
208    /// Timed out waiting for the next press of the tap-dance key.
209    NextPressTimeout(u8),
210}
211
212/// The state of a pressed tap-dance key.
213#[derive(Debug, Clone, PartialEq)]
214pub struct PendingKeyState {
215    press_count: u8,
216}
217
218impl PendingKeyState {
219    /// Constructs the initial pressed key state
220    fn new() -> PendingKeyState {
221        PendingKeyState { press_count: 0 }
222    }
223
224    fn handle_event(
225        &mut self,
226        context: &Context,
227        keymap_index: u16,
228        event: key::Event<Event>,
229    ) -> (Option<TapDanceResolution>, key::KeyEvents<Event>) {
230        match event {
231            key::Event::Key {
232                key_event: Event::NextPressTimeout(press_timed_out),
233                keymap_index: ev_kmi,
234            } if ev_kmi == keymap_index && press_timed_out == self.press_count => (
235                Some(TapDanceResolution(self.press_count)),
236                key::KeyEvents::no_events(),
237            ),
238
239            key::Event::Input(input::Event::Press {
240                keymap_index: ev_kmi,
241            }) if ev_kmi == keymap_index => {
242                self.press_count += 1;
243
244                let Context { config } = context;
245                let timeout_ev = Event::NextPressTimeout(self.press_count);
246
247                let key_ev = key::Event::Key {
248                    keymap_index,
249                    key_event: timeout_ev,
250                };
251                let pke = key::KeyEvents::scheduled_event(key::ScheduledEvent::after(
252                    config.timeout,
253                    key_ev,
254                ));
255
256                (None, pke)
257            }
258
259            _ => (None, key::KeyEvents::no_events()),
260        }
261    }
262}