smart_keymap/
keymap.rs

1#[cfg(feature = "std")]
2mod distinct_reports;
3mod event_scheduler;
4/// The HID keyboard reporter.
5pub mod hid_keyboard_reporter;
6#[cfg(feature = "std")]
7mod observed_eb_keymap;
8#[cfg(feature = "std")]
9mod observed_keymap;
10
11use core::cmp::PartialEq;
12use core::fmt::Debug;
13use core::marker::Copy;
14use core::ops::Index;
15
16use serde::Deserialize;
17
18use crate::input;
19use crate::key;
20
21use key::Event;
22
23#[cfg(feature = "std")]
24pub use distinct_reports::DistinctReports;
25use event_scheduler::EventScheduler;
26use hid_keyboard_reporter::HIDKeyboardReporter;
27#[cfg(feature = "std")]
28pub use observed_eb_keymap::ObservedKeymap as ObservedEventBasedKeymap;
29#[cfg(feature = "std")]
30pub use observed_keymap::ObservedKeymap;
31
32/// Maximum number of pressed keys supported.
33pub const MAX_PRESSED_KEYS: usize = 16;
34
35const MAX_QUEUED_INPUT_EVENTS: usize = 32;
36
37/// Number of ticks before the next input event is processed in tick().
38pub const INPUT_QUEUE_TICK_DELAY: u8 = 1;
39
40/// Constructs an HID report or a sequence of key codes from the given sequence of [key::KeyOutput].
41#[derive(Debug, PartialEq)]
42pub struct KeymapOutput {
43    pressed_key_codes: heapless::Vec<key::KeyOutput, { MAX_PRESSED_KEYS }>,
44}
45
46impl Default for KeymapOutput {
47    fn default() -> Self {
48        Self {
49            pressed_key_codes: heapless::Vec::new(),
50        }
51    }
52}
53
54impl KeymapOutput {
55    /// Constructs a new keymap output.
56    pub fn new(pressed_key_codes: heapless::Vec<key::KeyOutput, { MAX_PRESSED_KEYS }>) -> Self {
57        Self { pressed_key_codes }
58    }
59
60    /// Returns the pressed key codes.
61    pub fn pressed_key_codes(&self) -> heapless::Vec<u8, 24> {
62        let mut result = heapless::Vec::new();
63
64        let modifiers = self
65            .pressed_key_codes
66            .iter()
67            .fold(key::KeyboardModifiers::new(), |acc, &ko| {
68                acc.union(&ko.key_modifiers())
69            });
70
71        result.extend(modifiers.as_key_codes());
72
73        result.extend(
74            self.pressed_key_codes
75                .iter()
76                .flat_map(|ko| match ko.key_code() {
77                    key::KeyUsage::Keyboard(kc) => Some(kc),
78                    _ => None,
79                }),
80        );
81
82        result
83    }
84
85    /// Returns the current HID keyboard report.
86    pub fn as_hid_boot_keyboard_report(&self) -> [u8; 8] {
87        let mut report = [0u8; 8];
88
89        let modifiers = self
90            .pressed_key_codes
91            .iter()
92            .fold(key::KeyboardModifiers::new(), |acc, &ko| {
93                acc.union(&ko.key_modifiers())
94            });
95
96        report[0] = modifiers.as_byte();
97
98        let key_codes = self
99            .pressed_key_codes
100            .iter()
101            .flat_map(|ko| match ko.key_code() {
102                key::KeyUsage::Keyboard(kc) => Some(kc),
103                _ => None,
104            })
105            .filter(|&kc| kc != 0);
106
107        for (i, key_code) in key_codes.take(6).enumerate() {
108            report[i + 2] = key_code;
109        }
110
111        report
112    }
113
114    /// Returns the pressed consumer codes.
115    pub fn pressed_consumer_codes(&self) -> heapless::Vec<u8, 24> {
116        self.pressed_key_codes
117            .iter()
118            .flat_map(|ko| match ko.key_code() {
119                key::KeyUsage::Consumer(uc) => Some(uc),
120                _ => None,
121            })
122            .collect()
123    }
124
125    /// Returns the pressed custom codes.
126    pub fn pressed_custom_codes(&self) -> heapless::Vec<u8, 24> {
127        self.pressed_key_codes
128            .iter()
129            .flat_map(|ko| match ko.key_code() {
130                key::KeyUsage::Custom(kc) => Some(kc),
131                _ => None,
132            })
133            .collect()
134    }
135
136    /// Returns the combined pressed mouse output.
137    pub fn pressed_mouse_output(&self) -> key::MouseOutput {
138        self.pressed_key_codes
139            .iter()
140            .filter_map(|ko| match ko.key_code() {
141                key::KeyUsage::Mouse(mo) => Some(mo),
142                _ => None,
143            })
144            .fold(key::MouseOutput::NO_OUTPUT, |acc, mo| acc.combine(&mo))
145    }
146}
147
148#[derive(Debug)]
149struct PendingState<R, Ev, PKS> {
150    keymap_index: u16,
151    key_ref: R,
152    pending_key_state: PKS,
153    queued_events: heapless::Vec<key::Event<Ev>, { MAX_PRESSED_KEYS }>,
154}
155
156/// Commands for managing Bluetooth profiles. (BLE pairing and bonding).
157#[derive(Deserialize, Debug, Clone, Copy, Eq, PartialEq)]
158pub enum BluetoothProfileCommand {
159    /// Disconnect the current profile.
160    Disconnect,
161    /// Clear the current profile. (Start pairing mode).
162    Clear,
163    /// Clear all profiles. (Start pairing mode).
164    ClearAll,
165    /// Switch to the previous profile.
166    Previous,
167    /// Switch to the next profile.
168    Next,
169    /// Switch to the given profile index.
170    Select(u8),
171}
172
173/// Callbacks for effect keys in the keymap.
174#[derive(Deserialize, Debug, Clone, Copy, Eq, PartialEq)]
175pub enum KeymapCallback {
176    /// Reset the keyboard
177    Reset,
178    /// Reset the keyboard to bootloader
179    ResetToBootloader,
180    /// Reset the keyboard to bootloader
181    Bluetooth(BluetoothProfileCommand),
182    /// A custom callback. Its behaviour is specific to the firmware implementation.
183    Custom(u8, u8),
184}
185
186/// Context provided from the keymap to the smart keys.
187#[derive(Debug, Clone, Copy)]
188pub struct KeymapContext {
189    /// Number of milliseconds since keymap has been initialized.
190    pub time_ms: u32,
191
192    /// Number of milliseconds since keymap received an input event.
193    pub idle_time_ms: u32,
194}
195
196impl KeymapContext {
197    /// Constructs a new default keymap context.
198    pub const fn new() -> Self {
199        KeymapContext {
200            time_ms: 0,
201            idle_time_ms: 0,
202        }
203    }
204}
205
206/// Trait for setting the keymap context.
207pub trait SetKeymapContext {
208    /// Sets the keymap context.
209    fn set_keymap_context(&mut self, context: KeymapContext);
210}
211
212/// Events related to the keymap.
213#[derive(Debug, Clone, Copy, PartialEq, Eq)]
214pub enum KeymapEvent {
215    /// Callback event (emitted by callback key).
216    Callback(KeymapCallback),
217    /// A pressed key resolved to a state with this key output.
218    ResolvedKeyOutput {
219        /// The keymap index of the key which resolved to the output.
220        keymap_index: u16,
221        /// The resolved key output.
222        key_output: key::KeyOutput,
223    },
224}
225
226#[derive(Debug)]
227enum CallbackFunction {
228    /// C callback
229    ExternC(extern "C" fn() -> ()),
230    /// Rust callback
231    Rust(fn() -> ()),
232}
233
234/// State for a keymap that handles input, and outputs HID keyboard reports.
235pub struct Keymap<I: Index<usize, Output = R>, R, Ctx, Ev: Debug, PKS, KS, S> {
236    key_refs: I,
237    key_system: S,
238    context: Ctx,
239    pressed_inputs: heapless::Vec<input::PressedInput<R, KS>, { MAX_PRESSED_KEYS }>,
240    event_scheduler: EventScheduler<Ev>,
241    ms_per_tick: u8,
242    idle_time: u32,
243    hid_reporter: HIDKeyboardReporter,
244    pending_key_state: Option<PendingState<R, Ev, PKS>>,
245    input_queue: heapless::spsc::Queue<input::Event, { MAX_QUEUED_INPUT_EVENTS }>,
246    input_queue_delay_counter: u8,
247    callbacks: heapless::LinearMap<KeymapCallback, CallbackFunction, 2>,
248}
249
250impl<
251        I: Debug + Index<usize, Output = R>,
252        R: Debug,
253        Ctx: Debug,
254        Ev: Debug,
255        PKS: Debug,
256        KS: Debug,
257        S: Debug,
258    > core::fmt::Debug for Keymap<I, R, Ctx, Ev, PKS, KS, S>
259{
260    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
261        f.debug_struct("Keymap")
262            .field("context", &self.context)
263            .field("event_scheduler", &self.event_scheduler)
264            .field("ms_per_tick", &self.ms_per_tick)
265            .field("idle_time", &self.idle_time)
266            .field("hid_reporter", &self.hid_reporter)
267            .field("input_queue", &self.input_queue)
268            .field("input_queue_delay_counter", &self.input_queue_delay_counter)
269            .field("pending_key_state", &self.pending_key_state)
270            .field("pressed_inputs", &self.pressed_inputs)
271            .finish_non_exhaustive()
272    }
273}
274
275impl<
276        I: Debug + Index<usize, Output = R>,
277        R: Copy + Debug,
278        Ctx: Debug + key::Context<Event = Ev> + SetKeymapContext,
279        Ev: Copy + Debug,
280        PKS: Debug,
281        KS: Copy + Debug + From<key::NoOpKeyState>,
282        S: key::System<R, Ref = R, Context = Ctx, Event = Ev, PendingKeyState = PKS, KeyState = KS>,
283    > Keymap<I, R, Ctx, Ev, PKS, KS, S>
284{
285    /// Constructs a new keymap with the given key definitions and context.
286    pub const fn new(key_refs: I, context: Ctx, key_system: S) -> Self {
287        Self {
288            key_refs,
289            key_system,
290            context,
291            pressed_inputs: heapless::Vec::new(),
292            event_scheduler: EventScheduler::new(),
293            ms_per_tick: 1,
294            idle_time: 0,
295            hid_reporter: HIDKeyboardReporter::new(),
296            pending_key_state: None,
297            input_queue: heapless::spsc::Queue::new(),
298            input_queue_delay_counter: 0,
299            callbacks: heapless::LinearMap::new(),
300        }
301    }
302
303    /// Initializes or resets the keyboard to an initial state.
304    pub fn init(&mut self) {
305        self.pressed_inputs.clear();
306        self.event_scheduler.init();
307        self.hid_reporter.init();
308        self.pending_key_state = None;
309        while !self.input_queue.is_empty() {
310            self.input_queue.dequeue().unwrap();
311        }
312        self.input_queue_delay_counter = 0;
313        self.ms_per_tick = 1;
314        self.idle_time = 0;
315    }
316
317    /// Registers the given callback to the keymap.
318    ///
319    /// Only one callback is set for each callback id.
320    pub fn set_callback(&mut self, callback_id: KeymapCallback, callback_fn: fn() -> ()) {
321        self.callbacks
322            .insert(callback_id, CallbackFunction::Rust(callback_fn))
323            .unwrap();
324    }
325
326    /// Registers the given callback to the keymap.
327    ///
328    /// Only one callback is set for each callback id.
329    pub fn set_callback_extern(
330        &mut self,
331        callback_id: KeymapCallback,
332        callback_fn: extern "C" fn() -> (),
333    ) {
334        self.callbacks
335            .insert(callback_id, CallbackFunction::ExternC(callback_fn))
336            .unwrap();
337    }
338
339    /// Sets the number of ms per tick().
340    pub fn set_ms_per_tick(&mut self, ms_per_tick: u8) {
341        self.ms_per_tick = ms_per_tick;
342    }
343
344    // If the pending key state is resolved,
345    //  then clear the pending key state.
346    fn resolve_pending_key_state(&mut self, key_state: KS) {
347        if let Some(PendingState {
348            keymap_index,
349            key_ref,
350            queued_events,
351            ..
352        }) = self.pending_key_state.take()
353        {
354            // Cancel events which were scheduled for the (pending) key.
355            self.event_scheduler
356                .cancel_events_for_keymap_index(keymap_index);
357
358            // Add the pending state's pressed key to pressed inputs
359            self.pressed_inputs
360                .push(input::PressedInput::pressed_key(
361                    keymap_index,
362                    key_ref,
363                    key_state,
364                ))
365                .unwrap();
366
367            // Schedule each of the queued events,
368            //  delaying each consecutive event by a tick
369            //  (in order to allow press/release events to affect the HID report)
370            let mut i = 1;
371            let mut old_input_queue: heapless::spsc::Queue<input::Event, MAX_QUEUED_INPUT_EVENTS> =
372                core::mem::take(&mut self.input_queue);
373
374            // Partition the events from the pending keymap index
375            //  separately from the other queued events.
376            // (Only queue the *last* event from the pending keymap index).
377            let (pending_input_ev, queued_events): (
378                heapless::Vec<key::Event<Ev>, { MAX_PRESSED_KEYS }>,
379                heapless::Vec<key::Event<Ev>, { MAX_PRESSED_KEYS }>,
380            ) = queued_events.iter().partition(|ev| match ev {
381                key::Event::Input(input::Event::Press {
382                    keymap_index: queued_kmi,
383                }) => *queued_kmi == keymap_index,
384                key::Event::Input(input::Event::Release {
385                    keymap_index: queued_kmi,
386                }) => *queued_kmi == keymap_index,
387                key::Event::Key {
388                    keymap_index: queued_kmi,
389                    ..
390                } => *queued_kmi == keymap_index,
391                _ => false,
392            });
393
394            for ev in queued_events.iter().chain(pending_input_ev.last()) {
395                match ev {
396                    key::Event::Input(ie) => {
397                        self.input_queue.enqueue(*ie).unwrap();
398                    }
399                    _ => {
400                        self.event_scheduler.schedule_after(i, *ev);
401                        i += 1;
402                    }
403                }
404            }
405
406            while let Some(ie) = old_input_queue.dequeue() {
407                self.input_queue.enqueue(ie).unwrap();
408            }
409
410            self.handle_pending_events();
411
412            // The resolved key state has output. Emit this as an event.
413            if let Some(key_output) = self.key_system.key_output(&key_ref, &key_state) {
414                let km_ev = KeymapEvent::ResolvedKeyOutput {
415                    keymap_index,
416                    key_output,
417                };
418                self.handle_event(key::Event::Keymap(km_ev));
419            }
420        }
421    }
422
423    /// Handles input events.
424    ///
425    /// Discards the input event if the input queue is full.
426    pub fn handle_input(&mut self, ev: input::Event) {
427        self.idle_time = 0;
428
429        if self.input_queue.is_full() {
430            return;
431        }
432
433        self.input_queue.enqueue(ev).unwrap();
434
435        if self.input_queue_delay_counter == 0 {
436            let ie = self.input_queue.dequeue().unwrap();
437            self.process_input(ie);
438            self.input_queue_delay_counter = INPUT_QUEUE_TICK_DELAY;
439        }
440    }
441
442    fn has_pressed_input_with_keymap_index(&self, keymap_index: u16) -> bool {
443        self.pressed_inputs.iter().any(|pi| match pi {
444            &input::PressedInput::Key(input::PressedKey {
445                keymap_index: ki, ..
446            }) => keymap_index == ki,
447            _ => false,
448        })
449    }
450
451    fn update_pending_state(&mut self, ev: key::Event<Ev>) {
452        if let Some(PendingState {
453            keymap_index,
454            key_ref,
455            pending_key_state,
456            queued_events,
457            ..
458        }) = &mut self.pending_key_state
459        {
460            let (mut maybe_npk, pke) = self.key_system.update_pending_state(
461                pending_key_state,
462                *keymap_index,
463                &self.context,
464                *key_ref,
465                ev,
466            );
467
468            pke.into_iter()
469                .for_each(|sch_ev| self.event_scheduler.schedule_event(sch_ev));
470
471            while let Some(npk) = maybe_npk.take() {
472                let pkr = match npk {
473                    key::NewPressedKey::Key(new_key_ref) => {
474                        *key_ref = new_key_ref;
475                        let (pkr, pke) = self.key_system.new_pressed_key(
476                            *keymap_index,
477                            &self.context,
478                            new_key_ref,
479                        );
480                        pke.into_iter()
481                            .for_each(|sch_ev| self.event_scheduler.schedule_event(sch_ev));
482                        pkr
483                    }
484                    key::NewPressedKey::NoOp => {
485                        let no_op_ks: KS = key::NoOpKeyState.into();
486                        key::PressedKeyResult::Resolved(no_op_ks)
487                    }
488                };
489
490                match pkr {
491                    key::PressedKeyResult::Resolved(ks) => {
492                        self.resolve_pending_key_state(ks);
493                        break;
494                    }
495                    key::PressedKeyResult::NewPressedKey(key::NewPressedKey::Key(new_key_ref)) => {
496                        maybe_npk = Some(key::NewPressedKey::Key(new_key_ref));
497                    }
498                    key::PressedKeyResult::NewPressedKey(key::NewPressedKey::NoOp) => {
499                        self.resolve_pending_key_state(key::NoOpKeyState.into());
500                        break;
501                    }
502                    key::PressedKeyResult::Pending(pks) => {
503                        *pending_key_state = pks;
504
505                        // Since the pending key state resolved into another pending key state,
506                        //  we re-queue all the input events that had been received.
507                        let orig_input_queue = core::mem::take(&mut self.input_queue);
508                        while let Some(ev) = queued_events.pop() {
509                            if let key::Event::Input(input_ev) = ev {
510                                self.input_queue.enqueue(input_ev).unwrap();
511                            }
512                        }
513                        orig_input_queue.iter().for_each(|&ev| {
514                            self.input_queue.enqueue(ev).unwrap();
515                        });
516                    }
517                }
518            }
519        }
520    }
521
522    fn process_input(&mut self, ev: input::Event) {
523        if let Some(pending_state) = &mut self.pending_key_state {
524            pending_state.queued_events.push(ev.into()).unwrap();
525            self.update_pending_state(ev.into());
526        } else {
527            // Update each of the pressed keys with the event.
528            self.pressed_inputs.iter_mut().for_each(|pi| {
529                if let input::PressedInput::Key(input::PressedKey {
530                    key_ref,
531                    key_state,
532                    keymap_index,
533                }) = pi
534                {
535                    self.key_system
536                        .update_state(key_state, key_ref, &self.context, *keymap_index, ev.into())
537                        .into_iter()
538                        .for_each(|sch_ev| self.event_scheduler.schedule_event(sch_ev));
539                }
540            });
541
542            self.context
543                .handle_event(ev.into())
544                .into_iter()
545                .for_each(|sch_ev| self.event_scheduler.schedule_event(sch_ev));
546
547            match ev {
548                input::Event::Press { keymap_index }
549                    if !self.has_pressed_input_with_keymap_index(keymap_index) =>
550                {
551                    let mut maybe_key_ref = Some(self.key_refs[keymap_index as usize]);
552
553                    while let Some(key_ref) = maybe_key_ref.take() {
554                        let (pkr, pke) =
555                            self.key_system
556                                .new_pressed_key(keymap_index, &self.context, key_ref);
557
558                        pke.into_iter()
559                            .for_each(|sch_ev| self.event_scheduler.schedule_event(sch_ev));
560
561                        match pkr {
562                            key::PressedKeyResult::Resolved(key_state) => {
563                                self.pressed_inputs
564                                    .push(input::PressedInput::pressed_key(
565                                        keymap_index,
566                                        key_ref,
567                                        key_state,
568                                    ))
569                                    .unwrap();
570
571                                // The resolved key state has output. Emit this as an event.
572                                if let Some(key_output) =
573                                    self.key_system.key_output(&key_ref, &key_state)
574                                {
575                                    let km_ev = KeymapEvent::ResolvedKeyOutput {
576                                        keymap_index,
577                                        key_output,
578                                    };
579                                    self.handle_event(key::Event::Keymap(km_ev));
580                                }
581                            }
582                            key::PressedKeyResult::NewPressedKey(key::NewPressedKey::Key(
583                                new_key_ref,
584                            )) => {
585                                maybe_key_ref = Some(new_key_ref);
586                            }
587                            key::PressedKeyResult::NewPressedKey(key::NewPressedKey::NoOp) => {
588                                let key_state: KS = key::NoOpKeyState.into();
589
590                                self.pressed_inputs
591                                    .push(input::PressedInput::pressed_key(
592                                        keymap_index,
593                                        key_ref,
594                                        key_state,
595                                    ))
596                                    .unwrap();
597                            }
598                            key::PressedKeyResult::Pending(pending_key_state) => {
599                                self.pending_key_state = Some(PendingState {
600                                    keymap_index,
601                                    key_ref,
602                                    pending_key_state,
603                                    queued_events: heapless::Vec::new(),
604                                });
605                            }
606                        }
607                    }
608                }
609                input::Event::Release { keymap_index } => {
610                    self.pressed_inputs
611                        .iter()
612                        .position(|pi| match pi {
613                            &input::PressedInput::Key(input::PressedKey {
614                                keymap_index: ki,
615                                ..
616                            }) => keymap_index == ki,
617                            _ => false,
618                        })
619                        .map(|i| self.pressed_inputs.remove(i));
620                }
621
622                input::Event::VirtualKeyPress { key_output } => {
623                    let pressed_key = input::PressedInput::Virtual(key_output);
624                    self.pressed_inputs.push(pressed_key).unwrap();
625                }
626                input::Event::VirtualKeyRelease { key_output } => {
627                    // Remove from pressed keys.
628                    self.pressed_inputs
629                        .iter()
630                        .position(|k| match k {
631                            input::PressedInput::Virtual(ko) => key_output == *ko,
632                            _ => false,
633                        })
634                        .map(|i| self.pressed_inputs.remove(i));
635                }
636
637                _ => {}
638            }
639        }
640
641        self.handle_pending_events();
642    }
643
644    // Called from handle_all_pending_events,
645    //  and for handling the (resolving) queue of events from pending key state.
646    fn handle_event(&mut self, ev: key::Event<Ev>) {
647        if let key::Event::Keymap(KeymapEvent::Callback(callback_id)) = ev {
648            match self.callbacks.get(&callback_id) {
649                Some(CallbackFunction::Rust(callback_fn)) => {
650                    callback_fn();
651                }
652                Some(CallbackFunction::ExternC(callback_fn)) => {
653                    callback_fn();
654                }
655                None => {}
656            }
657        }
658
659        // pending state needs to handle events
660        self.update_pending_state(ev);
661
662        // Update each of the pressed keys with the event.
663        self.pressed_inputs.iter_mut().for_each(|pi| {
664            if let input::PressedInput::Key(input::PressedKey {
665                key_state,
666                key_ref,
667                keymap_index,
668            }) = pi
669            {
670                self.key_system
671                    .update_state(key_state, key_ref, &self.context, *keymap_index, ev)
672                    .into_iter()
673                    .for_each(|sch_ev| self.event_scheduler.schedule_event(sch_ev));
674            }
675        });
676
677        // Update context with the event
678        self.context
679            .handle_event(ev)
680            .into_iter()
681            .for_each(|sch_ev| self.event_scheduler.schedule_event(sch_ev));
682
683        if let Event::Input(input_ev) = ev {
684            self.process_input(input_ev);
685        }
686    }
687
688    fn handle_pending_events(&mut self) {
689        // take from pending
690        while let Some(ev) = self.event_scheduler.dequeue() {
691            self.handle_event(ev);
692        }
693    }
694
695    /// Advances the state of the keymap by one tick.
696    pub fn tick(&mut self) {
697        let km_context = KeymapContext {
698            time_ms: self.event_scheduler.schedule_counter,
699            idle_time_ms: self.idle_time,
700        };
701        self.context.set_keymap_context(km_context);
702
703        if !self.input_queue.is_empty() && self.input_queue_delay_counter == 0 {
704            let ie = self.input_queue.dequeue().unwrap();
705            self.process_input(ie);
706            self.input_queue_delay_counter = INPUT_QUEUE_TICK_DELAY;
707        }
708
709        if self.input_queue_delay_counter > 0 {
710            self.input_queue_delay_counter -= 1;
711        }
712
713        self.event_scheduler.tick(self.ms_per_tick);
714
715        self.handle_pending_events();
716
717        self.idle_time += self.ms_per_tick as u32;
718    }
719
720    /// Returns the the pressed key outputs.
721    pub fn pressed_keys(&self) -> heapless::Vec<key::KeyOutput, { MAX_PRESSED_KEYS }> {
722        let pressed_key_codes = self.pressed_inputs.iter().filter_map(|pi| match pi {
723            input::PressedInput::Key(input::PressedKey {
724                key_ref, key_state, ..
725            }) => self.key_system.key_output(key_ref, key_state),
726            &input::PressedInput::Virtual(key_output) => Some(key_output),
727        });
728
729        pressed_key_codes.collect()
730    }
731
732    fn tick_by(&mut self, delta_ms: u32) {
733        if delta_ms == 0 {
734            self.tick();
735        } else {
736            for _ in 0..(delta_ms / self.ms_per_tick as u32) {
737                self.tick();
738            }
739        }
740    }
741
742    /// Handles input events.
743    ///
744    /// Discards the input event if the input queue is full.
745    ///
746    /// Returns the time in ms until the next scheduled event, if any.
747    ///  (Time until next tick, if any, will always be >0, so 0 can be used as "NO EVENTS")
748    pub fn handle_input_after_time(&mut self, delta_ms: u32, ev: input::Event) -> Option<u32> {
749        self.tick_by(delta_ms);
750        self.handle_input(ev);
751        let next_event_time = self.event_scheduler.next_event_time();
752        debug_assert!(next_event_time != Some(0));
753        next_event_time
754    }
755
756    /// If the event scheduler has a next scheduled event,
757    ///  it ticks the keymap forward to that event,
758    ///  returning the time in ms until the following event.
759    ///
760    /// Otherwise, does nothing and returns None.
761    pub fn tick_to_next_scheduled_event(&mut self) -> Option<u32> {
762        if let Some(delta_ms) = self.event_scheduler.next_event_time() {
763            self.tick_by(delta_ms);
764            self.event_scheduler.next_event_time()
765        } else {
766            None
767        }
768    }
769
770    /// Updates the keymap indicating a report is sent; returns the reportable keymap output.
771    pub fn report_output(&mut self) -> KeymapOutput {
772        self.hid_reporter.update(self.pressed_keys());
773        self.hid_reporter.report_sent();
774
775        KeymapOutput::new(self.hid_reporter.reportable_key_outputs())
776    }
777
778    /// Returns the current HID keyboard report.
779    #[doc(hidden)]
780    pub fn boot_keyboard_report(&self) -> [u8; 8] {
781        KeymapOutput::new(self.pressed_keys()).as_hid_boot_keyboard_report()
782    }
783
784    #[doc(hidden)]
785    pub fn has_scheduled_events(&self) -> bool {
786        !self.event_scheduler.pending_events.is_empty()
787            || !self.event_scheduler.scheduled_events.is_empty()
788            || !self.input_queue.is_empty()
789    }
790}
791
792#[cfg(test)]
793mod tests {
794    use super::*;
795
796    #[test]
797    fn test_keymap_output_pressed_key_codes_includes_modifier_key_code() {
798        // Assemble - include modifier key left ctrl
799        let mut input: heapless::Vec<key::KeyOutput, { MAX_PRESSED_KEYS }> = heapless::Vec::new();
800        input.push(key::KeyOutput::from_key_code(0x04)).unwrap();
801        input.push(key::KeyOutput::from_key_code(0xE0)).unwrap();
802
803        // Act - construct the output
804        let keymap_output = KeymapOutput::new(input);
805        let pressed_key_codes = keymap_output.pressed_key_codes();
806
807        // Assert - check the 0xE0 gets included as a key code.
808        assert!(pressed_key_codes.contains(&0xE0))
809    }
810
811    #[test]
812    fn test_keymap_output_as_hid_boot_keyboard_report_gathers_modifiers() {
813        // Assemble - include modifier key left ctrl
814        let mut input: heapless::Vec<key::KeyOutput, { MAX_PRESSED_KEYS }> = heapless::Vec::new();
815        input.push(key::KeyOutput::from_key_code(0x04)).unwrap();
816        input.push(key::KeyOutput::from_key_code(0xE0)).unwrap();
817
818        // Act - construct the output
819        let keymap_output = KeymapOutput::new(input);
820        let actual_report: [u8; 8] = keymap_output.as_hid_boot_keyboard_report();
821
822        // Assert - check the 0xE0 gets considered as a "modifier".
823        let expected_report: [u8; 8] = [0x01, 0, 0x04, 0, 0, 0, 0, 0];
824        assert_eq!(expected_report, actual_report);
825    }
826
827    #[test]
828    fn test_keymap_many_input_events_without_tick_or_report() {
829        // Assemble
830        let mut keymap = {
831            use crate as smart_keymap;
832            use smart_keymap::key::composite as key_system;
833
834            use key_system::Context;
835            use key_system::Ref;
836            const KEY_COUNT: usize = 1;
837            const KEY_REFS: [Ref; KEY_COUNT] = [smart_keymap::key::composite::Ref::Keyboard(
838                smart_keymap::key::keyboard::Ref::KeyCode(0x04),
839            )];
840            const CONTEXT: Context = Context::from_config(key_system::Config::new());
841
842            smart_keymap::keymap::Keymap::new(
843                KEY_REFS,
844                CONTEXT,
845                smart_keymap::key::composite::System::array_based(
846                    smart_keymap::key::automation::System::new([]),
847                    smart_keymap::key::callback::System::new([]),
848                    smart_keymap::key::chorded::System::new([], []),
849                    smart_keymap::key::keyboard::System::new([]),
850                    smart_keymap::key::layered::System::new([], []),
851                    smart_keymap::key::sticky::System::new([]),
852                    smart_keymap::key::tap_dance::System::new([]),
853                    smart_keymap::key::tap_hold::System::new([]),
854                ),
855            )
856        };
857
858        // Act
859        for _ in 0..100 {
860            keymap.handle_input(input::Event::Press { keymap_index: 0 });
861            keymap.handle_input(input::Event::Release { keymap_index: 0 });
862        }
863
864        // Assert
865        // (expect no panics)
866    }
867}