rush_sync_server/input/
mod.rs

1// =====================================================
2// FILE: src/input/mod.rs - EVENTS INTEGRIERT
3// =====================================================
4
5pub mod input;
6pub mod keyboard;
7
8// ✅ EVENTS direkt hier statt eigene Datei
9use crossterm::event::{self as crossterm_event, Event as CrosstermEvent, KeyEvent};
10use tokio::sync::mpsc::{self, Sender};
11use tokio::time::{interval, Duration};
12
13#[derive(Debug)]
14pub enum AppEvent {
15    Input(KeyEvent),
16    Tick,
17    Resize(u16, u16),
18}
19
20pub struct EventHandler {
21    rx: mpsc::Receiver<AppEvent>,
22    shutdown_tx: Vec<Sender<()>>,
23}
24
25impl EventHandler {
26    pub fn new(tick_rate: Duration) -> Self {
27        let (tx, rx) = mpsc::channel(100);
28        let mut shutdown_tx = Vec::new();
29
30        // Shutdown-Kanal für Input-Task
31        let (input_shutdown_tx, mut input_shutdown_rx) = mpsc::channel(1);
32        shutdown_tx.push(input_shutdown_tx);
33
34        // Input-Handler Task
35        let input_tx = tx.clone();
36        tokio::spawn(async move {
37            let mut last_event_time = tokio::time::Instant::now();
38            let min_event_interval = Duration::from_millis(33);
39
40            loop {
41                tokio::select! {
42                    _ = input_shutdown_rx.recv() => break,
43                    _ = async {
44                        if crossterm_event::poll(Duration::from_millis(99)).unwrap() {
45                            let now = tokio::time::Instant::now();
46                            if now.duration_since(last_event_time) >= min_event_interval {
47                                if let Ok(event) = crossterm_event::read() {
48                                    match event {
49                                        CrosstermEvent::Key(key) => {
50                                            let _ = input_tx.send(AppEvent::Input(key)).await;
51                                        }
52                                        CrosstermEvent::Resize(width, height) => {
53                                            let _ = input_tx.send(AppEvent::Resize(width, height)).await;
54                                        }
55                                        _ => {}
56                                    }
57                                    last_event_time = now;
58                                }
59                            }
60                        }
61                    } => {}
62                }
63            }
64        });
65
66        // Tick-Handler Task
67        let (tick_shutdown_tx, mut tick_shutdown_rx) = mpsc::channel(1);
68        shutdown_tx.push(tick_shutdown_tx);
69
70        let tick_tx = tx;
71        tokio::spawn(async move {
72            let mut interval = interval(tick_rate);
73            loop {
74                tokio::select! {
75                    _ = tick_shutdown_rx.recv() => break,
76                    _ = interval.tick() => {
77                        let _ = tick_tx.send(AppEvent::Tick).await;
78                    }
79                }
80            }
81        });
82
83        EventHandler { rx, shutdown_tx }
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.iter() {
92            let _ = tx.send(()).await;
93        }
94    }
95}