use crate::timer::Timer;
use crate::usb::control::{
get_configuration_descriptor, set_configuration, set_idle, set_protocol,
};
use crate::usb::descriptor::ConfigurationDescriptor;
use crate::usb::dwc2::{Channel, ControlEndpoint, TransferError};
use crate::usb::hid::{is_boot_interface, HidInterface, BOOT_PROTOCOL};
use crate::usb::Device;
const PROTOCOL_KEYBOARD: u8 = 1;
const FIRST_KEY_USAGE: u8 = 4;
const KEY_SLOTS: usize = 6;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct Modifiers(
pub u8,
);
impl Modifiers {
pub fn left_ctrl(&self) -> bool {
self.0 & (1 << 0) != 0
}
pub fn left_shift(&self) -> bool {
self.0 & (1 << 1) != 0
}
pub fn left_alt(&self) -> bool {
self.0 & (1 << 2) != 0
}
pub fn left_gui(&self) -> bool {
self.0 & (1 << 3) != 0
}
pub fn right_ctrl(&self) -> bool {
self.0 & (1 << 4) != 0
}
pub fn right_shift(&self) -> bool {
self.0 & (1 << 5) != 0
}
pub fn right_alt(&self) -> bool {
self.0 & (1 << 6) != 0
}
pub fn right_gui(&self) -> bool {
self.0 & (1 << 7) != 0
}
pub fn shift(&self) -> bool {
self.left_shift() || self.right_shift()
}
pub fn ctrl(&self) -> bool {
self.left_ctrl() || self.right_ctrl()
}
pub fn alt(&self) -> bool {
self.left_alt() || self.right_alt()
}
pub fn gui(&self) -> bool {
self.left_gui() || self.right_gui()
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct KeyboardReport {
pub modifiers: Modifiers,
pub keys: [u8; KEY_SLOTS],
}
impl KeyboardReport {
const fn empty() -> Self {
Self {
modifiers: Modifiers(0),
keys: [0; KEY_SLOTS],
}
}
pub fn parse(report: &[u8]) -> Option<Self> {
if report.len() < 8 {
return None;
}
let mut keys = [0u8; KEY_SLOTS];
keys.copy_from_slice(&report[2..8]);
Some(Self {
modifiers: Modifiers(report[0]),
keys,
})
}
pub fn pressed_keys(&self) -> impl Iterator<Item = u8> + '_ {
self.keys.iter().copied().filter(|&k| k >= FIRST_KEY_USAGE)
}
pub fn boot_report(&self) -> [u8; 8] {
let mut report = [0u8; 8];
report[0] = self.modifiers.0;
report[2..8].copy_from_slice(&self.keys);
report
}
fn holds(&self, usage: u8) -> bool {
self.keys.contains(&usage)
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum KeyEvent {
Pressed(u8),
Released(u8),
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct KeyEvents {
previous: KeyboardReport,
current: KeyboardReport,
}
impl KeyEvents {
pub fn report(&self) -> &KeyboardReport {
&self.current
}
pub fn iter(&self) -> KeyEventIter<'_> {
KeyEventIter {
events: self,
releases_done: false,
index: 0,
}
}
}
pub struct KeyEventIter<'a> {
events: &'a KeyEvents,
releases_done: bool,
index: usize,
}
impl Iterator for KeyEventIter<'_> {
type Item = KeyEvent;
fn next(&mut self) -> Option<KeyEvent> {
if !self.releases_done {
while self.index < KEY_SLOTS {
let usage = self.events.previous.keys[self.index];
self.index += 1;
if usage >= FIRST_KEY_USAGE && !self.events.current.holds(usage) {
return Some(KeyEvent::Released(usage));
}
}
self.releases_done = true;
self.index = 0;
}
while self.index < KEY_SLOTS {
let usage = self.events.current.keys[self.index];
self.index += 1;
if usage >= FIRST_KEY_USAGE && !self.events.previous.holds(usage) {
return Some(KeyEvent::Pressed(usage));
}
}
None
}
}
pub struct Keyboard {
endpoint: ControlEndpoint,
interface: u8,
report_endpoint: u8,
toggle: bool,
previous: KeyboardReport,
}
impl Keyboard {
pub fn from_device(
channel: &mut Channel,
timer: &Timer,
device: Device,
) -> Result<Option<Keyboard>, TransferError> {
let mut config = [0u8; 64];
let len = get_configuration_descriptor(channel, timer, device.endpoint, 0, &mut config)?;
let Some(interface) = HidInterface::find(&config[..len], |iface| {
is_boot_interface(iface, PROTOCOL_KEYBOARD)
}) else {
return Ok(None);
};
let Some(config_value) = ConfigurationDescriptor::parse(&config[..len]).map(|c| c.value())
else {
return Ok(None);
};
set_configuration(channel, timer, device.endpoint, config_value)?;
set_protocol(
channel,
timer,
device.endpoint,
interface.interface,
BOOT_PROTOCOL,
)?;
let _ = set_idle(channel, timer, device.endpoint, interface.interface, 0);
Ok(Some(Keyboard {
endpoint: ControlEndpoint {
max_packet_size: interface.max_packet_size,
..device.endpoint
},
interface: interface.interface,
report_endpoint: interface.endpoint,
toggle: false,
previous: KeyboardReport::empty(),
}))
}
pub fn interface(&self) -> u8 {
self.interface
}
pub fn report_endpoint(&self) -> u8 {
self.report_endpoint
}
pub fn max_packet_size(&self) -> u16 {
self.endpoint.max_packet_size
}
pub fn poll(
&mut self,
channel: &mut Channel,
timer: &Timer,
) -> Result<Option<KeyEvents>, TransferError> {
let mut buffer = [0u8; 8];
let received = match channel.interrupt_in(
self.endpoint,
self.report_endpoint,
&mut self.toggle,
&mut buffer,
timer,
) {
Ok(received) => received,
Err(TransferError::Nak) => return Ok(None),
Err(error) => return Err(error),
};
let Some(current) = KeyboardReport::parse(&buffer[..received]) else {
return Ok(None);
};
let previous = self.previous;
self.previous = current;
Ok(Some(KeyEvents { previous, current }))
}
}
pub fn usage_to_ascii(usage: u8, shift: bool) -> Option<char> {
let character = match usage {
0x04..=0x1d => {
let base = if shift { b'A' } else { b'a' };
(base + (usage - 0x04)) as char
}
0x1e..=0x26 => {
const SHIFTED: [u8; 9] = *b"!@#$%^&*(";
if shift {
SHIFTED[(usage - 0x1e) as usize] as char
} else {
(b'1' + (usage - 0x1e)) as char
}
}
0x27 if shift => ')',
0x27 => '0',
0x28 => '\n', 0x2a => '\u{8}', 0x2b => '\t', 0x2c => ' ', 0x2d if shift => '_',
0x2d => '-',
0x2e if shift => '+',
0x2e => '=',
0x2f if shift => '{',
0x2f => '[',
0x30 if shift => '}',
0x30 => ']',
0x31 if shift => '|',
0x31 => '\\',
0x33 if shift => ':',
0x33 => ';',
0x34 if shift => '"',
0x34 => '\'',
0x35 if shift => '~',
0x35 => '`',
0x36 if shift => '<',
0x36 => ',',
0x37 if shift => '>',
0x37 => '.',
0x38 if shift => '?',
0x38 => '/',
_ => return None,
};
Some(character)
}