Multikey support

Signed-off-by: Nicholas Mello <nick@nmello.dev>
This commit is contained in:
2026-07-25 15:26:40 -05:00
committed by Nick Mello
parent 2b99a56a4a
commit ea01fe2071
3 changed files with 56 additions and 94 deletions

View File

@@ -1,4 +1,4 @@
use crate::usb::KeyboardEvent; use alloc::vec::Vec;
use embassy_rp::gpio::Input; use embassy_rp::gpio::Input;
use embassy_sync::blocking_mutex::raw::RawMutex; use embassy_sync::blocking_mutex::raw::RawMutex;
use embassy_sync::channel::Sender; use embassy_sync::channel::Sender;
@@ -46,7 +46,7 @@ impl<'d, const KEY_N: usize> Keyboard<'d, KEY_N> {
Ok(()) Ok(())
} }
pub async fn process<'ch, M, const N: usize>(mut self, sender: Sender<'ch, M, KeyboardEvent, N>) pub async fn process<'ch, M, const N: usize>(mut self, sender: Sender<'ch, M, Vec<char>, N>)
where where
M: RawMutex, M: RawMutex,
{ {
@@ -57,14 +57,14 @@ impl<'d, const KEY_N: usize> Keyboard<'d, KEY_N> {
.collect::<FuturesUnordered<_>>() .collect::<FuturesUnordered<_>>()
.next() .next()
.await; .await;
let mut pressed: Vec<char> = Vec::new();
for key in self.keys.iter_mut().filter_map(|opt| opt.as_mut()) { for key in self.keys.iter_mut().filter_map(|opt| opt.as_mut()) {
sender if key.button.is_low() {
.send(KeyboardEvent { pressed.push(key.value);
key: key.value, }
action: key.button.get_level().into(), }
}) sender.send(pressed).await;
.await;
}
} }
} }
} }

View File

