binocular/runtime/interactive/
input.rs1use crate::infra::channel::Sender;
2use crossterm::event::{self, Event, KeyEvent, KeyEventKind};
3use std::time::Duration;
4
5pub enum InputEvent {
6 Key(KeyEvent),
7 Resize(u16, u16),
8 Tick,
9}
10
11pub fn spawn_input_handler(tx: impl Sender<InputEvent>) {
12 std::thread::spawn(move || {
13 let tick_rate = Duration::from_millis(16);
14 let mut last_tick = std::time::Instant::now();
15
16 loop {
17 let timeout = tick_rate
18 .checked_sub(last_tick.elapsed())
19 .unwrap_or_else(|| Duration::from_secs(0));
20
21 if event::poll(timeout).unwrap_or(false) {
22 match event::read() {
23 Ok(Event::Key(key)) => {
24 if key.kind == KeyEventKind::Press {
25 let _ = tx.send(InputEvent::Key(key));
26 }
27 }
28 Ok(Event::Resize(w, h)) => {
29 let _ = tx.send(InputEvent::Resize(w, h));
30 }
31 _ => {}
32 }
33 }
34
35 if last_tick.elapsed() >= tick_rate {
36 let _ = tx.send(InputEvent::Tick);
37 last_tick = std::time::Instant::now();
38 }
39 }
40 });
41}