diff options
Diffstat (limited to 'src/main.rs')
| -rw-r--r-- | src/main.rs | 100 |
1 files changed, 100 insertions, 0 deletions
diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..7f372c1 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,100 @@ +use std::io::{self, Read, Write, IsTerminal}; +use std::os::unix::io::AsRawFd; +use termios::*; + +struct ScopedRawMode { + fd: i32, + settings: Termios, +} + +impl Drop for ScopedRawMode { + fn drop(&mut self) { + self.disable(); + } +} + +impl ScopedRawMode { + fn on_fd(fd: i32) -> Self { + let mut termios = Termios::from_fd(fd).unwrap(); + let settings = termios.clone(); + cfmakeraw(&mut termios); + tcsetattr(fd, TCSANOW, &termios).unwrap(); + Self { fd, settings } + } + + fn disable(&self) { + tcsetattr(self.fd, TCSANOW, &self.settings).unwrap(); + } +} + +macro_rules! print { + ($($x:tt)*) => {{ + write!(io::stdout(), $($x)*).unwrap(); + io::stdout().flush().unwrap(); + }} +} + +fn main() { + let stdin = io::stdin(); + let stdout = io::stdout(); + + if !stdin.is_terminal() { + println!("need to run in a tty"); + return; + } + + let fd = stdin.as_raw_fd(); + let _scoped_raw = ScopedRawMode::on_fd(fd); // needs to be a var, gets dropped on scope exit, + // even if something panics + + let mut stdin = stdin.lock(); + let mut stdout = stdout.lock(); + + let mut buffer = [0u8; 1]; + + loop { + let Ok(_) = stdin.read_exact(&mut buffer) else { + break; + }; + + match buffer[0] { + // EOF + 4 => { + break; + } + + // Enter + b'\r' => { + println!("\r"); + } + + // Backspace (127 on most systems) + 127 => { + write!(stdout, "\x08 \x08").unwrap(); + stdout.flush().unwrap(); + } + + // Escape sequence + 27 => { + let mut seq = [0u8; 2]; + stdin.read_exact(&mut seq).unwrap(); + + if seq[0] == b'[' { + match seq[1] { + b'A' => print!("Up"), + b'B' => print!("Down"), + b'C' => print!("Right"), + b'D' => print!("Left"), + _ => {} + } + } + } + + // Normal character + x => { + stdout.write(&[x]).unwrap(); + stdout.flush().unwrap(); + } + } + } +} |
