diff --git a/examples/keys.rs b/examples/keys.rs index a67f931..1b44bc7 100644 --- a/examples/keys.rs +++ b/examples/keys.rs @@ -23,6 +23,7 @@ fn main() { Key::Char(c) => println!("{}", c), Key::Alt(c) => println!("^{}", c), Key::Ctrl(c) => println!("*{}", c), + Key::Esc => println!("ESC"), Key::Left => println!("←"), Key::Right => println!("→"), Key::Up => println!("↑"), diff --git a/src/event.rs b/src/event.rs index 5760228..7d0a970 100644 --- a/src/event.rs +++ b/src/event.rs @@ -90,6 +90,8 @@ pub enum Key { Ctrl(char), /// Null byte. Null, + /// Esc key. + Esc, #[allow(missing_docs)] #[doc(hidden)] diff --git a/src/input.rs b/src/input.rs index 6d57cdb..26abd3e 100644 --- a/src/input.rs +++ b/src/input.rs @@ -7,11 +7,11 @@ use event::{parse_event, Event, Key}; use raw::IntoRawMode; /// An iterator over input keys. -pub struct Keys { - iter: Events, +pub struct Keys { + iter: Events, } -impl>> Iterator for Keys { +impl Iterator for Keys { type Item = Result; fn next(&mut self) -> Option> { @@ -27,29 +27,59 @@ impl>> Iterator for Keys { } /// An iterator over input events. -pub struct Events { - bytes: I, +pub struct Events { + source: R, + leftover: Option, } -impl>> Iterator for Events { +impl Iterator for Events { type Item = Result; fn next(&mut self) -> Option> { - let iter = &mut self.bytes; - match iter.next() { - Some(item) => Some(parse_event(item, iter).or(Ok(Event::Unsupported))), - None => None, + let mut source = &mut self.source; + + if let Some(c) = self.leftover { + // we have a leftover byte, use it + self.leftover = None; + return Some(parse_event(Ok(c), &mut source.bytes()).or(Ok(Event::Unsupported))); } + + // Here we read two bytes at a time. We need to distinguish between single ESC key presses, + // and escape sequences (which start with ESC or a x1B byte). The idea is that if this is + // an escape sequence, we will read multiple bytes (the first byte being ESC) but if this + // is a single ESC keypress, we will only read a single byte. + let mut buf = [0u8; 2]; + let res = match source.read(&mut buf) { + Ok(0) => return None, + Ok(1) => match buf[0] { + b'\x1B' => Ok(Event::Key(Key::Esc)), + c => parse_event(Ok(c), &mut source.bytes()), + }, + Ok(2) => { + if buf[0] != b'\x1B' { + // this is not an escape sequence, but we read two bytes, save the second byte + // for later + self.leftover = Some(buf[1]); + } + + let mut iter = buf[1..2].iter().map(|c| Ok(*c)).chain(source.bytes()); + parse_event(Ok(buf[0]), &mut iter) + } + Ok(_) => unreachable!(), + Err(e) => Err(e), + }; + + Some(res.or(Ok(Event::Unsupported))) } } /// Extension to `Read` trait. pub trait TermRead { /// An iterator over input events. - fn events(self) -> Events> where Self: Sized; + fn events(self) -> Events where Self: Sized; /// An iterator over key inputs. - fn keys(self) -> Keys> where Self: Sized; + fn keys(self) -> Keys where Self: Sized; /// Read a line. /// @@ -68,12 +98,13 @@ pub trait TermRead { } impl TermRead for R { - fn events(self) -> Events> { + fn events(self) -> Events { Events { - bytes: self.bytes(), + source: self, + leftover: None, } } - fn keys(self) -> Keys> { + fn keys(self) -> Keys { Keys { iter: self.events(), } @@ -213,6 +244,13 @@ mod test { assert!(st.next().is_none()); } + #[test] + fn test_esc_key() { + let mut st = b"\x1B".keys(); + assert_eq!(st.next().unwrap().unwrap(), Key::Esc); + assert!(st.next().is_none()); + } + fn line_match(a: &str, b: Option<&str>) { let mut sink = io::sink();