Skip to main content

cardputer_adv_keyboard/
lib.rs

1//! A keyboard driver for the [M5Stack Cardputer-Adv](https://docs.m5stack.com/en/core/Cardputer-Adv), built on top of the [tca8418](https://crates.io/crates/tca8418) driver.
2//! Handles key press/release events, shift/Fn layer resolution and modifier tracking.
3//!
4//! This crate provides a [Keyboard] type that can be created using any type that implements [I2c].
5//! This is provided by your HAL.
6//! All methods using the underlying I²C bus return a [tca8418::Error] on I²C failure.
7//!
8//! You can get all pending inputs using [.inputs()](Keyboard::inputs) on the created [Keyboard].
9//! This drains the FIFO of the TCA8418 which can store up to 10 events.
10//!
11//! You can either use polling or the TCA8418's interrupt output to know when events are available.
12//!
13//! # Examples
14//! Here is a basic example on how to capture user text input.
15//! See the examples in the repository for a full example app using esp-hal.
16//!
17//! ```rust,no_run
18//! # fn process_input(_input: &heapless::String<64>) {}
19//! # fn example(i2c: impl embedded_hal::i2c::I2c) {
20//! use cardputer_adv_keyboard::{KeyInput, Keyboard};
21//! use heapless::String;
22//!
23//! let mut input_string: String<64> = String::new();
24//!
25//! // You need to create i2c using your HAL crate.
26//! let mut keyboard = Keyboard::new(i2c).unwrap();
27//!
28//! loop {
29//!     for input in keyboard.inputs().unwrap() {
30//!         match input {
31//!             KeyInput::Char(c) => { input_string.push(c).ok(); }
32//!             KeyInput::Backspace => { input_string.pop(); }
33//!             KeyInput::Enter => {
34//!                 process_input(&input_string);
35//!                 input_string.clear();
36//!             }
37//!             _ => {}
38//!         }
39//!     }
40//! }
41//! # }
42//!
43//! ```
44//!
45//! ## KeyInput
46//! A [KeyInput] represents a resolved key press. This encompasses everything that is printed on the keyboard, including the Shift and Fn layers.
47//!
48//!
49//! ### Some examples
50//! | Pressed keys | Result |
51//! |------|--------|
52//! | `w` | `KeyInput::Char('w')` |
53//! | Shift + `w` | `KeyInput::Char('W')` |
54//! | `;` | `KeyInput::Char(';')` |
55//! | Shift + `;` | `KeyInput::Char(':')` |
56//! | `Space` | `KeyInput::Char(' ')`|
57//!
58//! The other character keys work the same.
59//! If a key has no Shift or Fn layer, it just returns it's default character, even when modifiers are pressed.
60//!
61//! All special keys have their own KeyInput variant, for example:
62//! | Pressed keys | Result |
63//! |------|--------|
64//! | Fn + `` ` `` | `KeyInput::Escape` |
65//! | Fn + `;` | `KeyInput::Arrow(Arrow::Up)` |
66//! | Fn + `Backspace` | `KeyInput::Delete` |
67//!
68//! # Advanced usage
69//! If you need more information about key events (key releases, pressed modifiers) you can directly get the [KeyboardEvents](KeyboardEvent) using `.events()`.
70//! Using these you can create custom chords (like Ctrl + C) or track if a key is being held.
71//!
72//! ## Listening for custom combinations
73//! ```rust,no_run
74//! # fn copy() {}
75//! # fn paste() {}
76//! # fn redo() {}
77//! # fn undo() {}
78//! # fn example(keyboard: &mut cardputer_adv_keyboard::Keyboard<impl embedded_hal::i2c::I2c>) {
79//! use cardputer_adv_keyboard::{PhysicalKey, ModifierState};
80//! for event in keyboard.events().unwrap() {
81//!     // Only act on presses
82//!     if !event.state.is_pressed() {
83//!         continue;
84//!     }
85//!
86//!     match (event.physical_key, event.modifiers) {
87//!         (PhysicalKey::C, ModifierState { ctrl: true, .. }) => copy(),
88//!         (PhysicalKey::V, ModifierState { ctrl: true, .. }) => paste(),
89//!         (PhysicalKey::Z, ModifierState { ctrl: true, shift: true, .. }) => redo(),
90//!         (PhysicalKey::Z, ModifierState { ctrl: true, .. }) => undo(),
91//!         _ => {}
92//!     }
93//! }
94//! # }
95//! ```
96//!
97//! ## Tracking held keys
98//! ```rust,no_run
99//! # struct Player{};
100//! # impl Player {
101//! #     fn move_forward(&self) {}
102//! #     fn jump(&self) {}
103//! # }
104//! # fn example(keyboard: &mut cardputer_adv_keyboard::Keyboard<impl embedded_hal::i2c::I2c>) {
105//! # let player = Player {};
106//! use cardputer_adv_keyboard::{PhysicalKey, KeyState};
107//! let mut w_held = false;
108//!
109//! loop {
110//!     for event in keyboard.events().unwrap() {
111//!         match (event.physical_key, event.state) {
112//!             (PhysicalKey::W, KeyState::Pressed) => w_held = true,
113//!             (PhysicalKey::W, KeyState::Released) => w_held = false,
114//!             (PhysicalKey::Space, KeyState::Pressed) => player.jump(),
115//!             _ => {}
116//!         }
117//!     }
118//!
119//!     if w_held {
120//!         player.move_forward();
121//!     }
122//! }
123//! # }
124//! ```
125
126#![no_std]
127
128use embedded_hal::i2c::I2c;
129use tca8418::{InterruptFlags, PinMask, Tca8418};
130
131/// Maximum number of events returned from a single [`Keyboard::events`] call.
132const MAX_EVENTS: usize = 10;
133
134/// This type represents a key event (press or release).
135///
136/// Each event carries a [`physical_key`](Self::physical_key) identifying
137/// which key on the keyboard was pressed or released.
138///
139/// On presses, [`input`](Self::input) contains the resolved [`KeyInput`]
140/// after applying shift/Fn modifiers.
141/// On releases it is `None`.
142///
143/// If you only care about basic input then you can just use `input`.
144/// If you need raw information about pressed and released keys (games, custom bindings) you can use `physical_key` and the additional information in this struct.
145#[derive(Debug, Clone, Copy, PartialEq, Eq)]
146#[cfg_attr(feature = "defmt", derive(defmt::Format))]
147pub struct KeyboardEvent {
148    /// The resolved semantic input, if applicable.
149    ///
150    /// `Some` on key press, `None` on key release. Release events should
151    /// be matched by `physical_key`, not by resolved input, since the modifier
152    /// state may have changed between press and release.
153    pub input: Option<KeyInput>,
154    /// Which physical key was pressed or released. This is always independent of modifier keys.
155    pub physical_key: PhysicalKey,
156    /// Whether the key was pressed or released.
157    pub state: KeyState,
158    /// The modifier state at the time of this event.
159    pub modifiers: ModifierState,
160}
161
162/// Whether a key was pressed or released.
163#[derive(Debug, Clone, Copy, PartialEq, Eq)]
164#[cfg_attr(feature = "defmt", derive(defmt::Format))]
165pub enum KeyState {
166    Pressed,
167    Released,
168}
169
170impl KeyState {
171    pub fn is_pressed(self) -> bool {
172        matches!(self, KeyState::Pressed)
173    }
174
175    pub fn is_released(self) -> bool {
176        matches!(self, KeyState::Released)
177    }
178}
179/// The semantic meaning of a key press after applying modifiers.
180///
181/// This represents what a key *produces*, not which key was physically
182/// pressed. For example, pressing `W` while holding Shift produces
183/// `KeyInput::Char('W')`, and pressing `;` while holding Fn produces
184/// `KeyInput::Arrow(Arrow::Up)`.
185///
186/// ## Some examples
187/// | Pressed keys | Resulting KeyInput |
188/// |------|--------|
189/// | `;` | `Char(';')` |
190/// | Shift + `;` | `Char(':')` |
191/// | Fn + `;` | `Arrow(Arrow::Up)` |
192/// | Space | `Char(' ')` |
193/// | Fn + `` ` `` | `Escape` |
194/// | Fn + Backspace | `Delete` |
195///
196/// If a key has no special meaning for the currently pressed modifier, it just returns its default.
197///
198/// Fn + `w` => `Char('w')`
199///
200/// If a key has both a Shift and Fn layer, the Fn layer is always prioritized when both are pressed.
201///
202/// Fn + Shift + `;` => `Arrow(Arrow::Up)`
203///
204#[derive(Debug, Clone, Copy, PartialEq, Eq)]
205#[cfg_attr(feature = "defmt", derive(defmt::Format))]
206pub enum KeyInput {
207    /// A printable character after applying shift/Fn modifiers.
208    Char(char),
209    /// Enter / Return key.
210    Enter,
211    /// Backspace key.
212    Backspace,
213    /// Delete (Fn + Backspace).
214    Delete,
215    /// Tab key.
216    Tab,
217    /// Escape (Fn + Backtick).
218    Escape,
219    /// An arrow key (Fn + `;` `,` `.` `/`).
220    Arrow(Arrow),
221    /// A modifier key was pressed (Shift, Fn, Ctrl, Opt, Alt).
222    Modifier(Modifier),
223}
224
225/// Arrow key directions.
226#[derive(Debug, Clone, Copy, PartialEq, Eq)]
227#[cfg_attr(feature = "defmt", derive(defmt::Format))]
228pub enum Arrow {
229    Up,
230    Down,
231    Left,
232    Right,
233}
234
235/// Modifier keys.
236#[derive(Debug, Clone, Copy, PartialEq, Eq)]
237#[cfg_attr(feature = "defmt", derive(defmt::Format))]
238pub enum Modifier {
239    Shift,
240    Fn,
241    Ctrl,
242    Opt,
243    Alt,
244}
245
246/// This represents an actual physical key on the Cardputer keyboard.
247///
248/// Named after the labels on the keyboard.
249///
250/// | | | | | | | | | | | | | | |
251/// |---|---|---|---|---|---|---|---|---|---|---|---|---|---|
252/// | [`Backtick`](Self::Backtick) | [`N1`](Self::N1) | [`N2`](Self::N2) | [`N3`](Self::N3) | [`N4`](Self::N4) | [`N5`](Self::N5) | [`N6`](Self::N6) | [`N7`](Self::N7) | [`N8`](Self::N8) | [`N9`](Self::N9) | [`N0`](Self::N0) | [`Minus`](Self::Minus) | [`Equal`](Self::Equal) | [`Backspace`](Self::Backspace) |
253/// | [`Tab`](Self::Tab) | [`Q`](Self::Q) | [`W`](Self::W) | [`E`](Self::E) | [`R`](Self::R) | [`T`](Self::T) | [`Y`](Self::Y) | [`U`](Self::U) | [`I`](Self::I) | [`O`](Self::O) | [`P`](Self::P) | [`LeftBracket`](Self::LeftBracket) | [`RightBracket`](Self::RightBracket) | [`Backslash`](Self::Backslash) |
254/// | [`Fn`](Self::Fn) | [`Shift`](Self::Shift) | [`A`](Self::A) | [`S`](Self::S) | [`D`](Self::D) | [`F`](Self::F) | [`G`](Self::G) | [`H`](Self::H) | [`J`](Self::J) | [`K`](Self::K) | [`L`](Self::L) | [`Semicolon`](Self::Semicolon) | [`Apostrophe`](Self::Apostrophe) | [`Enter`](Self::Enter) |
255/// | [`Ctrl`](Self::Ctrl) | [`Opt`](Self::Opt) | [`Alt`](Self::Alt) | [`Z`](Self::Z) | [`X`](Self::X) | [`C`](Self::C) | [`V`](Self::V) | [`B`](Self::B) | [`N`](Self::N) | [`M`](Self::M) | [`Comma`](Self::Comma) | [`Period`](Self::Period) | [`Slash`](Self::Slash) | [`Space`](Self::Space) |
256#[derive(Debug, Clone, Copy, PartialEq, Eq)]
257#[cfg_attr(feature = "defmt", derive(defmt::Format))]
258#[rustfmt::skip]
259pub enum PhysicalKey {
260    // Row 0
261    Backtick, N1, N2, N3, N4, N5, N6, N7, N8, N9, N0, Minus, Equal, Backspace,
262    // Row 1
263    Tab, Q, W, E, R, T, Y, U, I, O, P, LeftBracket, RightBracket, Backslash,
264    // Row 2
265    Fn, Shift, A, S, D, F, G, H, J, K, L, Semicolon, Apostrophe, Enter,
266    // Row 3
267    Ctrl, Opt, Alt, Z, X, C, V, B, N, M, Comma, Period, Slash, Space,
268}
269
270/// Defines the semantic behavior of a single key.
271#[derive(Debug, Clone, Copy, PartialEq, Eq)]
272enum KeymapEntry {
273    /// A character key with (normal, shifted) variants.
274    Char(char, char),
275    /// One of the [modifier][Modifier] keys (Shift, Fn, Ctrl, Opt, Alt)
276    Mod(Modifier),
277    /// The enter key
278    Enter,
279    Backspace,
280    Tab,
281}
282
283/// Mapping from TCA8418 reported key position to physical key.
284const PHYSICAL_KEYS: [[PhysicalKey; 14]; 4] = {
285    use PhysicalKey as Pk;
286    [
287        [
288            Pk::Backtick,
289            Pk::N1,
290            Pk::N2,
291            Pk::N3,
292            Pk::N4,
293            Pk::N5,
294            Pk::N6,
295            Pk::N7,
296            Pk::N8,
297            Pk::N9,
298            Pk::N0,
299            Pk::Minus,
300            Pk::Equal,
301            Pk::Backspace,
302        ],
303        [
304            Pk::Tab,
305            Pk::Q,
306            Pk::W,
307            Pk::E,
308            Pk::R,
309            Pk::T,
310            Pk::Y,
311            Pk::U,
312            Pk::I,
313            Pk::O,
314            Pk::P,
315            Pk::LeftBracket,
316            Pk::RightBracket,
317            Pk::Backslash,
318        ],
319        [
320            Pk::Fn,
321            Pk::Shift,
322            Pk::A,
323            Pk::S,
324            Pk::D,
325            Pk::F,
326            Pk::G,
327            Pk::H,
328            Pk::J,
329            Pk::K,
330            Pk::L,
331            Pk::Semicolon,
332            Pk::Apostrophe,
333            Pk::Enter,
334        ],
335        [
336            Pk::Ctrl,
337            Pk::Opt,
338            Pk::Alt,
339            Pk::Z,
340            Pk::X,
341            Pk::C,
342            Pk::V,
343            Pk::B,
344            Pk::N,
345            Pk::M,
346            Pk::Comma,
347            Pk::Period,
348            Pk::Slash,
349            Pk::Space,
350        ],
351    ]
352};
353
354/// Maps each physical key to its behavior.
355///
356/// This is a mapping that maps what each key on the keyboard actually produces when pressed.
357/// This also includes multiple layers if the key supports it.
358fn keymap(key: PhysicalKey) -> KeymapEntry {
359    use KeymapEntry::*;
360    use Modifier as Mo;
361
362    match key {
363        // Row 0
364        PhysicalKey::Backtick => Char('`', '~'),
365        PhysicalKey::N1 => Char('1', '!'),
366        PhysicalKey::N2 => Char('2', '@'),
367        PhysicalKey::N3 => Char('3', '#'),
368        PhysicalKey::N4 => Char('4', '$'),
369        PhysicalKey::N5 => Char('5', '%'),
370        PhysicalKey::N6 => Char('6', '^'),
371        PhysicalKey::N7 => Char('7', '&'),
372        PhysicalKey::N8 => Char('8', '*'),
373        PhysicalKey::N9 => Char('9', '('),
374        PhysicalKey::N0 => Char('0', ')'),
375        PhysicalKey::Minus => Char('-', '_'),
376        PhysicalKey::Equal => Char('=', '+'),
377        PhysicalKey::Backspace => Backspace,
378
379        // Row 1
380        PhysicalKey::Tab => Tab,
381        PhysicalKey::Q => Char('q', 'Q'),
382        PhysicalKey::W => Char('w', 'W'),
383        PhysicalKey::E => Char('e', 'E'),
384        PhysicalKey::R => Char('r', 'R'),
385        PhysicalKey::T => Char('t', 'T'),
386        PhysicalKey::Y => Char('y', 'Y'),
387        PhysicalKey::U => Char('u', 'U'),
388        PhysicalKey::I => Char('i', 'I'),
389        PhysicalKey::O => Char('o', 'O'),
390        PhysicalKey::P => Char('p', 'P'),
391        PhysicalKey::LeftBracket => Char('[', '{'),
392        PhysicalKey::RightBracket => Char(']', '}'),
393        PhysicalKey::Backslash => Char('\\', '|'),
394
395        // Row 2
396        PhysicalKey::Fn => Mod(Mo::Fn),
397        PhysicalKey::Shift => Mod(Mo::Shift),
398        PhysicalKey::A => Char('a', 'A'),
399        PhysicalKey::S => Char('s', 'S'),
400        PhysicalKey::D => Char('d', 'D'),
401        PhysicalKey::F => Char('f', 'F'),
402        PhysicalKey::G => Char('g', 'G'),
403        PhysicalKey::H => Char('h', 'H'),
404        PhysicalKey::J => Char('j', 'J'),
405        PhysicalKey::K => Char('k', 'K'),
406        PhysicalKey::L => Char('l', 'L'),
407        PhysicalKey::Semicolon => Char(';', ':'),
408        PhysicalKey::Apostrophe => Char('\'', '"'),
409        PhysicalKey::Enter => Enter,
410
411        // Row 3
412        PhysicalKey::Ctrl => Mod(Mo::Ctrl),
413        PhysicalKey::Opt => Mod(Mo::Opt),
414        PhysicalKey::Alt => Mod(Mo::Alt),
415        PhysicalKey::Z => Char('z', 'Z'),
416        PhysicalKey::X => Char('x', 'X'),
417        PhysicalKey::C => Char('c', 'C'),
418        PhysicalKey::V => Char('v', 'V'),
419        PhysicalKey::B => Char('b', 'B'),
420        PhysicalKey::N => Char('n', 'N'),
421        PhysicalKey::M => Char('m', 'M'),
422        PhysicalKey::Comma => Char(',', '<'),
423        PhysicalKey::Period => Char('.', '>'),
424        PhysicalKey::Slash => Char('/', '?'),
425        PhysicalKey::Space => Char(' ', ' '),
426    }
427}
428
429/// State that tracks which modifier keys are currently held down.
430#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
431#[cfg_attr(feature = "defmt", derive(defmt::Format))]
432pub struct ModifierState {
433    pub shift: bool,
434    pub fn_key: bool,
435    pub ctrl: bool,
436    pub opt: bool,
437    pub alt: bool,
438}
439
440/// High-level keyboard driver for the Cardputer-Adv.
441///
442/// The idea is to make getting input from the keyboard as easy as possible
443/// while also exposing the raw key presses for more advanced use cases.
444///
445/// # Getting started
446///
447/// Create a [`Keyboard`] from [`I2c`] to create the keyboard instance and configure the hardware.
448///
449/// ```rust,no_run
450/// # fn example(i2c: impl embedded_hal::i2c::I2c) {
451/// use tca8418::Tca8418;
452/// use cardputer_adv_keyboard::Keyboard;
453///
454/// let mut keyboard = Keyboard::new(i2c).unwrap();
455/// # }
456/// ```
457///
458/// # Basic usage
459///
460/// Get an Iterator over [`KeyInput`]s by using [.inputs()](`Keyboard::inputs`).
461/// A [`KeyInput`] encompasses everything that is printed on the keyboard.
462///
463/// For example, pressing the `w` key results in [`KeyInput::Char('w')`](KeyInput::Char).
464/// If you press `w` while holding Shift (`Aa` key) you get
465/// [`KeyInput::Char('W')`](KeyInput::Char). The same goes for every other key
466/// that represents a character.
467///
468/// The function keys (Enter, Escape, Modifier keys, etc.)
469/// have their own [`KeyInput`] variant.
470///
471/// Using this, getting text input is as easy as:
472///
473/// ```rust,no_run
474/// # fn example(keyboard: &mut cardputer_adv_keyboard::Keyboard<impl embedded_hal::i2c::I2c>) {
475/// use cardputer_adv_keyboard::KeyInput;
476///
477/// for input in keyboard.inputs().unwrap() {
478///     match input {
479///         KeyInput::Char(c) => { /* Do something with the input character */}
480///         KeyInput::Backspace => { /* Handle backspace */}
481///         KeyInput::Enter => { /* Submit */ }
482///         _ => {}
483///     }
484/// }
485/// # }
486/// ```
487///
488/// # Advanced usage
489///  
490/// If you need more detailed information about key events like released keys or currently held modifiers
491/// (for games, custom bindings, etc.), you can use [.events()](`Keyboard::events`) get an Iterator over
492/// all pending [`KeyboardEvents`](KeyboardEvent).
493///
494/// In addition to an optional [`input`](KeyboardEvent::input), each [`KeyboardEvent`] also has the following fields:
495///
496/// - [`physical_key`](KeyboardEvent::physical_key): a [`PhysicalKey`] identifying
497///   which key on the keyboard caused this event, regardless of modifier state.
498/// - [`state`](KeyboardEvent::state): whether it was a
499///   [`Pressed`](KeyState::Pressed) or [`Released`](KeyState::Released) event.
500/// - [`modifiers`](KeyboardEvent::modifiers): a [`ModifierState`]
501///   showing which modifiers were held at the time of the event.
502///
503/// For example, detecting a Ctrl+C combination:
504///
505/// ```rust,no_run
506/// # fn example(event: cardputer_adv_keyboard::KeyboardEvent) {
507/// use cardputer_adv_keyboard::PhysicalKey;
508///
509/// match (event.physical_key, event.modifiers.ctrl) {
510///     (PhysicalKey::C, true) => { /* handle Ctrl+C */ }
511///     _ => {}
512/// }
513/// # }
514/// ```
515///
516/// # Iterator convenience methods
517/// ```rust,no_run
518/// # fn example(keyboard: &mut cardputer_adv_keyboard::Keyboard<impl embedded_hal::i2c::I2c>) {
519/// // Only resolved inputs (skips releases automatically)
520/// // This is what most people would need from a keyboard library.
521/// keyboard.inputs().unwrap();
522///
523/// // If you need every single event (including releases, information about pressed modifiers)
524/// // you can use .events().
525/// let events = keyboard.events().unwrap();
526///
527/// // Only press events
528/// let key_presses = keyboard.events().unwrap().presses_only();
529/// // Only release events
530/// let key_releases = events.releases_only();
531/// // When using either of them you are throwing away all of the other events.
532/// # }
533/// ```
534pub struct Keyboard<I2C> {
535    tca8418: Tca8418<I2C>,
536    modifiers: ModifierState,
537}
538impl<I2C, E> Keyboard<I2C>
539where
540    I2C: I2c<Error = E>,
541{
542    /// Create a new keyboard driver instance and initialize it
543    pub fn new(i2c: I2C) -> Result<Self, tca8418::Error<E>> {
544        let mut keyboard = Self {
545            tca8418: Tca8418::new(i2c),
546            modifiers: ModifierState::default(),
547        };
548        keyboard.init()?;
549        Ok(keyboard)
550    }
551
552    /// Initialize the TCA8418 for the Cardputer-Adv keyboard.
553    ///
554    /// Configures 7 rows (R0–R6) × 8 columns (C0–C7) and drains any
555    /// stale events from the FIFO.
556    fn init(&mut self) -> Result<(), tca8418::Error<E>> {
557        let pins = PinMask::rows(0x7F) | PinMask::cols(0xFF);
558        self.tca8418.configure_keypad(pins)?;
559        while self.tca8418.read_event()?.is_some() {}
560        self.clear_interrupts()?;
561        Ok(())
562    }
563
564    /// Process a single raw TCA8418 event into a high-level keyboard event.
565    ///
566    /// Updates modifier state for modifier presses/releases. Returns a
567    /// [`KeyboardEvent`] with `input: Some(...)` for presses and
568    /// `input: None` for releases.
569    fn process_event(&mut self, event: tca8418::KeyEvent) -> Option<KeyboardEvent> {
570        let raw_key = match event.key {
571            tca8418::Key::KeypadMatrix(k) => k,
572            _ => return None,
573        };
574
575        let physical = Self::physical_key_from(raw_key.row, raw_key.col)?;
576        let entry = keymap(physical);
577        let state = if event.pressed {
578            KeyState::Pressed
579        } else {
580            KeyState::Released
581        };
582
583        if let KeymapEntry::Mod(m) = entry {
584            self.update_modifier(m, event.pressed);
585            return Some(KeyboardEvent {
586                input: if event.pressed {
587                    Some(KeyInput::Modifier(m))
588                } else {
589                    None
590                },
591                physical_key: physical,
592                state,
593                modifiers: self.modifiers,
594            });
595        }
596
597        Some(KeyboardEvent {
598            input: if event.pressed {
599                Some(self.resolve_key(physical))
600            } else {
601                None
602            },
603            physical_key: physical,
604            state,
605            modifiers: self.modifiers,
606        })
607    }
608
609    /// Read all pending events from the TCA8418 and return them as an iterator of [KeyInputs](KeyInput)
610    ///
611    /// This drains all events from the TCA8418 FIFO including key releases, which will be discarded.
612    /// If you also need key releases, use [.events()](Keyboard::events) instead.
613    pub fn inputs(&mut self) -> Result<impl Iterator<Item = KeyInput>, tca8418::Error<E>> {
614        Ok(self.events()?.inputs())
615    }
616
617    /// Read all pending events from the TCA8418 and return an Iterator over [KeyboardEvent].
618    ///
619    /// This drains all events from the TCA8418 FIFO.
620    pub fn events(&mut self) -> Result<KeyboardEventIter, tca8418::Error<E>> {
621        let mut events = [None; MAX_EVENTS];
622        let mut count = 0;
623
624        for raw in self.tca8418.events()? {
625            if let Some(event) = self.process_event(raw) {
626                events[count] = Some(event);
627                count += 1;
628            }
629        }
630
631        Ok(KeyboardEventIter {
632            events,
633            index: 0,
634            count,
635        })
636    }
637
638    /// Get a reference to the underlying TCA8418 driver.
639    pub fn tca8418(&self) -> &Tca8418<I2C> {
640        &self.tca8418
641    }
642
643    /// Get a mutable reference to the underlying TCA8418 driver.
644    pub fn tca8418_mut(&mut self) -> &mut Tca8418<I2C> {
645        &mut self.tca8418
646    }
647
648    /// Consume this keyboard and return the underlying TCA8418 driver.
649    pub fn into_inner(self) -> Tca8418<I2C> {
650        self.tca8418
651    }
652
653    /// Map a TCA8418 (row, col) to the physical key at that position.
654    fn physical_key_from(tca_row: u8, tca_col: u8) -> Option<PhysicalKey> {
655        let phys_row = (tca_col % 4) as usize;
656        let phys_col = if tca_col >= 4 {
657            tca_row as usize * 2 + 1
658        } else {
659            tca_row as usize * 2
660        };
661
662        if phys_row < 4 && phys_col < 14 {
663            Some(PHYSICAL_KEYS[phys_row][phys_col])
664        } else {
665            None
666        }
667    }
668
669    /// Resolve a keymap entry into a semantic input using the current
670    /// modifier state.
671    fn resolve_key(&self, physical_key: PhysicalKey) -> KeyInput {
672        let entry = keymap(physical_key);
673        match entry {
674            KeymapEntry::Char(normal, shifted) => {
675                if self.modifiers.fn_key {
676                    // Handle fn layer
677                    match physical_key {
678                        PhysicalKey::Backtick => KeyInput::Escape,
679                        PhysicalKey::Backslash => KeyInput::Delete,
680                        PhysicalKey::Semicolon => KeyInput::Arrow(Arrow::Up),
681                        PhysicalKey::Comma => KeyInput::Arrow(Arrow::Left),
682                        PhysicalKey::Period => KeyInput::Arrow(Arrow::Down),
683                        PhysicalKey::Slash => KeyInput::Arrow(Arrow::Right),
684                        _ => {
685                            if self.modifiers.shift {
686                                KeyInput::Char(shifted)
687                            } else {
688                                KeyInput::Char(normal)
689                            }
690                        }
691                    }
692                } else if self.modifiers.shift {
693                    KeyInput::Char(shifted)
694                } else {
695                    KeyInput::Char(normal)
696                }
697            }
698            KeymapEntry::Enter => KeyInput::Enter,
699            KeymapEntry::Backspace => {
700                if self.modifiers.fn_key {
701                    KeyInput::Delete
702                } else {
703                    KeyInput::Backspace
704                }
705            }
706            KeymapEntry::Tab => KeyInput::Tab,
707            KeymapEntry::Mod(m) => KeyInput::Modifier(m),
708        }
709    }
710
711    /// Update internal modifier state.
712    fn update_modifier(&mut self, modifier: Modifier, pressed: bool) {
713        match modifier {
714            Modifier::Shift => self.modifiers.shift = pressed,
715            Modifier::Fn => self.modifiers.fn_key = pressed,
716            Modifier::Ctrl => self.modifiers.ctrl = pressed,
717            Modifier::Opt => self.modifiers.opt = pressed,
718            Modifier::Alt => self.modifiers.alt = pressed,
719        }
720    }
721
722    /// Check if the TCA8418 has available key events in its FIFO
723    pub fn events_available(&mut self) -> Result<bool, tca8418::Error<E>> {
724        Ok(self.tca8418.event_count()? > 0)
725    }
726
727    /// See if the keyboard event interrupt status flag is set
728    pub fn has_key_interrupt_pending(&mut self) -> Result<bool, tca8418::Error<E>> {
729        self.tca8418.has_pending_key_event()
730    }
731
732    /// Enable keyboard event interrupts
733    pub fn enable_keyboard_interrupt(&mut self) -> Result<(), tca8418::Error<E>> {
734        self.tca8418.enable_key_event_interrupt(true)
735    }
736
737    /// Disable keyboard event interrupts
738    pub fn disable_keyboard_interrupt(&mut self) -> Result<(), tca8418::Error<E>> {
739        self.tca8418.enable_key_event_interrupt(false)
740    }
741
742    /// See if the overflow interrupt status flag is set
743    pub fn has_overflow_interrupt_pending(&mut self) -> Result<bool, tca8418::Error<E>> {
744        self.tca8418.has_pending_key_event()
745    }
746
747    /// Enable FIFO overflow interrupt
748    pub fn enable_overflow_interrupt(&mut self) -> Result<(), tca8418::Error<E>> {
749        self.tca8418.enable_overflow_interrupt(true)
750    }
751
752    /// Disable FIFO overflow interrupt
753    pub fn disable_overflow_interrupt(&mut self) -> Result<(), tca8418::Error<E>> {
754        self.tca8418.enable_overflow_interrupt(false)
755    }
756
757    /// Clear all interrupt flags.
758    pub fn clear_interrupts(&mut self) -> Result<(), tca8418::Error<E>> {
759        self.tca8418.clear_all_interrupts()
760    }
761
762    /// Clear the keyboard event interrupt flag.
763    pub fn clear_keyboard_interrupt(&mut self) -> Result<(), tca8418::Error<E>> {
764        self.tca8418.clear_interrupts(InterruptFlags::K_INT)
765    }
766
767    /// Clear the overflow interrupt flag.
768    pub fn clear_overflow_interrupt(&mut self) -> Result<(), tca8418::Error<E>> {
769        self.tca8418.clear_interrupts(InterruptFlags::OVR_FLOW_INT)
770    }
771}
772
773/// Iterator over processed keyboard events from a single [`Keyboard::events`] call.
774pub struct KeyboardEventIter {
775    events: [Option<KeyboardEvent>; MAX_EVENTS],
776    index: usize,
777    count: usize,
778}
779
780impl KeyboardEventIter {
781    /// Filter to only key-press events.
782    pub fn presses_only(self) -> impl Iterator<Item = KeyboardEvent> {
783        self.filter(|e| e.state.is_pressed())
784    }
785
786    /// Filter to only key-release events.
787    pub fn releases_only(self) -> impl Iterator<Item = KeyboardEvent> {
788        self.filter(|e| e.state.is_released())
789    }
790
791    /// Extract just the resolved inputs, skipping key releases.
792    pub fn inputs(self) -> impl Iterator<Item = KeyInput> {
793        self.filter_map(|e| e.input)
794    }
795}
796
797impl Iterator for KeyboardEventIter {
798    type Item = KeyboardEvent;
799
800    fn next(&mut self) -> Option<Self::Item> {
801        if self.index >= self.count {
802            return None;
803        }
804        let event = self.events[self.index].take();
805        self.index += 1;
806        event
807    }
808
809    fn size_hint(&self) -> (usize, Option<usize>) {
810        let remaining = self.count - self.index;
811        (remaining, Some(remaining))
812    }
813}
814
815impl ExactSizeIterator for KeyboardEventIter {}