From 6ffb32c543f1745e94caac8a4e78930c93d44661 Mon Sep 17 00:00:00 2001 From: CrispyPin Date: Sun, 19 Mar 2023 00:10:08 +0100 Subject: [PATCH] init - implement raw mode --- .gitignore | 2 + .rustfmt.toml | 1 + Cargo.toml | 11 ++++ examples/print.rs | 23 +++++++ src/event.rs | 11 ++++ src/lib.rs | 2 + src/raw_mode.rs | 160 ++++++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 210 insertions(+) create mode 100644 .gitignore create mode 100644 .rustfmt.toml create mode 100644 Cargo.toml create mode 100644 examples/print.rs create mode 100644 src/event.rs create mode 100644 src/lib.rs create mode 100644 src/raw_mode.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4fffb2f --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/target +/Cargo.lock diff --git a/.rustfmt.toml b/.rustfmt.toml new file mode 100644 index 0000000..218e203 --- /dev/null +++ b/.rustfmt.toml @@ -0,0 +1 @@ +hard_tabs = true diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..71dd7ba --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "ants" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] + +[[example]] +name = "print" diff --git a/examples/print.rs b/examples/print.rs new file mode 100644 index 0000000..0e7a7a2 --- /dev/null +++ b/examples/print.rs @@ -0,0 +1,23 @@ +use ants::{event::Events, raw_mode}; +use std::{ + io::{stdin, Read}, + time::{Duration, SystemTime}, +}; + +fn main() { + raw_mode::enter().unwrap(); + + let start_time = SystemTime::now(); + + let mut buf = Vec::new(); + while start_time.elapsed().unwrap() < Duration::from_secs(5) { + let mut b = [0u8]; + if let Ok(_n) = stdin().read(&mut b) { + if b[0] != 0 { + buf.push(b[0]); + print!("[{}]:{}\n\r", b[0], String::from_utf8_lossy(&buf)); + } + } + } + raw_mode::exit().unwrap(); +} diff --git a/src/event.rs b/src/event.rs new file mode 100644 index 0000000..c236374 --- /dev/null +++ b/src/event.rs @@ -0,0 +1,11 @@ +use std::io::{stdin, Stdin}; + +pub struct Events { + bytes: Stdin, +} + +impl Events { + pub fn new() -> Self { + Self { bytes: stdin() } + } +} diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..f9f073d --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,2 @@ +pub mod event; +pub mod raw_mode; diff --git a/src/raw_mode.rs b/src/raw_mode.rs new file mode 100644 index 0000000..74e5afa --- /dev/null +++ b/src/raw_mode.rs @@ -0,0 +1,160 @@ +use std::{ + ffi::{c_char, c_int, c_uint}, + io::{self, Result}, + os::fd::{self, AsFd}, +}; + +static mut PREV_TERMINAL_STATE: Option = None; + +pub fn enter() -> Result<()> { + if unsafe { PREV_TERMINAL_STATE.is_some() } { + return Ok(()); + } + + let mut state = Termios::default(); + let stdin = io::stdin(); + + unsafe { + // save current terminal state + check_err(tcgetattr(stdin.as_fd(), &mut state))?; + PREV_TERMINAL_STATE = Some(state.clone()); + } + // https://man7.org/linux/man-pages/man3/termios.3.html + // termios.c_iflag &= !(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON); + // termios.c_oflag &= !OPOST; + // termios.c_lflag &= !(ECHO | ECHONL | ICANON | ISIG | IEXTEN); + // termios.c_cflag &= !(CSIZE | PARENB); + // termios.c_cflag |= CS8; + unsafe { + // set to raw mode + cfmakeraw(&state); + check_err(tcsetattr(stdin.as_fd(), 0, &state))?; + } + Ok(()) +} + +pub fn exit() -> Result<()> { + unsafe { + if let Some(termios) = PREV_TERMINAL_STATE.as_ref() { + let stdin = io::stdin(); + check_err(tcsetattr(stdin.as_fd(), 0, termios))?; + } + } + Ok(()) +} + +fn check_err(val: c_int) -> Result<()> { + if val == -1 { + Err(io::Error::last_os_error()) + } else { + Ok(()) + } +} + +#[derive(Clone, Default)] +#[repr(C)] +struct Termios { + pub c_iflag: c_uint, + pub c_oflag: c_uint, + pub c_cflag: c_uint, + pub c_lflag: c_uint, + pub c_line: c_char, + pub c_cc: [c_char; 32], + // these two seem to be platform specific and don't need to be used + // pub c_ispeed: c_int, + // pub c_ospeed: c_int, +} + +#[link(name = "c")] +extern "C" { + /// get terminal flags for fd + fn tcgetattr(fd: fd::BorrowedFd, termios_p: *mut Termios) -> c_int; + /// set terminal flags for fd + fn tcsetattr(fd: fd::BorrowedFd, optional_actions: c_int, termios_p: *const Termios) -> c_int; + /// set terminal flags to raw mode + fn cfmakeraw(termios_p: *const Termios); +} +/* +const TCIOFF: c_int = 2; +const TCION: c_int = 3; +const TCOOFF: c_int = 0; +const TCOON: c_int = 1; +const TCIFLUSH: c_int = 0; +const TCOFLUSH: c_int = 1; +const TCIOFLUSH: c_int = 2; +const NL0: c_uint = 0x00000000; +const NL1: c_uint = 0x00000100; +const TAB0: c_uint = 0x00000000; +const CR0: c_uint = 0x00000000; +const FF0: c_uint = 0x00000000; +const BS0: c_uint = 0x00000000; +const VT0: c_uint = 0x00000000; +const VERASE: usize = 2; +const VKILL: usize = 3; +const VINTR: usize = 0; +const VQUIT: usize = 1; +const VLNEXT: usize = 15; +const IGNBRK: c_uint = 0x00000001; +const BRKINT: c_uint = 0x00000002; +const IGNPAR: c_uint = 0x00000004; +const PARMRK: c_uint = 0x00000008; +const INPCK: c_uint = 0x00000010; +const ISTRIP: c_uint = 0x00000020; +const INLCR: c_uint = 0x00000040; +const IGNCR: c_uint = 0x00000080; +const ICRNL: c_uint = 0x00000100; +const IXANY: c_uint = 0x00000800; +const IMAXBEL: c_uint = 0x00002000; +const OPOST: c_uint = 0x1; +const CS5: c_uint = 0x00000000; +const CRTSCTS: c_uint = 0x80000000; +const ECHO: c_uint = 0x00000008; +const OCRNL: c_uint = 0o000010; +const ONOCR: c_uint = 0o000020; +const ONLRET: c_uint = 0o000040; +const OFILL: c_uint = 0o000100; +const OFDEL: c_uint = 0o000200; + +const IXON: c_uint = 0x00000400; +const IXOFF: c_uint = 0x00001000; +const ONLCR: c_uint = 0x4; +const CSIZE: c_uint = 0x00000030; +const CS6: c_uint = 0x00000010; +const CS7: c_uint = 0x00000020; +const CS8: c_uint = 0x00000030; +const CSTOPB: c_uint = 0x00000040; +const CREAD: c_uint = 0x00000080; +const PARENB: c_uint = 0x00000100; +const PARODD: c_uint = 0x00000200; +const HUPCL: c_uint = 0x00000400; +const CLOCAL: c_uint = 0x00000800; +const ECHOKE: c_uint = 0x00000800; +const ECHOE: c_uint = 0x00000010; +const ECHOK: c_uint = 0x00000020; +const ECHONL: c_uint = 0x00000040; +const ECHOPRT: c_uint = 0x00000400; +const ECHOCTL: c_uint = 0x00000200; +const ISIG: c_uint = 0x00000001; +const ICANON: c_uint = 0x00000002; +const PENDIN: c_uint = 0x00004000; +const NOFLSH: c_uint = 0x00000080; +const CIBAUD: c_uint = 0o02003600000; +const CBAUDEX: c_uint = 0o010000; +const VSWTC: usize = 7; +const OLCUC: c_uint = 0o000002; +const NLDLY: c_uint = 0o000400; +const CRDLY: c_uint = 0o003000; +const TABDLY: c_uint = 0o014000; +const BSDLY: c_uint = 0o020000; +const FFDLY: c_uint = 0o100000; +const VTDLY: c_uint = 0o040000; +const XTABS: c_uint = 0o014000; + +const VEOL: usize = 11; +const VEOL2: usize = 16; +const VMIN: usize = 6; +const IEXTEN: c_uint = 0x00008000; +const TOSTOP: c_uint = 0x00000100; +const FLUSHO: c_uint = 0x00001000; +const EXTPROC: c_uint = 0x00010000; +// */