use std::cell::RefCell;
const MOD_SHIFT: u8 = 1;
const MOD_CONTROL: u8 = 2;
const MOD_ALT: u8 = 4;
const MOD_META: u8 = 8;
pub struct Keyboard {
modifiers: RefCell<u8>,
pressed_keys: RefCell<Vec<String>>,
}
impl std::fmt::Debug for Keyboard {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Keyboard")
.field("modifiers", &self.modifiers.borrow())
.field("pressed_count", &self.pressed_keys.borrow().len())
.finish()
}
}
impl Keyboard {
pub fn new() -> Self {
Self {
modifiers: RefCell::new(0),
pressed_keys: RefCell::new(Vec::new()),
}
}
pub fn is_shift_pressed(&self) -> bool {
*self.modifiers.borrow() & MOD_SHIFT != 0
}
pub fn is_control_pressed(&self) -> bool {
*self.modifiers.borrow() & MOD_CONTROL != 0
}
pub fn is_alt_pressed(&self) -> bool {
*self.modifiers.borrow() & MOD_ALT != 0
}
pub fn is_meta_pressed(&self) -> bool {
*self.modifiers.borrow() & MOD_META != 0
}
pub fn modifier_count(&self) -> u8 {
let m = *self.modifiers.borrow();
let mut n = 0;
if m & MOD_SHIFT != 0 {
n += 1;
}
if m & MOD_CONTROL != 0 {
n += 1;
}
if m & MOD_ALT != 0 {
n += 1;
}
if m & MOD_META != 0 {
n += 1;
}
n
}
pub fn pressed_keys(&self) -> Vec<String> {
self.pressed_keys.borrow().clone()
}
pub fn set_modifier(&self, mod_flag: u8, on: bool) {
let mut m = self.modifiers.borrow_mut();
if on {
*m |= mod_flag;
} else {
*m &= !mod_flag;
}
}
pub fn add_pressed_key(&self, key: impl Into<String>) {
let k = key.into();
let mut pressed = self.pressed_keys.borrow_mut();
if !pressed.contains(&k) {
pressed.push(k);
}
}
pub fn remove_pressed_key(&self, key: &str) {
self.pressed_keys.borrow_mut().retain(|k| k != key);
}
pub fn reset(&self) {
*self.modifiers.borrow_mut() = 0;
self.pressed_keys.borrow_mut().clear();
}
}
impl Default for Keyboard {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn new_no_modifiers() {
let k = Keyboard::new();
assert!(!k.is_shift_pressed());
assert!(!k.is_control_pressed());
assert!(!k.is_alt_pressed());
assert!(!k.is_meta_pressed());
assert_eq!(k.modifier_count(), 0);
}
#[test]
fn set_shift() {
let k = Keyboard::new();
k.set_modifier(MOD_SHIFT, true);
assert!(k.is_shift_pressed());
assert_eq!(k.modifier_count(), 1);
k.set_modifier(MOD_SHIFT, false);
assert!(!k.is_shift_pressed());
}
#[test]
fn set_multiple_modifiers() {
let k = Keyboard::new();
k.set_modifier(MOD_SHIFT, true);
k.set_modifier(MOD_CONTROL, true);
k.set_modifier(MOD_ALT, true);
k.set_modifier(MOD_META, true);
assert_eq!(k.modifier_count(), 4);
}
#[test]
fn pressed_keys_track() {
let k = Keyboard::new();
assert_eq!(k.pressed_keys().len(), 0);
k.add_pressed_key("a");
k.add_pressed_key("b");
assert_eq!(k.pressed_keys().len(), 2);
k.remove_pressed_key("a");
assert_eq!(k.pressed_keys().len(), 1);
}
#[test]
fn duplicate_pressed_key_no_dup() {
let k = Keyboard::new();
k.add_pressed_key("a");
k.add_pressed_key("a");
assert_eq!(k.pressed_keys().len(), 1);
}
#[test]
fn reset_clears_all() {
let k = Keyboard::new();
k.set_modifier(MOD_SHIFT, true);
k.add_pressed_key("a");
k.reset();
assert_eq!(k.modifier_count(), 0);
assert_eq!(k.pressed_keys().len(), 0);
}
}