use crossterm::event::{KeyCode, KeyEvent, KeyModifiers, MouseButton, MouseEvent, MouseEventKind};
pub fn is_activate_key(key: &KeyEvent) -> bool {
matches!(key.code, KeyCode::Enter | KeyCode::Char(' '))
}
pub fn is_navigation_key(key: &KeyEvent) -> bool {
matches!(
key.code,
KeyCode::Tab
| KeyCode::BackTab
| KeyCode::Up
| KeyCode::Down
| KeyCode::Left
| KeyCode::Right
)
}
pub fn is_tab(key: &KeyEvent) -> bool {
key.code == KeyCode::Tab && !key.modifiers.contains(KeyModifiers::SHIFT)
}
pub fn is_backtab(key: &KeyEvent) -> bool {
key.code == KeyCode::BackTab
|| (key.code == KeyCode::Tab && key.modifiers.contains(KeyModifiers::SHIFT))
}
pub fn is_close_key(key: &KeyEvent) -> bool {
key.code == KeyCode::Esc
}
pub fn is_enter(key: &KeyEvent) -> bool {
key.code == KeyCode::Enter
}
pub fn is_space(key: &KeyEvent) -> bool {
key.code == KeyCode::Char(' ')
}
pub fn is_backspace(key: &KeyEvent) -> bool {
key.code == KeyCode::Backspace
}
pub fn is_delete(key: &KeyEvent) -> bool {
key.code == KeyCode::Delete
}
pub fn is_arrow_key(key: &KeyEvent) -> bool {
matches!(
key.code,
KeyCode::Up | KeyCode::Down | KeyCode::Left | KeyCode::Right
)
}
pub fn is_home(key: &KeyEvent) -> bool {
key.code == KeyCode::Home
}
pub fn is_end(key: &KeyEvent) -> bool {
key.code == KeyCode::End
}
pub fn get_char(key: &KeyEvent) -> Option<char> {
match key.code {
KeyCode::Char(c) => {
if key.modifiers.is_empty() || key.modifiers == KeyModifiers::SHIFT {
Some(c)
} else {
None
}
}
_ => None,
}
}
pub fn is_left_click(mouse: &MouseEvent) -> bool {
matches!(mouse.kind, MouseEventKind::Down(MouseButton::Left))
}
pub fn is_right_click(mouse: &MouseEvent) -> bool {
matches!(mouse.kind, MouseEventKind::Down(MouseButton::Right))
}
pub fn get_scroll(mouse: &MouseEvent) -> Option<i16> {
match mouse.kind {
MouseEventKind::ScrollUp => Some(-1),
MouseEventKind::ScrollDown => Some(1),
_ => None,
}
}
pub fn get_mouse_pos(mouse: &MouseEvent) -> (u16, u16) {
(mouse.column, mouse.row)
}
pub fn is_mouse_move(mouse: &MouseEvent) -> bool {
matches!(mouse.kind, MouseEventKind::Moved)
}
pub fn is_mouse_drag(mouse: &MouseEvent) -> bool {
matches!(mouse.kind, MouseEventKind::Drag(_))
}
pub fn has_ctrl(key: &KeyEvent) -> bool {
key.modifiers.contains(KeyModifiers::CONTROL)
}
pub fn has_alt(key: &KeyEvent) -> bool {
key.modifiers.contains(KeyModifiers::ALT)
}
pub fn has_shift(key: &KeyEvent) -> bool {
key.modifiers.contains(KeyModifiers::SHIFT)
}
pub fn is_ctrl_a(key: &KeyEvent) -> bool {
key.code == KeyCode::Char('a') && has_ctrl(key)
}
pub fn is_ctrl_e(key: &KeyEvent) -> bool {
key.code == KeyCode::Char('e') && has_ctrl(key)
}
pub fn is_ctrl_u(key: &KeyEvent) -> bool {
key.code == KeyCode::Char('u') && has_ctrl(key)
}
pub fn is_ctrl_k(key: &KeyEvent) -> bool {
key.code == KeyCode::Char('k') && has_ctrl(key)
}
pub fn is_ctrl_w(key: &KeyEvent) -> bool {
key.code == KeyCode::Char('w') && has_ctrl(key)
}
#[cfg(test)]
mod tests {
use super::*;
use crossterm::event::KeyEventKind;
fn make_key(code: KeyCode, modifiers: KeyModifiers) -> KeyEvent {
KeyEvent {
code,
modifiers,
kind: KeyEventKind::Press,
state: crossterm::event::KeyEventState::empty(),
}
}
#[test]
fn test_is_activate_key() {
assert!(is_activate_key(&make_key(
KeyCode::Enter,
KeyModifiers::NONE
)));
assert!(is_activate_key(&make_key(
KeyCode::Char(' '),
KeyModifiers::NONE
)));
assert!(!is_activate_key(&make_key(
KeyCode::Char('a'),
KeyModifiers::NONE
)));
}
#[test]
fn test_is_navigation_key() {
assert!(is_navigation_key(&make_key(
KeyCode::Tab,
KeyModifiers::NONE
)));
assert!(is_navigation_key(&make_key(
KeyCode::BackTab,
KeyModifiers::NONE
)));
assert!(is_navigation_key(&make_key(
KeyCode::Up,
KeyModifiers::NONE
)));
assert!(is_navigation_key(&make_key(
KeyCode::Down,
KeyModifiers::NONE
)));
assert!(!is_navigation_key(&make_key(
KeyCode::Enter,
KeyModifiers::NONE
)));
}
#[test]
fn test_is_tab_and_backtab() {
assert!(is_tab(&make_key(KeyCode::Tab, KeyModifiers::NONE)));
assert!(!is_tab(&make_key(KeyCode::Tab, KeyModifiers::SHIFT)));
assert!(is_backtab(&make_key(KeyCode::BackTab, KeyModifiers::NONE)));
assert!(is_backtab(&make_key(KeyCode::Tab, KeyModifiers::SHIFT)));
assert!(!is_backtab(&make_key(KeyCode::Tab, KeyModifiers::NONE)));
}
#[test]
fn test_get_char() {
assert_eq!(
get_char(&make_key(KeyCode::Char('a'), KeyModifiers::NONE)),
Some('a')
);
assert_eq!(
get_char(&make_key(KeyCode::Char('A'), KeyModifiers::SHIFT)),
Some('A')
);
assert_eq!(
get_char(&make_key(KeyCode::Char('a'), KeyModifiers::CONTROL)),
None
);
assert_eq!(
get_char(&make_key(KeyCode::Enter, KeyModifiers::NONE)),
None
);
}
#[test]
fn test_modifier_checks() {
let ctrl_a = make_key(KeyCode::Char('a'), KeyModifiers::CONTROL);
assert!(has_ctrl(&ctrl_a));
assert!(!has_alt(&ctrl_a));
assert!(!has_shift(&ctrl_a));
let shift_a = make_key(KeyCode::Char('A'), KeyModifiers::SHIFT);
assert!(!has_ctrl(&shift_a));
assert!(has_shift(&shift_a));
}
#[test]
fn test_ctrl_shortcuts() {
assert!(is_ctrl_a(&make_key(
KeyCode::Char('a'),
KeyModifiers::CONTROL
)));
assert!(is_ctrl_e(&make_key(
KeyCode::Char('e'),
KeyModifiers::CONTROL
)));
assert!(is_ctrl_u(&make_key(
KeyCode::Char('u'),
KeyModifiers::CONTROL
)));
assert!(is_ctrl_k(&make_key(
KeyCode::Char('k'),
KeyModifiers::CONTROL
)));
assert!(is_ctrl_w(&make_key(
KeyCode::Char('w'),
KeyModifiers::CONTROL
)));
}
#[test]
fn test_mouse_helpers() {
let left_click = MouseEvent {
kind: MouseEventKind::Down(MouseButton::Left),
column: 10,
row: 5,
modifiers: KeyModifiers::NONE,
};
assert!(is_left_click(&left_click));
assert!(!is_right_click(&left_click));
assert_eq!(get_mouse_pos(&left_click), (10, 5));
let scroll_up = MouseEvent {
kind: MouseEventKind::ScrollUp,
column: 0,
row: 0,
modifiers: KeyModifiers::NONE,
};
assert_eq!(get_scroll(&scroll_up), Some(-1));
let scroll_down = MouseEvent {
kind: MouseEventKind::ScrollDown,
column: 0,
row: 0,
modifiers: KeyModifiers::NONE,
};
assert_eq!(get_scroll(&scroll_down), Some(1));
}
#[test]
fn test_mouse_move() {
let mouse_move = MouseEvent {
kind: MouseEventKind::Moved,
column: 15,
row: 10,
modifiers: KeyModifiers::NONE,
};
assert!(is_mouse_move(&mouse_move));
assert!(!is_mouse_drag(&mouse_move));
assert_eq!(get_mouse_pos(&mouse_move), (15, 10));
let left_click = MouseEvent {
kind: MouseEventKind::Down(MouseButton::Left),
column: 5,
row: 5,
modifiers: KeyModifiers::NONE,
};
assert!(!is_mouse_move(&left_click));
}
#[test]
fn test_mouse_drag() {
let left_drag = MouseEvent {
kind: MouseEventKind::Drag(MouseButton::Left),
column: 20,
row: 15,
modifiers: KeyModifiers::NONE,
};
assert!(is_mouse_drag(&left_drag));
assert!(!is_mouse_move(&left_drag));
assert_eq!(get_mouse_pos(&left_drag), (20, 15));
let right_drag = MouseEvent {
kind: MouseEventKind::Drag(MouseButton::Right),
column: 5,
row: 5,
modifiers: KeyModifiers::NONE,
};
assert!(is_mouse_drag(&right_drag));
}
}