1use crate::app::AppResult;
2use ratatui::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 let Ok(poll_result) = event::poll(timeout) {
47 if poll_result {
48 if let Ok(event) = event::read() {
49 let send_result = match event {
50 CrosstermEvent::Key(e) => sender.send(Event::Key(e)),
51 CrosstermEvent::Mouse(e) => sender.send(Event::Mouse(e)),
52 CrosstermEvent::Resize(w, h) => {
53 sender.send(Event::Resize(w, h))
54 }
55 _ => Ok(()),
56 };
57 if send_result.is_err() {
58 break;
59 }
60 }
61 }
62 }
63
64 if last_tick.elapsed() >= tick_rate {
65 if sender.send(Event::Tick).is_err() {
66 break;
67 }
68 last_tick = Instant::now();
69 }
70 }
71 })
72 };
73 Self {
74 sender,
75 receiver,
76 handler,
77 }
78 }
79
80 pub fn next(&self) -> AppResult<Event> {
85 Ok(self.receiver.recv()?)
86 }
87}