termion/
event.rs

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