-
-
Notifications
You must be signed in to change notification settings - Fork 605
/
Copy pathinput.rs
146 lines (124 loc) · 3.18 KB
/
input.rs
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
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
use crate::notify_mutex::NotifyableMutex;
use anyhow::Result;
use crossbeam_channel::{unbounded, Receiver, Sender};
use crossterm::event::{self, Event, Event::Key, KeyEventKind};
use std::{
sync::{
atomic::{AtomicBool, Ordering},
Arc,
},
thread,
time::Duration,
};
static FAST_POLL_DURATION: Duration = Duration::from_millis(100);
static SLOW_POLL_DURATION: Duration = Duration::from_millis(10000);
///
#[derive(Clone, Copy, Debug)]
pub enum InputState {
Paused,
Polling,
}
///
#[derive(Clone, Debug)]
pub enum InputEvent {
Input(Event),
State(InputState),
}
///
#[derive(Clone)]
pub struct Input {
desired_state: Arc<NotifyableMutex<bool>>,
current_state: Arc<AtomicBool>,
receiver: Receiver<InputEvent>,
aborted: Arc<AtomicBool>,
}
impl Input {
///
pub fn new() -> Self {
let (tx, rx) = unbounded();
let desired_state = Arc::new(NotifyableMutex::new(true));
let current_state = Arc::new(AtomicBool::new(true));
let aborted = Arc::new(AtomicBool::new(false));
let arc_desired = Arc::clone(&desired_state);
let arc_current = Arc::clone(¤t_state);
let arc_aborted = Arc::clone(&aborted);
thread::spawn(move || {
if let Err(e) =
Self::input_loop(&arc_desired, &arc_current, &tx)
{
log::error!("input thread error: {}", e);
arc_aborted.store(true, Ordering::SeqCst);
}
});
Self {
receiver: rx,
desired_state,
current_state,
aborted,
}
}
///
pub fn receiver(&self) -> Receiver<InputEvent> {
self.receiver.clone()
}
///
pub fn set_polling(&self, enabled: bool) {
self.desired_state.set_and_notify(enabled);
}
fn shall_poll(&self) -> bool {
self.desired_state.get()
}
///
pub fn is_state_changing(&self) -> bool {
self.shall_poll()
!= self.current_state.load(Ordering::Relaxed)
}
pub fn is_aborted(&self) -> bool {
self.aborted.load(Ordering::SeqCst)
}
fn poll(dur: Duration) -> anyhow::Result<Option<Event>> {
if event::poll(dur)? {
Ok(Some(event::read()?))
} else {
Ok(None)
}
}
fn input_loop(
arc_desired: &Arc<NotifyableMutex<bool>>,
arc_current: &Arc<AtomicBool>,
tx: &Sender<InputEvent>,
) -> Result<()> {
let mut poll_duration = SLOW_POLL_DURATION;
loop {
if arc_desired.get() {
if !arc_current.load(Ordering::Relaxed) {
log::info!("input polling resumed");
tx.send(InputEvent::State(InputState::Polling))?;
}
arc_current.store(true, Ordering::Relaxed);
if let Some(e) = Self::poll(poll_duration)? {
// windows send key release too, only process key press
if let Key(key) = e {
if key.kind != KeyEventKind::Press {
continue;
}
}
tx.send(InputEvent::Input(e))?;
//Note: right after an input event we might have a reason to stop
// polling (external editor opening) so lets do a quick poll until the next input
// this fixes https://github.com/gitui-org/gitui/issues/1506
poll_duration = FAST_POLL_DURATION;
} else {
poll_duration = SLOW_POLL_DURATION;
}
} else {
if arc_current.load(Ordering::Relaxed) {
log::info!("input polling suspended");
tx.send(InputEvent::State(InputState::Paused))?;
}
arc_current.store(false, Ordering::Relaxed);
arc_desired.wait(true);
}
}
}
}