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