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>
227where
228    KS: From<key::NoOpKeyState<K::Context, K::Event>>,
229{
230    /// Constructs a new keymap with the given key definitions and context.
231    pub const fn new(key_definitions: I, context: Ctx) -> Self {
232        Self {
233            key_definitions,
234            context,
235            pressed_inputs: heapless::Vec::new(),
236            event_scheduler: EventScheduler::new(),
237            ms_per_tick: 1,
238            idle_time: 0,
239            hid_reporter: HIDKeyboardReporter::new(),
240            pending_key_state: None,
241            input_queue: heapless::spsc::Queue::new(),
242            input_queue_delay_counter: 0,
243            callbacks: heapless::LinearMap::new(),
244        }
245    }
246
247    /// Initializes or resets the keyboard to an initial state.
248    pub fn init(&mut self) {
249        self.pressed_inputs.clear();
250        self.event_scheduler.init();
251        self.hid_reporter.init();
252        self.pending_key_state = None;
253        while !self.input_queue.is_empty() {
254            self.input_queue.dequeue().unwrap();
255        }
256        self.input_queue_delay_counter = 0;
257        self.ms_per_tick = 1;
258        self.idle_time = 0;
259    }
260
261    /// Registers the given callback to the keymap.
262    ///
263    /// Only one callback is set for each callback id.
264    pub fn set_callback(&mut self, callback_id: KeymapCallback, callback_fn: fn() -> ()) {
265        self.callbacks
266            .insert(callback_id, CallbackFunction::Rust(callback_fn))
267            .unwrap();
268    }
269
270    /// Registers the given callback to the keymap.
271    ///
272    /// Only one callback is set for each callback id.
273    pub fn set_callback_extern(
274        &mut self,
275        callback_id: KeymapCallback,
276        callback_fn: extern "C" fn() -> (),
277    ) {
278        self.callbacks
279            .insert(callback_id, CallbackFunction::ExternC(callback_fn))
280            .unwrap();
281    }
282
283    /// Sets the number of ms per tick().
284    pub fn set_ms_per_tick(&mut self, ms_per_tick: u8) {
285        self.ms_per_tick = ms_per_tick;
286    }
287
288    // If the pending key state is resolved,
289    //  then clear the pending key state.
290    fn resolve_pending_key_state(&mut self, key_state: KS) {
291        if let Some(PendingState {
292            key_path,
293            queued_events,
294            ..
295        }) = self.pending_key_state.take()
296        {
297            // Cancel events which were scheduled for the (pending) key.
298            let keymap_index = key_path.keymap_index();
299            self.event_scheduler
300                .cancel_events_for_keymap_index(keymap_index);
301
302            // Add the pending state's pressed key to pressed inputs
303            self.pressed_inputs
304                .push(input::PressedInput::pressed_key(key_state, keymap_index))
305                .unwrap();
306
307            // Schedule each of the queued events,
308            //  delaying each consecutive event by a tick
309            //  (in order to allow press/release events to affect the HID report)
310            let mut i = 1;
311            let mut old_input_queue: heapless::spsc::Queue<input::Event, MAX_QUEUED_INPUT_EVENTS> =
312                core::mem::take(&mut self.input_queue);
313
314            // Partition the events from the pending keymap index
315            //  separately from the other queued events.
316            // (Only queue the *last* event from the pending keymap index).
317            let (pending_input_ev, queued_events): (
318                heapless::Vec<key::Event<Ev>, { MAX_PRESSED_KEYS }>,
319                heapless::Vec<key::Event<Ev>, { MAX_PRESSED_KEYS }>,
320            ) = queued_events.iter().partition(|ev| match ev {
321                key::Event::Input(input::Event::Press {
322                    keymap_index: queued_kmi,
323                }) => *queued_kmi == keymap_index,
324                key::Event::Input(input::Event::Release {
325                    keymap_index: queued_kmi,
326                }) => *queued_kmi == keymap_index,
327                key::Event::Key {
328                    keymap_index: queued_kmi,
329                    ..
330                } => *queued_kmi == keymap_index,
331                _ => false,
332            });
333
334            for ev in queued_events.iter().chain(pending_input_ev.last()) {
335                match ev {
336                    key::Event::Input(ie) => {
337                        self.input_queue.enqueue(*ie).unwrap();
338                    }
339                    _ => {
340                        self.event_scheduler.schedule_after(i, *ev);
341                        i += 1;
342                    }
343                }
344            }
345
346            while let Some(ie) = old_input_queue.dequeue() {
347                self.input_queue.enqueue(ie).unwrap();
348            }
349
350            self.handle_pending_events();
351
352            // The resolved key state has output. Emit this as an event.
353            if let Some(key_state) = key_state.key_output() {
354                let km_ev = KeymapEvent::ResolvedKeyOutput {
355                    keymap_index,
356                    key_output: key_state,
357                };
358                self.handle_event(key::Event::Keymap(km_ev));
359            }
360        }
361    }
362
363    /// Handles input events.
364    pub fn handle_input(&mut self, ev: input::Event) {
365        self.idle_time = 0;
366
367        if self.input_queue.is_full() {
368            return;
369        }
370
371        self.input_queue.enqueue(ev).unwrap();
372
373        if self.input_queue_delay_counter == 0 {
374            let ie = self.input_queue.dequeue().unwrap();
375            self.process_input(ie);
376            self.input_queue_delay_counter = INPUT_QUEUE_TICK_DELAY;
377        }
378    }
379
380    fn has_pressed_input_with_keymap_index(&self, keymap_index: u16) -> bool {
381        self.pressed_inputs.iter().any(|pi| match pi {
382            &input::PressedInput::Key(input::PressedKey {
383                keymap_index: ki, ..
384            }) => keymap_index == ki,
385            _ => false,
386        })
387    }
388
389    fn process_input(&mut self, ev: input::Event) {
390        if let Some(PendingState {
391            key_path,
392            pending_key_state,
393            queued_events,
394            ..
395        }) = &mut self.pending_key_state
396        {
397            queued_events.push(ev.into()).unwrap();
398
399            let pending_key = &self.key_definitions[key_path.keymap_index() as usize];
400            let pending_key = pending_key.lookup(&key_path[1..]);
401            let (mut maybe_npk, pke) = pending_key.handle_event(
402                pending_key_state,
403                &self.context,
404                key_path.clone(),
405                ev.into(),
406            );
407
408            pke.into_iter()
409                .for_each(|sch_ev| self.event_scheduler.schedule_event(sch_ev));
410
411            while let Some(npk) = maybe_npk.take() {
412                let pkr = match npk {
413                    key::NewPressedKey::Key(new_key_path) => {
414                        let new_key = &self.key_definitions[new_key_path.keymap_index() as usize];
415                        let new_key = new_key.lookup(&new_key_path[1..]);
416                        let (pkr, pke) =
417                            new_key.new_pressed_key(&self.context, new_key_path.clone());
418                        pke.into_iter()
419                            .for_each(|sch_ev| self.event_scheduler.schedule_event(sch_ev));
420                        pkr
421                    }
422                    key::NewPressedKey::NoOp => {
423                        let no_op_ks: KS = key::NoOpKeyState::new().into();
424                        key::PressedKeyResult::Resolved(no_op_ks)
425                    }
426                };
427
428                match pkr {
429                    key::PressedKeyResult::Resolved(ks) => {
430                        self.resolve_pending_key_state(ks);
431                        break;
432                    }
433                    key::PressedKeyResult::NewPressedKey(key::NewPressedKey::Key(new_key_path)) => {
434                        maybe_npk = Some(key::NewPressedKey::Key(new_key_path));
435                    }
436                    key::PressedKeyResult::NewPressedKey(key::NewPressedKey::NoOp) => {
437                        self.resolve_pending_key_state(key::NoOpKeyState::new().into());
438                        break;
439                    }
440                    key::PressedKeyResult::Pending(kp, pks) => {
441                        *key_path = kp;
442                        *pending_key_state = pks;
443
444                        // Since the pending key state resolved into another pending key state,
445                        //  we re-queue all the input events that had been received.
446                        let orig_input_queue = core::mem::take(&mut self.input_queue);
447                        while let Some(ev) = queued_events.pop() {
448                            match ev {
449                                key::Event::Input(input_ev) => {
450                                    self.input_queue.enqueue(input_ev).unwrap();
451                                }
452                                _ => {}
453                            }
454                        }
455                        orig_input_queue.iter().for_each(|&ev| {
456                            self.input_queue.enqueue(ev).unwrap();
457                        });
458                    }
459                }
460            }
461        } else {
462            // Update each of the pressed keys with the event.
463            self.pressed_inputs.iter_mut().for_each(|pi| {
464                if let input::PressedInput::Key(pressed_key) = pi {
465                    pressed_key
466                        .handle_event(&self.context, ev.into())
467                        .into_iter()
468                        .for_each(|sch_ev| self.event_scheduler.schedule_event(sch_ev));
469                }
470            });
471
472            self.context
473                .handle_event(ev.into())
474                .into_iter()
475                .for_each(|sch_ev| self.event_scheduler.schedule_event(sch_ev));
476
477            match ev {
478                input::Event::Press { keymap_index }
479                    if !self.has_pressed_input_with_keymap_index(keymap_index) =>
480                {
481                    let mut maybe_key_path = Some(key::key_path(keymap_index));
482
483                    while let Some(key_path) = maybe_key_path.take() {
484                        let key = &self.key_definitions[key_path.keymap_index() as usize]
485                            .lookup(&key_path[1..]);
486
487                        let (pkr, pke) = key.new_pressed_key(&self.context, key_path);
488
489                        pke.into_iter()
490                            .for_each(|sch_ev| self.event_scheduler.schedule_event(sch_ev));
491
492                        match pkr {
493                            key::PressedKeyResult::Resolved(key_state) => {
494                                self.pressed_inputs
495                                    .push(input::PressedInput::pressed_key(key_state, keymap_index))
496                                    .unwrap();
497
498                                // The resolved key state has output. Emit this as an event.
499                                if let Some(key_output) = key_state.key_output() {
500                                    let km_ev = KeymapEvent::ResolvedKeyOutput {
501                                        keymap_index,
502                                        key_output,
503                                    };
504                                    self.handle_event(key::Event::Keymap(km_ev));
505                                }
506                            }
507                            key::PressedKeyResult::NewPressedKey(key::NewPressedKey::Key(
508                                new_key_path,
509                            )) => {
510                                maybe_key_path = Some(new_key_path);
511                            }
512                            key::PressedKeyResult::NewPressedKey(key::NewPressedKey::NoOp) => {
513                                let key_state: KS = key::NoOpKeyState::new().into();
514
515                                self.pressed_inputs
516                                    .push(input::PressedInput::pressed_key(key_state, keymap_index))
517                                    .unwrap();
518                            }
519                            key::PressedKeyResult::Pending(key_path, pending_key_state) => {
520                                self.pending_key_state = Some(PendingState {
521                                    key_path,
522                                    pending_key_state,
523                                    queued_events: heapless::Vec::new(),
524                                });
525                            }
526                        }
527                    }
528                }
529                input::Event::Release { keymap_index } => {
530                    self.pressed_inputs
531                        .iter()
532                        .position(|pi| match pi {
533                            &input::PressedInput::Key(input::PressedKey {
534                                keymap_index: ki,
535                                ..
536                            }) => keymap_index == ki,
537                            _ => false,
538                        })
539                        .map(|i| self.pressed_inputs.remove(i));
540
541                    self.event_scheduler
542                        .cancel_events_for_keymap_index(keymap_index);
543                }
544
545                input::Event::VirtualKeyPress { key_output } => {
546                    let pressed_key = input::PressedInput::Virtual(key_output);
547                    self.pressed_inputs.push(pressed_key).unwrap();
548                }
549                input::Event::VirtualKeyRelease { key_output } => {
550                    // Remove from pressed keys.
551                    self.pressed_inputs
552                        .iter()
553                        .position(|k| match k {
554                            input::PressedInput::Virtual(ko) => key_output == *ko,
555                            _ => false,
556                        })
557                        .map(|i| self.pressed_inputs.remove(i));
558                }
559
560                _ => {}
561            }
562        }
563
564        self.handle_pending_events();
565    }
566
567    // Called from handle_all_pending_events,
568    //  and for handling the (resolving) queue of events from pending key state.
569    fn handle_event(&mut self, ev: key::Event<Ev>) {
570        if let key::Event::Keymap(KeymapEvent::Callback(callback_id)) = ev {
571            match self.callbacks.get(&callback_id) {
572                Some(CallbackFunction::Rust(callback_fn)) => {
573                    callback_fn();
574                }
575                Some(CallbackFunction::ExternC(callback_fn)) => {
576                    callback_fn();
577                }
578                None => {}
579            }
580        }
581
582        // pending state needs to handle events
583        if let Some(PendingState {
584            key_path,
585            pending_key_state,
586            queued_events,
587            ..
588        }) = &mut self.pending_key_state
589        {
590            let pending_key = &self.key_definitions[key_path.keymap_index() as usize];
591            let pending_key = pending_key.lookup(&key_path[1..]);
592            let (mut maybe_npk, pke) =
593                pending_key.handle_event(pending_key_state, &self.context, key_path.clone(), ev);
594
595            pke.into_iter()
596                .for_each(|sch_ev| self.event_scheduler.schedule_event(sch_ev));
597
598            while let Some(npk) = maybe_npk.take() {
599                let pkr = match npk {
600                    key::NewPressedKey::Key(new_key_path) => {
601                        let new_key = &self.key_definitions[new_key_path.keymap_index() as usize];
602                        let new_key = new_key.lookup(&new_key_path[1..]);
603                        let (pkr, pke) =
604                            new_key.new_pressed_key(&self.context, new_key_path.clone());
605                        pke.into_iter()
606                            .for_each(|sch_ev| self.event_scheduler.schedule_event(sch_ev));
607                        pkr
608                    }
609                    key::NewPressedKey::NoOp => {
610                        let no_op_ks: KS = key::NoOpKeyState::new().into();
611                        key::PressedKeyResult::Resolved(no_op_ks)
612                    }
613                };
614
615                match pkr {
616                    key::PressedKeyResult::Resolved(ks) => {
617                        self.resolve_pending_key_state(ks);
618                        break;
619                    }
620                    key::PressedKeyResult::NewPressedKey(key::NewPressedKey::Key(new_key_path)) => {
621                        maybe_npk = Some(key::NewPressedKey::Key(new_key_path));
622                    }
623                    key::PressedKeyResult::NewPressedKey(key::NewPressedKey::NoOp) => {
624                        self.resolve_pending_key_state(key::NoOpKeyState::new().into());
625                        break;
626                    }
627                    key::PressedKeyResult::Pending(kp, pks) => {
628                        *key_path = kp;
629                        *pending_key_state = pks;
630
631                        // Since the pending key state resolved into another pending key state,
632                        //  we re-queue all the input events that had been received.
633                        let orig_input_queue = core::mem::take(&mut self.input_queue);
634                        while let Some(ev) = queued_events.pop() {
635                            match ev {
636                                key::Event::Input(input_ev) => {
637                                    self.input_queue.enqueue(input_ev).unwrap();
638                                }
639                                _ => {}
640                            }
641                        }
642                        orig_input_queue.iter().for_each(|&ev| {
643                            self.input_queue.enqueue(ev).unwrap();
644                        });
645                    }
646                }
647            }
648        }
649
650        // Update each of the pressed keys with the event.
651        self.pressed_inputs.iter_mut().for_each(|pi| {
652            if let input::PressedInput::Key(input::PressedKey {
653                key_state,
654                keymap_index,
655            }) = pi
656            {
657                key_state
658                    .handle_event(&self.context, *keymap_index, ev)
659                    .into_iter()
660                    .for_each(|sch_ev| self.event_scheduler.schedule_event(sch_ev));
661            }
662        });
663
664        // Update context with the event
665        self.context
666            .handle_event(ev)
667            .into_iter()
668            .for_each(|sch_ev| self.event_scheduler.schedule_event(sch_ev));
669
670        if let Event::Input(input_ev) = ev {
671            self.process_input(input_ev);
672        }
673    }
674
675    fn handle_pending_events(&mut self) {
676        // take from pending
677        while let Some(ev) = self.event_scheduler.dequeue() {
678            self.handle_event(ev);
679        }
680    }
681
682    /// Advances the state of the keymap by one tick.
683    pub fn tick(&mut self) {
684        let km_context = KeymapContext {
685            time_ms: self.event_scheduler.schedule_counter,
686            idle_time_ms: self.idle_time,
687        };
688        self.context.set_keymap_context(km_context);
689
690        if !self.input_queue.is_empty() && self.input_queue_delay_counter == 0 {
691            let ie = self.input_queue.dequeue().unwrap();
692            self.process_input(ie);
693            self.input_queue_delay_counter = INPUT_QUEUE_TICK_DELAY;
694        }
695
696        if self.input_queue_delay_counter > 0 {
697            self.input_queue_delay_counter -= 1;
698        }
699
700        self.event_scheduler.tick(self.ms_per_tick);
701
702        self.handle_pending_events();
703
704        self.idle_time += self.ms_per_tick as u32;
705    }
706
707    /// Returns the the pressed key outputs.
708    pub fn pressed_keys(&self) -> heapless::Vec<key::KeyOutput, { MAX_PRESSED_KEYS }> {
709        let pressed_key_codes = self.pressed_inputs.iter().filter_map(|pi| match pi {
710            input::PressedInput::Key(pressed_key) => pressed_key.key_output(),
711            &input::PressedInput::Virtual(key_output) => Some(key_output),
712        });
713
714        pressed_key_codes.collect()
715    }
716
717    /// Updates the keymap indicating a report is sent; returns the reportable keymap output.
718    pub fn report_output(&mut self) -> KeymapOutput {
719        self.hid_reporter.update(self.pressed_keys());
720        self.hid_reporter.report_sent();
721
722        KeymapOutput::new(self.hid_reporter.reportable_key_outputs())
723    }
724
725    /// Returns the current HID keyboard report.
726    #[doc(hidden)]
727    pub fn boot_keyboard_report(&self) -> [u8; 8] {
728        KeymapOutput::new(self.pressed_keys()).as_hid_boot_keyboard_report()
729    }
730
731    #[doc(hidden)]
732    pub fn has_scheduled_events(&self) -> bool {
733        !self.event_scheduler.pending_events.is_empty()
734            || !self.event_scheduler.scheduled_events.is_empty()
735            || !self.input_queue.is_empty()
736    }
737}
738
739#[cfg(test)]
740mod tests {
741    use super::*;
742
743    use crate::tuples;
744
745    #[test]
746    fn test_keymap_output_pressed_key_codes_includes_modifier_key_code() {
747        // Assemble - include modifier key left ctrl
748        let mut input: heapless::Vec<key::KeyOutput, { MAX_PRESSED_KEYS }> = heapless::Vec::new();
749        input.push(key::KeyOutput::from_key_code(0x04)).unwrap();
750        input.push(key::KeyOutput::from_key_code(0xE0)).unwrap();
751
752        // Act - construct the output
753        let keymap_output = KeymapOutput::new(input);
754        let pressed_key_codes = keymap_output.pressed_key_codes();
755
756        // Assert - check the 0xE0 gets included as a key code.
757        assert!(pressed_key_codes.contains(&0xE0))
758    }
759
760    #[test]
761    fn test_keymap_output_as_hid_boot_keyboard_report_gathers_modifiers() {
762        // Assemble - include modifier key left ctrl
763        let mut input: heapless::Vec<key::KeyOutput, { MAX_PRESSED_KEYS }> = heapless::Vec::new();
764        input.push(key::KeyOutput::from_key_code(0x04)).unwrap();
765        input.push(key::KeyOutput::from_key_code(0xE0)).unwrap();
766
767        // Act - construct the output
768        let keymap_output = KeymapOutput::new(input);
769        let actual_report: [u8; 8] = keymap_output.as_hid_boot_keyboard_report();
770
771        // Assert - check the 0xE0 gets considered as a "modifier".
772        let expected_report: [u8; 8] = [0x01, 0, 0x04, 0, 0, 0, 0, 0];
773        assert_eq!(expected_report, actual_report);
774    }
775
776    #[test]
777    fn test_keymap_with_keyboard_key_with_composite_context() {
778        use key::composite;
779        use key::keyboard;
780        use tuples::Keys1;
781
782        use composite::{Context, Event, KeyState, PendingKeyState};
783
784        // Assemble
785        type Ctx = Context;
786        type K = composite::Chorded<composite::Layered<composite::TapHold<keyboard::Key>>>;
787        let keys: Keys1<K, Context, Event, PendingKeyState, KeyState> =
788            Keys1::new((composite::Chorded(composite::Layered(composite::TapHold(
789                keyboard::Key::new(0x04),
790            ))),));
791        let context: Ctx = composite::DEFAULT_CONTEXT;
792        let mut keymap = Keymap::new(keys, context);
793
794        // Act
795        keymap.handle_input(input::Event::Press { keymap_index: 0 });
796        let actual_report = keymap.boot_keyboard_report();
797
798        // Assert
799        let expected_report: [u8; 8] = [0, 0, 0x04, 0, 0, 0, 0, 0];
800        assert_eq!(expected_report, actual_report);
801    }
802
803    #[test]
804    fn test_keymap_with_composite_keyboard_key() {
805        use key::{composite, keyboard};
806        use tuples::Keys1;
807
808        use composite::{Context, Event, KeyState, PendingKeyState};
809
810        // Assemble
811        let keys: Keys1<composite::Key, Context, Event, PendingKeyState, KeyState> =
812            Keys1::new((composite::Key::keyboard(keyboard::Key::new(0x04)),));
813        let context: Context = composite::DEFAULT_CONTEXT;
814        let mut keymap = Keymap::new(keys, context);
815
816        // Act
817        keymap.handle_input(input::Event::Press { keymap_index: 0 });
818        let actual_report = keymap.boot_keyboard_report();
819
820        // Assert
821        let expected_report: [u8; 8] = [0, 0, 0x04, 0, 0, 0, 0, 0];
822        assert_eq!(expected_report, actual_report);
823    }
824
825    #[test]
826    fn test_keymap_many_input_events_without_tick_or_report() {
827        use key::{composite, keyboard};
828        use tuples::Keys1;
829
830        use composite::{Context, Event, KeyState, PendingKeyState};
831
832        // Assemble
833        let keys: Keys1<composite::Key, Context, Event, PendingKeyState, KeyState> =
834            Keys1::new((composite::Key::keyboard(keyboard::Key::new(0x04)),));
835        let context: Context = composite::DEFAULT_CONTEXT;
836        let mut keymap = Keymap::new(keys, context);
837
838        // Act
839        for _ in 0..100 {
840            keymap.handle_input(input::Event::Press { keymap_index: 0 });
841            keymap.handle_input(input::Event::Release { keymap_index: 0 });
842        }
843
844        // Assert
845        // (expect no panics)
846    }
847}