1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
use anyhow::Result;
use crossterm::event::{self, Event, KeyEvent, MouseButton, MouseEventKind};
use std::time::Duration;
use tokio::sync::mpsc;
#[derive(Debug)]
pub enum AppEvent {
Key(KeyEvent),
Paste(String),
MouseScrollUp { x: u16, y: u16 },
MouseScrollDown { x: u16, y: u16 },
MouseClick { x: u16, y: u16 },
MouseDrag { x: u16, y: u16 },
MouseUp { x: u16, y: u16 },
Resize((), ()),
Tick,
}
pub struct EventHandler {
rx: mpsc::UnboundedReceiver<AppEvent>,
}
impl EventHandler {
pub fn new(tick_rate: Duration) -> Self {
let (tx, rx) = mpsc::unbounded_channel();
tokio::spawn(async move {
loop {
if event::poll(tick_rate).unwrap_or(false) {
match event::read() {
Ok(Event::Key(key)) => {
if tx.send(AppEvent::Key(key)).is_err() {
return;
}
}
Ok(Event::Mouse(mouse)) => match mouse.kind {
MouseEventKind::ScrollUp => {
if tx
.send(AppEvent::MouseScrollUp {
x: mouse.column,
y: mouse.row,
})
.is_err()
{
return;
}
}
MouseEventKind::ScrollDown => {
if tx
.send(AppEvent::MouseScrollDown {
x: mouse.column,
y: mouse.row,
})
.is_err()
{
return;
}
}
MouseEventKind::Down(MouseButton::Left) => {
if tx
.send(AppEvent::MouseClick {
x: mouse.column,
y: mouse.row,
})
.is_err()
{
return;
}
}
MouseEventKind::Drag(MouseButton::Left) => {
if tx
.send(AppEvent::MouseDrag {
x: mouse.column,
y: mouse.row,
})
.is_err()
{
return;
}
}
MouseEventKind::Up(MouseButton::Left) => {
if tx
.send(AppEvent::MouseUp {
x: mouse.column,
y: mouse.row,
})
.is_err()
{
return;
}
}
_ => {}
},
Ok(Event::Paste(text)) => {
if tx.send(AppEvent::Paste(text)).is_err() {
return;
}
}
Ok(Event::Resize(_w, _h)) => {
if tx.send(AppEvent::Resize((), ())).is_err() {
return;
}
}
_ => {}
}
} else if tx.send(AppEvent::Tick).is_err() {
return;
}
}
});
Self { rx }
}
pub async fn next(&mut self) -> Result<AppEvent> {
self.rx
.recv()
.await
.ok_or_else(|| anyhow::anyhow!("Event channel closed"))
}
}