Merge branch 'master' of github.com:Ticki/libterm

This commit is contained in:
ticki 2016-12-18 19:29:18 +01:00
commit f9eaf6d0bc
4 changed files with 36 additions and 23 deletions

View File

@ -3,9 +3,7 @@
//! # Example //! # Example
//! //!
//! ```rust //! ```rust
//! use termion::{color, style}; //! use termion::color;
//!
//! use std::io;
//! //!
//! fn main() { //! fn main() {
//! println!("{}Red", color::Fg(color::Red)); //! println!("{}Red", color::Fg(color::Red));

View File

@ -5,7 +5,7 @@ use std::ascii::AsciiExt;
use std::str; use std::str;
/// An event reported by the terminal. /// An event reported by the terminal.
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] #[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum Event { pub enum Event {
/// A key press. /// A key press.
Key(Key), Key(Key),
@ -13,6 +13,9 @@ pub enum Event {
Mouse(MouseEvent), Mouse(MouseEvent),
/// An event that cannot currently be evaluated. /// An event that cannot currently be evaluated.
Unsupported, Unsupported,
/// A CSI sequence unrecognized by termion. Does not inlude the leading `^[`.
UnknownCsi(Vec<u8>),
} }
/// A mouse related event. /// A mouse related event.
@ -93,7 +96,6 @@ pub enum Key {
/// Esc key. /// Esc key.
Esc, Esc,
#[allow(missing_docs)]
#[doc(hidden)] #[doc(hidden)]
__IsNotComplete __IsNotComplete
} }
@ -108,11 +110,13 @@ where I: Iterator<Item = Result<u8, Error>>
Ok(match iter.next() { Ok(match iter.next() {
Some(Ok(b'O')) => { Some(Ok(b'O')) => {
match iter.next() { match iter.next() {
// F1-F4
Some(Ok(val @ b'P' ... b'S')) => Event::Key(Key::F(1 + val - b'P')), Some(Ok(val @ b'P' ... b'S')) => Event::Key(Key::F(1 + val - b'P')),
_ => return error, _ => return error,
} }
} }
Some(Ok(b'[')) => { Some(Ok(b'[')) => {
// This is a CSI sequence.
match iter.next() { match iter.next() {
Some(Ok(b'D')) => Event::Key(Key::Left), Some(Ok(b'D')) => Event::Key(Key::Left),
Some(Ok(b'C')) => Event::Key(Key::Right), Some(Ok(b'C')) => Event::Key(Key::Right),
@ -198,17 +202,24 @@ where I: Iterator<Item = Result<u8, Error>>
buf.push(c); buf.push(c);
c = iter.next().unwrap().unwrap(); c = iter.next().unwrap().unwrap();
} }
// Include the terminal char in the buffer.
// We'll want it if we return an unknown sequence.
buf.push(c);
match c { match c {
// rxvt mouse encoding: // rxvt mouse encoding:
// ESC [ Cb ; Cx ; Cy ; M // ESC [ Cb ; Cx ; Cy ; M
b'M' => { b'M' => {
let str_buf = String::from_utf8(buf).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 nums: Vec<u16> = str_buf[..str_buf.len()-1].split(';')
let cy = nums.next().unwrap().parse::<u16>().unwrap(); .map(|n| n.parse().unwrap())
.collect();
let cb = nums[0];
let cx = nums[1];
let cy = nums[2];
let event = match cb { let event = match cb {
32 => MouseEvent::Press(MouseButton::Left, cx, cy), 32 => MouseEvent::Press(MouseButton::Left, cx, cy),
@ -218,7 +229,7 @@ where I: Iterator<Item = Result<u8, Error>>
64 => MouseEvent::Hold(cx, cy), 64 => MouseEvent::Hold(cx, cy),
96 | 96 |
97 => MouseEvent::Press(MouseButton::WheelUp, cx, cy), 97 => MouseEvent::Press(MouseButton::WheelUp, cx, cy),
_ => return error, _ => return Ok(Event::UnknownCsi(str_buf.into_bytes())),
}; };
Event::Mouse(event) Event::Mouse(event)
@ -229,16 +240,20 @@ where I: Iterator<Item = Result<u8, Error>>
// This CSI sequence can be a list of semicolon-separated // This CSI sequence can be a list of semicolon-separated
// numbers. // numbers.
let nums: Vec<u8> = str_buf.split(';') let nums: Vec<u8> = str_buf[..str_buf.len()-1].split(';')
.map(|n| n.parse().unwrap()) .map(|n| n.parse().unwrap())
.collect(); .collect();
if nums.is_empty() { if nums.is_empty() {
return error; return Ok(Event::UnknownCsi(str_buf.into_bytes()));
} }
// TODO: handle multiple values for key modififiers (ex: values // TODO: handle multiple values for key modififiers (ex: values
// [3, 2] means Shift+Delete) // [3, 2] means Shift+Delete)
if nums.len() > 1 {
return Ok(Event::UnknownCsi(str_buf.into_bytes()));
}
match nums[0] { match nums[0] {
1 | 7 => Event::Key(Key::Home), 1 | 7 => Event::Key(Key::Home),
2 => Event::Key(Key::Insert), 2 => Event::Key(Key::Insert),
@ -249,10 +264,10 @@ where I: Iterator<Item = Result<u8, Error>>
v @ 11...15 => Event::Key(Key::F(v - 10)), v @ 11...15 => Event::Key(Key::F(v - 10)),
v @ 17...21 => Event::Key(Key::F(v - 11)), v @ 17...21 => Event::Key(Key::F(v - 11)),
v @ 23...24 => Event::Key(Key::F(v - 12)), v @ 23...24 => Event::Key(Key::F(v - 12)),
_ => return error, _ => return Ok(Event::UnknownCsi(str_buf.into_bytes())),
} }
}, },
_ => return error, _ => return Ok(Event::UnknownCsi(buf)),
} }
}, },
_ => return error, _ => return error,

View File

@ -56,14 +56,14 @@ impl<R: Read> Iterator for Events<R> {
c => parse_event(Ok(c), &mut source.bytes()), c => parse_event(Ok(c), &mut source.bytes()),
}, },
Ok(2) => { Ok(2) => {
if buf[0] != b'\x1B' { let mut option_iter = &mut Some(buf[1]).into_iter();
// this is not an escape sequence, but we read two bytes, save the second byte let result = {
// for later let mut iter = option_iter.map(|c| Ok(c)).chain(source.bytes());
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) parse_event(Ok(buf[0]), &mut iter)
};
// If the option_iter wasn't consumed, keep the byte for later.
self.leftover = option_iter.next();
result
} }
Ok(_) => unreachable!(), Ok(_) => unreachable!(),
Err(e) => Err(e), Err(e) => Err(e),

View File

@ -11,7 +11,7 @@
//! //!
//! # Example //! # Example
//! //!
//! ```rust,ignore //! ```rust,no_run
//! use termion::raw::IntoRawMode; //! use termion::raw::IntoRawMode;
//! use std::io::{Write, stdout}; //! use std::io::{Write, stdout};
//! //!