termion/src/input.rs

163 lines
4.5 KiB
Rust
Raw Normal View History

2016-03-15 19:32:25 +00:00
use std::io::{self, Read, Write};
use std::thread;
use std::sync::mpsc;
use {IntoRawMode, AsyncReader};
#[cfg(feature = "nightly")]
2016-03-09 10:38:43 +00:00
use std::io::{Chars, CharsError};
/// A key.
2016-03-15 19:32:25 +00:00
#[derive(Debug)]
pub enum Key {
/// Backspace.
Backspace,
/// Left arrow.
Left,
/// Right arrow.
Right,
/// Up arrow.
Up,
/// Down arrow.
Down,
/// Normal character.
Char(char),
2016-03-10 14:12:59 +00:00
/// Alt modified character.
Alt(char),
/// Ctrl modified character.
///
/// Note that certain keys may not be modifiable with `ctrl`, due to limitations of terminals.
Ctrl(char),
/// Invalid character code.
Invalid,
/// IO error.
2016-03-15 19:32:25 +00:00
Error(io::Error),
2016-03-15 17:01:33 +00:00
/// Null byte.
Null,
2016-03-13 10:55:24 +00:00
#[allow(missing_docs)]
#[doc(hidden)]
__IsNotComplete
}
/// An iterator over input keys.
#[cfg(feature = "nightly")]
2016-03-09 10:38:43 +00:00
pub struct Keys<I> {
chars: I,
}
#[cfg(feature = "nightly")]
2016-03-09 10:38:43 +00:00
impl<I: Iterator<Item = Result<char, CharsError>>> Iterator for Keys<I> {
type Item = Key;
fn next(&mut self) -> Option<Key> {
match self.chars.next() {
Some(Ok('\x1B')) => Some(match self.chars.next() {
Some(Ok('[')) => match self.chars.next() {
Some(Ok('D')) => Key::Left,
Some(Ok('C')) => Key::Right,
Some(Ok('A')) => Key::Up,
Some(Ok('B')) => Key::Down,
_ => Key::Invalid,
},
Some(Ok(c)) => Key::Alt(c),
Some(Err(_)) | None => Key::Invalid,
}),
2016-03-10 20:57:42 +00:00
Some(Ok('\n')) | Some(Ok('\r')) => Some(Key::Char('\n')),
Some(Ok('\t')) => Some(Key::Char('\t')),
Some(Ok('\x7F')) => Some(Key::Backspace),
2016-03-10 14:21:11 +00:00
Some(Ok(c @ '\x01' ... '\x1A')) => Some(Key::Ctrl((c as u8 - 0x1 + b'a') as char)),
2016-03-10 14:12:59 +00:00
Some(Ok(c @ '\x1C' ... '\x1F')) => Some(Key::Ctrl((c as u8 - 0x1C + b'4') as char)),
None => None,
2016-03-15 19:56:53 +00:00
Some(Ok('\0')) => Some(Key::Null),
2016-03-15 17:01:33 +00:00
Some(Ok(c)) => Some(Key::Char(c)),
2016-03-15 19:56:53 +00:00
Some(Err(e)) => Some(Key::Error(io::Error::new(io::ErrorKind::InvalidData, e))),
}
}
}
/// Extension to `Read` trait.
2016-03-08 20:39:24 +00:00
pub trait TermRead {
/// An iterator over key inputs.
#[cfg(feature = "nightly")]
2016-03-09 10:38:43 +00:00
fn keys(self) -> Keys<Chars<Self>> where Self: Sized;
/// Read a password.
2016-03-08 09:08:50 +00:00
///
/// EOT and ETX will abort the prompt, returning `None`. Newline or carriage return will
/// complete the password input.
2016-03-15 19:32:25 +00:00
fn read_passwd<W: Write>(&mut self, writer: &mut W) -> io::Result<Option<String>>;
/// Turn the reader into a asynchronous reader.
///
/// This will spawn up another thread listening for event, buffering them in a mpsc queue.
fn into_async(self) -> AsyncReader where Self: Send;
}
2016-03-08 20:39:24 +00:00
impl<R: Read> TermRead for R {
#[cfg(feature = "nightly")]
2016-03-09 10:38:43 +00:00
fn keys(self) -> Keys<Chars<R>> {
Keys {
chars: self.chars(),
}
}
2016-03-15 19:32:25 +00:00
fn read_passwd<W: Write>(&mut self, writer: &mut W) -> io::Result<Option<String>> {
2016-03-08 07:51:34 +00:00
let _raw = try!(writer.into_raw_mode());
let mut passbuf = Vec::with_capacity(30);
for c in self.bytes() {
2016-03-08 07:51:34 +00:00
match c {
2016-03-13 10:55:24 +00:00
Err(e) => return Err(e),
Ok(0) | Ok(3) | Ok(4) => return Ok(None),
Ok(b'\n') | Ok(b'\r') => break,
Ok(c) => passbuf.push(c),
}
}
2016-03-15 19:32:25 +00:00
let passwd = try!(String::from_utf8(passbuf).map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e)));
Ok(Some(passwd))
}
2016-03-15 19:32:25 +00:00
fn into_async(self) -> AsyncReader where R: Send + 'static {
let (send, recv) = mpsc::channel();
thread::spawn(move || {
let mut reader = self;
loop {
let mut buf = [0];
if send.send(if let Err(k) = reader.read(&mut buf) {
Err(k)
} else {
Ok(buf[0])
}).is_err() {
return;
};
}
});
AsyncReader {
recv: recv,
}
}
}
2016-03-09 16:18:31 +00:00
#[cfg(test)]
mod test {
#[cfg(feature = "nightly")]
#[test]
fn test_keys() {
2016-03-09 18:17:00 +00:00
use {TermRead, Key};
2016-03-09 16:18:31 +00:00
let mut i = b"\x1Bayo\x7F\x1B[D".keys();
assert_eq!(i.next(), Some(Key::Alt('a')));
assert_eq!(i.next(), Some(Key::Char('y')));
assert_eq!(i.next(), Some(Key::Char('o')));
assert_eq!(i.next(), Some(Key::Backspace));
assert_eq!(i.next(), Some(Key::Left));
assert_eq!(i.next(), None);
}
}