1 //! Mouse and key events.
2 
3 use std::io::{Error, ErrorKind};
4 use std::ascii::AsciiExt;
5 use std::str;
6 
7 /// An event reported by the terminal.
8 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
9 pub enum Event {
10     /// A key press.
11     Key(Key),
12     /// A mouse button press, release or wheel use at specific coordinates.
13     Mouse(MouseEvent),
14     /// An event that cannot currently be evaluated.
15     Unsupported(Vec<u8>),
16 }
17 
18 /// A mouse related event.
19 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
20 pub enum MouseEvent {
21     /// A mouse button was pressed.
22     ///
23     /// The coordinates are one-based.
24     Press(MouseButton, u16, u16),
25     /// A mouse button was released.
26     ///
27     /// The coordinates are one-based.
28     Release(u16, u16),
29     /// A mouse button is held over the given coordinates.
30     ///
31     /// The coordinates are one-based.
32     Hold(u16, u16),
33 }
34 
35 /// A mouse button.
36 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
37 pub enum MouseButton {
38     /// The left mouse button.
39     Left,
40     /// The right mouse button.
41     Right,
42     /// The middle mouse button.
43     Middle,
44     /// Mouse wheel is going up.
45     ///
46     /// This event is typically only used with Mouse::Press.
47     WheelUp,
48     /// Mouse wheel is going down.
49     ///
50     /// This event is typically only used with Mouse::Press.
51     WheelDown,
52 }
53 
54 /// A key.
55 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
56 pub enum Key {
57     /// Backspace.
58     Backspace,
59     /// Left arrow.
60     Left,
61     /// Right arrow.
62     Right,
63     /// Up arrow.
64     Up,
65     /// Down arrow.
66     Down,
67     /// Home key.
68     Home,
69     /// End key.
70     End,
71     /// Page Up key.
72     PageUp,
73     /// Page Down key.
74     PageDown,
75     /// Delete key.
76     Delete,
77     /// Insert key.
78     Insert,
79     /// Function keys.
80     ///
81     /// Only function keys 1 through 12 are supported.
82     F(u8),
83     /// Normal character.
84     Char(char),
85     /// Alt modified character.
86     Alt(char),
87     /// Ctrl modified character.
88     ///
89     /// Note that certain keys may not be modifiable with `ctrl`, due to limitations of terminals.
90     Ctrl(char),
91     /// Null byte.
92     Null,
93     /// Esc key.
94     Esc,
95 
96     #[doc(hidden)]
97     __IsNotComplete,
98 }
99 
100 /// Parse an Event from `item` and possibly subsequent bytes through `iter`.
parse_event<I>(item: u8, iter: &mut I) -> Result<Event, Error> where I: Iterator<Item = Result<u8, Error>>101 pub fn parse_event<I>(item: u8, iter: &mut I) -> Result<Event, Error>
102     where I: Iterator<Item = Result<u8, Error>>
103 {
104     let error = Error::new(ErrorKind::Other, "Could not parse an event");
105     match item {
106         b'\x1B' => {
107             // This is an escape character, leading a control sequence.
108             Ok(match iter.next() {
109                    Some(Ok(b'O')) => {
110                 match iter.next() {
111                     // F1-F4
112                     Some(Ok(val @ b'P'...b'S')) => Event::Key(Key::F(1 + val - b'P')),
113                     _ => return Err(error),
114                 }
115             }
116                    Some(Ok(b'[')) => {
117                 // This is a CSI sequence.
118                 parse_csi(iter).ok_or(error)?
119             }
120                    Some(Ok(c)) => {
121                 let ch = parse_utf8_char(c, iter);
122                 Event::Key(Key::Alt(try!(ch)))
123             }
124                    Some(Err(_)) | None => return Err(error),
125                })
126         }
127         b'\n' | b'\r' => Ok(Event::Key(Key::Char('\n'))),
128         b'\t' => Ok(Event::Key(Key::Char('\t'))),
129         b'\x7F' => Ok(Event::Key(Key::Backspace)),
130         c @ b'\x01'...b'\x1A' => Ok(Event::Key(Key::Ctrl((c as u8 - 0x1 + b'a') as char))),
131         c @ b'\x1C'...b'\x1F' => Ok(Event::Key(Key::Ctrl((c as u8 - 0x1C + b'4') as char))),
132         b'\0' => Ok(Event::Key(Key::Null)),
133         c => {
134             Ok({
135                    let ch = parse_utf8_char(c, iter);
136                    Event::Key(Key::Char(try!(ch)))
137                })
138         }
139     }
140 }
141 
142 /// Parses a CSI sequence, just after reading ^[
143 ///
144 /// Returns None if an unrecognized sequence is found.
parse_csi<I>(iter: &mut I) -> Option<Event> where I: Iterator<Item = Result<u8, Error>>145 fn parse_csi<I>(iter: &mut I) -> Option<Event>
146     where I: Iterator<Item = Result<u8, Error>>
147 {
148     Some(match iter.next() {
149              Some(Ok(b'[')) => match iter.next() {
150                  Some(Ok(val @ b'A'...b'E')) => Event::Key(Key::F(1 + val - b'A')),
151                  _ => return None,
152              },
153              Some(Ok(b'D')) => Event::Key(Key::Left),
154              Some(Ok(b'C')) => Event::Key(Key::Right),
155              Some(Ok(b'A')) => Event::Key(Key::Up),
156              Some(Ok(b'B')) => Event::Key(Key::Down),
157              Some(Ok(b'H')) => Event::Key(Key::Home),
158              Some(Ok(b'F')) => Event::Key(Key::End),
159              Some(Ok(b'M')) => {
160         // X10 emulation mouse encoding: ESC [ CB Cx Cy (6 characters only).
161         let mut next = || iter.next().unwrap().unwrap();
162 
163         let cb = next() as i8 - 32;
164         // (1, 1) are the coords for upper left.
165         let cx = next().saturating_sub(32) as u16;
166         let cy = next().saturating_sub(32) as u16;
167         Event::Mouse(match cb & 0b11 {
168                          0 => {
169                              if cb & 0x40 != 0 {
170                                  MouseEvent::Press(MouseButton::WheelUp, cx, cy)
171                              } else {
172                                  MouseEvent::Press(MouseButton::Left, cx, cy)
173                              }
174                          }
175                          1 => {
176                              if cb & 0x40 != 0 {
177                                  MouseEvent::Press(MouseButton::WheelDown, cx, cy)
178                              } else {
179                                  MouseEvent::Press(MouseButton::Middle, cx, cy)
180                              }
181                          }
182                          2 => MouseEvent::Press(MouseButton::Right, cx, cy),
183                          3 => MouseEvent::Release(cx, cy),
184                          _ => return None,
185                      })
186     }
187              Some(Ok(b'<')) => {
188         // xterm mouse encoding:
189         // ESC [ < Cb ; Cx ; Cy (;) (M or m)
190         let mut buf = Vec::new();
191         let mut c = iter.next().unwrap().unwrap();
192         while match c {
193                   b'm' | b'M' => false,
194                   _ => true,
195               } {
196             buf.push(c);
197             c = iter.next().unwrap().unwrap();
198         }
199         let str_buf = String::from_utf8(buf).unwrap();
200         let nums = &mut str_buf.split(';');
201 
202         let cb = nums.next()
203             .unwrap()
204             .parse::<u16>()
205             .unwrap();
206         let cx = nums.next()
207             .unwrap()
208             .parse::<u16>()
209             .unwrap();
210         let cy = nums.next()
211             .unwrap()
212             .parse::<u16>()
213             .unwrap();
214 
215         let event = match cb {
216             0...2 | 64...65 => {
217                 let button = match cb {
218                     0 => MouseButton::Left,
219                     1 => MouseButton::Middle,
220                     2 => MouseButton::Right,
221                     64 => MouseButton::WheelUp,
222                     65 => MouseButton::WheelDown,
223                     _ => unreachable!(),
224                 };
225                 match c {
226                     b'M' => MouseEvent::Press(button, cx, cy),
227                     b'm' => MouseEvent::Release(cx, cy),
228                     _ => return None,
229                 }
230             }
231             32 => MouseEvent::Hold(cx, cy),
232             3 => MouseEvent::Release(cx, cy),
233             _ => return None,
234         };
235 
236         Event::Mouse(event)
237     }
238              Some(Ok(c @ b'0'...b'9')) => {
239         // Numbered escape code.
240         let mut buf = Vec::new();
241         buf.push(c);
242         let mut c = iter.next().unwrap().unwrap();
243         // The final byte of a CSI sequence can be in the range 64-126, so
244         // let's keep reading anything else.
245         while c < 64 || c > 126 {
246             buf.push(c);
247             c = iter.next().unwrap().unwrap();
248         }
249 
250         match c {
251             // rxvt mouse encoding:
252             // ESC [ Cb ; Cx ; Cy ; M
253             b'M' => {
254                 let str_buf = String::from_utf8(buf).unwrap();
255 
256                 let nums: Vec<u16> = str_buf.split(';').map(|n| n.parse().unwrap()).collect();
257 
258                 let cb = nums[0];
259                 let cx = nums[1];
260                 let cy = nums[2];
261 
262                 let event = match cb {
263                     32 => MouseEvent::Press(MouseButton::Left, cx, cy),
264                     33 => MouseEvent::Press(MouseButton::Middle, cx, cy),
265                     34 => MouseEvent::Press(MouseButton::Right, cx, cy),
266                     35 => MouseEvent::Release(cx, cy),
267                     64 => MouseEvent::Hold(cx, cy),
268                     96 | 97 => MouseEvent::Press(MouseButton::WheelUp, cx, cy),
269                     _ => return None,
270                 };
271 
272                 Event::Mouse(event)
273             }
274             // Special key code.
275             b'~' => {
276                 let str_buf = String::from_utf8(buf).unwrap();
277 
278                 // This CSI sequence can be a list of semicolon-separated
279                 // numbers.
280                 let nums: Vec<u8> = str_buf.split(';').map(|n| n.parse().unwrap()).collect();
281 
282                 if nums.is_empty() {
283                     return None;
284                 }
285 
286                 // TODO: handle multiple values for key modififiers (ex: values
287                 // [3, 2] means Shift+Delete)
288                 if nums.len() > 1 {
289                     return None;
290                 }
291 
292                 match nums[0] {
293                     1 | 7 => Event::Key(Key::Home),
294                     2 => Event::Key(Key::Insert),
295                     3 => Event::Key(Key::Delete),
296                     4 | 8 => Event::Key(Key::End),
297                     5 => Event::Key(Key::PageUp),
298                     6 => Event::Key(Key::PageDown),
299                     v @ 11...15 => Event::Key(Key::F(v - 10)),
300                     v @ 17...21 => Event::Key(Key::F(v - 11)),
301                     v @ 23...24 => Event::Key(Key::F(v - 12)),
302                     _ => return None,
303                 }
304             }
305             _ => return None,
306         }
307     }
308              _ => return None,
309          })
310 
311 }
312 
313 /// Parse `c` as either a single byte ASCII char or a variable size UTF-8 char.
parse_utf8_char<I>(c: u8, iter: &mut I) -> Result<char, Error> where I: Iterator<Item = Result<u8, Error>>314 fn parse_utf8_char<I>(c: u8, iter: &mut I) -> Result<char, Error>
315     where I: Iterator<Item = Result<u8, Error>>
316 {
317     let error = Err(Error::new(ErrorKind::Other, "Input character is not valid UTF-8"));
318     if c.is_ascii() {
319         Ok(c as char)
320     } else {
321         let bytes = &mut Vec::new();
322         bytes.push(c);
323 
324         loop {
325             match iter.next() {
326                 Some(Ok(next)) => {
327                     bytes.push(next);
328                     if let Ok(st) = str::from_utf8(bytes) {
329                         return Ok(st.chars().next().unwrap());
330                     }
331                     if bytes.len() >= 4 {
332                         return error;
333                     }
334                 }
335                 _ => return error,
336             }
337         }
338     }
339 }
340 
341 #[cfg(test)]
342 #[test]
test_parse_utf8()343 fn test_parse_utf8() {
344     let st = "abcéŷ¤£€ù%323";
345     let ref mut bytes = st.bytes().map(|x| Ok(x));
346     let chars = st.chars();
347     for c in chars {
348         let b = bytes.next().unwrap().unwrap();
349         assert!(c == parse_utf8_char(b, bytes).unwrap());
350     }
351 }
352