#![no_std]
#![deny(missing_docs)]
use arraydeque::ArrayDeque;
use arrayvec::ArrayVec;
use keycode_macro::parse_keycode_converter_data;
parse_keycode_converter_data!();
#[derive(Debug, Clone, PartialEq, Eq, Hash, Copy)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum KeyState {
Pressed,
Released,
}
pub const NUM_KEYS: usize = 256;
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct KeyboardState {
key_rollover: Option<usize>,
key_state: ArrayDeque<[Option<KeyMap>; NUM_KEYS]>,
modifier_state: KeyModifiers,
input_report: ArrayVec<[u8; NUM_KEYS]>,
}
impl<'a> KeyboardState {
pub fn new(key_rollover: Option<usize>) -> KeyboardState {
KeyboardState {
key_rollover,
key_state: ArrayDeque::new(),
modifier_state: KeyModifiers::empty(),
input_report: ArrayVec::new(),
}
}
pub fn update_key(self: &mut Self, key: KeyMap, state: KeyState) {
match state {
KeyState::Pressed => {
if let Some(key_modifier) = key.modifier {
self.modifier_state.insert(key_modifier);
return;
}
if self.key_state.contains(&Some(key)) {
return;
}
if self.key_state.is_full() {
return;
}
if let Some(key_rollover) = self.key_rollover {
if self.key_state.len() >= key_rollover {
return;
}
}
self.key_state.push_back(Some(key)).unwrap();
}
KeyState::Released => {
if let Some(key_modifier) = key.modifier {
self.modifier_state.remove(key_modifier);
return;
}
if self.key_state.is_empty() {
return;
}
self.key_state.retain(|k| *k != Some(key));
}
}
}
pub fn usb_input_report(self: &mut Self) -> &[u8] {
let mut input_report: ArrayVec<[u8; NUM_KEYS]> = ArrayVec::new();
input_report.push(self.modifier_state.bits());
input_report.push(0);
for possible_key in self.key_state.iter() {
if let Some(key) = possible_key {
input_report.push(key.usb as u8);
}
}
let min_input_report_size = self
.key_rollover
.map(|key_rollover_without_modifiers| key_rollover_without_modifiers + 2)
.unwrap_or(8);
if input_report.len() < min_input_report_size {
for _ in input_report.len()..min_input_report_size {
input_report.push(0);
}
}
self.input_report = input_report;
self.input_report.as_slice()
}
}