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
122
123
124
125
126
127
128
use crossbeam::channel::{unbounded, Receiver, Sender};
use crossterm::{
input::{self, TerminalInput},
screen::RawScreen,
};
use std::sync::{
atomic::{AtomicUsize, Ordering},
Arc,
};
use std::thread;
use std::time::{Duration, Instant};
use crate::{errors::Error, events::Event};
const DOUBLE_CLICK_MAX_DURATION: Duration = Duration::from_millis(700);
struct TimedEvent {
time: Instant,
event: Event,
}
impl From<Event> for TimedEvent {
fn from(event: Event) -> Self {
TimedEvent {
time: Instant::now(),
event,
}
}
}
pub struct EventSource {
rx_events: Receiver<Event>,
tx_quit: Sender<bool>,
event_count: Arc<AtomicUsize>,
_raw_screen: RawScreen,
}
impl EventSource {
pub fn new() -> Result<EventSource, Error> {
let (tx_events, rx_events) = unbounded();
let (tx_quit, rx_quit) = unbounded();
let event_count = Arc::new(AtomicUsize::new(0));
let internal_event_count = Arc::clone(&event_count);
let _raw_screen = RawScreen::into_raw_mode()?;
let input = TerminalInput::new();
let mut last_event: Option<TimedEvent> = None;
let mut crossterm_events = input.read_sync();
thread::spawn(move || {
loop {
let crossterm_event = crossterm_events.next();
if let Some(mut event) = Event::from_crossterm_event(crossterm_event) {
if let Event::Click(x, y) = event {
if let Some(TimedEvent {
time,
event: Event::Click(_, last_y),
}) = last_event
{
if last_y == y && time.elapsed() < DOUBLE_CLICK_MAX_DURATION {
event = Event::DoubleClick(x, y);
}
}
}
last_event = Some(TimedEvent::from(event.clone()));
internal_event_count.fetch_add(1, Ordering::SeqCst);
tx_events.send(event).unwrap();
let quit = rx_quit.recv().unwrap();
if quit {
input::stop_reading_thread();
return;
}
}
}
});
Ok(EventSource {
rx_events,
tx_quit,
event_count,
_raw_screen,
})
}
pub fn unblock(&self, quit: bool) {
self.tx_quit.send(quit).unwrap();
}
pub fn shared_event_count(&self) -> Arc<AtomicUsize> {
Arc::clone(&self.event_count)
}
pub fn receiver(&self) -> Receiver<Event> {
self.rx_events.clone()
}
}