1use crate::error::{Error, Result};
2use std::fmt;
3use std::io::{self, Read};
4use std::ops::{Deref, DerefMut};
5use std::os::unix::io::AsRawFd;
6use std::str;
7
8pub struct StdinRawMode {
9 stdin: io::Stdin,
10 orig: termios::Termios,
11}
12
13impl StdinRawMode {
18 pub fn new() -> Result<StdinRawMode> {
19 use termios::*;
20
21 let stdin = io::stdin();
22 let fd = stdin.as_raw_fd();
23 let mut termios = Termios::from_fd(fd)?;
24 let orig = termios;
25
26 termios.c_lflag &= !(ECHO | ICANON | ISIG | IEXTEN);
28 termios.c_iflag &= !(IXON | ICRNL | BRKINT | INPCK | ISTRIP);
30 termios.c_oflag &= !OPOST;
32 termios.c_cflag |= CS8;
34 termios.c_cc[VMIN] = 1;
36 termios.c_cc[VTIME] = 0;
37 tcsetattr(fd, TCSAFLUSH, &termios)?;
39
40 Ok(StdinRawMode { stdin, orig })
41 }
42
43 pub fn input_keys(self) -> InputSequences {
44 InputSequences { stdin: self }
45 }
46}
47
48impl Drop for StdinRawMode {
49 fn drop(&mut self) {
50 termios::tcsetattr(self.stdin.as_raw_fd(), termios::TCSAFLUSH, &self.orig).unwrap();
52 }
53}
54
55impl Deref for StdinRawMode {
56 type Target = io::Stdin;
57
58 fn deref(&self) -> &Self::Target {
59 &self.stdin
60 }
61}
62
63impl DerefMut for StdinRawMode {
64 fn deref_mut(&mut self) -> &mut Self::Target {
65 &mut self.stdin
66 }
67}
68
69#[derive(PartialEq, Debug, Clone)]
70pub enum KeySeq {
71 Unidentified,
72 Utf8Key(char),
73 Key(u8), LeftKey,
75 RightKey,
76 UpKey,
77 DownKey,
78 PageUpKey,
79 PageDownKey,
80 HomeKey,
81 EndKey,
82 DeleteKey,
83 Cursor(usize, usize), }
85
86impl fmt::Display for KeySeq {
87 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
88 use KeySeq::*;
89 match self {
90 Unidentified => write!(f, "UNKNOWN"),
91 Key(b' ') => write!(f, "SPACE"),
92 Key(b) if b.is_ascii_control() => write!(f, "\\x{:x}", b),
93 Key(b) => write!(f, "{}", *b as char),
94 Utf8Key(c) => write!(f, "{}", c),
95 LeftKey => write!(f, "LEFT"),
96 RightKey => write!(f, "RIGHT"),
97 UpKey => write!(f, "UP"),
98 DownKey => write!(f, "DOWN"),
99 PageUpKey => write!(f, "PAGEUP"),
100 PageDownKey => write!(f, "PAGEDOWN"),
101 HomeKey => write!(f, "HOME"),
102 EndKey => write!(f, "END"),
103 DeleteKey => write!(f, "DELETE"),
104 Cursor(r, c) => write!(f, "CURSOR({},{})", r, c),
105 }
106 }
107}
108
109#[derive(PartialEq, Debug, Clone)]
110pub struct InputSeq {
111 pub key: KeySeq,
112 pub ctrl: bool,
113 pub alt: bool,
114}
115
116impl InputSeq {
117 pub fn new(key: KeySeq) -> Self {
118 Self {
119 key,
120 ctrl: false,
121 alt: false,
122 }
123 }
124
125 pub fn ctrl(key: KeySeq) -> Self {
126 Self {
127 key,
128 ctrl: true,
129 alt: false,
130 }
131 }
132
133 pub fn alt(key: KeySeq) -> Self {
134 Self {
135 key,
136 ctrl: false,
137 alt: true,
138 }
139 }
140}
141
142impl fmt::Display for InputSeq {
143 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
144 if self.ctrl {
145 write!(f, "C-")?;
146 }
147 if self.alt {
148 write!(f, "M-")?;
149 }
150 write!(f, "{}", self.key)
151 }
152}
153
154pub struct InputSequences {
155 stdin: StdinRawMode,
156}
157
158impl InputSequences {
159 fn read_byte(&mut self) -> Result<Option<u8>> {
160 let mut one_byte: [u8; 1] = [0];
161 Ok(if self.stdin.read(&mut one_byte)? == 0 {
162 None
163 } else {
164 Some(one_byte[0])
165 })
166 }
167
168 fn decode_escape_sequence(&mut self) -> Result<InputSeq> {
169 use KeySeq::*;
170
171 match self.read_byte()? {
175 Some(b'[') => { }
176 Some(b) if b.is_ascii_control() => return Ok(InputSeq::new(Key(0x1b))), Some(b) => {
178 let mut seq = self.decode(b)?;
181 seq.alt = true;
182 return Ok(seq);
183 }
184 None => return Ok(InputSeq::new(Key(0x1b))),
185 };
186
187 let mut buf = vec![];
190 let cmd = loop {
191 if let Some(b) = self.read_byte()? {
192 match b {
193 b'A' | b'B' | b'C' | b'D' | b'F' | b'H' | b'K' | b'J' | b'R' | b'c' | b'f'
195 | b'g' | b'h' | b'l' | b'm' | b'n' | b'q' | b't' | b'y' | b'~' => break b,
196 _ => buf.push(b),
197 }
198 } else {
199 return Ok(InputSeq::new(Unidentified));
201 }
202 };
203
204 fn parse_bytes_as_usize(b: &[u8]) -> Option<usize> {
205 str::from_utf8(b).ok().and_then(|s| s.parse().ok())
206 }
207
208 let mut args = buf.split(|b| *b == b';');
209 match cmd {
210 b'R' => {
211 let mut i = args.filter_map(parse_bytes_as_usize);
213 match (i.next(), i.next()) {
214 (Some(r), Some(c)) => Ok(InputSeq::new(Cursor(r, c))),
215 _ => Ok(InputSeq::new(Unidentified)),
216 }
217 }
218 b'A' | b'B' | b'C' | b'D' => {
221 let key = match cmd {
222 b'A' => UpKey,
223 b'B' => DownKey,
224 b'C' => RightKey,
225 b'D' => LeftKey,
226 _ => unreachable!(),
227 };
228 let ctrl = args.next() == Some(b"1") && args.next() == Some(b"5");
229 let alt = false;
230 Ok(InputSeq { key, ctrl, alt })
231 }
232 b'~' => {
233 match args.next() {
235 Some(b"5") => Ok(InputSeq::new(PageUpKey)),
236 Some(b"6") => Ok(InputSeq::new(PageDownKey)),
237 Some(b"1") | Some(b"7") => Ok(InputSeq::new(HomeKey)),
238 Some(b"4") | Some(b"8") => Ok(InputSeq::new(EndKey)),
239 Some(b"3") => Ok(InputSeq::new(DeleteKey)),
240 _ => Ok(InputSeq::new(Unidentified)),
241 }
242 }
243 b'H' | b'F' => {
244 let key = match cmd {
246 b'H' => HomeKey,
247 b'F' => EndKey,
248 _ => unreachable!(),
249 };
250 let ctrl = args.next() == Some(b"1") && args.next() == Some(b"5");
251 let alt = false;
252 Ok(InputSeq { key, ctrl, alt })
253 }
254 _ => unreachable!(),
255 }
256 }
257
258 fn decode_utf8(&mut self, b: u8) -> Result<InputSeq> {
259 let mut buf = [0; 4];
261 buf[0] = b;
262 let mut len = 1;
263
264 loop {
265 if let Some(b) = self.read_byte()? {
266 buf[len] = b;
267 len += 1;
268 } else {
269 return Err(Error::NotUtf8Input(buf[..len].to_vec()));
270 }
271
272 if let Ok(s) = str::from_utf8(&buf) {
273 return Ok(InputSeq::new(KeySeq::Utf8Key(s.chars().next().unwrap())));
274 }
275
276 if len == 4 {
277 return Err(Error::NotUtf8Input(buf.to_vec()));
278 }
279 }
280 }
281
282 fn decode(&mut self, b: u8) -> Result<InputSeq> {
283 use KeySeq::*;
284 match b {
285 0x00..=0x1f => match b {
287 0x1b => self.decode_escape_sequence(),
289 0x00 | 0x1f => Ok(InputSeq::ctrl(Key(b | 0b0010_0000))),
291 0x01c | 0x01d => Ok(InputSeq::ctrl(Key(b | 0b0100_0000))),
293 _ => Ok(InputSeq::ctrl(Key(b | 0b0110_0000))),
296 },
297 0x20..=0x7f => Ok(InputSeq::new(Key(b))),
300 0x80..=0x9f => Ok(InputSeq::new(KeySeq::Unidentified)),
304 0xa0..=0xff => self.decode_utf8(b),
306 }
307 }
308
309 fn read_seq(&mut self) -> Result<InputSeq> {
310 if let Some(b) = self.read_byte()? {
311 self.decode(b)
312 } else {
313 Ok(InputSeq::new(KeySeq::Unidentified))
314 }
315 }
316}
317
318impl Iterator for InputSequences {
319 type Item = Result<InputSeq>;
320
321 fn next(&mut self) -> Option<Self::Item> {
324 Some(self.read_seq())
325 }
326}