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 match event {
36 Some(Ok(Event::Key(key))) => {
37 if key.kind != KeyEventKind::Press {
40 continue;
41 }
42 if tx.send(AppEvent::Key(key)).is_err() {
43 break;
44 }
45 }
46 Some(Ok(Event::Mouse(mouse))) => {
47 if tx.send(AppEvent::Mouse(mouse)).is_err() {
48 break;
49 }
50 }
51 Some(Ok(Event::Resize(w, h))) => {
52 if tx.send(AppEvent::Resize(w, h)).is_err() {
53 break;
54 }
55 }
56 Some(Err(_)) | None => break,
57 _ => {}
58 }
59 }
60 }
61 }
62 });
63
64 Self { rx, _task: task }
65 }
66
67 pub async fn next(&mut self) -> Option<AppEvent> {
68 self.rx.recv().await
69 }
70}