Skip to main content

smart_keymap_core/key/
automation.rs

1use core::fmt::Debug;
2use core::ops::Index;
3
4use serde::Deserialize;
5
6use crate::input;
7use crate::key;
8
9const EXECUTION_QUEUE_SIZE: usize = 8;
10
11/// Reference for a automation key.
12#[derive(Deserialize, Debug, Clone, Copy, PartialEq)]
13pub struct Ref(pub u8);
14
15/// Value describing an automation key execution.
16#[derive(Deserialize, Debug, Clone, Copy, PartialEq)]
17pub struct Execution {
18    /// The start index into the instructions array.
19    pub start: u16,
20    /// The number of instructions to execute.
21    pub length: u16,
22}
23
24impl Execution {
25    /// An empty execution.
26    pub const EMPTY: Self = Self {
27        start: 0,
28        length: 0,
29    };
30
31    /// Returns true if the execution is empty (length == 0).
32    pub const fn is_empty(&self) -> bool {
33        self.length == 0
34    }
35
36    /// Increments the execution to the next instruction.
37    pub fn incr(&mut self) {
38        if self.length > 0 {
39            self.start += 1;
40            self.length -= 1;
41        }
42    }
43}
44
45/// Instructions for a automation key.
46#[derive(Deserialize, Debug, Clone, Copy, PartialEq)]
47pub struct KeyInstructions {
48    /// The automation instructions to execute when the key is pressed.
49    pub on_press: Execution,
50    /// The automation instructions to execute while the key is pressed.
51    pub while_pressed: Execution,
52    /// The automation instructions to execute when the key is released.
53    pub on_release: Execution,
54}
55
56/// Definition for a automation key.
57#[derive(Deserialize, Debug, Clone, Copy, PartialEq)]
58pub struct Key {
59    /// The automation instructions for the key.
60    pub automation_instructions: KeyInstructions,
61}
62
63/// An instruction for a automation key.
64#[derive(Deserialize, Debug, Default, Clone, Copy, PartialEq)]
65pub enum Instruction {
66    /// No operation.
67    #[default]
68    NoOp,
69    /// Press a key.
70    Press(key::KeyOutput),
71    /// Release a key.
72    Release(key::KeyOutput),
73    /// Taps a key.
74    Tap(key::KeyOutput),
75    /// Wait for a number of ticks.
76    Wait(u16),
77}
78
79/// Config for automation keys.
80#[derive(Deserialize, Clone, Copy, PartialEq)]
81pub struct Config<const INSTRUCTION_COUNT: usize> {
82    /// Concatenation of all the automation key instructions.
83    ///
84    /// Automation keys' instructions are defined by start+len into this array.
85    #[serde(deserialize_with = "deserialize_instructions")]
86    pub instructions: [Instruction; INSTRUCTION_COUNT],
87
88    /// Duration (in ticks) of each instruction.
89    #[serde(default = "default_instruction_duration")]
90    pub instruction_duration: u16,
91}
92
93struct InstructionsDebugHelper<'a, const INSTRUCTION_COUNT: usize> {
94    instructions: &'a [Instruction; INSTRUCTION_COUNT],
95}
96
97impl<'a, const INSTRUCTION_COUNT: usize> core::fmt::Debug
98    for InstructionsDebugHelper<'a, INSTRUCTION_COUNT>
99{
100    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
101        // Reverse-find the last non-NoOp instruction to avoid printing large arrays.
102        let last_non_noop_inst_pos = self
103            .instructions
104            .iter()
105            .rposition(|inst| *inst != Instruction::NoOp)
106            .map_or(0, |pos| pos + 1);
107        if last_non_noop_inst_pos < INSTRUCTION_COUNT {
108            f.debug_list()
109                .entries(&self.instructions[..last_non_noop_inst_pos])
110                .finish_non_exhaustive()
111        } else {
112            f.debug_list().entries(&self.instructions[..]).finish()
113        }
114    }
115}
116
117impl<const INSTRUCTION_COUNT: usize> core::fmt::Debug for Config<INSTRUCTION_COUNT> {
118    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
119        f.debug_struct("Config")
120            .field(
121                "instructions",
122                &InstructionsDebugHelper {
123                    instructions: &self.instructions,
124                },
125            )
126            .field("instruction_duration", &self.instruction_duration)
127            .finish()
128    }
129}
130
131/// Constructs an array of instructions for the given array.
132pub const fn instructions<const N: usize, const INSTRUCTION_COUNT: usize>(
133    instructions: [Instruction; N],
134) -> [Instruction; INSTRUCTION_COUNT] {
135    let mut cfg_instructions: [Instruction; INSTRUCTION_COUNT] =
136        [Instruction::NoOp; INSTRUCTION_COUNT];
137
138    if N > INSTRUCTION_COUNT {
139        panic!("Too many instructions for instructions array");
140    }
141
142    let mut i = 0;
143
144    while i < N {
145        cfg_instructions[i] = instructions[i];
146        i += 1;
147    }
148
149    cfg_instructions
150}
151
152/// Deserialize instructions.
153fn deserialize_instructions<'de, D, const INSTRUCTION_COUNT: usize>(
154    deserializer: D,
155) -> Result<[Instruction; INSTRUCTION_COUNT], D::Error>
156where
157    D: serde::Deserializer<'de>,
158{
159    let instructions_vec: heapless::Vec<Instruction, INSTRUCTION_COUNT> =
160        Deserialize::deserialize(deserializer)?;
161
162    let mut instructions_array: [Instruction; INSTRUCTION_COUNT] =
163        [Instruction::NoOp; INSTRUCTION_COUNT];
164    for (i, instruction) in instructions_vec.iter().enumerate() {
165        instructions_array[i] = *instruction;
166    }
167
168    Ok(instructions_array)
169}
170
171fn default_instruction_duration() -> u16 {
172    DEFAULT_INSTRUCTION_DURATION
173}
174
175/// The default instruction duration.
176pub const DEFAULT_INSTRUCTION_DURATION: u16 = 10;
177
178impl<const INSTRUCTION_COUNT: usize> Config<INSTRUCTION_COUNT> {
179    /// Constructs a new default [Config].
180    pub const fn new() -> Self {
181        Self {
182            instructions: [{ Instruction::NoOp }; INSTRUCTION_COUNT],
183            instruction_duration: DEFAULT_INSTRUCTION_DURATION,
184        }
185    }
186}
187
188impl<const INSTRUCTION_COUNT: usize> Default for Config<INSTRUCTION_COUNT> {
189    fn default() -> Self {
190        Self::new()
191    }
192}
193
194struct ExecutionsDebugHelper<'a> {
195    execution_queue: &'a [Execution; EXECUTION_QUEUE_SIZE],
196}
197
198impl core::fmt::Debug for ExecutionsDebugHelper<'_> {
199    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
200        // Reverse-find the last non-empty execution to avoid printing large arrays.
201        let last_non_empty_exec_pos = self
202            .execution_queue
203            .iter()
204            .rposition(|exec| !exec.is_empty())
205            .map_or(0, |pos| pos + 1);
206        if last_non_empty_exec_pos < EXECUTION_QUEUE_SIZE {
207            f.debug_list()
208                .entries(&self.execution_queue[..last_non_empty_exec_pos])
209                .finish_non_exhaustive()
210        } else {
211            f.debug_list().entries(&self.execution_queue[..]).finish()
212        }
213    }
214}
215
216/// Context for automation keys.
217#[derive(Clone, Copy, PartialEq)]
218pub struct Context<const INSTRUCTION_COUNT: usize> {
219    config: Config<INSTRUCTION_COUNT>,
220    execution_queue: [Execution; EXECUTION_QUEUE_SIZE],
221}
222
223impl<const INSTRUCTION_COUNT: usize> core::fmt::Debug for Context<INSTRUCTION_COUNT> {
224    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
225        f.debug_struct("Context")
226            .field("config", &self.config)
227            .field(
228                "execution_queue",
229                &ExecutionsDebugHelper {
230                    execution_queue: &self.execution_queue,
231                },
232            )
233            .finish()
234    }
235}
236
237impl<const INSTRUCTION_COUNT: usize> Context<INSTRUCTION_COUNT> {
238    /// Constructs a new [Context] with the given [Config].
239    pub const fn from_config(config: Config<INSTRUCTION_COUNT>) -> Self {
240        let execution_queue = [Execution::EMPTY; EXECUTION_QUEUE_SIZE];
241        Self {
242            config,
243            execution_queue,
244        }
245    }
246
247    /// Re-construct from context's [Config], clearing the execution queue.
248    pub fn reset(&mut self) {
249        *self = Self::from_config(self.config);
250    }
251
252    /// Enqueues a new execution onto the execution queue.
253    pub fn enqueue(&mut self, new_execution: Execution) -> usize {
254        // Ignore empty executions.
255        if new_execution.is_empty() {
256            return EXECUTION_QUEUE_SIZE;
257        }
258
259        for (i, exec) in self.execution_queue.iter_mut().enumerate() {
260            if exec.is_empty() {
261                *exec = new_execution;
262                return i;
263            }
264        }
265
266        // Queue is full, drop the new execution.
267        EXECUTION_QUEUE_SIZE
268    }
269
270    fn execute_head(&mut self, keymap_index: u16) -> key::KeyEvents<Event> {
271        let mut pke = key_events_for(self.config, keymap_index, self.execution_queue[0]);
272
273        self.execution_queue[0].incr();
274
275        if self.execution_queue[0].is_empty() {
276            self.execution_queue.rotate_left(1);
277            self.execution_queue[EXECUTION_QUEUE_SIZE - 1] = Execution::EMPTY;
278
279            // If there's more to execute, schedule it to execute.
280            if !self.execution_queue[0].is_empty() {
281                pke.schedule_event(
282                    self.config.instruction_duration,
283                    key::Event::Key {
284                        keymap_index,
285                        key_event: Event::NextInstruction,
286                    },
287                );
288            }
289        }
290
291        pke
292    }
293}
294
295impl<const INSTRUCTION_COUNT: usize> key::Context for Context<INSTRUCTION_COUNT> {
296    type Event = Event;
297
298    fn reset(&mut self) {
299        Context::reset(self);
300    }
301
302    fn handle_event(&mut self, event: key::Event<Self::Event>) -> key::KeyEvents<Self::Event> {
303        match event {
304            key::Event::Key {
305                key_event: Event::Enqueue(execution),
306                keymap_index,
307            } if !execution.is_empty() => {
308                let exec_immediately = self.execution_queue[0].is_empty();
309
310                self.enqueue(execution);
311
312                if exec_immediately {
313                    self.execute_head(keymap_index)
314                } else {
315                    key::KeyEvents::no_events()
316                }
317            }
318            key::Event::Key {
319                key_event: Event::NextInstruction,
320                keymap_index,
321            } => {
322                if !self.execution_queue[0].is_empty() {
323                    self.execute_head(keymap_index)
324                } else {
325                    key::KeyEvents::no_events()
326                }
327            }
328            _ => key::KeyEvents::no_events(),
329        }
330    }
331}
332
333/// The event type for automation keys.
334#[derive(Debug, Clone, Copy, PartialEq)]
335pub enum Event {
336    /// Enqueues an execution onto the Context's execution queue.
337    Enqueue(Execution),
338    /// Indicates to the context to execute the next instruction.
339    NextInstruction,
340    /// Indicates that the execution has finished.
341    ExecutionFinished,
342}
343
344/// Converts the instruction to a scheduled event, if applicable.
345pub fn key_events_for<const INSTRUCTION_COUNT: usize>(
346    config: Config<INSTRUCTION_COUNT>,
347    keymap_index: u16,
348    Execution { start, length }: Execution,
349) -> key::KeyEvents<Event> {
350    let instruction = config.instructions[start as usize];
351
352    let next_key_ev = if length > 1 {
353        key::Event::Key {
354            keymap_index,
355            key_event: Event::NextInstruction,
356        }
357    } else {
358        key::Event::Key {
359            keymap_index,
360            key_event: Event::ExecutionFinished,
361        }
362    };
363
364    match instruction {
365        Instruction::NoOp => {
366            let mut pke = key::KeyEvents::no_events();
367            pke.schedule_event(config.instruction_duration, next_key_ev);
368            pke
369        }
370        Instruction::Press(key_output) => {
371            let mut pke = key::KeyEvents::event(key::Event::Input(input::Event::VirtualKeyPress {
372                key_output,
373            }));
374            pke.schedule_event(config.instruction_duration, next_key_ev);
375            pke
376        }
377        Instruction::Release(key_output) => {
378            let mut pke =
379                key::KeyEvents::event(key::Event::Input(input::Event::VirtualKeyRelease {
380                    key_output,
381                }));
382            pke.schedule_event(config.instruction_duration, next_key_ev);
383            pke
384        }
385        Instruction::Tap(key_output) => {
386            let mut pke = key::KeyEvents::event(key::Event::Input(input::Event::VirtualKeyPress {
387                key_output,
388            }));
389            pke.schedule_event(
390                config.instruction_duration,
391                key::Event::Input(input::Event::VirtualKeyRelease { key_output }),
392            );
393            pke.schedule_event(config.instruction_duration, next_key_ev);
394            pke
395        }
396        Instruction::Wait(ticks) => {
397            let mut pke = key::KeyEvents::no_events();
398            pke.schedule_event(ticks, next_key_ev);
399            pke
400        }
401    }
402}
403
404/// The pending key state type for automation keys. (No pending state).
405#[derive(Debug, Clone, Copy, PartialEq)]
406pub struct PendingKeyState;
407
408/// Key state used by [System].
409#[derive(Debug, Clone, Copy, PartialEq)]
410pub struct KeyState;
411
412/// The [key::System] implementation for automation keys.
413#[derive(Debug, Clone, Copy, PartialEq)]
414pub struct System<R: Debug, Keys: Index<usize, Output = Key>, const INSTRUCTION_COUNT: usize> {
415    keys: Keys,
416    _marker: core::marker::PhantomData<(R, [(); INSTRUCTION_COUNT])>,
417}
418
419impl<R: Debug, Keys: Index<usize, Output = Key>, const INSTRUCTION_COUNT: usize>
420    System<R, Keys, INSTRUCTION_COUNT>
421{
422    /// Constructs a new [System].
423    pub const fn new(keys: Keys) -> Self {
424        Self {
425            keys,
426            _marker: core::marker::PhantomData,
427        }
428    }
429}
430
431impl<R: Copy + Debug, Keys: Debug + Index<usize, Output = Key>, const INSTRUCTION_COUNT: usize>
432    key::System<R> for System<R, Keys, INSTRUCTION_COUNT>
433{
434    type Ref = Ref;
435    type Context = Context<INSTRUCTION_COUNT>;
436    type Event = Event;
437    type PendingKeyState = PendingKeyState;
438    type KeyState = KeyState;
439
440    fn new_pressed_key(
441        &self,
442        keymap_index: u16,
443        _context: &Self::Context,
444        Ref(key_index): Ref,
445    ) -> (
446        key::PressedKeyResult<R, Self::PendingKeyState, Self::KeyState>,
447        key::KeyEvents<Self::Event>,
448    ) {
449        let pkr = key::PressedKeyResult::Resolved(KeyState);
450
451        let Key {
452            automation_instructions:
453                KeyInstructions {
454                    on_press: execution,
455                    ..
456                },
457        } = self.keys[key_index as usize];
458        let key_ev = key::Event::Key {
459            keymap_index,
460            key_event: if !execution.is_empty() {
461                Event::Enqueue(execution)
462            } else {
463                // Trigger "while_pressed"
464                Event::ExecutionFinished
465            },
466        };
467        let pke = key::KeyEvents::event(key_ev);
468
469        (pkr, pke)
470    }
471
472    fn update_pending_state(
473        &self,
474        _pending_state: &mut Self::PendingKeyState,
475        _keymap_index: u16,
476        _context: &Self::Context,
477        _key_ref: Ref,
478        _event: key::Event<Self::Event>,
479    ) -> (Option<key::NewPressedKey<R>>, key::KeyEvents<Self::Event>) {
480        panic!()
481    }
482
483    fn update_state(
484        &self,
485        _key_state: &mut Self::KeyState,
486        Ref(key_index): &Self::Ref,
487        _context: &Self::Context,
488        keymap_index: u16,
489        event: key::Event<Self::Event>,
490    ) -> key::KeyEvents<Self::Event> {
491        match event {
492            key::Event::Key {
493                key_event: Event::ExecutionFinished,
494                keymap_index: ev_kmi,
495            } if keymap_index == ev_kmi => {
496                // Execution finished while key is pressed;
497                //  enqueue the while_pressed instructions.
498                let Key {
499                    automation_instructions:
500                        KeyInstructions {
501                            while_pressed: execution,
502                            ..
503                        },
504                } = self.keys[*key_index as usize];
505                let key_ev = key::Event::Key {
506                    keymap_index,
507                    key_event: Event::Enqueue(execution),
508                };
509                key::KeyEvents::event(key_ev)
510            }
511            key::Event::Input(input::Event::Release {
512                keymap_index: ev_kmi,
513            }) if keymap_index == ev_kmi => {
514                // Key released.
515                //  enqueue the on_release instructions.
516                let Key {
517                    automation_instructions:
518                        KeyInstructions {
519                            on_release: execution,
520                            ..
521                        },
522                } = self.keys[*key_index as usize];
523                let key_ev = key::Event::Key {
524                    keymap_index,
525                    key_event: Event::Enqueue(execution),
526                };
527                key::KeyEvents::event(key_ev)
528            }
529            _ => key::KeyEvents::no_events(),
530        }
531    }
532
533    fn key_output(
534        &self,
535        _key_ref: &Self::Ref,
536        _key_state: &Self::KeyState,
537    ) -> Option<key::KeyOutput> {
538        None
539    }
540}
541
542#[cfg(test)]
543mod tests {
544    use super::*;
545
546    #[test]
547    fn test_sizeof_ref() {
548        assert_eq!(1, core::mem::size_of::<Ref>());
549    }
550
551    #[test]
552    fn test_sizeof_event() {
553        assert_eq!(6, core::mem::size_of::<Event>());
554    }
555}