Skip to main content

smart_keymap_core/key/
tap_dance.rs

1use core::fmt::Debug;
2use core::ops::Index;
3
4use serde::Deserialize;
5
6use crate::input;
7use crate::key;
8
9/// Reference for a tap dance key.
10#[derive(Deserialize, Debug, Clone, Copy, PartialEq)]
11pub struct Ref(pub u8);
12
13/// Configuration settings for tap dance keys.
14#[derive(Deserialize, Debug, Clone, Copy, PartialEq)]
15pub struct Config {
16    /// The timeout (in number of milliseconds) for the next press of the tap-dance.
17    #[serde(default = "default_timeout")]
18    pub timeout: u16,
19}
20
21/// The default timeout.
22pub const DEFAULT_TIMEOUT: u16 = 200;
23
24fn default_timeout() -> u16 {
25    DEFAULT_TIMEOUT
26}
27
28/// Default tap dance config.
29pub const DEFAULT_CONFIG: Config = Config {
30    timeout: DEFAULT_TIMEOUT,
31};
32
33impl Config {
34    /// Constructs a new default [Config].
35    pub const fn new() -> Self {
36        DEFAULT_CONFIG
37    }
38}
39
40impl Default for Config {
41    /// Returns the default context.
42    fn default() -> Self {
43        DEFAULT_CONFIG
44    }
45}
46
47/// A key with tap-dance functionality.
48#[derive(Deserialize, Debug, Clone, Copy, PartialEq)]
49pub struct Key<R, const MAX_TAP_DANCE_DEFINITIONS: usize> {
50    /// Tap-Dance definitions.
51    #[serde(bound(deserialize = "R: Deserialize<'de>"))]
52    #[serde(deserialize_with = "deserialize_definitions")]
53    definitions: [Option<R>; MAX_TAP_DANCE_DEFINITIONS],
54}
55
56/// Deserialize definitions.
57fn deserialize_definitions<'de, R, D, const MAX_TAP_DANCE_DEFINITIONS: usize>(
58    deserializer: D,
59) -> Result<[Option<R>; MAX_TAP_DANCE_DEFINITIONS], D::Error>
60where
61    R: Deserialize<'de>,
62    D: serde::Deserializer<'de>,
63{
64    let defs_vec: heapless::Vec<Option<R>, MAX_TAP_DANCE_DEFINITIONS> =
65        Deserialize::deserialize(deserializer)?;
66
67    match defs_vec.into_array() {
68        Ok(arr) => Ok(arr),
69        Err(_) => Err(serde::de::Error::custom(
70            "Unable to deserialize tap_dance definitions",
71        )),
72    }
73}
74
75impl<R: Copy, const MAX_TAP_DANCE_DEFINITIONS: usize> Key<R, MAX_TAP_DANCE_DEFINITIONS> {
76    /// Constructs a new tap-dance key.
77    pub const fn new(
78        definitions: [Option<R>; MAX_TAP_DANCE_DEFINITIONS],
79    ) -> Key<R, MAX_TAP_DANCE_DEFINITIONS> {
80        Key { definitions }
81    }
82
83    /// Construct the tap-dance key from the given slice of keys.
84    pub const fn from_definitions(defs: &[R]) -> Self {
85        let mut definitions: [Option<R>; MAX_TAP_DANCE_DEFINITIONS] =
86            [None; MAX_TAP_DANCE_DEFINITIONS];
87        let mut idx = 0;
88        while idx < definitions.len() && idx < defs.len() {
89            definitions[idx] = Some(defs[idx]);
90            idx += 1;
91        }
92        Self::new(definitions)
93    }
94}
95
96/// Context for [Key].
97#[derive(Debug, Clone, Copy, PartialEq)]
98pub struct Context {
99    config: Config,
100}
101
102impl Context {
103    /// Constructs a context from the given config
104    pub const fn from_config(config: Config) -> Context {
105        Context { config }
106    }
107
108    /// Re-construct from context's [Config] (no other runtime state).
109    pub fn reset(&mut self) {
110        *self = Self::from_config(self.config);
111    }
112}
113
114/// Resolution of a tap-dance key. (Index of the tap-dance definition).
115#[derive(Debug, Clone, Copy, PartialEq)]
116pub struct TapDanceResolution(u8);
117
118/// Events emitted by a tap-dance key.
119#[derive(Debug, Clone, Copy, PartialEq)]
120pub enum Event {
121    /// Timed out waiting for the next press of the tap-dance key.
122    NextPressTimeout(u8),
123}
124
125/// The state of a pressed tap-dance key.
126#[derive(Debug, Clone, Copy, PartialEq)]
127pub struct PendingKeyState {
128    press_count: u8,
129}
130
131impl PendingKeyState {
132    /// Constructs the initial pressed key state
133    fn new() -> PendingKeyState {
134        PendingKeyState { press_count: 0 }
135    }
136
137    fn handle_event(
138        &mut self,
139        context: &Context,
140        keymap_index: u16,
141        event: key::Event<Event>,
142    ) -> (Option<TapDanceResolution>, key::KeyEvents<Event>) {
143        match event {
144            key::Event::Key {
145                key_event: Event::NextPressTimeout(press_timed_out),
146                keymap_index: ev_kmi,
147            } if ev_kmi == keymap_index && press_timed_out == self.press_count => (
148                Some(TapDanceResolution(self.press_count)),
149                key::KeyEvents::no_events(),
150            ),
151
152            key::Event::Input(input::Event::Press {
153                keymap_index: ev_kmi,
154            }) if ev_kmi == keymap_index => {
155                self.press_count += 1;
156
157                let Context { config } = context;
158                let timeout_ev = Event::NextPressTimeout(self.press_count);
159
160                let key_ev = key::Event::Key {
161                    keymap_index,
162                    key_event: timeout_ev,
163                };
164                let pke = key::KeyEvents::scheduled_event(key::ScheduledEvent::after(
165                    config.timeout,
166                    key_ev,
167                ));
168
169                (None, pke)
170            }
171
172            _ => (None, key::KeyEvents::no_events()),
173        }
174    }
175}
176
177/// The key state for System. (No state).
178#[derive(Debug, Clone, Copy, PartialEq)]
179pub struct KeyState;
180
181/// The [key::System] implementation for tap dance keys.
182#[derive(Debug, Clone, Copy, PartialEq)]
183pub struct System<
184    R,
185    Keys: Index<usize, Output = Key<R, MAX_TAP_DANCE_DEFINITIONS>>,
186    const MAX_TAP_DANCE_DEFINITIONS: usize,
187> {
188    keys: Keys,
189}
190
191impl<
192        R,
193        Keys: Index<usize, Output = Key<R, MAX_TAP_DANCE_DEFINITIONS>>,
194        const MAX_TAP_DANCE_DEFINITIONS: usize,
195    > System<R, Keys, MAX_TAP_DANCE_DEFINITIONS>
196{
197    /// Constructs a new [System] with the given key data.
198    pub const fn new(key_data: Keys) -> Self {
199        Self { keys: key_data }
200    }
201}
202
203impl<
204        R: Copy + Debug,
205        Keys: Debug + Index<usize, Output = Key<R, MAX_TAP_DANCE_DEFINITIONS>>,
206        const MAX_TAP_DANCE_DEFINITIONS: usize,
207    > key::System<R> for System<R, Keys, MAX_TAP_DANCE_DEFINITIONS>
208{
209    type Ref = Ref;
210    type Context = Context;
211    type Event = Event;
212    type PendingKeyState = PendingKeyState;
213    type KeyState = KeyState;
214
215    fn new_pressed_key(
216        &self,
217        keymap_index: u16,
218        context: &Self::Context,
219        _key_ref: Ref,
220    ) -> (
221        key::PressedKeyResult<R, Self::PendingKeyState, Self::KeyState>,
222        key::KeyEvents<Self::Event>,
223    ) {
224        let td_pks = PendingKeyState::new();
225        let pk = key::PressedKeyResult::Pending(td_pks);
226
227        let timeout_ev = Event::NextPressTimeout(0);
228        let key_ev = key::Event::Key {
229            keymap_index,
230            key_event: timeout_ev,
231        };
232        let pke = key::KeyEvents::scheduled_event(key::ScheduledEvent::after(
233            context.config.timeout,
234            key_ev,
235        ));
236
237        (pk, pke)
238    }
239
240    fn update_pending_state(
241        &self,
242        pending_state: &mut Self::PendingKeyState,
243        keymap_index: u16,
244        context: &Self::Context,
245        Ref(key_index): Ref,
246        event: key::Event<Self::Event>,
247    ) -> (Option<key::NewPressedKey<R>>, key::KeyEvents<Self::Event>) {
248        let key = &self.keys[key_index as usize];
249        let (maybe_resolution, pke) = pending_state.handle_event(context, keymap_index, event);
250
251        if let Some(TapDanceResolution(idx)) = maybe_resolution {
252            if let Some(new_key_ref) = key.definitions[idx as usize] {
253                (
254                    Some(key::NewPressedKey::key(new_key_ref)),
255                    pke.into_events(),
256                )
257            } else {
258                (None, pke.into_events())
259            }
260        } else {
261            // check pending_state press_count against key definitions
262            let definition_count = key.definitions.iter().filter(|o| o.is_some()).count();
263            if pending_state.press_count as usize >= definition_count - 1 {
264                let idx = definition_count - 1;
265                if let Some(new_key_ref) = key.definitions[idx] {
266                    (
267                        Some(key::NewPressedKey::key(new_key_ref)),
268                        pke.into_events(),
269                    )
270                } else {
271                    (None, pke.into_events())
272                }
273            } else {
274                (None, pke.into_events())
275            }
276        }
277    }
278
279    fn update_state(
280        &self,
281        _key_state: &mut Self::KeyState,
282        _ref: &Self::Ref,
283        _context: &Self::Context,
284        _keymap_index: u16,
285        _event: key::Event<Self::Event>,
286    ) -> key::KeyEvents<Self::Event> {
287        panic!() // tap dance has no key state
288    }
289
290    fn key_output(
291        &self,
292        _key_ref: &Self::Ref,
293        _key_state: &Self::KeyState,
294    ) -> Option<key::KeyOutput> {
295        panic!() // tap dance has no key state
296    }
297}
298
299#[cfg(test)]
300mod tests {
301    use super::*;
302
303    #[test]
304    fn test_sizeof_ref() {
305        assert_eq!(1, core::mem::size_of::<Ref>());
306    }
307
308    #[test]
309    fn test_sizeof_event() {
310        assert_eq!(1, core::mem::size_of::<Event>());
311    }
312}