tits_rs/
event.rs

1use crossterm::event::{Event as CrosstermEvent, KeyEvent};
2use futures::{FutureExt, StreamExt};
3use tokio::sync::mpsc;
4
5use crate::app::AppResult;
6
7/// Terminal events.
8#[derive(Clone, Copy, Debug)]
9pub enum Event {
10    /// Terminal tick.
11    Tick,
12    /// Key press.
13    Key(KeyEvent),
14    /// Terminal resize.
15    Resize(u16, u16),
16}
17
18/// Terminal event handler.
19#[allow(dead_code)]
20#[derive(Debug)]
21pub struct EventHandler {
22    /// Event sender channel.
23    pub sender: mpsc::UnboundedSender<Event>,
24    /// Event receiver channel.
25    receiver: mpsc::UnboundedReceiver<Event>,
26    /// Event handler thread.
27    handler: tokio::task::JoinHandle<()>,
28}
29
30impl EventHandler {
31    /// Constructs a new instance of [`EventHandler`].
32    pub fn new() -> Self {
33        let (sender, receiver) = mpsc::unbounded_channel();
34        let _sender = sender.clone();
35        let handler = tokio::spawn(async move {
36            let mut reader = crossterm::event::EventStream::new();
37            loop {
38                let crossterm_event = reader.next().fuse();
39
40                tokio::select! {
41                  _ = _sender.closed() => {
42                    break;
43                  }
44                  Some(Ok(evt)) = crossterm_event => {
45                    match evt {
46                      CrosstermEvent::Key(key) => {
47                        if key.kind == crossterm::event::KeyEventKind::Press {
48                          _sender.send(Event::Key(key)).unwrap();
49                        }
50                      },
51                      CrosstermEvent::Resize(x, y) => {
52                        _sender.send(Event::Resize(x, y)).unwrap();
53                      },
54                      _ => {},
55                    }
56                  }
57                };
58            }
59        });
60        Self {
61            sender,
62            receiver,
63            handler,
64        }
65    }
66
67    /// Receive the next event from the handler thread.
68    ///
69    /// This function will always block the current thread if
70    /// there is no data available and it's possible for more data to be sent.
71    pub async fn next(&mut self) -> AppResult<Event> {
72        self.receiver
73            .recv()
74            .await
75            .ok_or(Box::new(std::io::Error::new(
76                std::io::ErrorKind::Other,
77                "This is an IO error",
78            )))
79    }
80}