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 {}