use std::{thread, time};
use std::sync::mpsc;
use std::error::Error;
use futures::{select, pin_mut, future::FutureExt};
use futures::StreamExt;
use futures::executor::block_on;
use crossterm::terminal::{disable_raw_mode, enable_raw_mode};
use crossterm::event; use crossterm::event::{Event, EventStream, KeyCode, KeyModifiers};
pub struct NbStdin {
reader: EventStream
}
impl NbStdin {
pub fn start() -> Self {
let nb = NbStdin{reader: EventStream::new()};
enable_raw_mode().unwrap();
nb
}
pub fn stop(&self) {
disable_raw_mode().unwrap();
}
pub fn break_with_esc(e: Event) -> bool {
match e {
Event::Key(ke) => {
if ke.code == KeyCode::Esc { return true; }
if ke.modifiers == KeyModifiers::CONTROL {
if ke.code == KeyCode::Char('c') { return true; } }
if ke.modifiers == KeyModifiers::CONTROL | KeyModifiers::SHIFT {
if ke.code == KeyCode::Char('C') { return true; } }
()
},
_ => ()
}
false
}
pub async fn async_stdin(&mut self, lambda: fn (e: Event) -> bool) -> Result<bool, Box<dyn Error>> {
match self.reader.next().await { None => (),
Some(Err(e)) => { println!("Error: {:?}", e); () },
Some(Ok(e)) => { if lambda(e) { return Ok(true); } }
}
Ok(false)
}
pub async fn select_stdin(timeout: time::Duration) -> Result<Option<Event>, Box<dyn Error>> {
let now = time::Instant::now();
let mut reader = EventStream::new();
loop {
let c = reader.next().fuse();
pin_mut!(c);
select! {
e = c => {
match e {
None => (),
Some(Err(e)) => { println!("Error: {:?}", e); () },
Some(Ok(e)) => { return Ok(Some(e)); }
}
},
complete => break,
default => {
if now.elapsed() < timeout { () } else { break; } }
}
}
Ok(None)
}
pub fn async_non_blocking_stdin(timeout: time::Duration, lambda: fn (e: Event) -> bool) -> bool {
let (tx, rx) = mpsc::channel();
let _handle = thread::spawn(move || {
loop {
match block_on(NbStdin::select_stdin(timeout)).unwrap() { None => (),
Some(e) => {
match tx.send(e) {
Ok(()) => break,
Err(_) => ()
}
}
}
}
()
});
match rx.recv_timeout(timeout) {
Ok(e) => { if lambda(e) { return true; } },
Err(mpsc::RecvTimeoutError::Timeout) => (),
Err(mpsc::RecvTimeoutError::Disconnected) => { println!("disconnected"); () } }
false
}
pub fn non_blocking_stdin(timeout: time::Duration, lambda: fn (e: Event) -> bool) -> bool {
let (tx, rx) = mpsc::channel();
let _handle = thread::spawn(move || {
loop {
if !event::poll(timeout).unwrap() { break; } else {
match event::read().unwrap() { e => {
match tx.send(e) {
Ok(()) => (),
Err(_) => ()
}
break;
}
}
}
}
()
});
match rx.recv_timeout(timeout) {
Ok(e) => { if lambda(e) { return true; } },
Err(mpsc::RecvTimeoutError::Timeout) => (),
Err(mpsc::RecvTimeoutError::Disconnected) => { println!("disconnected"); () } }
false
}
}