init - implement raw mode

This commit is contained in:
Crispy 2023-03-19 00:10:08 +01:00
commit 6ffb32c543
7 changed files with 210 additions and 0 deletions

2
.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
/target
/Cargo.lock

1
.rustfmt.toml Normal file
View file

@ -0,0 +1 @@
hard_tabs = true

11
Cargo.toml Normal file
View file

@ -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"

23
examples/print.rs Normal file
View file

@ -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();
}

11
src/event.rs Normal file
View file

@ -0,0 +1,11 @@
use std::io::{stdin, Stdin};
pub struct Events {
bytes: Stdin,
}
impl Events {
pub fn new() -> Self {
Self { bytes: stdin() }
}
}

2
src/lib.rs Normal file
View file

@ -0,0 +1,2 @@
pub mod event;
pub mod raw_mode;

160
src/raw_mode.rs Normal file
View file

@ -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<Termios> = 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;
// */