Skip to main content

keyberon_smart_keyboard/input/
smart_keymap.rs

1use core::fmt::Debug;
2use core::ops::Index;
3
4use smart_keymap::input;
5use smart_keymap::key;
6use smart_keymap::keymap::{self, Keymap, KeymapOutput, ReportHints, SetKeymapContext};
7
8/// Callbacks for the keymap.
9pub struct KeymapCallbacks {
10    /// Callback for resetting keyboard state.
11    pub reset: Option<fn() -> ()>,
12    /// Callback for entering the bootloader.
13    pub reset_to_bootloader: Option<fn() -> ()>,
14}
15
16/// The keyboard "backend",
17///  manages the keyboard from the events received
18///  (presses/releases of coordinates on a keyboard layout)
19///  through to listing HID scancodes to report using HIDs.
20///
21/// Type parameters match [Keymap].
22#[derive(Debug)]
23pub struct KeyboardBackend<
24    I: Index<usize, Output = R> = [smart_keymap::init::Ref; smart_keymap::init::KEY_COUNT],
25    R = smart_keymap::init::Ref,
26    Ctx = smart_keymap::init::Context,
27    Ev: Debug = smart_keymap::init::Event,
28    PKS = smart_keymap::init::PendingKeyState,
29    KS = smart_keymap::init::KeyState,
30    S = smart_keymap::init::System,
31> {
32    keymap: Keymap<I, R, Ctx, Ev, PKS, KS, S>,
33    keymap_output: KeymapOutput,
34}
35
36impl Default for KeyboardBackend {
37    fn default() -> Self {
38        Self::new()
39    }
40}
41
42impl KeyboardBackend {
43    /// Constructs a new keyboard backend using the board keymap
44    ///  ([smart_keymap::new_keymap]).
45    pub fn new() -> Self {
46        Self::new_with_keymap(smart_keymap::new_keymap())
47    }
48}
49
50impl<I, R, Ctx, Ev, PKS, KS, S> KeyboardBackend<I, R, Ctx, Ev, PKS, KS, S>
51where
52    I: Index<usize, Output = R>,
53    Ev: Debug,
54{
55    /// Constructs a new keyboard backend with the given keymap.
56    pub fn new_with_keymap(keymap: Keymap<I, R, Ctx, Ev, PKS, KS, S>) -> Self {
57        Self {
58            keymap,
59            keymap_output: KeymapOutput::default(),
60        }
61    }
62}
63
64impl<I, R, Ctx, Ev, PKS, KS, S> KeyboardBackend<I, R, Ctx, Ev, PKS, KS, S>
65where
66    I: Debug + Index<usize, Output = R>,
67    R: Copy + Debug,
68    Ctx: Debug + key::Context<Event = Ev> + SetKeymapContext + ReportHints,
69    Ev: Copy + Debug,
70    PKS: Debug,
71    KS: Copy + Debug + From<key::NoOpKeyState>,
72    S: key::System<R, Ref = R, Context = Ctx, Event = Ev, PendingKeyState = PKS, KeyState = KS>,
73{
74    /// Set the keymap callbacks.
75    pub fn set_callbacks(&mut self, callbacks: KeymapCallbacks) {
76        use keymap::KeymapCallback;
77        if let Some(callback_fn) = callbacks.reset {
78            self.keymap.set_callback(KeymapCallback::Reset, callback_fn);
79        }
80        if let Some(callback_fn) = callbacks.reset_to_bootloader {
81            self.keymap
82                .set_callback(KeymapCallback::ResetToBootloader, callback_fn);
83        }
84    }
85
86    /// Register a key event.
87    pub fn event(&mut self, event: input::Event) {
88        self.keymap.handle_input(event);
89    }
90
91    /// A time event.
92    ///
93    /// This method must be called regularly, typically every millisecond.
94    ///
95    /// Returns true if the pressed_key_codes have changed.
96    pub fn tick(&mut self) -> bool {
97        self.keymap.tick();
98
99        let keymap_output = self.keymap.report_output();
100
101        let old_keymap_output = core::mem::replace(&mut self.keymap_output, keymap_output);
102
103        old_keymap_output != self.keymap_output
104    }
105
106    /// Returns the current keymap output.
107    pub fn keymap_output(&self) -> &KeymapOutput {
108        &self.keymap_output
109    }
110}
111
112/// Constructs a [input::Event] from a [keyberon::layout::Event],
113///  using a map from row, column to (maybe) keymap index.
114pub fn keymap_index_of<const COLS: usize, const ROWS: usize>(
115    indices: &[[Option<u16>; COLS]; ROWS],
116    ev: keyberon::layout::Event,
117) -> Option<input::Event> {
118    match ev {
119        keyberon::layout::Event::Press(r, c) => {
120            indices[r as usize][c as usize].map(|keymap_index| input::Event::Press { keymap_index })
121        }
122        keyberon::layout::Event::Release(r, c) => indices[r as usize][c as usize]
123            .map(|keymap_index| input::Event::Release { keymap_index }),
124    }
125}