added read_char, read_line, read_async, read_async until for unix. Not 100% tested.
This commit is contained in:
parent
07502c016d
commit
9df976ed29
@ -23,11 +23,24 @@ mod input;
|
||||
|
||||
use input::keyboard::{async_input, input as stdin};
|
||||
|
||||
use crossterm::raw::IntoRawMode;
|
||||
|
||||
fn main()
|
||||
{
|
||||
async_input::read_async();
|
||||
// stdin::read_line();
|
||||
let context = Context::new();
|
||||
|
||||
{
|
||||
// let screen = ::crossterm::screen::AlternateScreen::from(context.clone());
|
||||
// screen.into_raw_mode(context.clone());
|
||||
|
||||
|
||||
async_input::async_reading_on_alternate_screen();
|
||||
// async_input::test();
|
||||
// stdin::t();
|
||||
// stdin::read_line();
|
||||
// stdin::read_char();
|
||||
// stdin::read_char();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -2,12 +2,18 @@ extern crate crossterm;
|
||||
|
||||
use self::crossterm::input::input;
|
||||
use self::crossterm::Context;
|
||||
use self::crossterm::Crossterm;
|
||||
use crossterm::terminal::ClearType;
|
||||
|
||||
use std::{thread, time};
|
||||
use std::io::Read;
|
||||
use crossterm::raw::IntoRawMode;
|
||||
|
||||
// this will capture the input until the given key was pressed.
|
||||
pub fn capture_input_until_a_certain_char_async()
|
||||
use std::io::{Read, Write, stdout};
|
||||
use std::time::Duration;
|
||||
|
||||
|
||||
/// this will capture the input until the given key.
|
||||
pub fn read_async_until()
|
||||
{
|
||||
let context = Context::new();
|
||||
let input = input(&context);
|
||||
@ -18,8 +24,15 @@ pub fn capture_input_until_a_certain_char_async()
|
||||
{
|
||||
let a = stdin.next();
|
||||
|
||||
println!("pressed key: {:?}", a);
|
||||
|
||||
if let Some(Ok(b'\r')) = a {
|
||||
println!("The enter key is hit and program is not listening to input anymore.");
|
||||
break;
|
||||
}
|
||||
|
||||
if let Some(Ok(b'x')) = a {
|
||||
println!("The key: x was pressed.");
|
||||
println!("The key: x was pressed and program is terminated.");
|
||||
break;
|
||||
}
|
||||
|
||||
@ -27,7 +40,7 @@ pub fn capture_input_until_a_certain_char_async()
|
||||
}
|
||||
}
|
||||
|
||||
// this will capture an character input until the given key was pressed.
|
||||
/// this will read pressed characters async until `x` is typed .
|
||||
pub fn read_async()
|
||||
{
|
||||
let context = Context::new();
|
||||
@ -39,13 +52,98 @@ pub fn read_async()
|
||||
{
|
||||
let a = stdin.next();
|
||||
|
||||
println!("pressed: {:?}", a);
|
||||
println!("pressed key: {:?}", a);
|
||||
|
||||
if let Some(Ok(b'x')) = a {
|
||||
println!("The key: x was pressed.");
|
||||
println!("The key: `x` was pressed and program is terminated.");
|
||||
break;
|
||||
}
|
||||
|
||||
thread::sleep(time::Duration::from_millis(50));
|
||||
}
|
||||
}
|
||||
|
||||
pub fn read_async_demo()
|
||||
{
|
||||
let crossterm = Crossterm::new();
|
||||
|
||||
// init some modules we use for this demo
|
||||
let input = crossterm.input();
|
||||
let terminal = crossterm.terminal();
|
||||
let mut cursor = crossterm.cursor();
|
||||
|
||||
// put stdout in raw mode so that characters wil not be outputted.
|
||||
let mut stdout = stdout().into_raw_mode(crossterm.context()).unwrap();
|
||||
|
||||
// this will setup the async reading.
|
||||
let mut stdin = input.read_async().bytes();
|
||||
|
||||
// clear terminal and reset the cursor.
|
||||
terminal.clear(ClearType::All);
|
||||
cursor.goto(1, 1);
|
||||
|
||||
|
||||
// loop until the enter key (\r) is pressed.
|
||||
loop {
|
||||
terminal.clear(ClearType::All);
|
||||
cursor.goto(1, 1);
|
||||
|
||||
// get the next pressed key
|
||||
let pressed_key = stdin.next();
|
||||
|
||||
write!(stdout, "\r{:?} <- Character pressed", pressed_key).unwrap();
|
||||
|
||||
// check if pressed key is enter (\r)
|
||||
if let Some(Ok(b'\r')) = pressed_key {
|
||||
break;
|
||||
}
|
||||
|
||||
// wait 200 ms and reset cursor write
|
||||
thread::sleep(Duration::from_millis(200));
|
||||
}
|
||||
}
|
||||
|
||||
pub fn async_reading_on_alternate_screen()
|
||||
{
|
||||
use crossterm::screen::AlternateScreen;
|
||||
|
||||
let crossterm = Crossterm::new();
|
||||
|
||||
// init some modules we use for this demo
|
||||
let input = crossterm.input();
|
||||
let terminal = crossterm.terminal();
|
||||
let mut cursor = crossterm.cursor();
|
||||
|
||||
// switch to alternate screen
|
||||
let mut alternate_screen = AlternateScreen::from(crossterm.context());
|
||||
// put alternate screen in raw mode so that characters wil not be outputted.
|
||||
let mut raw_screen = alternate_screen.into_raw_mode(crossterm.context());
|
||||
|
||||
// this will setup the async reading.
|
||||
let mut stdin = input.read_async().bytes();
|
||||
|
||||
// clear terminal and reset the cursor.
|
||||
terminal.clear(ClearType::All);
|
||||
cursor.goto(1, 1);
|
||||
|
||||
// panic!();
|
||||
|
||||
// loop until the enter key (\r) is pressed.
|
||||
loop {
|
||||
terminal.clear(ClearType::All);
|
||||
cursor.goto(1, 1);
|
||||
|
||||
// get the next pressed key
|
||||
let pressed_key = stdin.next();
|
||||
|
||||
write!(alternate_screen, "\r{:?} <- Character pressed", pressed_key).unwrap();
|
||||
|
||||
// check if pressed key is enter (\r)
|
||||
if let Some(Ok(b'\r')) = pressed_key {
|
||||
break;
|
||||
}
|
||||
|
||||
// wait 200 ms and reset cursor write
|
||||
thread::sleep(Duration::from_millis(200));
|
||||
}
|
||||
}
|
@ -44,7 +44,6 @@ impl TerminalInput
|
||||
pub fn read_async(&self) -> AsyncReader
|
||||
{
|
||||
self.terminal_input.read_async()
|
||||
// todo: async reading
|
||||
}
|
||||
|
||||
pub fn read_until_async(&self, delimiter: u8) -> AsyncReader
|
||||
|
@ -7,8 +7,9 @@ use self::windows_input::WindowsInput;
|
||||
#[cfg(target_os = "windows")]
|
||||
mod windows_input;
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
use self::unix_input::UnixInput;
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
mod unix_input;
|
||||
|
||||
|
||||
|
@ -3,124 +3,76 @@ use std::io::Write;
|
||||
use std::char;
|
||||
use std::sync::mpsc;
|
||||
use std::thread;
|
||||
use std::io::Read;
|
||||
|
||||
use super::super::terminal::terminal;
|
||||
//use super::super::kernel::unix_kernel::terminal::get_tty;
|
||||
use super::super::kernel::unix_kernel::terminal::{get_tty, read_char};
|
||||
use super::{ Key, ITerminalInput, AsyncReader };
|
||||
|
||||
pub struct UnixInput;
|
||||
|
||||
|
||||
impl UnixInput
|
||||
{
|
||||
pub fn new() -> UnixInput
|
||||
{
|
||||
UnixInput {}
|
||||
}
|
||||
}
|
||||
// fn read_line(&self) -> io::Result<String>
|
||||
// {
|
||||
// let mut rv = String::new();
|
||||
// io::stdin().read_line(&mut rv)?;
|
||||
// let len = rv.trim_right_matches(&['\r', '\n'][..]).len();
|
||||
// rv.truncate(len);
|
||||
// Ok(rv)
|
||||
// }
|
||||
//
|
||||
// fn read_char(&self) -> io::Result<char>
|
||||
// {
|
||||
// let mut buf = [0u8; 20];
|
||||
// let mut termios = termios::Termios::from_fd(fd)?;
|
||||
// let original = termios.clone();
|
||||
// termios::cfmakeraw(&mut termios);
|
||||
// termios::tcsetattr(fd, termios::TCSADRAIN, &termios)?;
|
||||
// let rv = unsafe {
|
||||
// let read = libc::read(fd, buf.as_mut_ptr() as *mut libc::c_void, 20);
|
||||
// if read < 0 {
|
||||
// Err(io::Error::last_os_error())
|
||||
// } else if buf[0] == b'\x03' {
|
||||
// Err(io::Error::new(io::ErrorKind::Interrupted, "read interrupted"))
|
||||
// } else {
|
||||
// Ok(key_from_escape_codes(&buf[..read as usize]))
|
||||
// }
|
||||
// };
|
||||
// termios::tcsetattr(fd, termios::TCSADRAIN, &original)?;
|
||||
//
|
||||
// // if the user hit ^C we want to signal SIGINT to outselves.
|
||||
// if let Err(ref err) = rv {
|
||||
// if err.kind() == io::ErrorKind::Interrupted {
|
||||
// unsafe { libc::raise(libc::SIGINT); }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// rv
|
||||
// }
|
||||
//
|
||||
// fn read_pressed_key(&self) -> io::Result<Key>
|
||||
// {
|
||||
// use Context;
|
||||
// let context = Context::new();
|
||||
//
|
||||
// let buf: [u8; 1024] = unsafe { ::std::mem::zeroed() };
|
||||
//// reading::read(&mut buf, &context.screen_manager);
|
||||
//
|
||||
// Ok(Key::Unknown)
|
||||
//// let pressed_char = unsafe { _getwch() };
|
||||
////
|
||||
//// // if 0 or 0xe0 we need to listen again because the next key will be an special key
|
||||
//// if pressed_char == 0 || pressed_char == 0xe0 {
|
||||
//// let special_key: i32 = unsafe { _getwch() };
|
||||
//// println!("spkey {}",special_key);
|
||||
//// return Ok(key_from_key_code(0x26));
|
||||
//// } else {
|
||||
//// match char::from_u32(pressed_char as u32)
|
||||
//// {
|
||||
//// Some(c) => return Ok(Key::Char(c)),
|
||||
//// None => { panic!("Some error needs to be returned") }
|
||||
//// }
|
||||
//// }
|
||||
// }
|
||||
//
|
||||
// fn read_async(&self) -> AsyncReader
|
||||
// {
|
||||
// let (send, recv) = mpsc::channel();
|
||||
//
|
||||
// thread::spawn(move || for i in get_tty().unwrap().bytes() {
|
||||
//
|
||||
// match i {
|
||||
// Ok(byte) => {
|
||||
// let end_of_stream = &byte == &delimiter;
|
||||
// let send_error = send.send(Ok(byte)).is_err();
|
||||
//
|
||||
// if end_of_stream || send_error { return; }
|
||||
// },
|
||||
// Err(_) => { return; }
|
||||
// }
|
||||
// });
|
||||
//
|
||||
// AsyncReader { recv: recv }
|
||||
// }
|
||||
//
|
||||
// fn read_until_async(&self, delimiter: u8) -> AsyncReader
|
||||
// {
|
||||
// let (tx, rx) = mpsc::channel();
|
||||
//
|
||||
// thread::spawn(move || {
|
||||
// loop
|
||||
// {
|
||||
// let pressed_char: u8 = (unsafe { _getwch() }) as u8;
|
||||
//
|
||||
// let end_of_stream = (pressed_char == delimiter);
|
||||
//
|
||||
// // we could return error but maybe option to keep listening until valid character is inputted.
|
||||
// if pressed_char == 0 || pressed_char == 0xe0 || end_of_stream {
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// tx.send(Ok(pressed_char as u8));
|
||||
// }
|
||||
// });
|
||||
//
|
||||
// AsyncReader { recv: rx }
|
||||
// }
|
||||
//}
|
||||
|
||||
}
|
||||
|
||||
impl ITerminalInput for UnixInput
|
||||
{
|
||||
fn read_line(&self) -> io::Result<String>
|
||||
{
|
||||
let mut rv = String::new();
|
||||
io::stdin().read_line(&mut rv)?;
|
||||
let len = rv.trim_right_matches(&['\r', '\n'][..]).len();
|
||||
rv.truncate(len);
|
||||
Ok(rv)
|
||||
}
|
||||
|
||||
fn read_char(&self) -> io::Result<char>
|
||||
{
|
||||
read_char()
|
||||
}
|
||||
|
||||
fn read_pressed_key(&self) -> io::Result<Key>
|
||||
{
|
||||
Ok(Key::Unknown)
|
||||
}
|
||||
|
||||
fn read_async(&self) -> AsyncReader
|
||||
{
|
||||
let (send, recv) = mpsc::channel();
|
||||
|
||||
thread::spawn(move || for i in get_tty().unwrap().bytes() {
|
||||
if send.send(i).is_err() {
|
||||
return;
|
||||
}
|
||||
});
|
||||
|
||||
AsyncReader { recv: recv }
|
||||
}
|
||||
|
||||
fn read_until_async(&self, delimiter: u8) -> AsyncReader
|
||||
{
|
||||
let (send, recv) = mpsc::channel();
|
||||
|
||||
thread::spawn(move || for i in get_tty().unwrap().bytes() {
|
||||
|
||||
match i {
|
||||
Ok(byte) => {
|
||||
let end_of_stream = &byte == &delimiter;
|
||||
let send_error = send.send(Ok(byte)).is_err();
|
||||
|
||||
if end_of_stream || send_error { return; }
|
||||
},
|
||||
Err(_) => { return; }
|
||||
}
|
||||
});
|
||||
|
||||
AsyncReader { recv: recv }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3,12 +3,13 @@
|
||||
pub use self::libc::termios;
|
||||
use self::libc::{c_int, c_ushort, ioctl, STDOUT_FILENO, TIOCGWINSZ};
|
||||
use state::commands::{IStateCommand, NoncanonicalModeCommand};
|
||||
use termios::Termios;
|
||||
use {libc, CommandManager, Context, StateManager};
|
||||
|
||||
use termios::{ Termios,cfmakeraw,tcsetattr,TCSADRAIN };
|
||||
use std::io::Error;
|
||||
use std::rc::Rc;
|
||||
use std::{io, mem, fs};
|
||||
use std::os::unix::io::AsRawFd;
|
||||
|
||||
/// A representation of the size of the current terminal.
|
||||
#[repr(C)]
|
||||
@ -140,6 +141,70 @@ pub fn get_tty() -> io::Result<fs::File> {
|
||||
fs::OpenOptions::new().read(true).write(true).open("/dev/tty")
|
||||
}
|
||||
|
||||
|
||||
pub fn read_char() -> io::Result<char>
|
||||
{
|
||||
let mut buf = [0u8; 20];
|
||||
|
||||
// get tty raw handle.
|
||||
let tty_f;
|
||||
|
||||
let fd = unsafe
|
||||
{
|
||||
if libc::isatty(libc::STDIN_FILENO) == 1
|
||||
{
|
||||
libc::STDIN_FILENO
|
||||
} else {
|
||||
tty_f = fs::File::open("/dev/tty")?;
|
||||
tty_f.as_raw_fd()
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
let mut termios = Termios::from_fd(fd)?;
|
||||
let original = termios.clone();
|
||||
|
||||
make_raw(&mut termios);
|
||||
tcsetattr(fd, TCSADRAIN, &termios)?;
|
||||
|
||||
// read input and convert it to char
|
||||
let rv = unsafe {
|
||||
let read = libc::read(fd, buf.as_mut_ptr() as *mut libc::c_void, 20);
|
||||
|
||||
if read < 0 {
|
||||
Err(io::Error::last_os_error())
|
||||
} else if buf[0] == b'\x03' {
|
||||
Err(io::Error::new(io::ErrorKind::Interrupted, "read interrupted"))
|
||||
} else {
|
||||
let mut pressed_char = Ok(' ');
|
||||
|
||||
if let Ok(s) = ::std::str::from_utf8(&buf[..read as usize])
|
||||
{
|
||||
if let Some(c) = s.chars().next()
|
||||
{
|
||||
pressed_char = Ok(c);
|
||||
}
|
||||
}else {
|
||||
pressed_char = Err(io::Error::new(io::ErrorKind::Interrupted, "Could not parse char to utf8 char"));
|
||||
}
|
||||
|
||||
pressed_char
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
tcsetattr(fd, TCSADRAIN, &original)?;
|
||||
|
||||
// if the user hit ^C we want to signal SIGINT to outselves.
|
||||
if let Err(ref err) = rv {
|
||||
if err.kind() == io::ErrorKind::Interrupted {
|
||||
unsafe { libc::raise(libc::SIGINT); }
|
||||
}
|
||||
}
|
||||
|
||||
rv
|
||||
}
|
||||
|
||||
pub fn exit() {
|
||||
::std::process::exit(0);
|
||||
}
|
||||
|
@ -27,6 +27,8 @@
|
||||
use super::super::cursor;
|
||||
use super::super::style;
|
||||
use super::super::terminal::terminal;
|
||||
use super::super::input::input;
|
||||
|
||||
use Context;
|
||||
|
||||
use std::fmt::Display;
|
||||
@ -126,6 +128,11 @@ impl Crossterm {
|
||||
return style::TerminalColor::new(self.context.clone());
|
||||
}
|
||||
|
||||
pub fn input(&self) -> input::TerminalInput
|
||||
{
|
||||
return input::TerminalInput::new(self.context.clone());
|
||||
}
|
||||
|
||||
/// Wraps an displayable object so it can be formatted with colors and attributes.
|
||||
///
|
||||
/// Check `/examples/color` in the library for more specific examples.
|
||||
|
@ -107,6 +107,7 @@ impl AlternateScreen {
|
||||
context: context.clone(),
|
||||
command_id: command_id,
|
||||
};
|
||||
|
||||
screen.to_alternate();
|
||||
return screen;
|
||||
}
|
||||
@ -134,6 +135,7 @@ impl AlternateScreen {
|
||||
let mut mx = &state_manager.get(self.command_id);
|
||||
{
|
||||
let mut command = mx.lock().unwrap();
|
||||
|
||||
command.execute();
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user