use crossterm::event::{
KeyCode,
KeyEvent,
KeyEventKind,
KeyModifiers,
};
#[derive(Debug, Clone, PartialEq)]
pub enum Event {
Key(KeyEvent),
Mouse(crossterm::event::MouseEvent),
Resize(u16, u16),
Paste(String),
FocusGained,
FocusLost,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum Key {
Char(char, Modifiers),
Code(KeyCode, Modifiers),
}
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
pub struct Modifiers {
pub shift: bool,
pub ctrl: bool,
pub alt: bool,
}
impl Modifiers {
pub fn none() -> Self {
Self::default()
}
pub fn ctrl() -> Self {
Self {
ctrl: true,
..Default::default()
}
}
pub fn shift() -> Self {
Self {
shift: true,
..Default::default()
}
}
pub fn alt() -> Self {
Self {
alt: true,
..Default::default()
}
}
pub fn ctrl_shift() -> Self {
Self {
ctrl: true,
shift: true,
..Default::default()
}
}
}
impl Key {
pub fn enter() -> Self {
Key::Code(KeyCode::Enter, Modifiers::none())
}
pub fn left() -> Self {
Key::Code(KeyCode::Left, Modifiers::none())
}
pub fn right() -> Self {
Key::Code(KeyCode::Right, Modifiers::none())
}
pub fn up() -> Self {
Key::Code(KeyCode::Up, Modifiers::none())
}
pub fn down() -> Self {
Key::Code(KeyCode::Down, Modifiers::none())
}
pub fn backspace() -> Self {
Key::Code(KeyCode::Backspace, Modifiers::none())
}
pub fn delete() -> Self {
Key::Code(KeyCode::Delete, Modifiers::none())
}
pub fn home() -> Self {
Key::Code(KeyCode::Home, Modifiers::none())
}
pub fn end() -> Self {
Key::Code(KeyCode::End, Modifiers::none())
}
pub fn tab() -> Self {
Key::Code(KeyCode::Tab, Modifiers::none())
}
pub fn esc() -> Self {
Key::Code(KeyCode::Esc, Modifiers::none())
}
pub fn ctrl(c: char) -> Self {
Key::Char(c, Modifiers::ctrl())
}
pub fn ctrl_shift(c: char) -> Self {
Key::Char(c, Modifiers::ctrl_shift())
}
pub fn alt(c: char) -> Self {
Key::Char(c, Modifiers::alt())
}
pub fn char(c: char) -> Self {
Key::Char(c, Modifiers::none())
}
}
pub fn matches_key(event: &Event, key: &Key) -> bool {
let Event::Key(key_event) = event else {
return false;
};
if key_event.kind == KeyEventKind::Release {
return false;
}
let km = key_event.modifiers;
let mods = Modifiers {
shift: km.contains(KeyModifiers::SHIFT),
ctrl: km.contains(KeyModifiers::CONTROL),
alt: km.contains(KeyModifiers::ALT),
};
match key {
| Key::Char(expected, expected_mods) => {
if let KeyCode::Char(c) = key_event.code {
c == *expected && mods == *expected_mods
} else {
false
}
},
| Key::Code(expected, expected_mods) => {
key_event.code == *expected && mods == *expected_mods
},
}
}