@@ -5,8 +5,10 @@ mod heartbeat;
mod keyboard; mod keyboard;
mod usb; mod usb;
extern crate alloc;
use crate::heartbeat::heartbeat; use crate::heartbeat::heartbeat;
use crate::keyboard::Keyboard; use crate::keyboard::Keyboard;
use alloc::vec::Vec;
use defmt::*; use defmt::*;
use embassy_executor::Spawner; use embassy_executor::Spawner;
use embassy_futures::join::join; use embassy_futures::join::join;
@@ -37,7 +39,7 @@ async fn main(_spawner: Spawner) {
); );
} }
let keyboard_events: Channel<ThreadModeRawMutex, usb::KeyboardEvent, 64> = Channel::new(); let keyboard_events: Channel<ThreadModeRawMutex, Vec<char>, 64> = Channel::new();
let p = embassy_rp::init(Default::default()); let p = embassy_rp::init(Default::default());
@@ -57,40 +59,40 @@ async fn main(_spawner: Spawner) {
} }
let mut signal_pin = Input::new(p.PIN_16, Pull::None); let mut signal_pin = Input::new(p.PIN_16, Pull::None);
signal_pin.set_schmitt(true); signal_pin.set_schmitt(true);
match keyboard.add_key(signal_pin, 'a') { match keyboard.add_key(signal_pin, 's') {
Ok(()) => info!("Key 'a' registered"), Ok(()) => info!("Key 's' registered"),
Err(e) => { Err(e) => {
defmt::panic!("Failed to register key! {:?}", e); defmt::panic!("Failed to register key! {:?}", e);
} }
} }
let mut signal_pin = Input::new(p.PIN_17, Pull::None); let mut signal_pin = Input::new(p.PIN_17, Pull::None);
signal_pin.set_schmitt(true); signal_pin.set_schmitt(true);
match keyboard.add_key(signal_pin, 'a') { match keyboard.add_key(signal_pin, 'x') {
Ok(()) => info!("Key 'a' registered"), Ok(()) => info!("Key 'x' registered"),
Err(e) => { Err(e) => {
defmt::panic!("Failed to register key! {:?}", e); defmt::panic!("Failed to register key! {:?}", e);
} }
} }
let mut signal_pin = Input::new(p.PIN_18, Pull::None); let mut signal_pin = Input::new(p.PIN_18, Pull::None);
signal_pin.set_schmitt(true); signal_pin.set_schmitt(true);
match keyboard.add_key(signal_pin, 'a') { match keyboard.add_key(signal_pin, 'd') {
Ok(()) => info!("Key 'a' registered"), Ok(()) => info!("Key 'd' registered"),
Err(e) => { Err(e) => {
defmt::panic!("Failed to register key! {:?}", e); defmt::panic!("Failed to register key! {:?}", e);
} }
} }
let mut signal_pin = Input::new(p.PIN_19, Pull::None); let mut signal_pin = Input::new(p.PIN_19, Pull::None);
signal_pin.set_schmitt(true); signal_pin.set_schmitt(true);
match keyboard.add_key(signal_pin, 'a') { match keyboard.add_key(signal_pin, 'c') {
Ok(()) => info!("Key 'a' registered"), Ok(()) => info!("Key 'c' registered"),
Err(e) => { Err(e) => {
defmt::panic!("Failed to register key! {:?}", e); defmt::panic!("Failed to register key! {:?}", e);
} }
} }
let mut signal_pin = Input::new(p.PIN_20, Pull::None); let mut signal_pin = Input::new(p.PIN_20, Pull::None);
signal_pin.set_schmitt(true); signal_pin.set_schmitt(true);
match keyboard.add_key(signal_pin, 'a') { match keyboard.add_key(signal_pin, 'w') {
Ok(()) => info!("Key 'a' registered"), Ok(()) => info!("Key 'w' registered"),
Err(e) => { Err(e) => {
defmt::panic!("Failed to register key! {:?}", e); defmt::panic!("Failed to register key! {:?}", e);
} }

View File

@@ -1,8 +1,8 @@
use alloc::vec::Vec;
use core::cell::OnceCell; use core::cell::OnceCell;
use core::sync::atomic::{AtomicBool, AtomicU8, Ordering}; use core::sync::atomic::{AtomicBool, AtomicU8, Ordering};
use defmt::*; use defmt::*;
use embassy_futures::join::join; use embassy_futures::join::join;
use embassy_rp::gpio::Level;
use embassy_rp::peripherals::USB; use embassy_rp::peripherals::USB;
use embassy_rp::usb::Driver; use embassy_rp::usb::Driver;
use embassy_sync::blocking_mutex::raw::RawMutex; use embassy_sync::blocking_mutex::raw::RawMutex;
@@ -18,27 +18,6 @@ use usbd_hid::descriptor::{KeyboardReport, SerializedDescriptor};
pub static HID_PROTOCOL_MODE: AtomicU8 = AtomicU8::new(HidProtocolMode::Boot as u8); pub static HID_PROTOCOL_MODE: AtomicU8 = AtomicU8::new(HidProtocolMode::Boot as u8);
#[derive(Clone, Copy)]
pub enum KeyboardAction {
Press,
Depress,
}
impl From<Level> for KeyboardAction {
fn from(value: Level) -> Self {
match value {
Level::High => KeyboardAction::Depress,
Level::Low => KeyboardAction::Press,
}
}
}
#[derive(Clone, Copy)]
pub struct KeyboardEvent {
pub key: char,
pub action: KeyboardAction,
}
pub struct UsbKeyboardBuf<'d> { pub struct UsbKeyboardBuf<'d> {
// Create embassy-usb DeviceBuilder using the driver and config. // Create embassy-usb DeviceBuilder using the driver and config.
// It needs some buffers for building the descriptors. // It needs some buffers for building the descriptors.
@@ -128,7 +107,7 @@ impl<'d> UsbKeyboard<'d> {
} }
} }
pub async fn run<'ch, M, const N: usize>(self, receiver: Receiver<'ch, M, KeyboardEvent, N>) pub async fn run<'ch, M, const N: usize>(self, receiver: Receiver<'ch, M, Vec<char>, N>)
where where
M: RawMutex, M: RawMutex,
{ {
@@ -148,58 +127,39 @@ impl<'d> UsbKeyboard<'d> {
loop { loop {
let event = receiver.receive().await; let event = receiver.receive().await;
match event { let mut boot_keys = [0, 0, 0, 0, 0, 0, 0, 0];
KeyboardEvent {
key: 'a', for (&key, idx) in event.iter().zip(2usize..) {
action: KeyboardAction::Press, let boot_key = match key {
} => { 'd' => 79,
if HID_PROTOCOL_MODE.load(Ordering::Relaxed) == HidProtocolMode::Boot as u8 'a' => 80,
{ 's' => 81,
match writer.write(&[0, 0, 4, 0, 0, 0, 0, 0]).await { 'w' => 82,
('a'..='z') => (key as u8) - b'a' + 4,
_ => defmt::panic!("Not supported key: {}", key),
};
boot_keys[idx] = boot_key;
}
if HID_PROTOCOL_MODE.load(Ordering::Relaxed) == HidProtocolMode::Boot as u8 {
match writer.write(&boot_keys).await {
Ok(()) => {} Ok(()) => {}
Err(e) => warn!("Failed to send boot report: {:?}", e), Err(e) => warn!("Failed to send boot report: {:?}", e),
}; };
} else { } else {
// Create a report with the A key pressed. (no shift modifier) defmt::unimplemented!("Only supports boot mode keyboards!");
let report = KeyboardReport { // // Create a report with the A key pressed. (no shift modifier)
keycodes: [4, 0, 0, 0, 0, 0], // let report = KeyboardReport {
leds: 0, // keycodes: [4, 0, 0, 0, 0, 0],
modifier: 0, // leds: 0,
reserved: 0, // modifier: 0,
}; // reserved: 0,
// Send the report. // };
match writer.write_serialize(&report).await { // // Send the report.
Ok(()) => {} // match writer.write_serialize(&report).await {
Err(e) => warn!("Failed to send report: {:?}", e), // Ok(()) => {}
}; // Err(e) => warn!("Failed to send report: {:?}", e),
} // };
}
KeyboardEvent {
key: 'a',
action: KeyboardAction::Depress,
} => {
if HID_PROTOCOL_MODE.load(Ordering::Relaxed) == HidProtocolMode::Boot as u8
{
match writer.write(&[0, 0, 0, 0, 0, 0, 0, 0]).await {
Ok(()) => {}
Err(e) => warn!("Failed to send boot report: {:?}", e),
};
} else {
let report = KeyboardReport {
keycodes: [0, 0, 0, 0, 0, 0],
leds: 0,
modifier: 0,
reserved: 0,
};
match writer.write_serialize(&report).await {
Ok(()) => {}
Err(e) => warn!("Failed to send report: {:?}", e),
};
}
}
_ => {
defmt::panic!("Unexpected event!");
}
} }
} }
}; };