1use crossterm::event::{Event, EventStream, KeyEvent, KeyEventKind, MouseEvent};
2use std::time::Duration;
3use tokio::sync::mpsc;
4use tokio_stream::StreamExt;
5
6#[derive(Debug)]
7pub enum AppEvent {
8 Key(KeyEvent),
9 Mouse(MouseEvent),
10 Tick,
11 Resize(u16, u16),
12}
13
14pub struct EventHandler {
15 rx: mpsc::UnboundedReceiver<AppEvent>,
16 _task: tokio::task::JoinHandle<()>,
17}
18
19impl EventHandler {
20 pub fn new(tick_rate: Duration) -> Self {
21 let (tx, rx) = mpsc::unbounded_channel();
22
23 let task = tokio::spawn(async move {
24 let mut reader = EventStream::new();
25 let mut tick_interval = tokio::time::interval(tick_rate);
26
27 loop {
28 tokio::select! {
29 _ = tick_interval.tick() => {
30 if tx.send(AppEvent::Tick).is_err() {
31 break;
32 }
33 }
34 event = reader.next() => {
35 let app_event = match event {
38 Some(Ok(Event::Key(key))) if key.kind == KeyEventKind::Press => {
39 AppEvent::Key(key)
40 }
41 Some(Ok(Event::Mouse(mouse))) => AppEvent::Mouse(mouse),
42 Some(Ok(Event::Resize(w, h))) => AppEvent::Resize(w, h),
43 Some(Err(_)) | None => break,
44 _ => continue,
45 };
46 if tx.send(app_event).is_err() {
47 break;
48 }
49 }
50 }
51 }
52 });
53
54 Self { rx, _task: task }
55 }
56
57 pub async fn next(&mut self) -> Option<AppEvent> {
58 self.rx.recv().await
59 }
60}