1use crate::app::AppResult;
2use crossterm::event::{self, Event as CrosstermEvent, KeyEvent, MouseEvent};
3use std::sync::mpsc;
4use std::thread;
5use std::time::{Duration, Instant};
6
7#[derive(Clone, Copy, Debug)]
9pub enum Event {
10 Tick,
12 Key(KeyEvent),
14 Mouse(MouseEvent),
16 Resize(u16, u16),
18}
19
20#[allow(dead_code)]
22#[derive(Debug)]
23pub struct EventHandler {
24 sender: mpsc::Sender<Event>,
26 receiver: mpsc::Receiver<Event>,
28 handler: thread::JoinHandle<()>,
30}
31
32impl EventHandler {
33 pub fn new(tick_rate: u64) -> Self {
35 let tick_rate = Duration::from_millis(tick_rate);
36 let (sender, receiver) = mpsc::channel();
37 let handler = {
38 let sender = sender.clone();
39 thread::spawn(move || {
40 let mut last_tick = Instant::now();
41 loop {
42 let timeout = tick_rate
43 .checked_sub(last_tick.elapsed())
44 .unwrap_or(tick_rate);
45
46 if event::poll(timeout).expect("no events available") {
47 match event::read().expect("unable to read event") {
48 CrosstermEvent::Key(e) => sender.send(Event::Key(e)),
49 CrosstermEvent::Mouse(e) => sender.send(Event::Mouse(e)),
50 CrosstermEvent::Resize(w, h) => sender.send(Event::Resize(w, h)),
51 CrosstermEvent::FocusGained => Ok(()),
52 CrosstermEvent::FocusLost => Ok(()),
53 CrosstermEvent::Paste(_) => unimplemented!(),
54 }
55 .expect("failed to send terminal event")
56 }
57
58 if last_tick.elapsed() >= tick_rate {
59 sender.send(Event::Tick).expect("failed to send tick event");
60 last_tick = Instant::now();
61 }
62 }
63 })
64 };
65 Self {
66 sender,
67 receiver,
68 handler,
69 }
70 }
71
72 pub fn next(&self) -> AppResult<Event> {
77 Ok(self.receiver.recv()?)
78 }
79}