1use crate::kernel::log::KernelLogs;
2use std::io;
3use std::sync::mpsc;
4use std::thread;
5use std::time::Duration;
6use termion::event::Key;
7use termion::input::TermRead;
8
9pub enum Event<I> {
11 Input(I),
12 Kernel(String),
13 Tick,
14}
15
16#[allow(dead_code)]
18pub struct Events {
19 pub tx: mpsc::Sender<Event<Key>>,
20 pub rx: mpsc::Receiver<Event<Key>>,
21 input_handler: thread::JoinHandle<()>,
22 kernel_handler: thread::JoinHandle<()>,
23 tick_handler: thread::JoinHandle<()>,
24}
25
26impl Events {
27 pub fn new(refresh_rate: u64, kernel_logs: &KernelLogs) -> Self {
29 let refresh_rate = Duration::from_millis(refresh_rate);
31 let (tx, rx) = mpsc::channel();
33 let input_handler = {
35 let tx = tx.clone();
36 thread::spawn(move || {
37 let stdin = io::stdin();
38 for key in stdin.keys().flatten() {
39 tx.send(Event::Input(key)).unwrap();
40 }
41 })
42 };
43 let kernel_handler = {
45 let tx = tx.clone();
46 let mut kernel_logs = kernel_logs.clone();
47 thread::spawn(move || loop {
48 if kernel_logs.update() {
49 tx.send(Event::Kernel(kernel_logs.output.to_string()))
50 .unwrap_or_default();
51 }
52 thread::sleep(refresh_rate * 10);
53 })
54 };
55 let tick_handler = {
57 let tx = tx.clone();
58 thread::spawn(move || loop {
59 tx.send(Event::Tick).unwrap_or_default();
60 thread::sleep(refresh_rate);
61 })
62 };
63 Self {
65 tx,
66 rx,
67 input_handler,
68 kernel_handler,
69 tick_handler,
70 }
71 }
72}
73
74#[cfg(test)]
75mod tests {
76 use super::*;
77 use std::error::Error;
78 #[test]
79 fn test_events() -> Result<(), Box<dyn Error>> {
80 let kernel_logs = KernelLogs::default();
81 let events = Events::new(100, &kernel_logs);
82 let mut i = 0;
83 loop {
84 let tx = events.tx.clone();
85 thread::spawn(move || {
86 let _ = tx.send(Event::Input(Key::Char(
87 std::char::from_digit(i, 10).unwrap_or('x'),
88 )));
89 });
90 i += 1;
91 match events.rx.recv()? {
92 Event::Input(v) => {
93 if v == Key::Char('9') {
94 break;
95 }
96 }
97 Event::Tick => thread::sleep(Duration::from_millis(100)),
98 Event::Kernel(log) => assert!(!log.is_empty()),
99 }
100 }
101 Ok(())
102 }
103}