161 lines
4.8 KiB
Rust
161 lines
4.8 KiB
Rust
#![allow(dead_code)]
|
|
|
|
use crate::{button::Modifier, keys::Key};
|
|
use bytemuck::{cast_ref, Pod, Zeroable};
|
|
use core::mem::size_of;
|
|
|
|
/// KeyboardReport describes a report and its companion descriptor that can be
|
|
/// used to send keyboard button presses to a host and receive the status of the
|
|
/// keyboard LEDs.
|
|
///
|
|
/// Unlike usbd_hids KeyboardReport, this one supports N-key rollover.
|
|
#[derive(Clone, Copy, PartialEq, Eq, Zeroable, Pod)]
|
|
#[cfg(feature = "n-key-rollover")]
|
|
#[repr(C, packed)]
|
|
pub struct KeyboardReport {
|
|
pub modifier: u8,
|
|
|
|
/// Bitmap representing all keycodes from 0 to 215
|
|
pub keycodes: [u8; 27],
|
|
}
|
|
|
|
#[cfg(not(feature = "n-key-rollover"))]
|
|
pub use ::usbd_hid::descriptor::KeyboardReport;
|
|
|
|
#[cfg(feature = "n-key-rollover")]
|
|
pub const EMPTY_KEYBOARD_REPORT: KeyboardReport = KeyboardReport {
|
|
modifier: 0,
|
|
keycodes: [0; 27],
|
|
};
|
|
|
|
#[cfg(not(feature = "n-key-rollover"))]
|
|
pub const EMPTY_KEYBOARD_REPORT: KeyboardReport = KeyboardReport {
|
|
modifier: 0,
|
|
leds: 0,
|
|
reserved: 0,
|
|
keycodes: [0; 6],
|
|
};
|
|
|
|
/// Get the byte index, and the mask for that byte, in the keycode bitmap.
|
|
fn key_to_byte_mask(key: Key) -> (usize, u8) {
|
|
let keycode = u8::from(key);
|
|
let byte = keycode >> 3;
|
|
let bit = keycode & 0b111;
|
|
let mask = 1 << bit;
|
|
|
|
(usize::from(byte), mask)
|
|
}
|
|
|
|
#[cfg(feature = "n-key-rollover")]
|
|
impl KeyboardReport {
|
|
#[inline(always)]
|
|
pub fn set_key(&mut self, key: Key, pressed: bool) {
|
|
let (byte_i, mask) = key_to_byte_mask(key);
|
|
|
|
if let Some(k) = self.keycodes.get_mut(byte_i) {
|
|
if pressed {
|
|
*k |= mask;
|
|
} else {
|
|
*k &= !mask;
|
|
}
|
|
} else {
|
|
log::warn!("Tried to set out-of-range keycode: 0x{:x}", u8::from(key));
|
|
}
|
|
}
|
|
|
|
#[inline(always)]
|
|
pub fn press_key(&mut self, key: Key) {
|
|
self.set_key(key, true)
|
|
}
|
|
|
|
#[inline(always)]
|
|
pub fn release_key(&mut self, key: Key) {
|
|
self.set_key(key, false)
|
|
}
|
|
|
|
#[inline(always)]
|
|
pub fn key_pressed(&mut self, key: Key) -> bool {
|
|
let (byte_i, mask) = key_to_byte_mask(key);
|
|
if let Some(k) = self.keycodes.get_mut(byte_i) {
|
|
(*k & mask) != 0
|
|
} else {
|
|
log::warn!("Tried to get out-of-range keycode: 0x{:x}", u8::from(key));
|
|
false
|
|
}
|
|
}
|
|
|
|
#[inline(always)]
|
|
pub fn set_modifier(&mut self, modifier: Modifier, pressed: bool) {
|
|
if pressed {
|
|
self.modifier |= u8::from(modifier);
|
|
} else {
|
|
self.modifier &= !u8::from(modifier);
|
|
}
|
|
}
|
|
|
|
#[inline(always)]
|
|
pub fn press_modifier(&mut self, modifier: Modifier) {
|
|
self.set_modifier(modifier, true)
|
|
}
|
|
|
|
#[inline(always)]
|
|
pub fn release_modifier(&mut self, modifier: Modifier) {
|
|
self.set_modifier(modifier, false)
|
|
}
|
|
|
|
#[inline(always)]
|
|
pub fn modifier_pressed(&mut self, modifier: Modifier) -> bool {
|
|
(self.modifier & u8::from(modifier)) != 0
|
|
}
|
|
|
|
#[inline(always)]
|
|
pub fn as_bytes(&self) -> &[u8; size_of::<KeyboardReport>()] {
|
|
cast_ref(self)
|
|
}
|
|
}
|
|
|
|
// bitmasks for the `modifier` field
|
|
|
|
#[cfg(feature = "n-key-rollover")]
|
|
impl usbd_hid::descriptor::SerializedDescriptor for KeyboardReport {
|
|
fn desc() -> &'static [u8] {
|
|
// Manually define the descriptor since I can't figure out how to get
|
|
// gen_hid_descriptor to generate the correct one.
|
|
&[
|
|
0x05, 0x01, // usage page 1 (generic desktop)
|
|
0x09, 0x06, // usage (keyboard)
|
|
0xa1, 0x01, // collection (application)
|
|
//
|
|
0x05, 0x07, // usage page 7 (keyboard/keypad)
|
|
0x19, 0xe0, // local usage minimum
|
|
0x29, 0xe7, // local usage maximum
|
|
0x15, 0x00, // local minimum
|
|
0x25, 0x01, // local maximum
|
|
0x75, 0x01, // report size (1 bit)
|
|
0x95, 0x08, // report count (8)
|
|
0x81, 0x02, // input (variable)
|
|
//
|
|
0x19, 0x00, // local usage minimum
|
|
//0x29, 0x67, // local usage maximum (0x67)
|
|
//0x95, 0x68, // report count (0x68)
|
|
0x29, 215, // local usage maximum (215)
|
|
0x95, 216, // report count (216)
|
|
0x81, 0x02, // input (variable)
|
|
//
|
|
0x05, 0x08, // usage page 8 (led page)
|
|
0x19, 0x01, // local usage minimum
|
|
0x29, 0x05, // local usage maximum
|
|
0x15, 0x00, // logical min
|
|
0x25, 0x01, // logical max
|
|
0x75, 0x01, // report size
|
|
0x95, 0x05, // report count
|
|
0x91, 0x02, // output (variable)
|
|
//
|
|
0x75, 0x03, // report size
|
|
0x95, 0x01, // report count
|
|
0x91, 0x01, // output (constant)
|
|
0xc0, // end collection
|
|
]
|
|
}
|
|
}
|