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.add_event(key::ScheduledEvent::after(
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 sch_ev = key::ScheduledEvent::after(config.instruction_duration, next_key_ev);
367            key::KeyEvents::scheduled_event(sch_ev)
368        }
369        Instruction::Press(key_output) => {
370            let sch_ev =
371                key::ScheduledEvent::immediate(key::Event::Input(input::Event::VirtualKeyPress {
372                    key_output,
373                }));
374
375            let mut pke = key::KeyEvents::scheduled_event(sch_ev);
376            let sch_ev = key::ScheduledEvent::after(config.instruction_duration, next_key_ev);
377            pke.add_event(sch_ev);
378
379            pke
380        }
381        Instruction::Release(key_output) => {
382            let sch_ev = key::ScheduledEvent::immediate(key::Event::Input(
383                input::Event::VirtualKeyRelease { key_output },
384            ));
385
386            let mut pke = key::KeyEvents::scheduled_event(sch_ev);
387            let sch_ev = key::ScheduledEvent::after(config.instruction_duration, next_key_ev);
388            pke.add_event(sch_ev);
389
390            pke
391        }
392        Instruction::Tap(key_output) => {
393            let sch_press_ev =
394                key::ScheduledEvent::immediate(key::Event::Input(input::Event::VirtualKeyPress {
395                    key_output,
396                }));
397            let sch_release_ev = key::ScheduledEvent::after(
398                config.instruction_duration,
399                key::Event::Input(input::Event::VirtualKeyRelease { key_output }),
400            );
401
402            let mut pke = key::KeyEvents::scheduled_event(sch_press_ev);
403            pke.add_event(sch_release_ev);
404            let sch_ev = key::ScheduledEvent::after(config.instruction_duration, next_key_ev);
405            pke.add_event(sch_ev);
406
407            pke
408        }
409        Instruction::Wait(ticks) => {
410            let sch_ev = key::ScheduledEvent::after(ticks, next_key_ev);
411            key::KeyEvents::scheduled_event(sch_ev)
412        }
413    }
414}
415
416/// The pending key state type for automation keys. (No pending state).
417#[derive(Debug, Clone, Copy, PartialEq)]
418pub struct PendingKeyState;
419
420/// Key state used by [System].
421#[derive(Debug, Clone, Copy, PartialEq)]
422pub struct KeyState;
423
424/// The [key::System] implementation for automation keys.
425#[derive(Debug, Clone, Copy, PartialEq)]
426pub struct System<R: Debug, Keys: Index<usize, Output = Key>, const INSTRUCTION_COUNT: usize> {
427    keys: Keys,
428    _marker: core::marker::PhantomData<(R, [(); INSTRUCTION_COUNT])>,
429}
430
431impl<R: Debug, Keys: Index<usize, Output = Key>, const INSTRUCTION_COUNT: usize>
432    System<R, Keys, INSTRUCTION_COUNT>
433{
434    /// Constructs a new [System].
435    pub const fn new(keys: Keys) -> Self {
436        Self {
437            keys,
438            _marker: core::marker::PhantomData,
439        }
440    }
441}
442
443impl<R: Copy + Debug, Keys: Debug + Index<usize, Output = Key>, const INSTRUCTION_COUNT: usize>
444    key::System<R> for System<R, Keys, INSTRUCTION_COUNT>
445{
446    type Ref = Ref;
447    type Context = Context<INSTRUCTION_COUNT>;
448    type Event = Event;
449    type PendingKeyState = PendingKeyState;
450    type KeyState = KeyState;
451
452    fn new_pressed_key(
453        &self,
454        keymap_index: u16,
455        _context: &Self::Context,
456        Ref(key_index): Ref,
457    ) -> (
458        key::PressedKeyResult<R, Self::PendingKeyState, Self::KeyState>,
459        key::KeyEvents<Self::Event>,
460    ) {
461        let pkr = key::PressedKeyResult::Resolved(KeyState);
462
463        let Key {
464            automation_instructions:
465                KeyInstructions {
466                    on_press: execution,
467                    ..
468                },
469        } = self.keys[key_index as usize];
470        let key_ev = key::Event::Key {
471            keymap_index,
472            key_event: if !execution.is_empty() {
473                Event::Enqueue(execution)
474            } else {
475                // Trigger "while_pressed"
476                Event::ExecutionFinished
477            },
478        };
479        let pke = key::KeyEvents::event(key_ev);
480
481        (pkr, pke)
482    }
483
484    fn update_pending_state(
485        &self,
486        _pending_state: &mut Self::PendingKeyState,
487        _keymap_index: u16,
488        _context: &Self::Context,
489        _key_ref: Ref,
490        _event: key::Event<Self::Event>,
491    ) -> (Option<key::NewPressedKey<R>>, key::KeyEvents<Self::Event>) {
492        panic!()
493    }
494
495    fn update_state(
496        &self,
497        _key_state: &mut Self::KeyState,
498        Ref(key_index): &Self::Ref,
499        _context: &Self::Context,
500        keymap_index: u16,
501        event: key::Event<Self::Event>,
502    ) -> key::KeyEvents<Self::Event> {
503        match event {
504            key::Event::Key {
505                key_event: Event::ExecutionFinished,
506                keymap_index: ev_kmi,
507            } if keymap_index == ev_kmi => {
508                // Execution finished while key is pressed;
509                //  enqueue the while_pressed instructions.
510                let Key {
511                    automation_instructions:
512                        KeyInstructions {
513                            while_pressed: execution,
514                            ..
515                        },
516                } = self.keys[*key_index as usize];
517                let key_ev = key::Event::Key {
518                    keymap_index,
519                    key_event: Event::Enqueue(execution),
520                };
521                key::KeyEvents::event(key_ev)
522            }
523            key::Event::Input(input::Event::Release {
524                keymap_index: ev_kmi,
525            }) if keymap_index == ev_kmi => {
526                // Key released.
527                //  enqueue the on_release instructions.
528                let Key {
529                    automation_instructions:
530                        KeyInstructions {
531                            on_release: execution,
532                            ..
533                        },
534                } = self.keys[*key_index as usize];
535                let key_ev = key::Event::Key {
536                    keymap_index,
537                    key_event: Event::Enqueue(execution),
538                };
539                key::KeyEvents::event(key_ev)
540            }
541            _ => key::KeyEvents::no_events(),
542        }
543    }
544
545    fn key_output(
546        &self,
547        _key_ref: &Self::Ref,
548        _key_state: &Self::KeyState,
549    ) -> Option<key::KeyOutput> {
550        None
551    }
552}
553
554#[cfg(test)]
555mod tests {
556    use super::*;
557
558    #[test]
559    fn test_sizeof_ref() {
560        assert_eq!(1, core::mem::size_of::<Ref>());
561    }
562
563    #[test]
564    fn test_sizeof_event() {
565        assert_eq!(6, core::mem::size_of::<Event>());
566    }
567}