use crossterm::event::{self, Event};
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{Arc, mpsc};
use std::thread::JoinHandle;
pub struct InputThread {
pub rx: mpsc::Receiver<Event>,
quit_flag: Arc<AtomicBool>,
pause_flag: Arc<AtomicBool>,
handle: Option<JoinHandle<()>>,
}
impl InputThread {
pub fn spawn() -> Self {
let (tx, rx) = mpsc::channel::<Event>();
let quit_flag = Arc::new(AtomicBool::new(false));
let pause_flag = Arc::new(AtomicBool::new(false));
let quit = Arc::clone(&quit_flag);
let pause = Arc::clone(&pause_flag);
let handle = std::thread::Builder::new()
.name("input-thread".into())
.spawn(move || {
Self::run_loop(tx, quit, pause);
})
.expect("failed to spawn input thread");
Self {
rx,
quit_flag,
pause_flag,
handle: Some(handle),
}
}
fn run_loop(tx: mpsc::Sender<Event>, quit: Arc<AtomicBool>, pause: Arc<AtomicBool>) {
while !quit.load(Ordering::Acquire) {
if pause.load(Ordering::Acquire) {
std::thread::sleep(std::time::Duration::from_millis(50));
continue;
}
match event::poll(std::time::Duration::from_millis(50)) {
Ok(true) => {
if pause.load(Ordering::Acquire) {
continue;
}
match event::read() {
Ok(evt) => {
if tx.send(evt).is_err() {
break;
}
}
Err(_) => {
std::thread::sleep(std::time::Duration::from_millis(10));
}
}
}
Ok(false) => {
}
Err(_) => {
std::thread::sleep(std::time::Duration::from_millis(10));
}
}
}
}
pub fn pause(&self) {
self.pause_flag.store(true, Ordering::Release);
std::thread::sleep(std::time::Duration::from_millis(120));
}
pub fn resume(&self) {
self.pause_flag.store(false, Ordering::Release);
}
pub fn drain(&self) {
while self.rx.try_recv().is_ok() {}
}
pub fn shutdown(mut self) {
self.stop_inner();
}
fn stop_inner(&mut self) {
self.quit_flag.store(true, Ordering::Release);
if let Some(handle) = self.handle.take() {
let _ = handle.join();
}
}
}
impl Drop for InputThread {
fn drop(&mut self) {
self.stop_inner();
}
}