95 lines
2.3 KiB
Rust
95 lines
2.3 KiB
Rust
use std::mem;
|
|
use std::io::{self,Write};
|
|
|
|
pub use libc::termios as Termios;
|
|
use libc::c_int;
|
|
|
|
use crate::Result;
|
|
|
|
fn get_terminal_attr() -> Result<Termios> {
|
|
extern "C" {
|
|
pub fn tcgetattr(fd: c_int, termptr: *mut Termios) -> c_int;
|
|
}
|
|
unsafe {
|
|
let mut termios = mem::zeroed();
|
|
if tcgetattr(0, &mut termios) == -1 {
|
|
bail!("error calling tcgetattr() on terminal: {}", io::Error::last_os_error());
|
|
}
|
|
Ok(termios)
|
|
}
|
|
}
|
|
|
|
fn set_terminal_attr(termios: &Termios) -> Result<()> {
|
|
extern "C" {
|
|
pub fn tcsetattr(fd: c_int, opt: c_int, termptr: *const Termios) -> c_int;
|
|
}
|
|
unsafe {
|
|
if tcsetattr(0, 0, termios) == -1 {
|
|
bail!("error calling tcsetattr() on terminal: {}", io::Error::last_os_error());
|
|
}
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
fn raw_terminal_attr(termios: &mut Termios) {
|
|
extern "C" {
|
|
pub fn cfmakeraw(termptr: *mut Termios);
|
|
}
|
|
unsafe { cfmakeraw(termios) }
|
|
}
|
|
|
|
pub struct RawTerminal<W: Write> {
|
|
output: W,
|
|
prev_ios: Termios,
|
|
raw_ios: Termios,
|
|
}
|
|
|
|
|
|
impl <W: Write> RawTerminal<W> {
|
|
|
|
pub fn raw_terminal_attr() -> Result<Termios> {
|
|
let mut ios = get_terminal_attr()?;
|
|
raw_terminal_attr(&mut ios);
|
|
ios.c_cc[libc::VMIN] = 0;
|
|
ios.c_cc[libc::VTIME] = 1;
|
|
Ok(ios)
|
|
}
|
|
|
|
pub fn create_with_termios(output: W, raw_ios: Termios) -> Result<Self> {
|
|
let prev_ios = get_terminal_attr()?;
|
|
set_terminal_attr(&raw_ios)?;
|
|
Ok(RawTerminal{ output, prev_ios, raw_ios })
|
|
}
|
|
|
|
pub fn create(output: W) -> Result<Self> {
|
|
let raw_ios = RawTerminal::<W>::raw_terminal_attr()?;
|
|
RawTerminal::create_with_termios(output, raw_ios)
|
|
}
|
|
|
|
pub fn suspend_raw_mode(&self) -> Result<()> {
|
|
set_terminal_attr(&self.prev_ios)?;
|
|
Ok(())
|
|
}
|
|
|
|
pub fn activate_raw_mode(&self) -> Result<()> {
|
|
set_terminal_attr(&self.raw_ios)?;
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
impl <W: Write> Drop for RawTerminal<W> {
|
|
fn drop(&mut self) {
|
|
self.suspend_raw_mode().unwrap()
|
|
}
|
|
}
|
|
|
|
impl<W: Write> Write for RawTerminal<W> {
|
|
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
|
self.output.write(buf)
|
|
}
|
|
|
|
fn flush(&mut self) -> io::Result<()> {
|
|
self.output.flush()
|
|
}
|
|
}
|