use crossterm::event::{read,
Event,
KeyCode,
KeyEvent,
KeyEventKind,
KeyEventState,
KeyModifiers};
use r3bl_core::{call_if_true, ch, Size};
use crate::DEVELOPMENT_MODE;
pub trait KeyPressReader {
fn read_key_press(&mut self) -> KeyPress;
}
#[derive(Debug, Default, PartialEq, Eq, Hash, Clone, Copy)]
pub enum KeyPress {
Up,
Down,
Enter,
Esc,
#[default]
Noop,
Error,
Space,
Resize(Size),
CtrlC,
}
pub struct CrosstermKeyPressReader {}
impl KeyPressReader for CrosstermKeyPressReader {
fn read_key_press(&mut self) -> KeyPress { read_key_press() }
}
fn read_key_press() -> KeyPress {
if cfg!(windows) {
read_key_press_windows()
} else {
read_key_press_unix()
}
}
fn read_key_press_unix() -> KeyPress {
let result_event = read();
match result_event {
Ok(event) => {
call_if_true!(DEVELOPMENT_MODE, {
tracing::debug!("got event: {event:?}");
});
match event {
crossterm::event::Event::Resize(width, height) => {
KeyPress::Resize(Size {
col_count: ch!(width),
row_count: ch!(height),
})
}
crossterm::event::Event::Key(KeyEvent {
modifiers: KeyModifiers::CONTROL,
code: KeyCode::Char('c'),
..
}) => KeyPress::CtrlC,
crossterm::event::Event::Key(KeyEvent { code, .. }) => {
match code {
crossterm::event::KeyCode::Up => KeyPress::Up,
crossterm::event::KeyCode::Down => KeyPress::Down,
crossterm::event::KeyCode::Enter => KeyPress::Enter,
crossterm::event::KeyCode::Esc => KeyPress::Esc,
crossterm::event::KeyCode::Char(' ') => KeyPress::Space,
_ => KeyPress::Noop,
}
}
_ => KeyPress::Noop,
}
}
Err(err) => {
tracing::error!("ERROR getting event: {err:?}");
KeyPress::Error
}
}
}
fn read_key_press_windows() -> KeyPress {
let result_event = read();
match result_event {
Ok(event) => {
call_if_true!(DEVELOPMENT_MODE, {
tracing::debug!("got event: {event:?}");
});
match event {
Event::Key(KeyEvent {
code: KeyCode::Enter,
modifiers: KeyModifiers::NONE,
kind: KeyEventKind::Press, state: KeyEventState::NONE,
}) => KeyPress::Enter,
Event::Key(KeyEvent {
code: KeyCode::Down,
modifiers: KeyModifiers::NONE,
kind: KeyEventKind::Press, state: KeyEventState::NONE,
}) => KeyPress::Down,
Event::Key(KeyEvent {
code: KeyCode::Up,
modifiers: KeyModifiers::NONE,
kind: KeyEventKind::Press, state: KeyEventState::NONE,
}) => KeyPress::Up,
Event::Key(KeyEvent {
code: KeyCode::Esc,
modifiers: KeyModifiers::NONE,
kind: KeyEventKind::Press, state: KeyEventState::NONE,
}) => KeyPress::Esc,
Event::Key(KeyEvent {
code: KeyCode::Char(' '),
modifiers: KeyModifiers::NONE,
kind: KeyEventKind::Press, state: KeyEventState::NONE,
}) => KeyPress::Space,
Event::Key(KeyEvent {
code: KeyCode::Char('c'),
modifiers: KeyModifiers::CONTROL,
kind: KeyEventKind::Press, state: KeyEventState::NONE,
}) => KeyPress::CtrlC,
Event::Resize(width, height) => KeyPress::Resize(Size {
col_count: ch!(width),
row_count: ch!(height),
}),
_ => KeyPress::Noop,
}
}
Err(err) => {
tracing::error!("ERROR getting event: {err:?}");
KeyPress::Error
}
}
}