Skip to main content

netwatch/
event.rs

1use anyhow::Result;
2use crossterm::event::{self, Event, KeyEvent};
3use std::time::Duration;
4use tokio::sync::mpsc;
5
6pub enum AppEvent {
7    Key(KeyEvent),
8    Tick,
9}
10
11pub struct EventHandler {
12    rx: mpsc::UnboundedReceiver<AppEvent>,
13}
14
15impl EventHandler {
16    pub fn new(tick_rate_ms: u64) -> Self {
17        let (tx, rx) = mpsc::unbounded_channel();
18        let tick_rate = Duration::from_millis(tick_rate_ms);
19
20        // Use a dedicated OS thread instead of tokio::spawn, since
21        // crossterm::event::poll() is a blocking call that would tie up
22        // a tokio worker thread permanently.
23        std::thread::spawn(move || {
24            loop {
25                if event::poll(tick_rate).unwrap_or(false) {
26                    if let Ok(Event::Key(key)) = event::read() {
27                        if tx.send(AppEvent::Key(key)).is_err() {
28                            return;
29                        }
30                    }
31                } else if tx.send(AppEvent::Tick).is_err() {
32                    return;
33                }
34            }
35        });
36
37        Self { rx }
38    }
39
40    pub async fn next(&mut self) -> Result<AppEvent> {
41        self.rx
42            .recv()
43            .await
44            .ok_or_else(|| anyhow::anyhow!("Event channel closed"))
45    }
46}