1use crossterm::event::{self, Event as CrosstermEvent, KeyEvent, KeyEventKind};
6use std::time::Duration;
7use tokio::sync::mpsc;
8
9#[derive(Debug, Clone, PartialEq)]
11pub enum Event {
12 Key(KeyEvent),
14 Tick,
16}
17
18pub struct EventHandler {
20 _sender: mpsc::UnboundedSender<Event>,
22 receiver: mpsc::UnboundedReceiver<Event>,
24 _handle: tokio::task::JoinHandle<()>,
26}
27
28impl EventHandler {
29 pub fn new(tick_rate: u64) -> Self {
35 let (sender, receiver) = mpsc::unbounded_channel();
36 let sender_clone = sender.clone();
37 let _handle = tokio::spawn(async move {
38 let mut tick_interval = tokio::time::interval(Duration::from_millis(tick_rate));
39 loop {
40 tokio::select! {
42 _ = tick_interval.tick() => {
43 if sender_clone.send(Event::Tick).is_err() {
44 break;
45 }
46 }
47 }
48 }
49 });
50
51 Self {
52 _sender: sender,
53 receiver,
54 _handle,
55 }
56 }
57
58 pub async fn next(&mut self) -> Event {
64 let key_event = tokio::task::spawn_blocking(move || {
66 if event::poll(Duration::from_millis(10)).ok()? {
67 if let CrosstermEvent::Key(key) = event::read().ok()? {
68 if key.kind == KeyEventKind::Press {
70 return Some(Some(Event::Key(key)));
71 }
72 }
73 }
74 Some(None)
75 })
76 .await
77 .ok()
78 .flatten();
79
80 if let Some(Some(event)) = key_event {
81 return event;
82 }
83
84 self.receiver.recv().await.unwrap_or(Event::Tick)
86 }
87}