Skip to main content

termion/
event.rs

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