use std::{io::Result as IoResult, ops::Deref, sync::mpsc, thread, time::Duration};
use crossterm::event::{self, Event, KeyEvent, KeyEventKind};
#[derive(Copy, Clone)]
pub enum TerminalEvent {
Tick,
Key(KeyEvent),
}
pub struct TerminalEventStream {
rx: mpsc::Receiver<IoResult<TerminalEvent>>,
}
impl TerminalEventStream {
pub fn new(tick_interval: Duration) -> Self {
let (tx, rx) = mpsc::channel();
let keyboard_tx = tx;
thread::spawn(move || keyboard_event_generator(tick_interval, keyboard_tx));
Self { rx }
}
}
impl Deref for TerminalEventStream {
type Target = mpsc::Receiver<IoResult<TerminalEvent>>;
fn deref(&self) -> &Self::Target {
&self.rx
}
}
fn keyboard_event_generator(tick_interval: Duration, tx: mpsc::Sender<IoResult<TerminalEvent>>) {
loop {
match event::poll(tick_interval) {
Ok(true) => {
let ev = event::read().expect("read terminal event should not fail");
if let Event::Key(key) = ev {
#[allow(clippy::collapsible_if)]
if key.kind != KeyEventKind::Release {
if tx.send(Ok(TerminalEvent::Key(key))).is_err() {
break;
}
}
}
}
Ok(false) => {
if tx.send(Ok(TerminalEvent::Tick)).is_err() {
break;
}
}
Err(kind) => {
if tx.send(Err(kind)).is_err() {
break;
}
}
}
}
}