1use std::time::Duration;
2
3use anyhow::{anyhow, Result};
4#[cfg(not(test))]
5use crossterm::event::{poll, read};
6use crossterm::event::{Event, KeyEvent, KeyEventKind, MouseEvent, MouseEventKind};
7#[cfg(test)]
8use read_event_mocks::{poll, read};
9
10pub trait EventReaderFn: Fn() -> Result<Option<Event>> + Send + Sync + 'static {}
12
13impl<FN: Fn() -> Result<Option<Event>> + Send + Sync + 'static> EventReaderFn for FN {}
14
15#[inline]
23pub fn read_event() -> Result<Option<Event>> {
24 if poll(Duration::from_millis(20)).unwrap_or(false) {
25 read()
26 .map(|event| {
27 match event {
28 e @ (Event::Key(KeyEvent {
29 kind: KeyEventKind::Press | KeyEventKind::Repeat,
30 ..
31 })
32 | Event::Mouse(MouseEvent {
33 kind: MouseEventKind::Down(_) | MouseEventKind::ScrollDown | MouseEventKind::ScrollUp,
34 ..
35 })
36 | Event::Resize(..)) => Some(e),
37 Event::Key(_) | Event::Mouse(_) | Event::Paste(_) | Event::FocusGained | Event::FocusLost => None,
38 }
39 })
40 .map_err(|err| anyhow!("{:#}", err).context("Unexpected Error"))
41 }
42 else {
43 Ok(None)
44 }
45}
46
47#[cfg(test)]
48mod read_event_mocks {
49 use std::{mem, time::Duration};
50
51 use crossterm::{
52 event::{Event, KeyCode, KeyEvent},
53 Result,
54 };
55 use lazy_static::lazy_static;
56 use parking_lot::Mutex;
57
58 lazy_static! {
59 pub static ref HAS_POLLED_EVENT: Mutex<Result<bool>> = Mutex::new(Ok(true));
60 pub static ref NEXT_EVENT: Mutex<Result<Event>> = Mutex::new(Ok(Event::Key(KeyEvent::from(KeyCode::Null))));
61 }
62
63 pub(crate) fn poll(_: Duration) -> Result<bool> {
64 let mut lock = HAS_POLLED_EVENT.lock();
65 mem::replace(&mut *lock, Ok(false))
66 }
67
68 pub(crate) fn read() -> Result<Event> {
69 let mut lock = NEXT_EVENT.lock();
70 mem::replace(&mut *lock, Ok(Event::Key(KeyEvent::from(KeyCode::Null))))
71 }
72}
73
74#[cfg(test)]
75mod tests {
76 use std::{io, io::ErrorKind};
77
78 use crossterm::event::{KeyCode, KeyEvent, KeyModifiers, MouseButton};
79
80 use super::*;
81
82 #[test]
83 #[serial_test::serial]
84 fn read_event_poll_error() {
85 let mut lock = read_event_mocks::HAS_POLLED_EVENT.lock();
86 *lock = Err(io::Error::from(ErrorKind::Other));
87 drop(lock);
88
89 assert!(read_event().unwrap().is_none());
90 }
91
92 #[test]
93 #[serial_test::serial]
94 fn read_event_poll_timeout() {
95 let mut lock = read_event_mocks::HAS_POLLED_EVENT.lock();
96 *lock = Ok(false);
97 drop(lock);
98
99 assert!(read_event().unwrap().is_none());
100 }
101
102 #[test]
103 #[serial_test::serial]
104 fn read_event_read_error() {
105 let mut lock = read_event_mocks::NEXT_EVENT.lock();
106 *lock = Err(io::Error::from(ErrorKind::Other));
107 drop(lock);
108
109 let mut lock = read_event_mocks::HAS_POLLED_EVENT.lock();
110 *lock = Ok(true);
111 drop(lock);
112
113 assert_eq!(read_event().unwrap_err().to_string(), "Unexpected Error");
114 }
115
116 #[test]
117 #[serial_test::serial]
118 fn read_event_read_key_press() {
119 let mut lock = read_event_mocks::NEXT_EVENT.lock();
120 *lock = Ok(Event::Key(KeyEvent::from(KeyCode::Enter)));
121 drop(lock);
122
123 let mut lock = read_event_mocks::HAS_POLLED_EVENT.lock();
124 *lock = Ok(true);
125 drop(lock);
126
127 assert_eq!(read_event().unwrap(), Some(Event::Key(KeyEvent::from(KeyCode::Enter))));
128 }
129
130 #[test]
131 #[serial_test::serial]
132 fn read_event_read_key_repeat() {
133 let mut lock = read_event_mocks::NEXT_EVENT.lock();
134 *lock = Ok(Event::Key(KeyEvent::new_with_kind(
135 KeyCode::Enter,
136 KeyModifiers::NONE,
137 KeyEventKind::Repeat,
138 )));
139 drop(lock);
140
141 let mut lock = read_event_mocks::HAS_POLLED_EVENT.lock();
142 *lock = Ok(true);
143 drop(lock);
144
145 assert_eq!(
146 read_event().unwrap(),
147 Some(Event::Key(KeyEvent::new_with_kind(
148 KeyCode::Enter,
149 KeyModifiers::NONE,
150 KeyEventKind::Repeat,
151 )))
152 );
153 }
154
155 #[test]
156 #[serial_test::serial]
157 fn read_event_read_mouse_down() {
158 let mut lock = read_event_mocks::NEXT_EVENT.lock();
159 *lock = Ok(Event::Mouse(MouseEvent {
160 kind: MouseEventKind::Down(MouseButton::Right),
161 column: 0,
162 row: 0,
163 modifiers: KeyModifiers::NONE,
164 }));
165 drop(lock);
166
167 let mut lock = read_event_mocks::HAS_POLLED_EVENT.lock();
168 *lock = Ok(true);
169 drop(lock);
170
171 assert_eq!(
172 read_event().unwrap(),
173 Some(Event::Mouse(MouseEvent {
174 kind: MouseEventKind::Down(MouseButton::Right),
175 column: 0,
176 row: 0,
177 modifiers: KeyModifiers::NONE
178 }))
179 );
180 }
181
182 #[test]
183 #[serial_test::serial]
184 fn read_event_read_mouse_scroll_down() {
185 let mut lock = read_event_mocks::NEXT_EVENT.lock();
186 *lock = Ok(Event::Mouse(MouseEvent {
187 kind: MouseEventKind::ScrollDown,
188 column: 0,
189 row: 0,
190 modifiers: KeyModifiers::NONE,
191 }));
192 drop(lock);
193
194 let mut lock = read_event_mocks::HAS_POLLED_EVENT.lock();
195 *lock = Ok(true);
196 drop(lock);
197
198 assert_eq!(
199 read_event().unwrap(),
200 Some(Event::Mouse(MouseEvent {
201 kind: MouseEventKind::ScrollDown,
202 column: 0,
203 row: 0,
204 modifiers: KeyModifiers::NONE
205 }))
206 );
207 }
208
209 #[test]
210 #[serial_test::serial]
211 fn read_event_read_mouse_scroll_up() {
212 let mut lock = read_event_mocks::NEXT_EVENT.lock();
213 *lock = Ok(Event::Mouse(MouseEvent {
214 kind: MouseEventKind::ScrollDown,
215 column: 0,
216 row: 0,
217 modifiers: KeyModifiers::NONE,
218 }));
219 drop(lock);
220
221 let mut lock = read_event_mocks::HAS_POLLED_EVENT.lock();
222 *lock = Ok(true);
223 drop(lock);
224
225 assert_eq!(
226 read_event().unwrap(),
227 Some(Event::Mouse(MouseEvent {
228 kind: MouseEventKind::ScrollDown,
229 column: 0,
230 row: 0,
231 modifiers: KeyModifiers::NONE
232 }))
233 );
234 }
235
236 #[test]
237 #[serial_test::serial]
238 fn read_event_read_resize() {
239 let mut lock = read_event_mocks::NEXT_EVENT.lock();
240 *lock = Ok(Event::Resize(1, 1));
241 drop(lock);
242
243 let mut lock = read_event_mocks::HAS_POLLED_EVENT.lock();
244 *lock = Ok(true);
245 drop(lock);
246
247 assert_eq!(read_event().unwrap(), Some(Event::Resize(1, 1)));
248 }
249
250 #[test]
251 #[serial_test::serial]
252 fn read_event_read_key_other() {
253 let mut lock = read_event_mocks::NEXT_EVENT.lock();
254 *lock = Ok(Event::Key(KeyEvent::new_with_kind(
255 KeyCode::Enter,
256 KeyModifiers::NONE,
257 KeyEventKind::Release,
258 )));
259 drop(lock);
260
261 let mut lock = read_event_mocks::HAS_POLLED_EVENT.lock();
262 *lock = Ok(true);
263 drop(lock);
264
265 assert_eq!(read_event().unwrap(), None);
266 }
267
268 #[test]
269 #[serial_test::serial]
270 fn read_event_read_mouse_other() {
271 let mut lock = read_event_mocks::NEXT_EVENT.lock();
272 *lock = Ok(Event::Mouse(MouseEvent {
273 kind: MouseEventKind::Moved,
274 column: 0,
275 row: 0,
276 modifiers: KeyModifiers::NONE,
277 }));
278 drop(lock);
279
280 let mut lock = read_event_mocks::HAS_POLLED_EVENT.lock();
281 *lock = Ok(true);
282 drop(lock);
283
284 assert_eq!(read_event().unwrap(), None);
285 }
286
287 #[test]
288 #[serial_test::serial]
289 fn read_event_read_paste() {
290 let mut lock = read_event_mocks::NEXT_EVENT.lock();
291 *lock = Ok(Event::Paste(String::from("Foo")));
292 drop(lock);
293
294 let mut lock = read_event_mocks::HAS_POLLED_EVENT.lock();
295 *lock = Ok(true);
296 drop(lock);
297
298 assert_eq!(read_event().unwrap(), None);
299 }
300
301 #[test]
302 #[serial_test::serial]
303 fn read_event_read_focus_gained() {
304 let mut lock = read_event_mocks::NEXT_EVENT.lock();
305 *lock = Ok(Event::FocusGained);
306 drop(lock);
307
308 let mut lock = read_event_mocks::HAS_POLLED_EVENT.lock();
309 *lock = Ok(true);
310 drop(lock);
311
312 assert_eq!(read_event().unwrap(), None);
313 }
314
315 #[test]
316 #[serial_test::serial]
317 fn read_event_read_focus_lost() {
318 let mut lock = read_event_mocks::NEXT_EVENT.lock();
319 *lock = Ok(Event::FocusLost);
320 drop(lock);
321
322 let mut lock = read_event_mocks::HAS_POLLED_EVENT.lock();
323 *lock = Ok(true);
324 drop(lock);
325
326 assert_eq!(read_event().unwrap(), None);
327 }
328}