From d57468cdc106699585dd0fea0361998293c26574 Mon Sep 17 00:00:00 2001
From: Sebastian Egbers <sebastian@egbers.info>
Date: Fri, 16 Oct 2020 11:26:49 +0200
Subject: [PATCH] Added Ctrl/Alt/Shift+Navigation key support.

---
 src/event.rs | 414 +++++++++++++++++++++++++++++----------------------
 1 file changed, 237 insertions(+), 177 deletions(-)

diff --git a/src/event.rs b/src/event.rs
index 8e36d5d..0d84353 100644
--- a/src/event.rs
+++ b/src/event.rs
@@ -57,16 +57,44 @@ pub enum Key {
     Backspace,
     /// Left arrow.
     Left,
+    /// Shift Left arrow.
+    ShiftLeft,
+    /// Alt Left arrow.
+    AltLeft,
+    /// Ctrl Left arrow.
+    CtrlLeft,
     /// Right arrow.
     Right,
+    /// Shift Right arrow.
+    ShiftRight,
+    /// Alt Right arrow.
+    AltRight,
+    /// Ctrl Right arrow.
+    CtrlRight,
     /// Up arrow.
     Up,
+    /// Shift Up arrow.
+    ShiftUp,
+    /// Alt Up arrow.
+    AltUp,
+    /// Ctrl Up arrow.
+    CtrlUp,
     /// Down arrow.
     Down,
+    /// Shift Down arrow.
+    ShiftDown,
+    /// Alt Down arrow.
+    AltDown,
+    /// Ctrl Down arrow
+    CtrlDown,
     /// Home key.
     Home,
+    /// Ctrl Home key.
+    CtrlHome,
     /// End key.
     End,
+    /// Ctrl End key.
+    CtrlEnd,
     /// Page Up key.
     PageUp,
     /// Page Down key.
@@ -100,30 +128,31 @@ pub enum Key {
 
 /// Parse an Event from `item` and possibly subsequent bytes through `iter`.
 pub fn parse_event<I>(item: u8, iter: &mut I) -> Result<Event, Error>
-    where I: Iterator<Item = Result<u8, Error>>
+    where
+        I: Iterator<Item = Result<u8, Error>>,
 {
     let error = Error::new(ErrorKind::Other, "Could not parse an event");
     match item {
         b'\x1B' => {
             // This is an escape character, leading a control sequence.
             Ok(match iter.next() {
-                   Some(Ok(b'O')) => {
-                match iter.next() {
-                    // F1-F4
-                    Some(Ok(val @ b'P'..=b'S')) => Event::Key(Key::F(1 + val - b'P')),
-                    _ => return Err(error),
+                Some(Ok(b'O')) => {
+                    match iter.next() {
+                        // F1-F4
+                        Some(Ok(val @ b'P'..=b'S')) => Event::Key(Key::F(1 + val - b'P')),
+                        _ => return Err(error),
+                    }
                 }
-            }
-                   Some(Ok(b'[')) => {
-                // This is a CSI sequence.
-                parse_csi(iter).ok_or(error)?
-            }
-                   Some(Ok(c)) => {
-                let ch = parse_utf8_char(c, iter)?;
-                Event::Key(Key::Alt(ch))
-            }
-                   Some(Err(_)) | None => return Err(error),
-               })
+                Some(Ok(b'[')) => {
+                    // This is a CSI sequence.
+                    parse_csi(iter).ok_or(error)?
+                }
+                Some(Ok(c)) => {
+                    let ch = parse_utf8_char(c, iter)?;
+                    Event::Key(Key::Alt(ch))
+                }
+                Some(Err(_)) | None => return Err(error),
+            })
         }
         b'\n' | b'\r' => Ok(Event::Key(Key::Char('\n'))),
         b'\t' => Ok(Event::Key(Key::Char('\t'))),
@@ -131,12 +160,10 @@ pub fn parse_event<I>(item: u8, iter: &mut I) -> Result<Event, Error>
         c @ b'\x01'..=b'\x1A' => Ok(Event::Key(Key::Ctrl((c as u8 - 0x1 + b'a') as char))),
         c @ b'\x1C'..=b'\x1F' => Ok(Event::Key(Key::Ctrl((c as u8 - 0x1C + b'4') as char))),
         b'\0' => Ok(Event::Key(Key::Null)),
-        c => {
-            Ok({
-                   let ch = parse_utf8_char(c, iter)?;
-                   Event::Key(Key::Char(ch))
-               })
-        }
+        c => Ok({
+            let ch = parse_utf8_char(c, iter)?;
+            Event::Key(Key::Char(ch))
+        }),
     }
 }
 
@@ -144,179 +171,212 @@ pub fn parse_event<I>(item: u8, iter: &mut I) -> Result<Event, Error>
 ///
 /// Returns None if an unrecognized sequence is found.
 fn parse_csi<I>(iter: &mut I) -> Option<Event>
-    where I: Iterator<Item = Result<u8, Error>>
+    where
+        I: Iterator<Item = Result<u8, Error>>,
 {
     Some(match iter.next() {
-             Some(Ok(b'[')) => match iter.next() {
-                 Some(Ok(val @ b'A'..=b'E')) => Event::Key(Key::F(1 + val - b'A')),
-                 _ => return None,
-             },
-             Some(Ok(b'D')) => Event::Key(Key::Left),
-             Some(Ok(b'C')) => Event::Key(Key::Right),
-             Some(Ok(b'A')) => Event::Key(Key::Up),
-             Some(Ok(b'B')) => Event::Key(Key::Down),
-             Some(Ok(b'H')) => Event::Key(Key::Home),
-             Some(Ok(b'F')) => Event::Key(Key::End),
-             Some(Ok(b'Z')) => Event::Key(Key::BackTab),
-             Some(Ok(b'M')) => {
-        // X10 emulation mouse encoding: ESC [ CB Cx Cy (6 characters only).
-        let mut next = || iter.next().unwrap().unwrap();
-
-        let cb = next() as i8 - 32;
-        // (1, 1) are the coords for upper left.
-        let cx = next().saturating_sub(32) as u16;
-        let cy = next().saturating_sub(32) as u16;
-        Event::Mouse(match cb & 0b11 {
-                         0 => {
-                             if cb & 0x40 != 0 {
-                                 MouseEvent::Press(MouseButton::WheelUp, cx, cy)
-                             } else {
-                                 MouseEvent::Press(MouseButton::Left, cx, cy)
-                             }
-                         }
-                         1 => {
-                             if cb & 0x40 != 0 {
-                                 MouseEvent::Press(MouseButton::WheelDown, cx, cy)
-                             } else {
-                                 MouseEvent::Press(MouseButton::Middle, cx, cy)
-                             }
-                         }
-                         2 => MouseEvent::Press(MouseButton::Right, cx, cy),
-                         3 => MouseEvent::Release(cx, cy),
-                         _ => return None,
-                     })
-    }
-             Some(Ok(b'<')) => {
-        // xterm mouse encoding:
-        // ESC [ < Cb ; Cx ; Cy (;) (M or m)
-        let mut buf = Vec::new();
-        let mut c = iter.next().unwrap().unwrap();
-        while match c {
-                  b'm' | b'M' => false,
-                  _ => true,
-              } {
-            buf.push(c);
-            c = iter.next().unwrap().unwrap();
-        }
-        let str_buf = String::from_utf8(buf).unwrap();
-        let nums = &mut str_buf.split(';');
-
-        let cb = nums.next()
-            .unwrap()
-            .parse::<u16>()
-            .unwrap();
-        let cx = nums.next()
-            .unwrap()
-            .parse::<u16>()
-            .unwrap();
-        let cy = nums.next()
-            .unwrap()
-            .parse::<u16>()
-            .unwrap();
-
-        let event = match cb {
-            0..=2 | 64..=65 => {
-                let button = match cb {
-                    0 => MouseButton::Left,
-                    1 => MouseButton::Middle,
-                    2 => MouseButton::Right,
-                    64 => MouseButton::WheelUp,
-                    65 => MouseButton::WheelDown,
-                    _ => unreachable!(),
-                };
-                match c {
-                    b'M' => MouseEvent::Press(button, cx, cy),
-                    b'm' => MouseEvent::Release(cx, cy),
-                    _ => return None,
-                }
-            }
-            32 => MouseEvent::Hold(cx, cy),
-            3 => MouseEvent::Release(cx, cy),
+        Some(Ok(b'[')) => match iter.next() {
+            Some(Ok(val @ b'A'..=b'E')) => Event::Key(Key::F(1 + val - b'A')),
             _ => return None,
-        };
+        },
+        Some(Ok(b'1')) => {
+            iter.next(); // Consume next char (;)
+            match iter.next() {
+                Some(Ok(b'2')) => { // Shift Modifier
+                    match iter.next() {
+                        Some(Ok(b'D')) => Event::Key(Key::ShiftLeft),
+                        Some(Ok(b'C')) => Event::Key(Key::ShiftRight),
+                        Some(Ok(b'A')) => Event::Key(Key::ShiftUp),
+                        Some(Ok(b'B')) => Event::Key(Key::ShiftDown),
+                        _ => return None,
+                    }
+                }
+                Some(Ok(b'3')) => { // Alt Modifier
+                    match iter.next() {
+                        Some(Ok(b'D')) => Event::Key(Key::AltLeft),
+                        Some(Ok(b'C')) => Event::Key(Key::AltRight),
+                        Some(Ok(b'A')) => Event::Key(Key::AltUp),
+                        Some(Ok(b'B')) => Event::Key(Key::AltDown),
+                        _ => return None,
+                    }
+                }
+                Some(Ok(b'5')) => { // Ctrl Modifier
+                    match iter.next() {
+                        Some(Ok(b'D')) => Event::Key(Key::CtrlLeft),
+                        Some(Ok(b'C')) => Event::Key(Key::CtrlRight),
+                        Some(Ok(b'A')) => Event::Key(Key::CtrlUp),
+                        Some(Ok(b'B')) => Event::Key(Key::CtrlDown),
+                        Some(Ok(b'H')) => Event::Key(Key::CtrlHome),
+                        Some(Ok(b'F')) => Event::Key(Key::CtrlEnd),
+                        _ => return None,
+                    }
+                }
+                _ => return None,
+            }
+        }
+        Some(Ok(b'D')) => Event::Key(Key::Left),
+        Some(Ok(b'C')) => Event::Key(Key::Right),
+        Some(Ok(b'A')) => Event::Key(Key::Up),
+        Some(Ok(b'B')) => Event::Key(Key::Down),
+        Some(Ok(b'H')) => Event::Key(Key::Home),
+        Some(Ok(b'F')) => Event::Key(Key::End),
+        Some(Ok(b'Z')) => Event::Key(Key::BackTab),
+        Some(Ok(b'M')) => {
+            // X10 emulation mouse encoding: ESC [ CB Cx Cy (6 characters only).
+            let mut next = || iter.next().unwrap().unwrap();
 
-        Event::Mouse(event)
-    }
-             Some(Ok(c @ b'0'..=b'9')) => {
-        // Numbered escape code.
-        let mut buf = Vec::new();
-        buf.push(c);
-        let mut c = iter.next().unwrap().unwrap();
-        // The final byte of a CSI sequence can be in the range 64-126, so
-        // let's keep reading anything else.
-        while c < 64 || c > 126 {
+            let cb = next() as i8 - 32;
+            // (1, 1) are the coords for upper left.
+            let cx = next().saturating_sub(32) as u16;
+            let cy = next().saturating_sub(32) as u16;
+            Event::Mouse(match cb & 0b11 {
+                0 => {
+                    if cb & 0x40 != 0 {
+                        MouseEvent::Press(MouseButton::WheelUp, cx, cy)
+                    } else {
+                        MouseEvent::Press(MouseButton::Left, cx, cy)
+                    }
+                }
+                1 => {
+                    if cb & 0x40 != 0 {
+                        MouseEvent::Press(MouseButton::WheelDown, cx, cy)
+                    } else {
+                        MouseEvent::Press(MouseButton::Middle, cx, cy)
+                    }
+                }
+                2 => MouseEvent::Press(MouseButton::Right, cx, cy),
+                3 => MouseEvent::Release(cx, cy),
+                _ => return None,
+            })
+        }
+        Some(Ok(b'<')) => {
+            // xterm mouse encoding:
+            // ESC [ < Cb ; Cx ; Cy (;) (M or m)
+            let mut buf = Vec::new();
+            let mut c = iter.next().unwrap().unwrap();
+            while match c {
+                b'm' | b'M' => false,
+                _ => true,
+            } {
+                buf.push(c);
+                c = iter.next().unwrap().unwrap();
+            }
+            let str_buf = String::from_utf8(buf).unwrap();
+            let nums = &mut str_buf.split(';');
+
+            let cb = nums.next().unwrap().parse::<u16>().unwrap();
+            let cx = nums.next().unwrap().parse::<u16>().unwrap();
+            let cy = nums.next().unwrap().parse::<u16>().unwrap();
+
+            let event = match cb {
+                0..=2 | 64..=65 => {
+                    let button = match cb {
+                        0 => MouseButton::Left,
+                        1 => MouseButton::Middle,
+                        2 => MouseButton::Right,
+                        64 => MouseButton::WheelUp,
+                        65 => MouseButton::WheelDown,
+                        _ => unreachable!(),
+                    };
+                    match c {
+                        b'M' => MouseEvent::Press(button, cx, cy),
+                        b'm' => MouseEvent::Release(cx, cy),
+                        _ => return None,
+                    }
+                }
+                32 => MouseEvent::Hold(cx, cy),
+                3 => MouseEvent::Release(cx, cy),
+                _ => return None,
+            };
+
+            Event::Mouse(event)
+        }
+        Some(Ok(c @ b'0'..=b'9')) => {
+            // Numbered escape code.
+            let mut buf = Vec::new();
             buf.push(c);
-            c = iter.next().unwrap().unwrap();
-        }
-
-        match c {
-            // rxvt mouse encoding:
-            // ESC [ Cb ; Cx ; Cy ; M
-            b'M' => {
-                let str_buf = String::from_utf8(buf).unwrap();
-
-                let nums: Vec<u16> = str_buf.split(';').map(|n| n.parse().unwrap()).collect();
-
-                let cb = nums[0];
-                let cx = nums[1];
-                let cy = nums[2];
-
-                let event = match cb {
-                    32 => MouseEvent::Press(MouseButton::Left, cx, cy),
-                    33 => MouseEvent::Press(MouseButton::Middle, cx, cy),
-                    34 => MouseEvent::Press(MouseButton::Right, cx, cy),
-                    35 => MouseEvent::Release(cx, cy),
-                    64 => MouseEvent::Hold(cx, cy),
-                    96 | 97 => MouseEvent::Press(MouseButton::WheelUp, cx, cy),
-                    _ => return None,
-                };
-
-                Event::Mouse(event)
+            let mut c = iter.next().unwrap().unwrap();
+            // The final byte of a CSI sequence can be in the range 64-126, so
+            // let's keep reading anything else.
+            while c < 64 || c > 126 {
+                buf.push(c);
+                c = iter.next().unwrap().unwrap();
             }
-            // Special key code.
-            b'~' => {
-                let str_buf = String::from_utf8(buf).unwrap();
 
-                // This CSI sequence can be a list of semicolon-separated
-                // numbers.
-                let nums: Vec<u8> = str_buf.split(';').map(|n| n.parse().unwrap()).collect();
+            match c {
+                // rxvt mouse encoding:
+                // ESC [ Cb ; Cx ; Cy ; M
+                b'M' => {
+                    let str_buf = String::from_utf8(buf).unwrap();
 
-                if nums.is_empty() {
-                    return None;
+                    let nums: Vec<u16> = str_buf.split(';').map(|n| n.parse().unwrap()).collect();
+
+                    let cb = nums[0];
+                    let cx = nums[1];
+                    let cy = nums[2];
+
+                    let event = match cb {
+                        32 => MouseEvent::Press(MouseButton::Left, cx, cy),
+                        33 => MouseEvent::Press(MouseButton::Middle, cx, cy),
+                        34 => MouseEvent::Press(MouseButton::Right, cx, cy),
+                        35 => MouseEvent::Release(cx, cy),
+                        64 => MouseEvent::Hold(cx, cy),
+                        96 | 97 => MouseEvent::Press(MouseButton::WheelUp, cx, cy),
+                        _ => return None,
+                    };
+
+                    Event::Mouse(event)
                 }
+                // Special key code.
+                b'~' => {
+                    let str_buf = String::from_utf8(buf).unwrap();
 
-                // TODO: handle multiple values for key modififiers (ex: values
-                // [3, 2] means Shift+Delete)
-                if nums.len() > 1 {
-                    return None;
-                }
+                    // This CSI sequence can be a list of semicolon-separated
+                    // numbers.
+                    let nums: Vec<u8> = str_buf.split(';').map(|n| n.parse().unwrap()).collect();
 
-                match nums[0] {
-                    1 | 7 => Event::Key(Key::Home),
-                    2 => Event::Key(Key::Insert),
-                    3 => Event::Key(Key::Delete),
-                    4 | 8 => Event::Key(Key::End),
-                    5 => Event::Key(Key::PageUp),
-                    6 => Event::Key(Key::PageDown),
-                    v @ 11..=15 => Event::Key(Key::F(v - 10)),
-                    v @ 17..=21 => Event::Key(Key::F(v - 11)),
-                    v @ 23..=24 => Event::Key(Key::F(v - 12)),
-                    _ => return None,
+                    if nums.is_empty() {
+                        return None;
+                    }
+
+                    // TODO: handle multiple values for key modififiers (ex: values
+                    // [3, 2] means Shift+Delete)
+                    if nums.len() > 1 {
+                        return None;
+                    }
+
+                    match nums[0] {
+                        1 | 7 => Event::Key(Key::Home),
+                        2 => Event::Key(Key::Insert),
+                        3 => Event::Key(Key::Delete),
+                        4 | 8 => Event::Key(Key::End),
+                        5 => Event::Key(Key::PageUp),
+                        6 => Event::Key(Key::PageDown),
+                        v @ 11..=15 => Event::Key(Key::F(v - 10)),
+                        v @ 17..=21 => Event::Key(Key::F(v - 11)),
+                        v @ 23..=24 => Event::Key(Key::F(v - 12)),
+                        v => {
+                            println!("{:?}", v);
+                            return None;
+                        }
+                    }
                 }
+                _ => return None,
             }
-            _ => return None,
         }
-    }
-             _ => return None,
-         })
-
+        _ => return None,
+    })
 }
 
 /// Parse `c` as either a single byte ASCII char or a variable size UTF-8 char.
 fn parse_utf8_char<I>(c: u8, iter: &mut I) -> Result<char, Error>
-    where I: Iterator<Item = Result<u8, Error>>
+    where
+        I: Iterator<Item = Result<u8, Error>>,
 {
-    let error = Err(Error::new(ErrorKind::Other, "Input character is not valid UTF-8"));
+    let error = Err(Error::new(
+        ErrorKind::Other,
+        "Input character is not valid UTF-8",
+    ));
     if c.is_ascii() {
         Ok(c as char)
     } else {