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