envelope_cli/tui/
event.rs1use crossterm::event::{self, Event as CrosstermEvent, KeyEvent, KeyEventKind, MouseEvent};
7use std::sync::mpsc;
8use std::thread;
9use std::time::{Duration, Instant};
10
11#[derive(Debug, Clone)]
13pub enum Event {
14 Key(KeyEvent),
16 Mouse(MouseEvent),
18 Resize(u16, u16),
20 Tick,
22}
23
24pub struct EventHandler {
26 #[allow(dead_code)]
28 sender: mpsc::Sender<Event>,
29 receiver: mpsc::Receiver<Event>,
31 #[allow(dead_code)]
33 handler: thread::JoinHandle<()>,
34}
35
36impl EventHandler {
37 pub fn new(tick_rate: Duration) -> Self {
39 let (sender, receiver) = mpsc::channel();
40 let handler = {
41 let sender = sender.clone();
42 thread::spawn(move || {
43 let mut last_tick = Instant::now();
44 loop {
45 let timeout = tick_rate
47 .checked_sub(last_tick.elapsed())
48 .unwrap_or(Duration::ZERO);
49
50 if event::poll(timeout).expect("Failed to poll events") {
52 match event::read().expect("Failed to read event") {
53 CrosstermEvent::Key(key) if key.kind == KeyEventKind::Press => {
54 if sender.send(Event::Key(key)).is_err() {
55 return;
56 }
57 }
58 CrosstermEvent::Mouse(mouse) => {
59 if sender.send(Event::Mouse(mouse)).is_err() {
60 return;
61 }
62 }
63 CrosstermEvent::Resize(width, height) => {
64 if sender.send(Event::Resize(width, height)).is_err() {
65 return;
66 }
67 }
68 _ => {}
69 }
70 }
71
72 if last_tick.elapsed() >= tick_rate {
74 if sender.send(Event::Tick).is_err() {
75 return;
76 }
77 last_tick = Instant::now();
78 }
79 }
80 })
81 };
82
83 Self {
84 sender,
85 receiver,
86 handler,
87 }
88 }
89
90 pub fn next(&self) -> Result<Event, mpsc::RecvError> {
92 self.receiver.recv()
93 }
94
95 #[allow(dead_code)]
97 pub fn try_next(&self) -> Result<Event, mpsc::TryRecvError> {
98 self.receiver.try_recv()
99 }
100}
101
102impl Default for EventHandler {
103 fn default() -> Self {
104 Self::new(Duration::from_millis(250))
105 }
106}