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 input::keyboard::{async_input, input as stdin};
|
||||||
|
|
||||||
|
use crossterm::raw::IntoRawMode;
|
||||||
|
|
||||||
fn main()
|
fn main()
|
||||||
{
|
{
|
||||||
async_input::read_async();
|
let context = Context::new();
|
||||||
// stdin::read_line();
|
|
||||||
|
{
|
||||||
|
// 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();
|
// stdin::read_char();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -2,12 +2,18 @@ extern crate crossterm;
|
|||||||
|
|
||||||
use self::crossterm::input::input;
|
use self::crossterm::input::input;
|
||||||
use self::crossterm::Context;
|
use self::crossterm::Context;
|
||||||
|
use self::crossterm::Crossterm;
|
||||||
|
use crossterm::terminal::ClearType;
|
||||||
|
|
||||||
use std::{thread, time};
|
use std::{thread, time};
|
||||||
use std::io::Read;
|
use crossterm::raw::IntoRawMode;
|
||||||
|
|
||||||
// this will capture the input until the given key was pressed.
|
use std::io::{Read, Write, stdout};
|
||||||
pub fn capture_input_until_a_certain_char_async()
|
use std::time::Duration;
|
||||||
|
|
||||||
|
|
||||||
|
/// this will capture the input until the given key.
|
||||||
|
pub fn read_async_until()
|
||||||
{
|
{
|
||||||
let context = Context::new();
|
let context = Context::new();
|
||||||
let input = input(&context);
|
let input = input(&context);
|
||||||
@ -18,8 +24,15 @@ pub fn capture_input_until_a_certain_char_async()
|
|||||||
{
|
{
|
||||||
let a = stdin.next();
|
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 {
|
if let Some(Ok(b'x')) = a {
|
||||||
println!("The key: x was pressed.");
|
println!("The key: x was pressed and program is terminated.");
|
||||||
break;
|
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()
|
pub fn read_async()
|
||||||
{
|
{
|
||||||
let context = Context::new();
|
let context = Context::new();
|
||||||
@ -39,13 +52,98 @@ pub fn read_async()
|
|||||||
{
|
{
|
||||||
let a = stdin.next();
|
let a = stdin.next();
|
||||||
|
|
||||||
println!("pressed: {:?}", a);
|
println!("pressed key: {:?}", a);
|
||||||
|
|
||||||
if let Some(Ok(b'x')) = 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;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
thread::sleep(time::Duration::from_millis(50));
|
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
|
pub fn read_async(&self) -> AsyncReader
|
||||||
{
|
{
|
||||||
self.terminal_input.read_async()
|
self.terminal_input.read_async()
|
||||||
// todo: async reading
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn read_until_async(&self, delimiter: u8) -> AsyncReader
|
pub fn read_until_async(&self, delimiter: u8) -> AsyncReader
|
||||||
|
@ -7,8 +7,9 @@ use self::windows_input::WindowsInput;
|
|||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
mod windows_input;
|
mod windows_input;
|
||||||
|
|
||||||
#[cfg(target_os = "windows")]
|
#[cfg(not(target_os = "windows"))]
|
||||||
use self::unix_input::UnixInput;
|
use self::unix_input::UnixInput;
|
||||||
|
#[cfg(not(target_os = "windows"))]
|
||||||
mod unix_input;
|
mod unix_input;
|
||||||
|
|
||||||
|
|
||||||
|
@ -3,124 +3,76 @@ use std::io::Write;
|
|||||||
use std::char;
|
use std::char;
|
||||||
use std::sync::mpsc;
|
use std::sync::mpsc;
|
||||||
use std::thread;
|
use std::thread;
|
||||||
|
use std::io::Read;
|
||||||
|
|
||||||
use super::super::terminal::terminal;
|
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 };
|
use super::{ Key, ITerminalInput, AsyncReader };
|
||||||
|
|
||||||
pub struct UnixInput;
|
pub struct UnixInput;
|
||||||
|
|
||||||
|
|
||||||
impl UnixInput
|
impl UnixInput
|
||||||
{
|
{
|
||||||
pub fn new() -> UnixInput
|
pub fn new() -> UnixInput
|
||||||
{
|
{
|
||||||
UnixInput {}
|
UnixInput {}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
// fn read_line(&self) -> io::Result<String>
|
}
|
||||||
// {
|
|
||||||
// let mut rv = String::new();
|
impl ITerminalInput for UnixInput
|
||||||
// io::stdin().read_line(&mut rv)?;
|
{
|
||||||
// let len = rv.trim_right_matches(&['\r', '\n'][..]).len();
|
fn read_line(&self) -> io::Result<String>
|
||||||
// rv.truncate(len);
|
{
|
||||||
// Ok(rv)
|
let mut rv = String::new();
|
||||||
// }
|
io::stdin().read_line(&mut rv)?;
|
||||||
//
|
let len = rv.trim_right_matches(&['\r', '\n'][..]).len();
|
||||||
// fn read_char(&self) -> io::Result<char>
|
rv.truncate(len);
|
||||||
// {
|
Ok(rv)
|
||||||
// let mut buf = [0u8; 20];
|
}
|
||||||
// let mut termios = termios::Termios::from_fd(fd)?;
|
|
||||||
// let original = termios.clone();
|
fn read_char(&self) -> io::Result<char>
|
||||||
// termios::cfmakeraw(&mut termios);
|
{
|
||||||
// termios::tcsetattr(fd, termios::TCSADRAIN, &termios)?;
|
read_char()
|
||||||
// let rv = unsafe {
|
}
|
||||||
// let read = libc::read(fd, buf.as_mut_ptr() as *mut libc::c_void, 20);
|
|
||||||
// if read < 0 {
|
fn read_pressed_key(&self) -> io::Result<Key>
|
||||||
// Err(io::Error::last_os_error())
|
{
|
||||||
// } else if buf[0] == b'\x03' {
|
Ok(Key::Unknown)
|
||||||
// Err(io::Error::new(io::ErrorKind::Interrupted, "read interrupted"))
|
}
|
||||||
// } else {
|
|
||||||
// Ok(key_from_escape_codes(&buf[..read as usize]))
|
fn read_async(&self) -> AsyncReader
|
||||||
// }
|
{
|
||||||
// };
|
let (send, recv) = mpsc::channel();
|
||||||
// termios::tcsetattr(fd, termios::TCSADRAIN, &original)?;
|
|
||||||
//
|
thread::spawn(move || for i in get_tty().unwrap().bytes() {
|
||||||
// // if the user hit ^C we want to signal SIGINT to outselves.
|
if send.send(i).is_err() {
|
||||||
// if let Err(ref err) = rv {
|
return;
|
||||||
// if err.kind() == io::ErrorKind::Interrupted {
|
}
|
||||||
// unsafe { libc::raise(libc::SIGINT); }
|
});
|
||||||
// }
|
|
||||||
// }
|
AsyncReader { recv: recv }
|
||||||
//
|
}
|
||||||
// rv
|
|
||||||
// }
|
fn read_until_async(&self, delimiter: u8) -> AsyncReader
|
||||||
//
|
{
|
||||||
// fn read_pressed_key(&self) -> io::Result<Key>
|
let (send, recv) = mpsc::channel();
|
||||||
// {
|
|
||||||
// use Context;
|
thread::spawn(move || for i in get_tty().unwrap().bytes() {
|
||||||
// let context = Context::new();
|
|
||||||
//
|
match i {
|
||||||
// let buf: [u8; 1024] = unsafe { ::std::mem::zeroed() };
|
Ok(byte) => {
|
||||||
//// reading::read(&mut buf, &context.screen_manager);
|
let end_of_stream = &byte == &delimiter;
|
||||||
//
|
let send_error = send.send(Ok(byte)).is_err();
|
||||||
// Ok(Key::Unknown)
|
|
||||||
//// let pressed_char = unsafe { _getwch() };
|
if end_of_stream || send_error { return; }
|
||||||
////
|
},
|
||||||
//// // if 0 or 0xe0 we need to listen again because the next key will be an special key
|
Err(_) => { return; }
|
||||||
//// if pressed_char == 0 || pressed_char == 0xe0 {
|
}
|
||||||
//// let special_key: i32 = unsafe { _getwch() };
|
});
|
||||||
//// println!("spkey {}",special_key);
|
|
||||||
//// return Ok(key_from_key_code(0x26));
|
AsyncReader { recv: recv }
|
||||||
//// } 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 }
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
|
|
||||||
|
@ -3,12 +3,13 @@
|
|||||||
pub use self::libc::termios;
|
pub use self::libc::termios;
|
||||||
use self::libc::{c_int, c_ushort, ioctl, STDOUT_FILENO, TIOCGWINSZ};
|
use self::libc::{c_int, c_ushort, ioctl, STDOUT_FILENO, TIOCGWINSZ};
|
||||||
use state::commands::{IStateCommand, NoncanonicalModeCommand};
|
use state::commands::{IStateCommand, NoncanonicalModeCommand};
|
||||||
use termios::Termios;
|
|
||||||
use {libc, CommandManager, Context, StateManager};
|
use {libc, CommandManager, Context, StateManager};
|
||||||
|
|
||||||
|
use termios::{ Termios,cfmakeraw,tcsetattr,TCSADRAIN };
|
||||||
use std::io::Error;
|
use std::io::Error;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::{io, mem, fs};
|
use std::{io, mem, fs};
|
||||||
|
use std::os::unix::io::AsRawFd;
|
||||||
|
|
||||||
/// A representation of the size of the current terminal.
|
/// A representation of the size of the current terminal.
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
@ -140,6 +141,70 @@ pub fn get_tty() -> io::Result<fs::File> {
|
|||||||
fs::OpenOptions::new().read(true).write(true).open("/dev/tty")
|
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() {
|
pub fn exit() {
|
||||||
::std::process::exit(0);
|
::std::process::exit(0);
|
||||||
}
|
}
|
||||||
|
@ -27,6 +27,8 @@
|
|||||||
use super::super::cursor;
|
use super::super::cursor;
|
||||||
use super::super::style;
|
use super::super::style;
|
||||||
use super::super::terminal::terminal;
|
use super::super::terminal::terminal;
|
||||||
|
use super::super::input::input;
|
||||||
|
|
||||||
use Context;
|
use Context;
|
||||||
|
|
||||||
use std::fmt::Display;
|
use std::fmt::Display;
|
||||||
@ -126,6 +128,11 @@ impl Crossterm {
|
|||||||
return style::TerminalColor::new(self.context.clone());
|
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.
|
/// Wraps an displayable object so it can be formatted with colors and attributes.
|
||||||
///
|
///
|
||||||
/// Check `/examples/color` in the library for more specific examples.
|
/// Check `/examples/color` in the library for more specific examples.
|
||||||
|
@ -107,6 +107,7 @@ impl AlternateScreen {
|
|||||||
context: context.clone(),
|
context: context.clone(),
|
||||||
command_id: command_id,
|
command_id: command_id,
|
||||||
};
|
};
|
||||||
|
|
||||||
screen.to_alternate();
|
screen.to_alternate();
|
||||||
return screen;
|
return screen;
|
||||||
}
|
}
|
||||||
@ -134,6 +135,7 @@ impl AlternateScreen {
|
|||||||
let mut mx = &state_manager.get(self.command_id);
|
let mut mx = &state_manager.get(self.command_id);
|
||||||
{
|
{
|
||||||
let mut command = mx.lock().unwrap();
|
let mut command = mx.lock().unwrap();
|
||||||
|
|
||||||
command.execute();
|
command.execute();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user