use std::sync::mpsc;
use std::thread;
use std::time::{Duration, Instant};
use anyhow::Result;
use crossterm::event::{self, Event as CrosstermEvent, KeyEvent};
pub enum Event {
Input(KeyEvent),
Tick,
Resize(u16, u16),
}
pub struct Events {
rx: mpsc::Receiver<Event>,
_tx: mpsc::Sender<Event>,
}
impl Events {
pub fn with_config(config: Config) -> Self {
let (tx, rx) = mpsc::channel();
let event_tx = tx.clone();
let tick_rate = config.tick_rate;
thread::spawn(move || {
let mut last_tick = Instant::now();
loop {
let timeout = tick_rate
.checked_sub(last_tick.elapsed())
.unwrap_or_else(|| Duration::from_secs(0));
match event::poll(timeout) {
Ok(true) => match event::read() {
Ok(CrosstermEvent::Key(key)) => {
if event_tx.send(Event::Input(key)).is_err() {
break;
}
}
Ok(CrosstermEvent::Resize(width, height)) => {
if event_tx.send(Event::Resize(width, height)).is_err() {
break;
}
}
Ok(_) => {}
Err(_) => break,
},
Ok(false) => {}
Err(_) => break,
}
if last_tick.elapsed() >= tick_rate {
if event_tx.send(Event::Tick).is_err() {
break;
}
last_tick = Instant::now();
}
}
});
Self { rx, _tx: tx }
}
pub fn next(&self) -> Result<Event> {
Ok(self.rx.recv()?)
}
}
pub struct Config {
pub tick_rate: Duration,
}
impl Default for Config {
fn default() -> Self {
Self {
tick_rate: Duration::from_millis(250),
}
}
}