use super::command::CommandId;
use super::geometry::Point;
use crossterm::event::{KeyCode as CKC, KeyEvent, KeyModifiers};
use std::time::{Duration, Instant};
pub type KeyCode = u16;
pub const KB_ESC: KeyCode = 0x011B;
pub const KB_ENTER: KeyCode = 0x1C0D;
pub const KB_BACKSPACE: KeyCode = 0x0E08;
pub const KB_TAB: KeyCode = 0x0F09;
pub const KB_SHIFT_TAB: KeyCode = 0x0F00;
pub const KB_F1: KeyCode = 0x3B00;
pub const KB_F2: KeyCode = 0x3C00;
pub const KB_F3: KeyCode = 0x3D00;
pub const KB_F4: KeyCode = 0x3E00;
pub const KB_F5: KeyCode = 0x3F00;
pub const KB_F6: KeyCode = 0x4000;
pub const KB_F7: KeyCode = 0x4100;
pub const KB_F8: KeyCode = 0x4200;
pub const KB_F9: KeyCode = 0x4300;
pub const KB_F10: KeyCode = 0x4400;
pub const KB_F11: KeyCode = 0x8500;
pub const KB_F12: KeyCode = 0x8600;
pub const KB_SHIFT_F12: KeyCode = 0x8601;
pub const KB_UP: KeyCode = 0x4800;
pub const KB_DOWN: KeyCode = 0x5000;
pub const KB_LEFT: KeyCode = 0x4B00;
pub const KB_RIGHT: KeyCode = 0x4D00;
pub const KB_HOME: KeyCode = 0x4700;
pub const KB_END: KeyCode = 0x4F00;
pub const KB_PGUP: KeyCode = 0x4900;
pub const KB_PGDN: KeyCode = 0x5100;
pub const KB_INS: KeyCode = 0x5200;
pub const KB_DEL: KeyCode = 0x5300;
pub const KB_ALT_X: KeyCode = 0x2D00;
pub const KB_ALT_F: KeyCode = 0x2100;
pub const KB_ALT_H: KeyCode = 0x2300;
pub const KB_ALT_O: KeyCode = 0x1800;
pub const KB_ALT_A: KeyCode = 0x1E00;
pub const KB_ALT_F3: KeyCode = 0x6A00;
pub const KB_ESC_F: KeyCode = 0x2101; pub const KB_ESC_H: KeyCode = 0x2301; pub const KB_ESC_X: KeyCode = 0x2D01; pub const KB_ESC_A: KeyCode = 0x1E01; pub const KB_ESC_O: KeyCode = 0x1801; pub const KB_ESC_E: KeyCode = 0x1201; pub const KB_ESC_S: KeyCode = 0x1F01; pub const KB_ESC_V: KeyCode = 0x2F01;
pub const KB_ESC_ESC: KeyCode = 0x011C;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum EventType {
Nothing,
Keyboard,
MouseDown,
MouseUp,
MouseMove,
MouseAuto,
MouseWheelUp, MouseWheelDown, Command,
Broadcast,
}
pub const EV_NOTHING: u16 = 0x0000;
pub const EV_MOUSE_DOWN: u16 = 0x0001;
pub const EV_MOUSE_UP: u16 = 0x0002;
pub const EV_MOUSE_MOVE: u16 = 0x0004;
pub const EV_MOUSE_AUTO: u16 = 0x0008;
pub const EV_MOUSE_WHEEL_UP: u16 = 0x0010;
pub const EV_MOUSE_WHEEL_DOWN: u16 = 0x0020;
pub const EV_MOUSE: u16 = 0x003F; pub const EV_KEYBOARD: u16 = 0x0040;
pub const EV_COMMAND: u16 = 0x0100;
pub const EV_BROADCAST: u16 = 0x0200;
pub const EV_MESSAGE: u16 = 0xFF00;
pub const MB_LEFT_BUTTON: u8 = 0x01;
pub const MB_MIDDLE_BUTTON: u8 = 0x02;
pub const MB_RIGHT_BUTTON: u8 = 0x04;
#[derive(Debug, Clone, Copy)]
pub struct MouseEvent {
pub pos: Point,
pub buttons: u8, pub double_click: bool,
}
#[derive(Debug, Clone, Copy)]
pub struct Event {
pub what: EventType,
pub key_code: KeyCode,
pub key_modifiers: KeyModifiers,
pub mouse: MouseEvent,
pub command: CommandId,
}
impl Event {
pub fn nothing() -> Self {
Self {
what: EventType::Nothing,
key_code: 0,
key_modifiers: KeyModifiers::empty(),
mouse: MouseEvent {
pos: Point::zero(),
buttons: 0,
double_click: false,
},
command: 0,
}
}
pub fn keyboard(key_code: KeyCode) -> Self {
Self {
what: EventType::Keyboard,
key_code,
key_modifiers: KeyModifiers::empty(),
..Self::nothing()
}
}
pub fn command(cmd: CommandId) -> Self {
Self {
what: EventType::Command,
command: cmd,
..Self::nothing()
}
}
pub fn broadcast(cmd: CommandId) -> Self {
Self {
what: EventType::Broadcast,
command: cmd,
..Self::nothing()
}
}
pub fn mouse(event_type: EventType, pos: Point, buttons: u8, double_click: bool) -> Self {
Self {
what: event_type,
mouse: MouseEvent {
pos,
buttons,
double_click,
},
..Self::nothing()
}
}
pub fn from_crossterm_key(key_event: KeyEvent) -> Self {
let key_code = crossterm_to_keycode(key_event);
Self {
what: EventType::Keyboard,
key_code,
key_modifiers: key_event.modifiers,
..Self::nothing()
}
}
pub fn clear(&mut self) {
self.what = EventType::Nothing;
}
}
impl Default for Event {
fn default() -> Self {
Self::nothing()
}
}
#[derive(Default)]
pub struct EscSequenceTracker {
last_esc_time: Option<Instant>,
waiting_for_char: bool,
}
impl EscSequenceTracker {
pub fn new() -> Self {
Self::default()
}
pub fn process_key(&mut self, key: KeyEvent) -> KeyCode {
if matches!(key.code, CKC::Esc) {
let now = Instant::now();
if let Some(last_time) = self.last_esc_time {
if now.duration_since(last_time) < Duration::from_millis(500) {
self.last_esc_time = None;
self.waiting_for_char = false;
return KB_ESC_ESC;
}
}
self.last_esc_time = Some(now);
self.waiting_for_char = true;
return 0; }
if self.waiting_for_char {
self.waiting_for_char = false;
self.last_esc_time = None;
if let CKC::Char(c) = key.code {
return match c.to_ascii_lowercase() {
'f' => KB_ESC_F,
'h' => KB_ESC_H,
'x' => KB_ESC_X,
'a' => KB_ESC_A,
'o' => KB_ESC_O,
'e' => KB_ESC_E,
's' => KB_ESC_S,
'v' => KB_ESC_V,
_ => crossterm_to_keycode(key),
};
}
}
if let Some(last_time) = self.last_esc_time {
if Instant::now().duration_since(last_time) > Duration::from_millis(500) {
self.last_esc_time = None;
self.waiting_for_char = false;
if matches!(key.code, CKC::Char(_)) {
return crossterm_to_keycode(key);
}
}
}
crossterm_to_keycode(key)
}
}
fn crossterm_to_keycode(key: KeyEvent) -> KeyCode {
match key.code {
CKC::Char(c) => {
if key.modifiers.contains(KeyModifiers::CONTROL) {
let c_lower = c.to_ascii_lowercase();
if c_lower >= 'a' && c_lower <= 'z' {
return (c_lower as u16) - ('a' as u16) + 1; }
}
if key.modifiers.contains(KeyModifiers::ALT) {
match c.to_ascii_lowercase() {
'a' => return KB_ALT_A,
'f' => return KB_ALT_F,
'h' => return KB_ALT_H,
'o' => return KB_ALT_O,
'x' => return KB_ALT_X,
_ => {}
}
}
c as u16
}
CKC::Enter => KB_ENTER,
CKC::Backspace => KB_BACKSPACE,
CKC::Tab => {
if key.modifiers.contains(KeyModifiers::SHIFT) {
KB_SHIFT_TAB
} else {
KB_TAB
}
}
CKC::BackTab => KB_SHIFT_TAB, CKC::Esc => KB_ESC,
CKC::Up => KB_UP,
CKC::Down => KB_DOWN,
CKC::Left => KB_LEFT,
CKC::Right => KB_RIGHT,
CKC::Home => KB_HOME,
CKC::End => KB_END,
CKC::PageUp => KB_PGUP,
CKC::PageDown => KB_PGDN,
CKC::Insert => KB_INS,
CKC::Delete => KB_DEL,
CKC::F(1) => KB_F1,
CKC::F(2) => KB_F2,
CKC::F(3) => {
if key.modifiers.contains(KeyModifiers::ALT) {
KB_ALT_F3
} else {
KB_F3
}
}
CKC::F(4) => KB_F4,
CKC::F(5) => KB_F5,
CKC::F(6) => KB_F6,
CKC::F(7) => KB_F7,
CKC::F(8) => KB_F8,
CKC::F(9) => KB_F9,
CKC::F(10) => KB_F10,
CKC::F(11) => KB_F11,
CKC::F(12) => {
if key.modifiers.contains(KeyModifiers::SHIFT) {
KB_SHIFT_F12
} else {
KB_F12
}
}
_ => 0,
}
}