rush_sync_server/input/
mod.rs

1pub mod keyboard;
2pub mod state;
3
4use crossterm::event::{self as crossterm_event, Event as CrosstermEvent, KeyEvent};
5use tokio::sync::mpsc::{self, Sender};
6use tokio::time::{interval, Duration, Instant};
7
8#[derive(Debug)]
9pub enum AppEvent {
10    Input(KeyEvent),
11    Tick,
12    Resize(u16, u16),
13}
14
15pub struct EventHandler {
16    rx: mpsc::Receiver<AppEvent>,
17    shutdown_tx: Vec<Sender<()>>,
18}
19
20impl EventHandler {
21    pub fn new(tick_rate: Duration) -> Self {
22        let (tx, rx) = mpsc::channel(100);
23        let mut shutdown_tx = Vec::new();
24
25        // Input event handler
26        let (input_shutdown_tx, input_shutdown_rx) = mpsc::channel(1);
27        shutdown_tx.push(input_shutdown_tx);
28        Self::spawn_input_handler(tx.clone(), input_shutdown_rx);
29
30        // Tick handler
31        let (tick_shutdown_tx, tick_shutdown_rx) = mpsc::channel(1);
32        shutdown_tx.push(tick_shutdown_tx);
33        Self::spawn_tick_handler(tx, tick_rate, tick_shutdown_rx);
34
35        EventHandler { rx, shutdown_tx }
36    }
37
38    fn spawn_input_handler(tx: mpsc::Sender<AppEvent>, mut shutdown_rx: mpsc::Receiver<()>) {
39        tokio::spawn(async move {
40            let (mut last_key_time, mut last_resize_time) = (Instant::now(), Instant::now());
41            let (key_interval, resize_interval) =
42                (Duration::from_millis(16), Duration::from_millis(50));
43
44            loop {
45                tokio::select! {
46                    _ = shutdown_rx.recv() => break,
47                    _ = async {
48                        if crossterm_event::poll(Duration::from_millis(99)).unwrap() {
49                            if let Ok(event) = crossterm_event::read() {
50                                let now = Instant::now();
51                                match event {
52                                    CrosstermEvent::Key(key) if now.duration_since(last_key_time) >= key_interval => {
53                                        let _ = tx.send(AppEvent::Input(key)).await;
54                                        last_key_time = now;
55                                    }
56                                    CrosstermEvent::Resize(w, h) if now.duration_since(last_resize_time) >= resize_interval => {
57                                        let _ = tx.send(AppEvent::Resize(w, h)).await;
58                                        last_resize_time = now;
59                                    }
60                                    _ => {}
61                                }
62                            }
63                        }
64                    } => {}
65                }
66            }
67        });
68    }
69
70    fn spawn_tick_handler(
71        tx: mpsc::Sender<AppEvent>,
72        tick_rate: Duration,
73        mut shutdown_rx: mpsc::Receiver<()>,
74    ) {
75        tokio::spawn(async move {
76            let mut interval = interval(tick_rate);
77            loop {
78                tokio::select! {
79                    _ = shutdown_rx.recv() => break,
80                    _ = interval.tick() => { let _ = tx.send(AppEvent::Tick).await; }
81                }
82            }
83        });
84    }
85
86    pub async fn next(&mut self) -> Option<AppEvent> {
87        self.rx.recv().await
88    }
89
90    pub async fn shutdown(&mut self) {
91        for tx in &self.shutdown_tx {
92            let _ = tx.send(()).await;
93        }
94    }
95}