// This file is part of Deja-vu. // // Deja-vu is free software: you can redistribute it and/or modify it // under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Deja-vu is distributed in the hope that it will be useful, but // WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. // See the GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Deja-vu. If not, see . // use std::time::Duration; use crossterm::event::{Event as CrosstermEvent, KeyEvent, MouseEvent}; use futures::{FutureExt, StreamExt}; use tokio::sync::mpsc; use crate::app::AppResult; /// Terminal events. #[derive(Clone, Copy, Debug)] pub enum Event { /// Terminal tick. Tick, /// Key press. Key(KeyEvent), /// Mouse click/scroll. Mouse(MouseEvent), /// Terminal resize. Resize(u16, u16), } /// Terminal event handler. #[allow(dead_code)] #[derive(Debug)] pub struct Handler { /// Event sender channel. sender: mpsc::UnboundedSender, /// Event receiver channel. receiver: mpsc::UnboundedReceiver, /// Event handler thread. handler: tokio::task::JoinHandle<()>, } impl Handler { /// Constructs a new instance of [`Handler`]. /// /// # Panics /// /// Will panic if `sender_clone ` doesn't unwrap #[must_use] pub fn new(tick_rate: u64) -> Self { let tick_rate = Duration::from_millis(tick_rate); let (sender, receiver) = mpsc::unbounded_channel(); let sender_clone = sender.clone(); let handler = tokio::spawn(async move { let mut reader = crossterm::event::EventStream::new(); let mut tick = tokio::time::interval(tick_rate); loop { let tick_delay = tick.tick(); let crossterm_event = reader.next().fuse(); tokio::select! { () = sender_clone.closed() => { break; } _ = tick_delay => { sender_clone.send(Event::Tick).unwrap(); } Some(Ok(evt)) = crossterm_event => { match evt { CrosstermEvent::Key(key) => { if key.kind == crossterm::event::KeyEventKind::Press { sender_clone.send(Event::Key(key)).unwrap(); } }, CrosstermEvent::Mouse(mouse) => { sender_clone.send(Event::Mouse(mouse)).unwrap(); }, CrosstermEvent::Resize(x, y) => { sender_clone.send(Event::Resize(x, y)).unwrap(); }, CrosstermEvent::FocusGained | CrosstermEvent::FocusLost | CrosstermEvent::Paste(_) => {}, } } }; } }); Self { sender, receiver, handler, } } /// Receive the next event from the handler thread. /// /// This function will always block the current thread if /// there is no data available and it's possible for more data to be sent. /// /// # Errors /// /// Will return error if a event is not found pub async fn next(&mut self) -> AppResult { self.receiver .recv() .await .ok_or(Box::new(std::io::Error::new( std::io::ErrorKind::Other, "This is an IO error", ))) } }