use crate::{
database::{CachedDocInfo, PkgKey},
Result,
};
use crossterm::event::{
self, Event as CrosstermEvent, KeyEvent, MouseButton, MouseEvent, MouseEventKind,
};
use std::{
sync::mpsc,
thread,
time::{Duration, Instant},
};
#[derive(Debug)]
pub enum Event {
Key(KeyEvent),
Mouse(MouseEvent),
MouseDoubleClick(u16, u16),
Resize(u16, u16),
DocCompiled(Box<CachedDocInfo>),
CrateDoc(Box<PkgKey>),
Downgraded(Box<PkgKey>),
}
pub type Sender = mpsc::Sender<Event>;
#[derive(Debug)]
pub struct EventHandler {
sender: mpsc::Sender<Event>,
receiver: mpsc::Receiver<Event>,
#[allow(dead_code)]
handler: thread::JoinHandle<()>,
}
impl EventHandler {
pub fn new(timeout: u64) -> Self {
let timeout = Duration::from_millis(timeout);
let (sender, receiver) = mpsc::channel();
let handler = {
let sender = sender.clone();
thread::spawn(move || {
let mut last_click = Instant::now();
loop {
if event::poll(timeout).expect("unable to poll for event") {
match event::read().expect("unable to read event") {
CrosstermEvent::Key(e) => {
if e.kind == event::KeyEventKind::Press {
sender.send(Event::Key(e))
} else {
Ok(()) }
}
CrosstermEvent::Mouse(e) => {
if let MouseEventKind::Down(MouseButton::Left) = &e.kind {
let now = Instant::now();
let old = std::mem::replace(&mut last_click, now);
if let Some(diff) = now.checked_duration_since(old) {
if diff < Duration::from_millis(450) {
sender
.send(Event::MouseDoubleClick(e.column, e.row))
.expect("failed to send MouseDoubleClick event");
continue; }
}
}
sender.send(Event::Mouse(e))
}
CrosstermEvent::Resize(w, h) => sender.send(Event::Resize(w, h)),
_ => Ok(()),
}
.expect("failed to send terminal event")
}
}
})
};
Self {
sender,
receiver,
handler,
}
}
pub fn next(&self) -> Result<Event> {
Ok(self.receiver.recv()?)
}
pub fn get_sender(&self) -> Sender {
self.sender.clone()
}
}