use crossterm::event::{self, Event as CrosstermEvent, KeyEvent, KeyEventKind};
use std::time::Duration;
use tokio::sync::mpsc;
#[derive(Debug, Clone, PartialEq)]
pub enum Event {
Key(KeyEvent),
Tick,
}
pub struct EventHandler {
_sender: mpsc::UnboundedSender<Event>,
receiver: mpsc::UnboundedReceiver<Event>,
_handle: tokio::task::JoinHandle<()>,
}
impl EventHandler {
pub fn new(tick_rate: u64) -> Self {
let (sender, receiver) = mpsc::unbounded_channel();
let sender_clone = sender.clone();
let _handle = tokio::spawn(async move {
let mut tick_interval = tokio::time::interval(Duration::from_millis(tick_rate));
loop {
tokio::select! {
_ = tick_interval.tick() => {
if sender_clone.send(Event::Tick).is_err() {
break;
}
}
}
}
});
Self {
_sender: sender,
receiver,
_handle,
}
}
pub async fn next(&mut self) -> Event {
let key_event = tokio::task::spawn_blocking(move || {
if event::poll(Duration::from_millis(10)).ok()? {
if let CrosstermEvent::Key(key) = event::read().ok()? {
if key.kind == KeyEventKind::Press {
return Some(Some(Event::Key(key)));
}
}
}
Some(None)
})
.await
.ok()
.flatten();
if let Some(Some(event)) = key_event {
return event;
}
self.receiver.recv().await.unwrap_or(Event::Tick)
}
}