diff --git a/examples/keys.rs b/examples/keys.rs index a67f931171642a0a0525f22cf346c881d0cfc12f..1b44bc72f6594da32668efab723e780fa78eabf5 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 5760228478a7ea8bcbdd4af4569874859d5a2740..7d0a970f50b3c7193fead7b78db324d14e124834 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 6d57cdba8f70906e0afa2444399a4f6e8764578d..26abd3e3a1c0704521f855a7a6f53d2430c9b5f3 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<I> { - iter: Events<I>, +pub struct Keys<R> { + iter: Events<R>, } -impl<I: Iterator<Item = Result<u8, io::Error>>> Iterator for Keys<I> { +impl<R: Read> Iterator for Keys<R> { type Item = Result<Key, io::Error>; fn next(&mut self) -> Option<Result<Key, io::Error>> { @@ -27,29 +27,59 @@ impl<I: Iterator<Item = Result<u8, io::Error>>> Iterator for Keys<I> { } /// An iterator over input events. -pub struct Events<I> { - bytes: I, +pub struct Events<R> { + source: R, + leftover: Option<u8>, } -impl<I: Iterator<Item = Result<u8, io::Error>>> Iterator for Events<I> { +impl<R: Read> Iterator for Events<R> { type Item = Result<Event, io::Error>; fn next(&mut self) -> Option<Result<Event, io::Error>> { - 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<io::Bytes<Self>> where Self: Sized; + fn events(self) -> Events<Self> where Self: Sized; /// An iterator over key inputs. - fn keys(self) -> Keys<io::Bytes<Self>> where Self: Sized; + fn keys(self) -> Keys<Self> where Self: Sized; /// Read a line. /// @@ -68,12 +98,13 @@ pub trait TermRead { } impl<R: Read> TermRead for R { - fn events(self) -> Events<io::Bytes<R>> { + fn events(self) -> Events<Self> { Events { - bytes: self.bytes(), + source: self, + leftover: None, } } - fn keys(self) -> Keys<io::Bytes<R>> { + fn keys(self) -> Keys<Self> { 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();