use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Mutex;
static SAVED: Mutex<Option<libc::termios>> = Mutex::new(None);
static QUIT: AtomicBool = AtomicBool::new(false);
pub fn restore() {
if let Ok(mut guard) = SAVED.lock() {
if let Some(settings) = guard.take() {
unsafe {
libc::tcsetattr(libc::STDIN_FILENO, libc::TCSANOW, &settings);
}
}
}
}
extern "C" fn on_signal(_signal: libc::c_int) {
restore();
unsafe { libc::_exit(0) }
}
pub fn watch_for_quit() -> bool {
if !crate::sys::stdin_is_terminal() {
return false;
}
let mut settings: libc::termios = unsafe { std::mem::zeroed() };
if unsafe { libc::tcgetattr(libc::STDIN_FILENO, &mut settings) } != 0 {
return false;
}
if let Ok(mut guard) = SAVED.lock() {
*guard = Some(settings);
}
let mut raw = settings;
raw.c_lflag &= !(libc::ICANON | libc::ECHO);
raw.c_cc[libc::VMIN] = 1;
raw.c_cc[libc::VTIME] = 0;
if unsafe { libc::tcsetattr(libc::STDIN_FILENO, libc::TCSANOW, &raw) } != 0 {
return false;
}
unsafe {
let handler = on_signal as *const () as libc::sighandler_t;
libc::signal(libc::SIGINT, handler);
libc::signal(libc::SIGTERM, handler);
libc::signal(libc::SIGHUP, handler);
}
std::thread::spawn(|| {
use std::io::Read;
let mut byte = [0u8; 1];
while std::io::stdin().read(&mut byte).unwrap_or(0) == 1 {
if byte[0] == b'q' || byte[0] == b'Q' {
QUIT.store(true, Ordering::SeqCst);
return;
}
}
});
true
}
pub fn quit_requested() -> bool {
QUIT.load(Ordering::SeqCst)
}