smart_keymap/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    /// Enqueues a new execution onto the execution queue.
248    pub fn enqueue(&mut self, new_execution: Execution) -> usize {
249        // Ignore empty executions.
250        if new_execution.is_empty() {
251            return EXECUTION_QUEUE_SIZE;
252        }
253
254        for (i, exec) in self.execution_queue.iter_mut().enumerate() {
255            if exec.is_empty() {
256                *exec = new_execution;
257                return i;
258            }
259        }
260
261        // Queue is full, drop the new execution.
262        EXECUTION_QUEUE_SIZE
263    }
264
265    fn execute_head(&mut self, keymap_index: u16) -> key::KeyEvents<Event> {
266        let mut pke = key_events_for(self.config, keymap_index, self.execution_queue[0]);
267
268        self.execution_queue[0].incr();
269
270        if self.execution_queue[0].is_empty() {
271            self.execution_queue.rotate_left(1);
272            self.execution_queue[EXECUTION_QUEUE_SIZE - 1] = Execution::EMPTY;
273
274            // If there's more to execute, schedule it to execute.
275            if !self.execution_queue[0].is_empty() {
276                pke.add_event(key::ScheduledEvent::after(
277                    self.config.instruction_duration,
278                    key::Event::Key {
279                        keymap_index,
280                        key_event: Event::NextInstruction,
281                    },
282                ));
283            }
284        }
285
286        pke
287    }
288}
289
290impl<const INSTRUCTION_COUNT: usize> key::Context for Context<INSTRUCTION_COUNT> {
291    type Event = Event;
292
293    fn handle_event(&mut self, event: key::Event<Self::Event>) -> key::KeyEvents<Self::Event> {
294        match event {
295            key::Event::Key {
296                key_event: Event::Enqueue(execution),
297                keymap_index,
298            } if !execution.is_empty() => {
299                let exec_immediately = self.execution_queue[0].is_empty();
300
301                self.enqueue(execution);
302
303                if exec_immediately {
304                    self.execute_head(keymap_index)
305                } else {
306                    key::KeyEvents::no_events()
307                }
308            }
309            key::Event::Key {
310                key_event: Event::NextInstruction,
311                keymap_index,
312            } => {
313                if !self.execution_queue[0].is_empty() {
314                    self.execute_head(keymap_index)
315                } else {
316                    key::KeyEvents::no_events()
317                }
318            }
319            _ => key::KeyEvents::no_events(),
320        }
321    }
322}
323
324/// The event type for automation keys.
325#[derive(Debug, Clone, Copy, PartialEq)]
326pub enum Event {
327    /// Enqueues an execution onto the Context's execution queue.
328    Enqueue(Execution),
329    /// Indicates to the context to execute the next instruction.
330    NextInstruction,
331    /// Indicates that the execution has finished.
332    ExecutionFinished,
333}
334
335/// Converts the instruction to a scheduled event, if applicable.
336pub fn key_events_for<const INSTRUCTION_COUNT: usize>(
337    config: Config<INSTRUCTION_COUNT>,
338    keymap_index: u16,
339    Execution { start, length }: Execution,
340) -> key::KeyEvents<Event> {
341    let instruction = config.instructions[start as usize];
342
343    let next_key_ev = if length > 1 {
344        key::Event::Key {
345            keymap_index,
346            key_event: Event::NextInstruction,
347        }
348    } else {
349        key::Event::Key {
350            keymap_index,
351            key_event: Event::ExecutionFinished,
352        }
353    };
354
355    match instruction {
356        Instruction::NoOp => {
357            let sch_ev = key::ScheduledEvent::after(config.instruction_duration, next_key_ev);
358            key::KeyEvents::scheduled_event(sch_ev)
359        }
360        Instruction::Press(key_output) => {
361            let sch_ev =
362                key::ScheduledEvent::immediate(key::Event::Input(input::Event::VirtualKeyPress {
363                    key_output,
364                }));
365
366            let mut pke = key::KeyEvents::scheduled_event(sch_ev);
367            let sch_ev = key::ScheduledEvent::after(config.instruction_duration, next_key_ev);
368            pke.add_event(sch_ev);
369
370            pke
371        }
372        Instruction::Release(key_output) => {
373            let sch_ev = key::ScheduledEvent::immediate(key::Event::Input(
374                input::Event::VirtualKeyRelease { key_output },
375            ));
376
377            let mut pke = key::KeyEvents::scheduled_event(sch_ev);
378            let sch_ev = key::ScheduledEvent::after(config.instruction_duration, next_key_ev);
379            pke.add_event(sch_ev);
380
381            pke
382        }
383        Instruction::Tap(key_output) => {
384            let sch_press_ev =
385                key::ScheduledEvent::immediate(key::Event::Input(input::Event::VirtualKeyPress {
386                    key_output,
387                }));
388            let sch_release_ev = key::ScheduledEvent::after(
389                config.instruction_duration,
390                key::Event::Input(input::Event::VirtualKeyRelease { key_output }),
391            );
392
393            let mut pke = key::KeyEvents::scheduled_event(sch_press_ev);
394            pke.add_event(sch_release_ev);
395            let sch_ev = key::ScheduledEvent::after(config.instruction_duration, next_key_ev);
396            pke.add_event(sch_ev);
397
398            pke
399        }
400        Instruction::Wait(ticks) => {
401            let sch_ev = key::ScheduledEvent::after(ticks, next_key_ev);
402            key::KeyEvents::scheduled_event(sch_ev)
403        }
404    }
405}
406
407/// The pending key state type for automation keys. (No pending state).
408#[derive(Debug, Clone, Copy, PartialEq)]
409pub struct PendingKeyState;
410
411/// Key state used by [System].
412#[derive(Debug, Clone, Copy, PartialEq)]
413pub struct KeyState;
414
415/// The [key::System] implementation for automation keys.
416#[derive(Debug, Clone, Copy, PartialEq)]
417pub struct System<R: Debug, Keys: Index<usize, Output = Key>, const INSTRUCTION_COUNT: usize> {
418    keys: Keys,
419    _marker: core::marker::PhantomData<(R, [(); INSTRUCTION_COUNT])>,
420}
421
422impl<R: Debug, Keys: Index<usize, Output = Key>, const INSTRUCTION_COUNT: usize>
423    System<R, Keys, INSTRUCTION_COUNT>
424{
425    /// Constructs a new [System].
426    pub const fn new(keys: Keys) -> Self {
427        Self {
428            keys,
429            _marker: core::marker::PhantomData,
430        }
431    }
432}
433
434impl<R: Copy + Debug, Keys: Debug + Index<usize, Output = Key>, const INSTRUCTION_COUNT: usize>
435    key::System<R> for System<R, Keys, INSTRUCTION_COUNT>
436{
437    type Ref = Ref;
438    type Context = Context<INSTRUCTION_COUNT>;
439    type Event = Event;
440    type PendingKeyState = PendingKeyState;
441    type KeyState = KeyState;
442
443    fn new_pressed_key(
444        &self,
445        keymap_index: u16,
446        _context: &Self::Context,
447        Ref(key_index): Ref,
448    ) -> (
449        key::PressedKeyResult<R, Self::PendingKeyState, Self::KeyState>,
450        key::KeyEvents<Self::Event>,
451    ) {
452        let pkr = key::PressedKeyResult::Resolved(KeyState);
453
454        let Key {
455            automation_instructions:
456                KeyInstructions {
457                    on_press: execution,
458                    ..
459                },
460        } = self.keys[key_index as usize];
461        let key_ev = key::Event::Key {
462            keymap_index,
463            key_event: if !execution.is_empty() {
464                Event::Enqueue(execution)
465            } else {
466                // Trigger "while_pressed"
467                Event::ExecutionFinished
468            },
469        };
470        let pke = key::KeyEvents::event(key_ev);
471
472        (pkr, pke)
473    }
474
475    fn update_pending_state(
476        &self,
477        _pending_state: &mut Self::PendingKeyState,
478        _keymap_index: u16,
479        _context: &Self::Context,
480        _key_ref: Ref,
481        _event: key::Event<Self::Event>,
482    ) -> (Option<key::NewPressedKey<R>>, key::KeyEvents<Self::Event>) {
483        panic!()
484    }
485
486    fn update_state(
487        &self,
488        _key_state: &mut Self::KeyState,
489        Ref(key_index): &Self::Ref,
490        _context: &Self::Context,
491        keymap_index: u16,
492        event: key::Event<Self::Event>,
493    ) -> key::KeyEvents<Self::Event> {
494        match event {
495            key::Event::Key {
496                key_event: Event::ExecutionFinished,
497                keymap_index: ev_kmi,
498            } if keymap_index == ev_kmi => {
499                // Execution finished while key is pressed;
500                //  enqueue the while_pressed instructions.
501                let Key {
502                    automation_instructions:
503                        KeyInstructions {
504                            while_pressed: execution,
505                            ..
506                        },
507                } = self.keys[*key_index as usize];
508                let key_ev = key::Event::Key {
509                    keymap_index,
510                    key_event: Event::Enqueue(execution),
511                };
512                key::KeyEvents::event(key_ev)
513            }
514            key::Event::Input(input::Event::Release {
515                keymap_index: ev_kmi,
516            }) if keymap_index == ev_kmi => {
517                // Key released.
518                //  enqueue the on_release instructions.
519                let Key {
520                    automation_instructions:
521                        KeyInstructions {
522                            on_release: execution,
523                            ..
524                        },
525                } = self.keys[*key_index as usize];
526                let key_ev = key::Event::Key {
527                    keymap_index,
528                    key_event: Event::Enqueue(execution),
529                };
530                key::KeyEvents::event(key_ev)
531            }
532            _ => key::KeyEvents::no_events(),
533        }
534    }
535
536    fn key_output(
537        &self,
538        _key_ref: &Self::Ref,
539        _key_state: &Self::KeyState,
540    ) -> Option<key::KeyOutput> {
541        None
542    }
543}
544
545#[cfg(test)]
546mod tests {
547    use super::*;
548
549    #[test]
550    fn test_sizeof_ref() {
551        assert_eq!(1, core::mem::size_of::<Ref>());
552    }
553
554    #[test]
555    fn test_sizeof_event() {
556        assert_eq!(6, core::mem::size_of::<Event>());
557    }
558}