From ea01fe2071a6416a8da07741cf93e66b38a45d56 Mon Sep 17 00:00:00 2001 From: Brandon Maier Date: Sat, 25 Jul 2026 15:26:40 -0500 Subject: [PATCH] Multikey support Signed-off-by: Nicholas Mello --- src/keyboard.rs | 16 +++---- src/main.rs | 24 ++++++----- src/usb.rs | 110 +++++++++++++++--------------------------------- 3 files changed, 56 insertions(+), 94 deletions(-) diff --git a/src/keyboard.rs b/src/keyboard.rs index 8cc03ee..a4ddaef 100644 --- a/src/keyboard.rs +++ b/src/keyboard.rs @@ -1,4 +1,4 @@ -use crate::usb::KeyboardEvent; +use alloc::vec::Vec; use embassy_rp::gpio::Input; use embassy_sync::blocking_mutex::raw::RawMutex; use embassy_sync::channel::Sender; @@ -46,7 +46,7 @@ impl<'d, const KEY_N: usize> Keyboard<'d, KEY_N> { 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, N>) where M: RawMutex, { @@ -57,14 +57,14 @@ impl<'d, const KEY_N: usize> Keyboard<'d, KEY_N> { .collect::>() .next() .await; + + let mut pressed: Vec = Vec::new(); for key in self.keys.iter_mut().filter_map(|opt| opt.as_mut()) { - sender - .send(KeyboardEvent { - key: key.value, - action: key.button.get_level().into(), - }) - .await; + if key.button.is_low() { + pressed.push(key.value); + } } + sender.send(pressed).await; } } } diff --git a/src/main.rs b/src/main.rs index d0e1fd1..3086845 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,8 +5,10 @@ mod heartbeat; mod keyboard; mod usb; +extern crate alloc; use crate::heartbeat::heartbeat; use crate::keyboard::Keyboard; +use alloc::vec::Vec; use defmt::*; use embassy_executor::Spawner; use embassy_futures::join::join; @@ -37,7 +39,7 @@ async fn main(_spawner: Spawner) { ); } - let keyboard_events: Channel = Channel::new(); + let keyboard_events: Channel, 64> = Channel::new(); 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); signal_pin.set_schmitt(true); - match keyboard.add_key(signal_pin, 'a') { - Ok(()) => info!("Key 'a' registered"), + match keyboard.add_key(signal_pin, 's') { + Ok(()) => info!("Key 's' registered"), Err(e) => { defmt::panic!("Failed to register key! {:?}", e); } } let mut signal_pin = Input::new(p.PIN_17, Pull::None); signal_pin.set_schmitt(true); - match keyboard.add_key(signal_pin, 'a') { - Ok(()) => info!("Key 'a' registered"), + match keyboard.add_key(signal_pin, 'x') { + Ok(()) => info!("Key 'x' registered"), Err(e) => { defmt::panic!("Failed to register key! {:?}", e); } } let mut signal_pin = Input::new(p.PIN_18, Pull::None); signal_pin.set_schmitt(true); - match keyboard.add_key(signal_pin, 'a') { - Ok(()) => info!("Key 'a' registered"), + match keyboard.add_key(signal_pin, 'd') { + Ok(()) => info!("Key 'd' registered"), Err(e) => { defmt::panic!("Failed to register key! {:?}", e); } } let mut signal_pin = Input::new(p.PIN_19, Pull::None); signal_pin.set_schmitt(true); - match keyboard.add_key(signal_pin, 'a') { - Ok(()) => info!("Key 'a' registered"), + match keyboard.add_key(signal_pin, 'c') { + Ok(()) => info!("Key 'c' registered"), Err(e) => { defmt::panic!("Failed to register key! {:?}", e); } } let mut signal_pin = Input::new(p.PIN_20, Pull::None); signal_pin.set_schmitt(true); - match keyboard.add_key(signal_pin, 'a') { - Ok(()) => info!("Key 'a' registered"), + match keyboard.add_key(signal_pin, 'w') { + Ok(()) => info!("Key 'w' registered"), Err(e) => { defmt::panic!("Failed to register key! {:?}", e); } diff --git a/src/usb.rs b/src/usb.rs index fafe632..f5146bf 100644 --- a/src/usb.rs +++ b/src/usb.rs @@ -1,8 +1,8 @@ +use alloc::vec::Vec; use core::cell::OnceCell; use core::sync::atomic::{AtomicBool, AtomicU8, Ordering}; use defmt::*; use embassy_futures::join::join; -use embassy_rp::gpio::Level; use embassy_rp::peripherals::USB; use embassy_rp::usb::Driver; 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); -#[derive(Clone, Copy)] -pub enum KeyboardAction { - Press, - Depress, -} - -impl From 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> { // Create embassy-usb DeviceBuilder using the driver and config. // 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, N>) where M: RawMutex, { @@ -148,58 +127,39 @@ impl<'d> UsbKeyboard<'d> { loop { let event = receiver.receive().await; - match event { - KeyboardEvent { - key: 'a', - action: KeyboardAction::Press, - } => { - if HID_PROTOCOL_MODE.load(Ordering::Relaxed) == HidProtocolMode::Boot as u8 - { - match writer.write(&[0, 0, 4, 0, 0, 0, 0, 0]).await { - Ok(()) => {} - Err(e) => warn!("Failed to send boot report: {:?}", e), - }; - } else { - // Create a report with the A key pressed. (no shift modifier) - let report = KeyboardReport { - keycodes: [4, 0, 0, 0, 0, 0], - leds: 0, - modifier: 0, - reserved: 0, - }; - // Send the report. - match writer.write_serialize(&report).await { - 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!"); - } + let mut boot_keys = [0, 0, 0, 0, 0, 0, 0, 0]; + + for (&key, idx) in event.iter().zip(2usize..) { + let boot_key = match key { + 'd' => 79, + 'a' => 80, + 's' => 81, + '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(()) => {} + Err(e) => warn!("Failed to send boot report: {:?}", e), + }; + } else { + defmt::unimplemented!("Only supports boot mode keyboards!"); + // // Create a report with the A key pressed. (no shift modifier) + // let report = KeyboardReport { + // keycodes: [4, 0, 0, 0, 0, 0], + // leds: 0, + // modifier: 0, + // reserved: 0, + // }; + // // Send the report. + // match writer.write_serialize(&report).await { + // Ok(()) => {} + // Err(e) => warn!("Failed to send report: {:?}", e), + // }; } } };