use std::io::{self, Read};
unsafe extern "C" {
fn c_enter_raw_mode();
fn c_exit_raw_mode();
fn c_set_stdin_nonblocking();
}
pub fn raw_mode() {
unsafe {
c_enter_raw_mode();
}
}
pub fn exit_raw_mode() {
unsafe {
c_exit_raw_mode();
}
}
pub fn set_stdin_nonblocking() {
unsafe {
c_set_stdin_nonblocking();
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Input {
Return,
Tab,
Up,
Down,
Left,
Right,
Backspace,
Escape,
Character(char),
}
impl Input {
pub fn get() -> io::Result<Self> {
let mut stdin = io::stdin();
let mut buffer = [0];
stdin.read_exact(&mut buffer)?;
let character = buffer[0] as char;
Ok(match character {
'\n' => Self::Return,
'\t' => Self::Tab,
'\x1b' => Self::parse_escape()?,
'\u{7f}' => Self::Backspace,
_ => Self::Character(character),
})
}
fn parse_escape() -> io::Result<Self> {
let mut stdin = io::stdin();
let mut buffer = [0, 0];
if let Err(e) = stdin.read_exact(&mut buffer) {
crate::logging::log(format!(
"Couldn't read next character because {e}. Returning Input::Escape"
));
return Ok(Self::Escape);
}
let sequence = match String::from_utf8(buffer.to_vec()) {
Ok(seq) => seq,
Err(e) => return Err(io::Error::other(e)),
};
Ok(match sequence.as_str() {
"[A" => Self::Up,
"[B" => Self::Down,
"[C" => Self::Right,
"[D" => Self::Left,
_ => Self::Character(' '), })
}
}
impl From<Input> for char {
fn from(value: Input) -> Self {
match value {
Input::Return => '\n',
Input::Character(c) => c,
Input::Tab => '\t',
_ => ' ',
}
}
}