parent
e0136891e7
commit
ddcda09602
@ -14,12 +14,4 @@ extern crate crossterm;
|
|||||||
//mod some_types;
|
//mod some_types;
|
||||||
//mod terminal;
|
//mod terminal;
|
||||||
|
|
||||||
use crossterm::style::{style, Color};
|
fn main() { }
|
||||||
|
|
||||||
fn main() {
|
|
||||||
let styled_object = style("'Red' text on 'White' background")
|
|
||||||
.with(Color::Rgb { r: 0xFF, g: 0, b: 0 })
|
|
||||||
.on(Color::Rgb { r: 0xFF, g: 0xFF, b: 0xFF });
|
|
||||||
|
|
||||||
println!("{}", styled_object);
|
|
||||||
}
|
|
@ -42,7 +42,8 @@ fn main() {
|
|||||||
thread::sleep(time::Duration::from_millis(100));
|
thread::sleep(time::Duration::from_millis(100));
|
||||||
count += 1;
|
count += 1;
|
||||||
}
|
}
|
||||||
}).join();
|
})
|
||||||
|
.join();
|
||||||
|
|
||||||
for thread in threads {
|
for thread in threads {
|
||||||
thread.join();
|
thread.join();
|
||||||
|
@ -121,7 +121,8 @@ fn handle_incoming_logs(more_jobs_rx: SyncFlagRx, queue: WorkQueue<String>) {
|
|||||||
}
|
}
|
||||||
std::thread::yield_now();
|
std::thread::yield_now();
|
||||||
}
|
}
|
||||||
}).join();
|
})
|
||||||
|
.join();
|
||||||
}
|
}
|
||||||
|
|
||||||
// start different threads that log contiguously.
|
// start different threads that log contiguously.
|
||||||
|
@ -87,7 +87,10 @@ pub fn write(stdout: &Option<&Arc<TerminalOutput>>, string: String) -> io::Resul
|
|||||||
pub fn write_str(stdout: &Option<&Arc<TerminalOutput>>, string: &str) -> io::Result<usize> {
|
pub fn write_str(stdout: &Option<&Arc<TerminalOutput>>, string: &str) -> io::Result<usize> {
|
||||||
match stdout {
|
match stdout {
|
||||||
None => match io::stdout().flush() {
|
None => match io::stdout().flush() {
|
||||||
Ok(_) => { write!(io::stdout(), "{}", string)?; Ok(string.len()) },
|
Ok(_) => {
|
||||||
|
write!(io::stdout(), "{}", string)?;
|
||||||
|
Ok(string.len())
|
||||||
|
}
|
||||||
Err(e) => Err(e),
|
Err(e) => Err(e),
|
||||||
},
|
},
|
||||||
Some(output) => output.write_str(string),
|
Some(output) => output.write_str(string),
|
||||||
|
@ -44,7 +44,8 @@ impl AlternateScreen {
|
|||||||
functions::get_module::<Box<commands::IAlternateScreenCommand + Sync + Send>>(
|
functions::get_module::<Box<commands::IAlternateScreenCommand + Sync + Send>>(
|
||||||
Box::from(commands::win_commands::ToAlternateScreenCommand::new()),
|
Box::from(commands::win_commands::ToAlternateScreenCommand::new()),
|
||||||
Box::from(commands::shared_commands::ToAlternateScreenCommand::new()),
|
Box::from(commands::shared_commands::ToAlternateScreenCommand::new()),
|
||||||
).unwrap();
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
#[cfg(not(target_os = "windows"))]
|
#[cfg(not(target_os = "windows"))]
|
||||||
let command = Box::from(commands::shared_commands::ToAlternateScreenCommand::new());
|
let command = Box::from(commands::shared_commands::ToAlternateScreenCommand::new());
|
||||||
|
@ -21,7 +21,7 @@ pub fn get_csbi() -> Result<CONSOLE_SCREEN_BUFFER_INFO> {
|
|||||||
let mut csbi = CONSOLE_SCREEN_BUFFER_INFO::empty();
|
let mut csbi = CONSOLE_SCREEN_BUFFER_INFO::empty();
|
||||||
let success;
|
let success;
|
||||||
|
|
||||||
unsafe { success = GetConsoleScreenBufferInfo(handle::get_current_handle()?, &mut csbi) }
|
unsafe { success = GetConsoleScreenBufferInfo(handle::get_current_out_handle()?, &mut csbi) }
|
||||||
|
|
||||||
if success == 0 {
|
if success == 0 {
|
||||||
return Err(io::Error::new(
|
return Err(io::Error::new(
|
||||||
@ -35,7 +35,7 @@ pub fn get_csbi() -> Result<CONSOLE_SCREEN_BUFFER_INFO> {
|
|||||||
|
|
||||||
/// Get buffer info and handle of the current screen.
|
/// Get buffer info and handle of the current screen.
|
||||||
pub fn get_csbi_and_handle() -> Result<(CONSOLE_SCREEN_BUFFER_INFO, HANDLE)> {
|
pub fn get_csbi_and_handle() -> Result<(CONSOLE_SCREEN_BUFFER_INFO, HANDLE)> {
|
||||||
let handle = handle::get_current_handle()?;
|
let handle = handle::get_current_out_handle()?;
|
||||||
let csbi = get_csbi_by_handle(&handle)?;
|
let csbi = get_csbi_by_handle(&handle)?;
|
||||||
|
|
||||||
return Ok((csbi, handle));
|
return Ok((csbi, handle));
|
||||||
@ -59,7 +59,7 @@ pub fn get_csbi_by_handle(handle: &HANDLE) -> Result<CONSOLE_SCREEN_BUFFER_INFO>
|
|||||||
|
|
||||||
/// Set the console screen buffer size
|
/// Set the console screen buffer size
|
||||||
pub fn set_console_screen_buffer_size(size: COORD) -> bool {
|
pub fn set_console_screen_buffer_size(size: COORD) -> bool {
|
||||||
let handle = handle::get_current_handle().unwrap();
|
let handle = handle::get_current_out_handle().unwrap();
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
if !kernel::is_true(SetConsoleScreenBufferSize(handle, size)) {
|
if !kernel::is_true(SetConsoleScreenBufferSize(handle, size)) {
|
||||||
|
@ -29,7 +29,7 @@ pub fn save_cursor_pos() {
|
|||||||
|
|
||||||
/// get the current cursor position.
|
/// get the current cursor position.
|
||||||
pub fn pos() -> (u16, u16) {
|
pub fn pos() -> (u16, u16) {
|
||||||
let handle = handle::get_current_handle().unwrap();
|
let handle = handle::get_current_out_handle().unwrap();
|
||||||
|
|
||||||
if let Ok(csbi) = csbi::get_csbi_by_handle(&handle) {
|
if let Ok(csbi) = csbi::get_csbi_by_handle(&handle) {
|
||||||
(
|
(
|
||||||
@ -57,7 +57,7 @@ pub fn set_console_cursor_position(x: i16, y: i16) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let handle = handle::get_current_handle().unwrap();
|
let handle = handle::get_current_out_handle().unwrap();
|
||||||
|
|
||||||
let position = COORD { X: x, Y: y };
|
let position = COORD { X: x, Y: y };
|
||||||
|
|
||||||
@ -80,7 +80,7 @@ pub fn set_console_cursor_position(x: i16, y: i16) {
|
|||||||
|
|
||||||
/// change the cursor visibility.
|
/// change the cursor visibility.
|
||||||
pub fn cursor_visibility(visable: bool) -> io::Result<()> {
|
pub fn cursor_visibility(visable: bool) -> io::Result<()> {
|
||||||
let handle = handle::get_current_handle().unwrap();
|
let handle = handle::get_current_out_handle().unwrap();
|
||||||
|
|
||||||
let cursor_info = CONSOLE_CURSOR_INFO {
|
let cursor_info = CONSOLE_CURSOR_INFO {
|
||||||
dwSize: 100,
|
dwSize: 100,
|
||||||
|
@ -1,49 +1,61 @@
|
|||||||
//! This module contains some logic for working with the console handle.
|
//! This module contains some logic for working with the console handle.
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use winapi::shared::minwindef::DWORD;
|
|
||||||
use winapi::um::errhandlingapi::GetLastError;
|
|
||||||
use winapi::um::fileapi::{CreateFileW, OPEN_EXISTING};
|
use winapi::um::fileapi::{CreateFileW, OPEN_EXISTING};
|
||||||
use winapi::um::handleapi::INVALID_HANDLE_VALUE;
|
use winapi::um::handleapi::INVALID_HANDLE_VALUE;
|
||||||
use winapi::um::processenv::GetStdHandle;
|
use winapi::um::processenv::GetStdHandle;
|
||||||
use winapi::um::winbase::{STD_INPUT_HANDLE, STD_OUTPUT_HANDLE};
|
use winapi::um::winbase::{STD_INPUT_HANDLE, STD_OUTPUT_HANDLE};
|
||||||
use winapi::um::winnt::{FILE_SHARE_WRITE, GENERIC_READ, GENERIC_WRITE};
|
use winapi::um::winnt::{FILE_SHARE_READ, FILE_SHARE_WRITE, GENERIC_READ, GENERIC_WRITE};
|
||||||
|
|
||||||
use std::io::{self, Result};
|
use std::io::{self, Result};
|
||||||
use std::ptr::null_mut;
|
use std::ptr::null_mut;
|
||||||
|
|
||||||
/// Get the handle of the active screen.
|
/// Get the handle of the active screen.
|
||||||
pub fn get_current_handle() -> Result<HANDLE> {
|
pub fn get_current_out_handle() -> Result<HANDLE> {
|
||||||
let dw: DWORD = 0;
|
let utf16: Vec<u16> = "CONOUT$\0".encode_utf16().collect();
|
||||||
unsafe {
|
let utf16_ptr: *const u16 = utf16.as_ptr();
|
||||||
let utf16: Vec<u16> = "CONOUT$\0".encode_utf16().collect();
|
|
||||||
let utf16_ptr: *const u16 = utf16.as_ptr();
|
|
||||||
|
|
||||||
let handle = CreateFileW(
|
let handle = unsafe {
|
||||||
|
CreateFileW(
|
||||||
utf16_ptr,
|
utf16_ptr,
|
||||||
GENERIC_READ | GENERIC_WRITE,
|
GENERIC_READ | GENERIC_WRITE,
|
||||||
FILE_SHARE_WRITE,
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||||
null_mut(),
|
null_mut(),
|
||||||
OPEN_EXISTING,
|
OPEN_EXISTING,
|
||||||
dw,
|
0,
|
||||||
null_mut(),
|
null_mut(),
|
||||||
);
|
)
|
||||||
|
};
|
||||||
|
|
||||||
if !is_valid_handle(&handle) {
|
if !is_valid_handle(&handle) {
|
||||||
unsafe {
|
return Err(io::Error::last_os_error());
|
||||||
let error = GetLastError();
|
|
||||||
return Err(io::Error::new(
|
|
||||||
io::ErrorKind::Other,
|
|
||||||
format!(
|
|
||||||
"Could not get output handle current handle!, error code: {}",
|
|
||||||
error
|
|
||||||
).as_ref(),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(handle)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ok(handle)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the handle of the active screen.
|
||||||
|
pub fn get_current_in_handle() -> Result<HANDLE> {
|
||||||
|
let utf16: Vec<u16> = "CONIN$\0".encode_utf16().collect();
|
||||||
|
let utf16_ptr: *const u16 = utf16.as_ptr();
|
||||||
|
|
||||||
|
let handle = unsafe {
|
||||||
|
CreateFileW(
|
||||||
|
utf16_ptr,
|
||||||
|
GENERIC_READ | GENERIC_WRITE,
|
||||||
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||||
|
null_mut(),
|
||||||
|
OPEN_EXISTING,
|
||||||
|
0,
|
||||||
|
null_mut(),
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
if !is_valid_handle(&handle) {
|
||||||
|
return Err(io::Error::last_os_error());
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(handle)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the std_output_handle of the console
|
/// Get the std_output_handle of the console
|
||||||
|
@ -30,7 +30,7 @@ pub fn get_console_mode(handle: &HANDLE, current_mode: &mut u32) -> bool {
|
|||||||
|
|
||||||
/// Change the console text attribute.
|
/// Change the console text attribute.
|
||||||
pub fn set_console_text_attribute(value: u16) -> bool {
|
pub fn set_console_text_attribute(value: u16) -> bool {
|
||||||
let handle = handle::get_current_handle().unwrap();
|
let handle = handle::get_current_out_handle().unwrap();
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
return is_true(SetConsoleTextAttribute(handle, value));
|
return is_true(SetConsoleTextAttribute(handle, value));
|
||||||
@ -39,7 +39,7 @@ pub fn set_console_text_attribute(value: u16) -> bool {
|
|||||||
|
|
||||||
/// Change console info.
|
/// Change console info.
|
||||||
pub fn set_console_info(absolute: bool, rect: &SMALL_RECT) -> bool {
|
pub fn set_console_info(absolute: bool, rect: &SMALL_RECT) -> bool {
|
||||||
let handle = handle::get_current_handle().unwrap();
|
let handle = handle::get_current_out_handle().unwrap();
|
||||||
|
|
||||||
let absolute = match absolute {
|
let absolute = match absolute {
|
||||||
true => 1,
|
true => 1,
|
||||||
|
@ -5,6 +5,7 @@ pub mod csbi;
|
|||||||
pub mod cursor;
|
pub mod cursor;
|
||||||
pub mod handle;
|
pub mod handle;
|
||||||
pub mod kernel;
|
pub mod kernel;
|
||||||
|
pub mod reading;
|
||||||
pub mod terminal;
|
pub mod terminal;
|
||||||
pub mod writing;
|
pub mod writing;
|
||||||
|
|
||||||
|
@ -1,84 +1,73 @@
|
|||||||
//use { Context, ScreenManager };
|
use super::handle::get_current_in_handle;
|
||||||
//use std::rc::Rc;
|
use std::io::{self, Error, Result};
|
||||||
//use std::sync::Mutex;
|
|
||||||
//
|
use std::{
|
||||||
//use winapi::um::consoleapi::ReadConsoleW;
|
mem::{self, zeroed},
|
||||||
//use winapi::um::winnt::HANDLE;
|
ptr::{null, null_mut},
|
||||||
//use winapi::um::wincon::{ COORD, PSMALL_RECT, ReadConsoleOutputA, CHAR_INFO, };
|
};
|
||||||
//use winapi::shared::minwindef::{ DWORD, LPDWORD, LPVOID };
|
|
||||||
//use winapi::shared::ntdef::NULL;
|
use winapi::{
|
||||||
//
|
shared::minwindef::{LPVOID, ULONG},
|
||||||
//use super::kernel;
|
um::consoleapi::{ReadConsoleInputW, ReadConsoleW},
|
||||||
//use winapi::ctypes::c_void;
|
um::wincon::CONSOLE_READCONSOLE_CONTROL,
|
||||||
//
|
um::wincon::{CHAR_INFO, CONSOLE_FONT_INFOEX, INPUT_RECORD, PCONSOLE_READCONSOLE_CONTROL},
|
||||||
//pub fn read(buf: &mut [u8], stdout: &Rc<Mutex<ScreenManager>>) {
|
};
|
||||||
//// // Read more if the buffer is empty
|
|
||||||
//// let mut utf16: Vec<u16> = Vec::new();
|
use std::io::Write;
|
||||||
//// let mut num: DWORD = 0;
|
|
||||||
////
|
/// Could be used to read a line from the stdin.
|
||||||
//// let handle = kernel::get_current_handle(&stdout);
|
/// Note that this is a blocking call and it continues when user pressed enter.
|
||||||
////
|
pub fn read_line(buf: &mut Vec<u8>) -> io::Result<usize> {
|
||||||
//// unsafe {
|
let handle = get_current_in_handle()?;
|
||||||
//// ReadConsoleW(handle,
|
|
||||||
//// utf16.as_mut_ptr() as LPVOID,
|
let mut utf16 = vec![0u16; 0x1000];
|
||||||
//// utf16.len() as u32,
|
let mut num = 0;
|
||||||
//// &mut num as LPDWORD,
|
let mut input_control = readconsole_input_control(CTRL_Z_MASK);
|
||||||
//// ptr::mut_null())
|
|
||||||
//// };
|
unsafe {
|
||||||
////
|
ReadConsoleW(
|
||||||
//// utf16.truncate(num as uint);
|
handle,
|
||||||
//// let utf8 = match from_utf16(utf16.as_slice()) {
|
utf16.as_mut_ptr() as LPVOID,
|
||||||
//// Some(utf8) => utf8.into_bytes(),
|
utf16.len() as u32,
|
||||||
//// None => {}
|
&mut num,
|
||||||
//// };
|
&mut input_control as PCONSOLE_READCONSOLE_CONTROL,
|
||||||
////
|
)
|
||||||
//// panic!(utf8);
|
};
|
||||||
//
|
|
||||||
//}
|
utf16.truncate(num as usize);
|
||||||
//
|
|
||||||
//pub fn read_line(stdout: &Rc<Mutex<ScreenManager>>) -> ::std::io::Result<String>
|
let mut data = match String::from_utf16(&utf16) {
|
||||||
//{
|
Ok(utf8) => utf8.into_bytes(),
|
||||||
// const BUFFER_LENGHT: u32 = 1024;
|
Err(..) => return Err(invalid_encoding()),
|
||||||
// let mut buffer: &mut [CHAR_INFO; BUFFER_LENGHT as usize] = unsafe {::std::mem::zeroed() };
|
};
|
||||||
//
|
|
||||||
// let handle = kernel::get_current_handle(&stdout);
|
if let Some(&last_byte) = data.last() {
|
||||||
//
|
if last_byte == CTRL_Z {
|
||||||
// let mut dw_mode: DWORD = 0;
|
data.pop();
|
||||||
// let console_mode = kernel::get_console_mode(&handle, &mut dw_mode);
|
}
|
||||||
//
|
};
|
||||||
// let ptr = buffer.as_ptr() as *const _ as *mut c_void;
|
|
||||||
// let mut chars_read: u32 = 0;
|
let a = &data
|
||||||
//
|
.into_iter()
|
||||||
// panic!();
|
.filter(|&x| x != 10 || x != 13)
|
||||||
// unsafe
|
.collect::<Vec<u8>>();
|
||||||
// {
|
|
||||||
// ReadConsoleW(handle, ptr, BUFFER_LENGHT , &mut chars_read, unsafe {::std::mem::zeroed() });
|
buf.write(a);
|
||||||
// }
|
Ok(num as usize)
|
||||||
//
|
}
|
||||||
// Ok(String::new())
|
|
||||||
//}
|
pub fn readconsole_input_control(wakeup_mask: ULONG) -> CONSOLE_READCONSOLE_CONTROL {
|
||||||
//
|
CONSOLE_READCONSOLE_CONTROL {
|
||||||
///// Read the console outptut.
|
nLength: mem::size_of::<CONSOLE_READCONSOLE_CONTROL>() as ULONG,
|
||||||
//pub fn read_console_output(
|
nInitialChars: 0,
|
||||||
// read_buffer: &HANDLE,
|
dwCtrlWakeupMask: wakeup_mask,
|
||||||
// copy_buffer: &mut [CHAR_INFO; 160],
|
dwControlKeyState: 0,
|
||||||
// buffer_size: COORD,
|
}
|
||||||
// buffer_coord: COORD,
|
}
|
||||||
// source_buffer: PSMALL_RECT,
|
|
||||||
//) {
|
fn invalid_encoding() -> io::Error {
|
||||||
//
|
io::Error::new(io::ErrorKind::InvalidData, "text was not valid unicode")
|
||||||
//
|
}
|
||||||
// unsafe {
|
|
||||||
// if !kernel::is_true(
|
const CTRL_Z: u8 = 0x1A;
|
||||||
// ReadConsoleOutputA(
|
const CTRL_Z_MASK: ULONG = 0x4000000; //1 << 0x1A
|
||||||
// *read_buffer, // screen buffer to read from
|
|
||||||
// copy_buffer.as_mut_ptr(), // buffer to copy into
|
|
||||||
// buffer_size, // col-row size of chiBuffer
|
|
||||||
// buffer_coord, // top left dest. cell in chiBuffer
|
|
||||||
// source_buffer,
|
|
||||||
// ), // screen buffer source rectangle
|
|
||||||
// ) {
|
|
||||||
// panic!("Cannot read console output");
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
|
@ -19,7 +19,7 @@ pub fn fill_console_output_character(
|
|||||||
start_location: COORD,
|
start_location: COORD,
|
||||||
cells_to_write: u32,
|
cells_to_write: u32,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
let handle = handle::get_current_handle().unwrap();
|
let handle = handle::get_current_out_handle().unwrap();
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
// fill the cells in console with blanks
|
// fill the cells in console with blanks
|
||||||
|
11
src/lib.rs
11
src/lib.rs
@ -12,17 +12,20 @@ mod common;
|
|||||||
mod kernel;
|
mod kernel;
|
||||||
mod modules;
|
mod modules;
|
||||||
|
|
||||||
pub use modules::terminal;
|
|
||||||
pub use modules::cursor;
|
pub use modules::cursor;
|
||||||
pub use modules::input;
|
pub use modules::input;
|
||||||
pub use modules::output;
|
pub use modules::output;
|
||||||
pub use modules::style;
|
pub use modules::style;
|
||||||
|
pub use modules::terminal;
|
||||||
|
|
||||||
pub use self::style::{color, style, Color, ColorType, Attribute, TerminalColor, ObjectStyle, StyledObject, DisplayableObject};
|
|
||||||
pub use self::cursor::{cursor, TerminalCursor};
|
pub use self::cursor::{cursor, TerminalCursor};
|
||||||
pub use self::input::{input, TerminalInput, AsyncReader, KeyEvent};
|
pub use self::input::{input, AsyncReader, KeyEvent, TerminalInput};
|
||||||
pub use self::terminal::{terminal, Terminal};
|
|
||||||
pub use self::output::TerminalOutput;
|
pub use self::output::TerminalOutput;
|
||||||
|
pub use self::style::{
|
||||||
|
color, style, Attribute, Color, ColorType, DisplayableObject, ObjectStyle, StyledObject,
|
||||||
|
TerminalColor,
|
||||||
|
};
|
||||||
|
pub use self::terminal::{terminal, Terminal};
|
||||||
pub use common::screen::{AlternateScreen, Screen};
|
pub use common::screen::{AlternateScreen, Screen};
|
||||||
pub use common::Crossterm;
|
pub use common::Crossterm;
|
||||||
|
|
||||||
|
@ -40,7 +40,8 @@ impl<'stdout> TerminalCursor<'stdout> {
|
|||||||
let cursor = functions::get_module::<Box<ITerminalCursor + Sync + Send>>(
|
let cursor = functions::get_module::<Box<ITerminalCursor + Sync + Send>>(
|
||||||
WinApiCursor::new(),
|
WinApiCursor::new(),
|
||||||
AnsiCursor::new(),
|
AnsiCursor::new(),
|
||||||
).unwrap();
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
#[cfg(not(target_os = "windows"))]
|
#[cfg(not(target_os = "windows"))]
|
||||||
let cursor = AnsiCursor::new() as Box<ITerminalCursor + Sync + Send>;
|
let cursor = AnsiCursor::new() as Box<ITerminalCursor + Sync + Send>;
|
||||||
@ -72,7 +73,8 @@ impl<'stdout> TerminalCursor<'stdout> {
|
|||||||
let cursor = functions::get_module::<Box<ITerminalCursor + Sync + Send>>(
|
let cursor = functions::get_module::<Box<ITerminalCursor + Sync + Send>>(
|
||||||
WinApiCursor::new(),
|
WinApiCursor::new(),
|
||||||
AnsiCursor::new(),
|
AnsiCursor::new(),
|
||||||
).unwrap();
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
#[cfg(not(target_os = "windows"))]
|
#[cfg(not(target_os = "windows"))]
|
||||||
let cursor = AnsiCursor::new() as Box<ITerminalCursor + Sync + Send>;
|
let cursor = AnsiCursor::new() as Box<ITerminalCursor + Sync + Send>;
|
||||||
|
@ -2,8 +2,8 @@
|
|||||||
//! Like reading a line, reading a character and reading asynchronously.
|
//! Like reading a line, reading a character and reading asynchronously.
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use Screen;
|
|
||||||
use std::{thread, time::Duration};
|
use std::{thread, time::Duration};
|
||||||
|
use Screen;
|
||||||
|
|
||||||
/// Struct that stores a platform-specific implementation for input related actions.
|
/// Struct that stores a platform-specific implementation for input related actions.
|
||||||
///
|
///
|
||||||
@ -78,6 +78,9 @@ impl<'stdout> TerminalInput<'stdout> {
|
|||||||
|
|
||||||
/// Read one line from the user input.
|
/// Read one line from the user input.
|
||||||
///
|
///
|
||||||
|
/// Note that this function only works when rawscreen is not turned on.
|
||||||
|
/// When you do want to read a line in raw mode please checkout `read_async` or `read_async_until`.
|
||||||
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// let input = input();
|
/// let input = input();
|
||||||
/// match input.read_line() {
|
/// match input.read_line() {
|
||||||
@ -86,7 +89,17 @@ impl<'stdout> TerminalInput<'stdout> {
|
|||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn read_line(&self) -> io::Result<String> {
|
pub fn read_line(&self) -> io::Result<String> {
|
||||||
self.terminal_input.read_line(&self.stdout)
|
if let Some(stdout) = self.stdout {
|
||||||
|
if stdout.is_in_raw_mode {
|
||||||
|
return Err(Error::new(ErrorKind::Other, "Crossterm does not support readline in raw mode this should be done instead whit `read_async` or `read_async_until`"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Read one character from the user input
|
/// Read one character from the user input
|
||||||
@ -198,15 +211,21 @@ impl<'stdout> TerminalInput<'stdout> {
|
|||||||
let pressed_key: Option<Result<u8, Error>> = stdin.next();
|
let pressed_key: Option<Result<u8, Error>> = stdin.next();
|
||||||
|
|
||||||
match pressed_key {
|
match pressed_key {
|
||||||
Some(Ok(value)) => {
|
Some(Ok(value)) => match key_event {
|
||||||
match key_event {
|
KeyEvent::OnKeyPress(ascii_code) => {
|
||||||
KeyEvent::OnKeyPress(ascii_code) => if value == ascii_code { break; },
|
if value == ascii_code {
|
||||||
KeyEvent::OnEnter => if value == b'\r' { break; },
|
|
||||||
KeyEvent::OnAnyKeyPress => {
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
KeyEvent::OnEnter => {
|
||||||
|
if value == b'\r' {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
KeyEvent::OnAnyKeyPress => {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
},
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@ use self::unix_input::UnixInput;
|
|||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
use self::windows_input::WindowsInput;
|
use self::windows_input::WindowsInput;
|
||||||
|
|
||||||
pub use self::input::{input, from_screen, TerminalInput};
|
pub use self::input::{from_screen, input, TerminalInput};
|
||||||
|
|
||||||
use std::io::{self, Error, ErrorKind, Read};
|
use std::io::{self, Error, ErrorKind, Read};
|
||||||
use std::sync::{mpsc, Arc};
|
use std::sync::{mpsc, Arc};
|
||||||
@ -29,8 +29,6 @@ use TerminalOutput;
|
|||||||
/// This trait is implemented for Windows and UNIX systems.
|
/// This trait is implemented for Windows and UNIX systems.
|
||||||
/// Unix is using the 'TTY' and windows is using 'libc' C functions to read the input.
|
/// Unix is using the 'TTY' and windows is using 'libc' C functions to read the input.
|
||||||
trait ITerminalInput {
|
trait ITerminalInput {
|
||||||
/// Read one line from the user input
|
|
||||||
fn read_line(&self, stdout: &Option<&Arc<TerminalOutput>>) -> io::Result<String>;
|
|
||||||
/// Read one character from the user input
|
/// Read one character from the user input
|
||||||
fn read_char(&self, stdout: &Option<&Arc<TerminalOutput>>) -> io::Result<char>;
|
fn read_char(&self, stdout: &Option<&Arc<TerminalOutput>>) -> io::Result<char>;
|
||||||
/// Read the input asynchronously from the user.
|
/// Read the input asynchronously from the user.
|
||||||
|
@ -15,14 +15,6 @@ impl UnixInput {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ITerminalInput for UnixInput {
|
impl ITerminalInput for UnixInput {
|
||||||
fn read_line(&self, __stdout: &Option<&Arc<TerminalOutput>>) -> 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, __stdout: &Option<&Arc<TerminalOutput>>) -> io::Result<char> {
|
fn read_char(&self, __stdout: &Option<&Arc<TerminalOutput>>) -> io::Result<char> {
|
||||||
read_char()
|
read_char()
|
||||||
}
|
}
|
||||||
|
@ -2,56 +2,20 @@
|
|||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
use winapi::um::winnt::INT;
|
use kernel::windows_kernel::reading::read_line;
|
||||||
|
|
||||||
use std::char;
|
use std::char;
|
||||||
use std::thread;
|
use std::thread;
|
||||||
|
use winapi::um::winnt::INT;
|
||||||
|
|
||||||
pub struct WindowsInput;
|
pub struct WindowsInput;
|
||||||
|
|
||||||
impl WindowsInput {
|
impl WindowsInput {
|
||||||
pub fn new() -> WindowsInput {
|
pub fn new() -> WindowsInput {
|
||||||
WindowsInput {}
|
WindowsInput
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ITerminalInput for WindowsInput {
|
impl ITerminalInput for WindowsInput {
|
||||||
fn read_line(&self, stdout: &Option<&Arc<TerminalOutput>>) -> io::Result<String> {
|
|
||||||
let mut chars: Vec<char> = Vec::new();
|
|
||||||
|
|
||||||
loop {
|
|
||||||
let is_raw_screen = match stdout {
|
|
||||||
Some(output) => output.is_in_raw_mode,
|
|
||||||
None => false,
|
|
||||||
};
|
|
||||||
|
|
||||||
// _getwch is without echo and _getwche is with echo
|
|
||||||
let pressed_char = unsafe {
|
|
||||||
if is_raw_screen {
|
|
||||||
_getwch()
|
|
||||||
} else {
|
|
||||||
_getwche()
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// 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 {
|
|
||||||
match char::from_u32(pressed_char as u32) {
|
|
||||||
Some(c) => {
|
|
||||||
if is_line_end(c) {
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
chars.push(c);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None => panic!("Some error needs to be returned"),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return Ok(chars.into_iter().collect());
|
|
||||||
}
|
|
||||||
|
|
||||||
fn read_char(&self, stdout: &Option<&Arc<TerminalOutput>>) -> io::Result<char> {
|
fn read_char(&self, stdout: &Option<&Arc<TerminalOutput>>) -> io::Result<char> {
|
||||||
let is_raw_screen = match stdout {
|
let is_raw_screen = match stdout {
|
||||||
Some(output) => output.is_in_raw_mode,
|
Some(output) => output.is_in_raw_mode,
|
||||||
|
@ -15,8 +15,8 @@ use self::winapi_output::WinApiOutput;
|
|||||||
|
|
||||||
pub use self::output::TerminalOutput;
|
pub use self::output::TerminalOutput;
|
||||||
|
|
||||||
use std::io;
|
|
||||||
use super::functions;
|
use super::functions;
|
||||||
|
use std::io;
|
||||||
|
|
||||||
/// This trait defines represents an stdout of an screen.
|
/// This trait defines represents an stdout of an screen.
|
||||||
/// This trait can be implemented so that an concrete implementation of the IStdout can forfill
|
/// This trait can be implemented so that an concrete implementation of the IStdout can forfill
|
||||||
|
@ -37,7 +37,8 @@ impl TerminalOutput {
|
|||||||
functions::get_module::<Box<IStdout + Send + Sync>>(
|
functions::get_module::<Box<IStdout + Send + Sync>>(
|
||||||
Box::from(WinApiOutput::new()),
|
Box::from(WinApiOutput::new()),
|
||||||
Box::from(AnsiOutput::new()),
|
Box::from(AnsiOutput::new()),
|
||||||
).unwrap();
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
#[cfg(not(target_os = "windows"))]
|
#[cfg(not(target_os = "windows"))]
|
||||||
let stdout = Box::from(AnsiOutput::new()) as Box<IStdout + Send + Sync>;
|
let stdout = Box::from(AnsiOutput::new()) as Box<IStdout + Send + Sync>;
|
||||||
@ -86,7 +87,8 @@ impl Default for TerminalOutput {
|
|||||||
let stdout = functions::get_module::<Box<IStdout + Send + Sync>>(
|
let stdout = functions::get_module::<Box<IStdout + Send + Sync>>(
|
||||||
Box::from(WinApiOutput::new()),
|
Box::from(WinApiOutput::new()),
|
||||||
Box::from(AnsiOutput::new()),
|
Box::from(AnsiOutput::new()),
|
||||||
).unwrap();
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
#[cfg(not(target_os = "windows"))]
|
#[cfg(not(target_os = "windows"))]
|
||||||
let stdout = Box::from(AnsiOutput::new()) as Box<IStdout + Send + Sync>;
|
let stdout = Box::from(AnsiOutput::new()) as Box<IStdout + Send + Sync>;
|
||||||
|
@ -54,11 +54,13 @@ fn write_str_ansi() {
|
|||||||
fn is_valid_write(result: ::std::io::Result<usize>, str_length: usize) {
|
fn is_valid_write(result: ::std::io::Result<usize>, str_length: usize) {
|
||||||
match result {
|
match result {
|
||||||
Err(_) => assert!(false),
|
Err(_) => assert!(false),
|
||||||
Ok(length) => if str_length == length {
|
Ok(length) => {
|
||||||
assert!(true)
|
if str_length == length {
|
||||||
} else {
|
assert!(true)
|
||||||
assert!(false)
|
} else {
|
||||||
},
|
assert!(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,7 +18,7 @@ impl IStdout for WinApiOutput {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn write(&self, buf: &[u8]) -> io::Result<usize> {
|
fn write(&self, buf: &[u8]) -> io::Result<usize> {
|
||||||
let handle = handle::get_current_handle().unwrap();
|
let handle = handle::get_current_out_handle().unwrap();
|
||||||
writing::write_char_buffer(&handle, buf)
|
writing::write_char_buffer(&handle, buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,7 +39,8 @@ impl<'stdout> TerminalColor<'stdout> {
|
|||||||
let color = functions::get_module::<Box<ITerminalColor + Sync + Send>>(
|
let color = functions::get_module::<Box<ITerminalColor + Sync + Send>>(
|
||||||
Box::from(WinApiColor::new()),
|
Box::from(WinApiColor::new()),
|
||||||
Box::from(AnsiColor::new()),
|
Box::from(AnsiColor::new()),
|
||||||
).unwrap();
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
#[cfg(not(target_os = "windows"))]
|
#[cfg(not(target_os = "windows"))]
|
||||||
let color = Box::from(AnsiColor::new()) as Box<ITerminalColor + Sync + Send>;
|
let color = Box::from(AnsiColor::new()) as Box<ITerminalColor + Sync + Send>;
|
||||||
@ -71,7 +72,8 @@ impl<'stdout> TerminalColor<'stdout> {
|
|||||||
let color = functions::get_module::<Box<ITerminalColor + Sync + Send>>(
|
let color = functions::get_module::<Box<ITerminalColor + Sync + Send>>(
|
||||||
Box::from(WinApiColor::new()),
|
Box::from(WinApiColor::new()),
|
||||||
Box::from(AnsiColor::new()),
|
Box::from(AnsiColor::new()),
|
||||||
).unwrap();
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
#[cfg(not(target_os = "windows"))]
|
#[cfg(not(target_os = "windows"))]
|
||||||
let color = Box::from(AnsiColor::new()) as Box<ITerminalColor + Sync + Send>;
|
let color = Box::from(AnsiColor::new()) as Box<ITerminalColor + Sync + Send>;
|
||||||
|
@ -111,11 +111,7 @@ pub enum Color {
|
|||||||
Grey,
|
Grey,
|
||||||
White,
|
White,
|
||||||
|
|
||||||
Rgb {
|
Rgb { r: u8, g: u8, b: u8 },
|
||||||
r: u8,
|
|
||||||
g: u8,
|
|
||||||
b: u8,
|
|
||||||
},
|
|
||||||
AnsiValue(u8),
|
AnsiValue(u8),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -101,8 +101,8 @@ impl ITerminalColor for WinApiColor {
|
|||||||
Color::White => fg_intensity | fg_red | fg_green | fg_blue,
|
Color::White => fg_intensity | fg_red | fg_green | fg_blue,
|
||||||
|
|
||||||
/* WinApi will be used for systems that do not support ANSI, those are windows version less then 10. RGB and 255 (AnsiBValue) colors are not supported in that case.*/
|
/* WinApi will be used for systems that do not support ANSI, those are windows version less then 10. RGB and 255 (AnsiBValue) colors are not supported in that case.*/
|
||||||
Color::Rgb{ r: _, g: _, b: _ } => { 0 }
|
Color::Rgb { r: _, g: _, b: _ } => 0,
|
||||||
Color::AnsiValue(_val) => { 0 }
|
Color::AnsiValue(_val) => 0,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
ColorType::Background => {
|
ColorType::Background => {
|
||||||
@ -124,8 +124,8 @@ impl ITerminalColor for WinApiColor {
|
|||||||
Color::White => bg_intensity | bg_red | bg_green | bg_blue,
|
Color::White => bg_intensity | bg_red | bg_green | bg_blue,
|
||||||
|
|
||||||
/* WinApi will be used for systems that do not support ANSI, those are windows version less then 10. RGB and 255 (AnsiBValue) colors are not supported in that case.*/
|
/* WinApi will be used for systems that do not support ANSI, those are windows version less then 10. RGB and 255 (AnsiBValue) colors are not supported in that case.*/
|
||||||
Color::Rgb{ r: _, g: _, b: _ } => { 0 }
|
Color::Rgb { r: _, g: _, b: _ } => 0,
|
||||||
Color::AnsiValue(_val) => { 0 }
|
Color::AnsiValue(_val) => 0,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -13,7 +13,7 @@ use self::ansi_terminal::AnsiTerminal;
|
|||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
use self::winapi_terminal::WinApiTerminal;
|
use self::winapi_terminal::WinApiTerminal;
|
||||||
|
|
||||||
pub use self::terminal::{terminal, from_screen, Terminal};
|
pub use self::terminal::{from_screen, terminal, Terminal};
|
||||||
|
|
||||||
use super::functions;
|
use super::functions;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
@ -32,7 +32,8 @@ impl<'stdout> Terminal<'stdout> {
|
|||||||
let terminal = functions::get_module::<Box<ITerminal + Sync + Send>>(
|
let terminal = functions::get_module::<Box<ITerminal + Sync + Send>>(
|
||||||
Box::new(WinApiTerminal::new()),
|
Box::new(WinApiTerminal::new()),
|
||||||
Box::new(AnsiTerminal::new()),
|
Box::new(AnsiTerminal::new()),
|
||||||
).unwrap();
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
#[cfg(not(target_os = "windows"))]
|
#[cfg(not(target_os = "windows"))]
|
||||||
let terminal = Box::from(AnsiTerminal::new()) as Box<ITerminal + Sync + Send>;
|
let terminal = Box::from(AnsiTerminal::new()) as Box<ITerminal + Sync + Send>;
|
||||||
@ -64,7 +65,8 @@ impl<'stdout> Terminal<'stdout> {
|
|||||||
let terminal = functions::get_module::<Box<ITerminal + Sync + Send>>(
|
let terminal = functions::get_module::<Box<ITerminal + Sync + Send>>(
|
||||||
Box::new(WinApiTerminal::new()),
|
Box::new(WinApiTerminal::new()),
|
||||||
Box::new(AnsiTerminal::new()),
|
Box::new(AnsiTerminal::new()),
|
||||||
).unwrap();
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
#[cfg(not(target_os = "windows"))]
|
#[cfg(not(target_os = "windows"))]
|
||||||
let terminal = Box::from(AnsiTerminal::new()) as Box<ITerminal + Sync + Send>;
|
let terminal = Box::from(AnsiTerminal::new()) as Box<ITerminal + Sync + Send>;
|
||||||
|
Loading…
Reference in New Issue
Block a user