#[cfg(any(feature = "crossterm", feature = "ratatui-crossterm"))]
use crate::crossterm::event::{
Event as CrosstermEvent, KeyCode, KeyEvent, KeyEventKind, KeyModifiers,
MouseEvent as CrosstermMouseEvent, MouseEventKind as CrosstermMouseEventKind,
};
#[cfg(feature = "arbitrary")]
use arbitrary::Arbitrary;
#[cfg(any(feature = "termion", feature = "ratatui-termion"))]
use termion::event::{Event as TermionEvent, Key as TermionKey, MouseEvent as TermionMouseEvent};
#[non_exhaustive]
#[derive(Clone, Copy, Debug)]
#[cfg_attr(feature = "arbitrary", derive(Arbitrary))]
pub enum Key {
Char(char),
F(u8),
Backspace,
Enter,
Left,
Right,
Up,
Down,
Tab,
Delete,
Home,
End,
PageUp,
PageDown,
Esc,
MouseScrollDown,
MouseScrollUp,
Null,
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "arbitrary", derive(Arbitrary))]
pub struct Input {
pub key: Key,
pub ctrl: bool,
pub alt: bool,
}
impl Default for Input {
fn default() -> Self {
Input {
key: Key::Null,
ctrl: false,
alt: false,
}
}
}
#[cfg(any(feature = "crossterm", feature = "ratatui-crossterm"))]
impl From<CrosstermEvent> for Input {
fn from(event: CrosstermEvent) -> Self {
match event {
CrosstermEvent::Key(key) if key.kind != KeyEventKind::Release => Self::from(key),
CrosstermEvent::Mouse(mouse) => Self::from(mouse),
_ => Self::default(),
}
}
}
#[cfg(any(feature = "crossterm", feature = "ratatui-crossterm"))]
impl From<KeyEvent> for Input {
fn from(key: KeyEvent) -> Self {
let ctrl = key.modifiers.contains(KeyModifiers::CONTROL);
let alt = key.modifiers.contains(KeyModifiers::ALT);
let key = match key.code {
KeyCode::Char(c) => Key::Char(c),
KeyCode::Backspace => Key::Backspace,
KeyCode::Enter => Key::Enter,
KeyCode::Left => Key::Left,
KeyCode::Right => Key::Right,
KeyCode::Up => Key::Up,
KeyCode::Down => Key::Down,
KeyCode::Tab => Key::Tab,
KeyCode::Delete => Key::Delete,
KeyCode::Home => Key::Home,
KeyCode::End => Key::End,
KeyCode::PageUp => Key::PageUp,
KeyCode::PageDown => Key::PageDown,
KeyCode::Esc => Key::Esc,
KeyCode::F(x) => Key::F(x),
_ => Key::Null,
};
Self { key, ctrl, alt }
}
}
#[cfg(any(feature = "crossterm", feature = "ratatui-crossterm"))]
impl From<CrosstermMouseEvent> for Input {
fn from(mouse: CrosstermMouseEvent) -> Self {
let key = match mouse.kind {
CrosstermMouseEventKind::ScrollDown => Key::MouseScrollDown,
CrosstermMouseEventKind::ScrollUp => Key::MouseScrollUp,
_ => return Self::default(),
};
let ctrl = mouse.modifiers.contains(KeyModifiers::CONTROL);
let alt = mouse.modifiers.contains(KeyModifiers::ALT);
Self { key, ctrl, alt }
}
}
#[cfg(any(feature = "termion", feature = "ratatui-termion"))]
impl From<TermionEvent> for Input {
fn from(event: TermionEvent) -> Self {
match event {
TermionEvent::Key(key) => Self::from(key),
TermionEvent::Mouse(mouse) => Self::from(mouse),
_ => Self::default(),
}
}
}
#[cfg(any(feature = "termion", feature = "ratatui-termion"))]
impl From<TermionKey> for Input {
fn from(key: TermionKey) -> Self {
use TermionKey::*;
let mut ctrl = false;
let mut alt = false;
let key = match key {
Char('\n' | '\r') => Key::Enter,
Char(c) => Key::Char(c),
Ctrl(c) => {
ctrl = true;
Key::Char(c)
}
Alt(c) => {
alt = true;
Key::Char(c)
}
Backspace => Key::Backspace,
Left => Key::Left,
Right => Key::Right,
Up => Key::Up,
Down => Key::Down,
Home => Key::Home,
End => Key::End,
PageUp => Key::PageUp,
PageDown => Key::PageDown,
BackTab => Key::Tab,
Delete => Key::Delete,
Esc => Key::Esc,
F(x) => Key::F(x),
_ => Key::Null,
};
Input { key, ctrl, alt }
}
}
#[cfg(any(feature = "termion", feature = "ratatui-termion"))]
impl From<TermionMouseEvent> for Input {
fn from(mouse: TermionMouseEvent) -> Self {
use termion::event::MouseButton;
let key = match mouse {
TermionMouseEvent::Press(MouseButton::WheelUp, ..) => Key::MouseScrollUp,
TermionMouseEvent::Press(MouseButton::WheelDown, ..) => Key::MouseScrollDown,
_ => return Self::default(),
};
Self {
key,
ctrl: false,
alt: false,
}
}
}