use super::{descriptor::*, usage::*, Dev, InputBuf, InputDev, OutputDev};
pub(super) trait KbdMap {
fn key(&self, c: char) -> Option<Key>;
}
impl std::fmt::Debug for dyn KbdMap + Send + Sync {
fn fmt(&self, _: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
Ok(())
}
}
type In = [u8; Kbd::IN_LEN as usize];
type Out = [u8; Kbd::OUT_LEN as usize];
#[derive(Debug)]
pub struct Kbd {
map: Box<dyn KbdMap + Send + Sync>,
inp: InputBuf<{ Kbd::IN_LEN as usize }>,
out: Out,
}
impl Kbd {
#[must_use]
pub fn new() -> Self {
Self {
map: Box::new(USKbd {}),
inp: InputBuf::default(),
out: Out::default(),
}
}
pub fn press(&mut self, k: Key) {
if k.u == self.last_key().u {
self.inp.add_input(In::default());
}
self.inp.add_input(k.into());
}
#[must_use]
pub fn last_key(&self) -> Key {
Key::from(self.inp.last_input())
}
pub fn write(&mut self, s: &str) {
for (i, c) in s.chars().enumerate() {
self.map.key(c).map_or_else(
|| panic!("invalid key at {i} in {s:?}: {c:?}"), |k| self.press(k),
);
}
}
#[must_use]
pub const fn num_lock(&self) -> bool {
self.ind().contains(KbdInd::NUM_LOCK)
}
#[must_use]
pub const fn caps_lock(&self) -> bool {
self.ind().contains(KbdInd::CAPS_LOCK)
}
#[must_use]
pub const fn scroll_lock(&self) -> bool {
self.ind().contains(KbdInd::SCROLL_LOCK)
}
const fn ind(&self) -> KbdInd {
KbdInd::from_bits_truncate(self.out[0])
}
}
impl Default for Kbd {
fn default() -> Self {
Self::new()
}
}
impl Dev for Kbd {
fn reset(&mut self) {
self.inp.reset();
self.out.fill(0);
}
#[rustfmt::skip]
fn report_descriptor(&self, report_id: u8) -> Items {
use Item::*;
use super::usage::KeyUsage::*;
Items::from([
GUsagePage(0x01), LUsage(0x06), MApplication([
GReportID(report_id),
GUsagePage(0x07), GReportSize(1),
GReportCount(8),
GLogicalMin(0),
GLogicalMax(1),
LUsageMin(0xE0), LUsageMax(0xE7), MInput(Attr::VAR),
GReportSize(8),
GReportCount(Self::IN_LEN - 1),
GLogicalMin(0x01),
GLogicalMax(KeypadHex as i32),
LUsageMin(0x01),
LUsageMax(KeypadHex as u32),
MInput(Attr::empty()),
GUsagePage(0x08), GReportSize(1),
GReportCount(5),
GLogicalMin(0),
GLogicalMax(1),
LUsageMin(0x01), LUsageMax(0x05), MOutput(Attr::VAR),
GReportSize(3),
GReportCount(1),
MOutput(Attr::CONST),
].into()),
])
}
}
impl InputDev for Kbd {
const IN_LEN: u8 = 2;
fn poll(&mut self) -> bool {
self.inp.poll()
}
fn input(&self) -> &[u8] {
self.inp.input()
}
}
impl OutputDev for Kbd {
const OUT_LEN: u8 = 1;
fn set_output(&mut self, out: &[u8]) {
if out.is_empty() {
return;
}
self.out = Out::try_from(out).unwrap();
}
fn output(&self) -> &[u8] {
&self.out
}
}
bitflags::bitflags! {
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
pub struct KeyMod: u8 {
const LCTRL = 1 << 0;
const LSHIFT = 1 << 1;
const LALT = 1 << 2;
const LGUI = 1 << 3;
const RCTRL = 1 << 4;
const RSHIFT = 1 << 5;
const RALT = 1 << 6;
const RGUI = 1 << 7;
}
}
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
pub struct Key {
m: KeyMod,
u: KeyUsage,
}
impl From<KeyUsage> for Key {
fn from(u: KeyUsage) -> Self {
Self {
m: KeyMod::empty(),
u,
}
}
}
impl Key {
#[must_use]
pub fn shift(u: KeyUsage) -> Self {
Self::from(u).with(KeyMod::LSHIFT)
}
#[must_use]
pub fn with(self, m: KeyMod) -> Self {
Self {
m: m | self.m,
..self
}
}
#[must_use]
pub fn is_empty(self) -> bool {
self == Self::default()
}
}
impl From<In> for Key {
fn from(v: In) -> Self {
Self {
m: KeyMod::from_bits_truncate(v[0]),
u: v[1].into(),
}
}
}
impl From<Key> for In {
fn from(k: Key) -> Self {
[k.m.bits(), k.u.into()]
}
}
bitflags::bitflags! {
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
struct KbdInd: u8 {
const NUM_LOCK = 1 << 0;
const CAPS_LOCK = 1 << 1;
const SCROLL_LOCK = 1 << 2;
const COMPOSE = 1 << 3;
const KANA = 1 << 4;
}
}
impl From<Out> for KbdInd {
fn from(v: Out) -> Self {
Self::from_bits_truncate(v[0])
}
}
impl From<KbdInd> for Out {
fn from(v: KbdInd) -> Self {
[v.bits()]
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn dev() {
let b = Kbd::default();
assert!(!b.report_descriptor(1).to_bytes().is_empty());
}
#[test]
fn input() {
use KeyUsage::*;
let mut b = Kbd::new();
b.write("Hello!\n");
let last = Key::from(KeyEnter);
assert_eq!(b.last_key(), last);
let want = [
Key::shift(KeyH),
Key::from(KeyE),
Key::from(KeyL),
Key::default(),
Key::from(KeyL),
Key::from(KeyO),
Key::shift(Key1),
Key::from(KeyEnter),
];
for k in want {
assert!(b.poll());
assert_eq!(b.input(), In::from(k));
assert_eq!(b.last_key(), last);
}
assert!(b.poll());
assert_eq!(b.input(), In::default());
assert_eq!(b.last_key(), Key::default());
assert!(!b.poll());
b.write("X");
b.reset();
assert!(!b.poll());
assert_eq!(b.input(), In::default());
assert!(Key::default().is_empty());
}
#[test]
fn output() {
let mut b = Kbd::new();
assert!(!b.num_lock());
assert!(!b.caps_lock());
assert!(!b.scroll_lock());
assert_eq!(b.output(), &[0]);
b.set_output(&Out::from(KbdInd::NUM_LOCK));
assert_eq!(KbdInd::from(b.out), KbdInd::NUM_LOCK);
assert!(b.num_lock());
assert!(!b.caps_lock());
assert!(!b.scroll_lock());
b.set_output(&Out::from(KbdInd::CAPS_LOCK | KbdInd::SCROLL_LOCK));
assert!(!b.num_lock());
assert!(b.caps_lock());
assert!(b.scroll_lock());
}
#[test]
#[should_panic]
fn unmapped_char() {
Kbd::new().write("•");
}
#[test]
#[should_panic]
fn invalid_output() {
Kbd::new().set_output(&[0, 0]);
}
}