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