Spaces:
Runtime error
Runtime error
/// Inspired by https://github.com/orhun/rust-tui-template/blob/472aa515119d4c94903eac12d9784417281dc7f5/src/event.rs | |
use crossterm::event; | |
use std::time::{Duration, Instant}; | |
use tokio::sync::{broadcast, mpsc}; | |
/// Events | |
pub(crate) enum Event { | |
/// Terminal tick. | |
Tick, | |
/// Key press. | |
Key(event::KeyEvent), | |
/// Terminal resize. | |
Resize(u16, u16), | |
} | |
pub(crate) async fn terminal_event_task( | |
fps: u32, | |
event_sender: mpsc::Sender<Event>, | |
mut shutdown_receiver: broadcast::Receiver<()>, | |
_shutdown_guard_sender: mpsc::Sender<()>, | |
) { | |
// End task if a message is received on shutdown_receiver | |
// _shutdown_guard_sender will be dropped once the task is finished | |
tokio::select! { | |
_ = event_loop(fps, event_sender) => { | |
}, | |
_ = shutdown_receiver.recv() => {} | |
} | |
} | |
/// Main event loop | |
async fn event_loop(fps: u32, event_sender: mpsc::Sender<Event>) { | |
// Frame budget | |
let per_frame = Duration::from_secs(1) / fps; | |
// When was last frame executed | |
let mut last_frame = Instant::now(); | |
loop { | |
// Sleep to avoid blocking the thread for too long | |
if let Some(sleep) = per_frame.checked_sub(last_frame.elapsed()) { | |
tokio::time::sleep(sleep).await; | |
} | |
// Get crossterm event and send a new one over the channel | |
if event::poll(Duration::from_secs(0)).expect("no events available") { | |
match event::read().expect("unable to read event") { | |
event::Event::Key(e) => event_sender.send(Event::Key(e)).await.unwrap_or(()), | |
event::Event::Resize(w, h) => { | |
event_sender.send(Event::Resize(w, h)).await.unwrap_or(()) | |
} | |
_ => (), | |
} | |
} | |
// Frame budget exceeded | |
if last_frame.elapsed() >= per_frame { | |
// Send tick | |
event_sender.send(Event::Tick).await.unwrap_or(()); | |
// Rest last_frame time | |
last_frame = Instant::now(); | |
} | |
} | |
} | |