use crossterm::event::{KeyCode, KeyModifiers};
use std::cell::RefCell;
use std::collections::HashMap;
use std::rc::Rc;
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct KeyBinding {
pub code: KeyCode,
pub modifiers: KeyModifiers,
}
impl KeyBinding {
pub fn new(code: KeyCode, modifiers: KeyModifiers) -> Self {
Self { code, modifiers }
}
pub fn key(code: KeyCode) -> Self {
Self::new(code, KeyModifiers::NONE)
}
pub fn ctrl(c: char) -> Self {
Self::new(KeyCode::Char(c), KeyModifiers::CONTROL)
}
pub fn alt(c: char) -> Self {
Self::new(KeyCode::Char(c), KeyModifiers::ALT)
}
pub fn shift(c: char) -> Self {
Self::new(KeyCode::Char(c), KeyModifiers::SHIFT)
}
pub fn matches(&self, code: KeyCode, modifiers: KeyModifiers) -> bool {
self.code == code && self.modifiers == modifiers
}
}
pub type CommandCallback = Rc<dyn Fn()>;
#[derive(Default)]
pub struct CommandRegistry {
commands: RefCell<HashMap<KeyBinding, CommandCallback>>,
}
impl CommandRegistry {
pub fn new() -> Self {
Self::default()
}
pub fn register(&self, binding: KeyBinding, callback: CommandCallback) {
self.commands.borrow_mut().insert(binding, callback);
}
pub fn clear(&self) {
self.commands.borrow_mut().clear();
}
pub fn execute(&self, code: KeyCode, modifiers: KeyModifiers) -> bool {
let commands = self.commands.borrow();
for (binding, callback) in commands.iter() {
if binding.matches(code, modifiers) {
callback();
return true;
}
}
false
}
pub fn has_binding(&self, code: KeyCode, modifiers: KeyModifiers) -> bool {
let commands = self.commands.borrow();
commands.keys().any(|b| b.matches(code, modifiers))
}
}