#![no_std]
use embedded_hal::i2c::I2c;
use tca8418::{InterruptFlags, PinMask, Tca8418};
const MAX_EVENTS: usize = 10;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct KeyboardEvent {
pub input: Option<KeyInput>,
pub physical_key: PhysicalKey,
pub state: KeyState,
pub modifiers: ModifierState,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum KeyState {
Pressed,
Released,
}
impl KeyState {
pub fn is_pressed(self) -> bool {
matches!(self, KeyState::Pressed)
}
pub fn is_released(self) -> bool {
matches!(self, KeyState::Released)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum KeyInput {
Char(char),
Enter,
Backspace,
Delete,
Tab,
Escape,
Arrow(Arrow),
Modifier(Modifier),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Arrow {
Up,
Down,
Left,
Right,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Modifier {
Shift,
Fn,
Ctrl,
Opt,
Alt,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[rustfmt::skip]
pub enum PhysicalKey {
Backtick, N1, N2, N3, N4, N5, N6, N7, N8, N9, N0, Minus, Equal, Backspace,
Tab, Q, W, E, R, T, Y, U, I, O, P, LeftBracket, RightBracket, Backslash,
Fn, Shift, A, S, D, F, G, H, J, K, L, Semicolon, Apostrophe, Enter,
Ctrl, Opt, Alt, Z, X, C, V, B, N, M, Comma, Period, Slash, Space,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum KeymapEntry {
Char(char, char),
Mod(Modifier),
Enter,
Backspace,
Tab,
}
const PHYSICAL_KEYS: [[PhysicalKey; 14]; 4] = {
use PhysicalKey as Pk;
[
[
Pk::Backtick,
Pk::N1,
Pk::N2,
Pk::N3,
Pk::N4,
Pk::N5,
Pk::N6,
Pk::N7,
Pk::N8,
Pk::N9,
Pk::N0,
Pk::Minus,
Pk::Equal,
Pk::Backspace,
],
[
Pk::Tab,
Pk::Q,
Pk::W,
Pk::E,
Pk::R,
Pk::T,
Pk::Y,
Pk::U,
Pk::I,
Pk::O,
Pk::P,
Pk::LeftBracket,
Pk::RightBracket,
Pk::Backslash,
],
[
Pk::Fn,
Pk::Shift,
Pk::A,
Pk::S,
Pk::D,
Pk::F,
Pk::G,
Pk::H,
Pk::J,
Pk::K,
Pk::L,
Pk::Semicolon,
Pk::Apostrophe,
Pk::Enter,
],
[
Pk::Ctrl,
Pk::Opt,
Pk::Alt,
Pk::Z,
Pk::X,
Pk::C,
Pk::V,
Pk::B,
Pk::N,
Pk::M,
Pk::Comma,
Pk::Period,
Pk::Slash,
Pk::Space,
],
]
};
fn keymap(key: PhysicalKey) -> KeymapEntry {
use KeymapEntry::*;
use Modifier as Mo;
match key {
PhysicalKey::Backtick => Char('`', '~'),
PhysicalKey::N1 => Char('1', '!'),
PhysicalKey::N2 => Char('2', '@'),
PhysicalKey::N3 => Char('3', '#'),
PhysicalKey::N4 => Char('4', '$'),
PhysicalKey::N5 => Char('5', '%'),
PhysicalKey::N6 => Char('6', '^'),
PhysicalKey::N7 => Char('7', '&'),
PhysicalKey::N8 => Char('8', '*'),
PhysicalKey::N9 => Char('9', '('),
PhysicalKey::N0 => Char('0', ')'),
PhysicalKey::Minus => Char('-', '_'),
PhysicalKey::Equal => Char('=', '+'),
PhysicalKey::Backspace => Backspace,
PhysicalKey::Tab => Tab,
PhysicalKey::Q => Char('q', 'Q'),
PhysicalKey::W => Char('w', 'W'),
PhysicalKey::E => Char('e', 'E'),
PhysicalKey::R => Char('r', 'R'),
PhysicalKey::T => Char('t', 'T'),
PhysicalKey::Y => Char('y', 'Y'),
PhysicalKey::U => Char('u', 'U'),
PhysicalKey::I => Char('i', 'I'),
PhysicalKey::O => Char('o', 'O'),
PhysicalKey::P => Char('p', 'P'),
PhysicalKey::LeftBracket => Char('[', '{'),
PhysicalKey::RightBracket => Char(']', '}'),
PhysicalKey::Backslash => Char('\\', '|'),
PhysicalKey::Fn => Mod(Mo::Fn),
PhysicalKey::Shift => Mod(Mo::Shift),
PhysicalKey::A => Char('a', 'A'),
PhysicalKey::S => Char('s', 'S'),
PhysicalKey::D => Char('d', 'D'),
PhysicalKey::F => Char('f', 'F'),
PhysicalKey::G => Char('g', 'G'),
PhysicalKey::H => Char('h', 'H'),
PhysicalKey::J => Char('j', 'J'),
PhysicalKey::K => Char('k', 'K'),
PhysicalKey::L => Char('l', 'L'),
PhysicalKey::Semicolon => Char(';', ':'),
PhysicalKey::Apostrophe => Char('\'', '"'),
PhysicalKey::Enter => Enter,
PhysicalKey::Ctrl => Mod(Mo::Ctrl),
PhysicalKey::Opt => Mod(Mo::Opt),
PhysicalKey::Alt => Mod(Mo::Alt),
PhysicalKey::Z => Char('z', 'Z'),
PhysicalKey::X => Char('x', 'X'),
PhysicalKey::C => Char('c', 'C'),
PhysicalKey::V => Char('v', 'V'),
PhysicalKey::B => Char('b', 'B'),
PhysicalKey::N => Char('n', 'N'),
PhysicalKey::M => Char('m', 'M'),
PhysicalKey::Comma => Char(',', '<'),
PhysicalKey::Period => Char('.', '>'),
PhysicalKey::Slash => Char('/', '?'),
PhysicalKey::Space => Char(' ', ' '),
}
}
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct ModifierState {
pub shift: bool,
pub fn_key: bool,
pub ctrl: bool,
pub opt: bool,
pub alt: bool,
}
pub struct Keyboard<I2C> {
tca8418: Tca8418<I2C>,
modifiers: ModifierState,
}
impl<I2C, E> Keyboard<I2C>
where
I2C: I2c<Error = E>,
{
pub fn new(i2c: I2C) -> Result<Self, tca8418::Error<E>> {
let mut keyboard = Self {
tca8418: Tca8418::new(i2c),
modifiers: ModifierState::default(),
};
keyboard.init()?;
Ok(keyboard)
}
fn init(&mut self) -> Result<(), tca8418::Error<E>> {
let pins = PinMask::rows(0x7F) | PinMask::cols(0xFF);
self.tca8418.configure_keypad(pins)?;
while self.tca8418.read_event()?.is_some() {}
self.clear_interrupts()?;
Ok(())
}
fn process_event(&mut self, event: tca8418::KeyEvent) -> Option<KeyboardEvent> {
let raw_key = match event.key {
tca8418::Key::KeypadMatrix(k) => k,
_ => return None,
};
let physical = Self::physical_key_from(raw_key.row, raw_key.col)?;
let entry = keymap(physical);
let state = if event.pressed {
KeyState::Pressed
} else {
KeyState::Released
};
if let KeymapEntry::Mod(m) = entry {
self.update_modifier(m, event.pressed);
return Some(KeyboardEvent {
input: if event.pressed {
Some(KeyInput::Modifier(m))
} else {
None
},
physical_key: physical,
state,
modifiers: self.modifiers,
});
}
Some(KeyboardEvent {
input: if event.pressed {
Some(self.resolve_key(physical))
} else {
None
},
physical_key: physical,
state,
modifiers: self.modifiers,
})
}
pub fn inputs(&mut self) -> Result<impl Iterator<Item = KeyInput>, tca8418::Error<E>> {
Ok(self.events()?.inputs())
}
pub fn events(&mut self) -> Result<KeyboardEventIter, tca8418::Error<E>> {
let mut events = [None; MAX_EVENTS];
let mut count = 0;
for raw in self.tca8418.events()? {
if let Some(event) = self.process_event(raw) {
events[count] = Some(event);
count += 1;
}
}
Ok(KeyboardEventIter {
events,
index: 0,
count,
})
}
pub fn tca8418(&self) -> &Tca8418<I2C> {
&self.tca8418
}
pub fn tca8418_mut(&mut self) -> &mut Tca8418<I2C> {
&mut self.tca8418
}
pub fn into_inner(self) -> Tca8418<I2C> {
self.tca8418
}
fn physical_key_from(tca_row: u8, tca_col: u8) -> Option<PhysicalKey> {
let phys_row = (tca_col % 4) as usize;
let phys_col = if tca_col >= 4 {
tca_row as usize * 2 + 1
} else {
tca_row as usize * 2
};
if phys_row < 4 && phys_col < 14 {
Some(PHYSICAL_KEYS[phys_row][phys_col])
} else {
None
}
}
fn resolve_key(&self, physical_key: PhysicalKey) -> KeyInput {
let entry = keymap(physical_key);
match entry {
KeymapEntry::Char(normal, shifted) => {
if self.modifiers.fn_key {
match physical_key {
PhysicalKey::Backtick => KeyInput::Escape,
PhysicalKey::Backslash => KeyInput::Delete,
PhysicalKey::Semicolon => KeyInput::Arrow(Arrow::Up),
PhysicalKey::Comma => KeyInput::Arrow(Arrow::Left),
PhysicalKey::Period => KeyInput::Arrow(Arrow::Down),
PhysicalKey::Slash => KeyInput::Arrow(Arrow::Right),
_ => {
if self.modifiers.shift {
KeyInput::Char(shifted)
} else {
KeyInput::Char(normal)
}
}
}
} else if self.modifiers.shift {
KeyInput::Char(shifted)
} else {
KeyInput::Char(normal)
}
}
KeymapEntry::Enter => KeyInput::Enter,
KeymapEntry::Backspace => {
if self.modifiers.fn_key {
KeyInput::Delete
} else {
KeyInput::Backspace
}
}
KeymapEntry::Tab => KeyInput::Tab,
KeymapEntry::Mod(m) => KeyInput::Modifier(m),
}
}
fn update_modifier(&mut self, modifier: Modifier, pressed: bool) {
match modifier {
Modifier::Shift => self.modifiers.shift = pressed,
Modifier::Fn => self.modifiers.fn_key = pressed,
Modifier::Ctrl => self.modifiers.ctrl = pressed,
Modifier::Opt => self.modifiers.opt = pressed,
Modifier::Alt => self.modifiers.alt = pressed,
}
}
pub fn events_available(&mut self) -> Result<bool, tca8418::Error<E>> {
Ok(self.tca8418.event_count()? > 0)
}
pub fn has_key_interrupt_pending(&mut self) -> Result<bool, tca8418::Error<E>> {
self.tca8418.has_pending_key_event()
}
pub fn enable_keyboard_interrupt(&mut self) -> Result<(), tca8418::Error<E>> {
self.tca8418.enable_key_event_interrupt(true)
}
pub fn disable_keyboard_interrupt(&mut self) -> Result<(), tca8418::Error<E>> {
self.tca8418.enable_key_event_interrupt(false)
}
pub fn has_overflow_interrupt_pending(&mut self) -> Result<bool, tca8418::Error<E>> {
self.tca8418.has_pending_key_event()
}
pub fn enable_overflow_interrupt(&mut self) -> Result<(), tca8418::Error<E>> {
self.tca8418.enable_overflow_interrupt(true)
}
pub fn disable_overflow_interrupt(&mut self) -> Result<(), tca8418::Error<E>> {
self.tca8418.enable_overflow_interrupt(false)
}
pub fn clear_interrupts(&mut self) -> Result<(), tca8418::Error<E>> {
self.tca8418.clear_all_interrupts()
}
pub fn clear_keyboard_interrupt(&mut self) -> Result<(), tca8418::Error<E>> {
self.tca8418.clear_interrupts(InterruptFlags::K_INT)
}
pub fn clear_overflow_interrupt(&mut self) -> Result<(), tca8418::Error<E>> {
self.tca8418.clear_interrupts(InterruptFlags::OVR_FLOW_INT)
}
}
pub struct KeyboardEventIter {
events: [Option<KeyboardEvent>; MAX_EVENTS],
index: usize,
count: usize,
}
impl KeyboardEventIter {
pub fn presses_only(self) -> impl Iterator<Item = KeyboardEvent> {
self.filter(|e| e.state.is_pressed())
}
pub fn releases_only(self) -> impl Iterator<Item = KeyboardEvent> {
self.filter(|e| e.state.is_released())
}
pub fn inputs(self) -> impl Iterator<Item = KeyInput> {
self.filter_map(|e| e.input)
}
}
impl Iterator for KeyboardEventIter {
type Item = KeyboardEvent;
fn next(&mut self) -> Option<Self::Item> {
if self.index >= self.count {
return None;
}
let event = self.events[self.index].take();
self.index += 1;
event
}
fn size_hint(&self) -> (usize, Option<usize>) {
let remaining = self.count - self.index;
(remaining, Some(remaining))
}
}
impl ExactSizeIterator for KeyboardEventIter {}