Refactored winapi and moved code to (crossterm_winapi) (#67)
* Refactored winapi and moved some code to its own crate (crossterm_winapi).
This commit is contained in:
parent
14bd60af78
commit
ff9b5d9a39
@ -10,9 +10,9 @@ keywords = ["console", "color", "cursor", "input", "terminal"]
|
|||||||
exclude = ["target", "Cargo.lock"]
|
exclude = ["target", "Cargo.lock"]
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
[target.'cfg(windows)'.dependencies]
|
[target.'cfg(windows)'.dependencies]
|
||||||
winapi = { version = "0.3.5", features = ["winbase","winuser","consoleapi","processenv","wincon", "handleapi","errhandlingapi"] }
|
winapi = { version = "0.3.5", features = ["winbase","winuser","consoleapi","processenv","wincon", "handleapi","errhandlingapi"] }
|
||||||
|
crossterm_winapi = { version = "0.0.0", git="https://github.com/TimonPost/crossterm_winapi" }
|
||||||
|
|
||||||
[target.'cfg(unix)'.dependencies]
|
[target.'cfg(unix)'.dependencies]
|
||||||
libc = "0.2.43"
|
libc = "0.2.43"
|
||||||
|
2
docs/some_common_bugs.txt
Normal file
2
docs/some_common_bugs.txt
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
Power shell does not interpreter 'DarkYellow' and is instead using gray Winapi.
|
||||||
|
Arc and manjaro konsole are not seeming to resize the terminal instead they are resizeing the buffer.
|
@ -10,7 +10,7 @@ use self::crossterm::{terminal, Screen};
|
|||||||
pub fn paint_foreground() {
|
pub fn paint_foreground() {
|
||||||
// Create a styled object.
|
// Create a styled object.
|
||||||
// Call the method `with()` on the object given by `style()` and pass in any Color from the Color enum.
|
// Call the method `with()` on the object given by `style()` and pass in any Color from the Color enum.
|
||||||
let mut styledobject = style("Red foreground").with(Color::Red);
|
let styledobject = style("Red foreground").with(Color::Red);
|
||||||
|
|
||||||
// Print the object to the given screen and.
|
// Print the object to the given screen and.
|
||||||
println!("Colored text: {}", styledobject);
|
println!("Colored text: {}", styledobject);
|
||||||
@ -26,7 +26,7 @@ pub fn paint_foreground() {
|
|||||||
pub fn paint_background() {
|
pub fn paint_background() {
|
||||||
// Create a styled object.
|
// Create a styled object.
|
||||||
// Call the method `with()` on the object given by `style()` and pass in any Color from the Color enum.
|
// Call the method `with()` on the object given by `style()` and pass in any Color from the Color enum.
|
||||||
let mut styledobject = style("Red foreground").on(Color::Red);
|
let styledobject = style("Red foreground").on(Color::Red);
|
||||||
|
|
||||||
// Print the object to the given screen and.
|
// Print the object to the given screen and.
|
||||||
println!("Colored text: {}", styledobject);
|
println!("Colored text: {}", styledobject);
|
||||||
@ -109,7 +109,10 @@ pub fn print_all_foreground_colors() {
|
|||||||
);
|
);
|
||||||
|
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
println!("{}", style("RGB color (10,10,10) ").with(Color::AnsiValue(50)));
|
println!(
|
||||||
|
"{}",
|
||||||
|
style("RGB color (10,10,10) ").with(Color::AnsiValue(50))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Print all available foreground colors | demonstration.
|
/// Print all available foreground colors | demonstration.
|
||||||
|
@ -9,7 +9,7 @@ use self::crossterm::Screen;
|
|||||||
/// Set the cursor to position X: 10, Y: 5 in the terminal.
|
/// Set the cursor to position X: 10, Y: 5 in the terminal.
|
||||||
pub fn goto() {
|
pub fn goto() {
|
||||||
// Get the cursor
|
// Get the cursor
|
||||||
let mut cursor = cursor();
|
let cursor = cursor();
|
||||||
// Set the cursor to position X: 10, Y: 5 in the terminal
|
// Set the cursor to position X: 10, Y: 5 in the terminal
|
||||||
cursor.goto(10, 5);
|
cursor.goto(10, 5);
|
||||||
}
|
}
|
||||||
@ -17,9 +17,11 @@ pub fn goto() {
|
|||||||
/// get the cursor position
|
/// get the cursor position
|
||||||
pub fn pos() {
|
pub fn pos() {
|
||||||
// Get the cursor
|
// Get the cursor
|
||||||
let mut cursor = cursor();
|
let cursor = cursor();
|
||||||
// get the cursor position.
|
// get the cursor position.
|
||||||
let (x, y) = cursor.pos();
|
let (x, y) = cursor.pos();
|
||||||
|
|
||||||
|
println!("{} {}", x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Move the cursor 3 up | demonstration.
|
/// Move the cursor 3 up | demonstration.
|
||||||
@ -81,7 +83,7 @@ pub fn move_left() {
|
|||||||
|
|
||||||
/// Save and reset cursor position | demonstration..
|
/// Save and reset cursor position | demonstration..
|
||||||
pub fn safe_and_reset_position() {
|
pub fn safe_and_reset_position() {
|
||||||
let mut cursor = cursor();
|
let cursor = cursor();
|
||||||
|
|
||||||
// Goto X: 5 Y: 5
|
// Goto X: 5 Y: 5
|
||||||
cursor.goto(5, 5);
|
cursor.goto(5, 5);
|
||||||
@ -101,19 +103,19 @@ pub fn safe_and_reset_position() {
|
|||||||
|
|
||||||
/// Hide cursor display | demonstration.
|
/// Hide cursor display | demonstration.
|
||||||
pub fn hide_cursor() {
|
pub fn hide_cursor() {
|
||||||
let mut cursor = cursor();
|
let cursor = cursor();
|
||||||
cursor.hide();
|
cursor.hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Show cursor display | demonstration.
|
/// Show cursor display | demonstration.
|
||||||
pub fn show_cursor() {
|
pub fn show_cursor() {
|
||||||
let mut cursor = cursor();
|
let cursor = cursor();
|
||||||
cursor.show();
|
cursor.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Show cursor display, only works on certain terminals.| demonstration
|
/// Show cursor display, only works on certain terminals.| demonstration
|
||||||
pub fn blink_cursor() {
|
pub fn blink_cursor() {
|
||||||
let mut cursor = cursor();
|
let cursor = cursor();
|
||||||
cursor.blink(false);
|
cursor.blink(false);
|
||||||
cursor.blink(false);
|
cursor.blink(false);
|
||||||
}
|
}
|
||||||
|
@ -8,10 +8,21 @@
|
|||||||
extern crate crossterm;
|
extern crate crossterm;
|
||||||
|
|
||||||
// modules that could be test
|
// modules that could be test
|
||||||
//mod color;
|
mod color;
|
||||||
//mod cursor;
|
mod cursor;
|
||||||
//mod input;
|
mod input;
|
||||||
//mod some_types;
|
//mod some_types;
|
||||||
//mod terminal;
|
mod terminal;
|
||||||
|
|
||||||
fn main() { }
|
fn main() {
|
||||||
|
use input::keyboard::input;
|
||||||
|
|
||||||
|
// color::print_all_foreground_colors();
|
||||||
|
// color::print_all_background_colors();
|
||||||
|
|
||||||
|
use terminal::alternate_screen;
|
||||||
|
// color::print_all_background_colors();
|
||||||
|
// color::print_all_foreground_colors();
|
||||||
|
|
||||||
|
alternate_screen::print_wait_screen_on_alternate_window();
|
||||||
|
}
|
||||||
|
@ -16,11 +16,11 @@ pub fn read_async_until() {
|
|||||||
// init some modules we use for this demo
|
// init some modules we use for this demo
|
||||||
let input = crossterm.input();
|
let input = crossterm.input();
|
||||||
let terminal = crossterm.terminal();
|
let terminal = crossterm.terminal();
|
||||||
let mut cursor = crossterm.cursor();
|
let cursor = crossterm.cursor();
|
||||||
|
|
||||||
let mut stdin = input.read_until_async(b'\r').bytes();
|
let mut stdin = input.read_until_async(b'\r').bytes();
|
||||||
|
|
||||||
for i in 0..100 {
|
for _i in 0..100 {
|
||||||
terminal.clear(ClearType::All);
|
terminal.clear(ClearType::All);
|
||||||
cursor.goto(1, 1);
|
cursor.goto(1, 1);
|
||||||
let a = stdin.next();
|
let a = stdin.next();
|
||||||
@ -68,7 +68,7 @@ pub fn read_async_demo() {
|
|||||||
// init some modules we use for this demo
|
// init some modules we use for this demo
|
||||||
let input = crossterm.input();
|
let input = crossterm.input();
|
||||||
let terminal = crossterm.terminal();
|
let terminal = crossterm.terminal();
|
||||||
let mut cursor = crossterm.cursor();
|
let cursor = crossterm.cursor();
|
||||||
|
|
||||||
// this will setup the async reading.
|
// this will setup the async reading.
|
||||||
let mut stdin = input.read_async().bytes();
|
let mut stdin = input.read_async().bytes();
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
extern crate crossterm;
|
extern crate crossterm;
|
||||||
|
|
||||||
use self::crossterm::input::{input, TerminalInput, KeyEvent};
|
use self::crossterm::input::{input, KeyEvent, TerminalInput};
|
||||||
use self::crossterm::Screen;
|
use self::crossterm::Screen;
|
||||||
|
|
||||||
pub fn read_char() {
|
pub fn read_char() {
|
||||||
|
@ -131,7 +131,7 @@ fn game_over_screen()
|
|||||||
|
|
||||||
terminal.clear(ClearType::All);
|
terminal.clear(ClearType::All);
|
||||||
|
|
||||||
println!("{}",messages::END_MESSAGE.join("\n\r"));
|
println!("{}", crossterm.style(format!("{}",messages::END_MESSAGE.join("\n\r"))).with(Color::Red));
|
||||||
// cursor.goto()
|
// cursor.goto()
|
||||||
cursor.show();
|
cursor.show();
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,7 @@ fn print_test_data() {
|
|||||||
|
|
||||||
/// Clear all lines in terminal | demonstration
|
/// Clear all lines in terminal | demonstration
|
||||||
pub fn clear_all_lines() {
|
pub fn clear_all_lines() {
|
||||||
let mut terminal = terminal();
|
let terminal = terminal();
|
||||||
|
|
||||||
print_test_data();
|
print_test_data();
|
||||||
|
|
||||||
@ -24,7 +24,7 @@ pub fn clear_all_lines() {
|
|||||||
|
|
||||||
/// Clear all lines from cursor position X:4, Y:4 down | demonstration
|
/// Clear all lines from cursor position X:4, Y:4 down | demonstration
|
||||||
pub fn clear_from_cursor_down() {
|
pub fn clear_from_cursor_down() {
|
||||||
let mut terminal = terminal();
|
let terminal = terminal();
|
||||||
|
|
||||||
print_test_data();
|
print_test_data();
|
||||||
|
|
||||||
@ -37,7 +37,7 @@ pub fn clear_from_cursor_down() {
|
|||||||
|
|
||||||
/// Clear all lines from cursor position X:4, Y:4 up | demonstration
|
/// Clear all lines from cursor position X:4, Y:4 up | demonstration
|
||||||
pub fn clear_from_cursor_up() {
|
pub fn clear_from_cursor_up() {
|
||||||
let mut terminal = terminal();
|
let terminal = terminal();
|
||||||
|
|
||||||
print_test_data();
|
print_test_data();
|
||||||
|
|
||||||
@ -50,12 +50,12 @@ pub fn clear_from_cursor_up() {
|
|||||||
|
|
||||||
/// Clear all lines from cursor position X:4, Y:4 up | demonstration
|
/// Clear all lines from cursor position X:4, Y:4 up | demonstration
|
||||||
pub fn clear_current_line() {
|
pub fn clear_current_line() {
|
||||||
let mut terminal = terminal();
|
let terminal = terminal();
|
||||||
|
|
||||||
print_test_data();
|
print_test_data();
|
||||||
|
|
||||||
// Set terminal cursor position (see example for more info).
|
// Set terminal cursor position (see example for more info).
|
||||||
cursor().goto(4, 4);
|
cursor().goto(4, 3);
|
||||||
|
|
||||||
// Clear current line cells.
|
// Clear current line cells.
|
||||||
terminal.clear(ClearType::CurrentLine);
|
terminal.clear(ClearType::CurrentLine);
|
||||||
@ -63,7 +63,7 @@ pub fn clear_current_line() {
|
|||||||
|
|
||||||
/// Clear all lines from cursor position X:4, Y:7 up | demonstration
|
/// Clear all lines from cursor position X:4, Y:7 up | demonstration
|
||||||
pub fn clear_until_new_line() {
|
pub fn clear_until_new_line() {
|
||||||
let mut terminal = terminal();
|
let terminal = terminal();
|
||||||
|
|
||||||
print_test_data();
|
print_test_data();
|
||||||
|
|
||||||
@ -76,7 +76,7 @@ pub fn clear_until_new_line() {
|
|||||||
|
|
||||||
/// Print the the current terminal size | demonstration.
|
/// Print the the current terminal size | demonstration.
|
||||||
pub fn print_terminal_size() {
|
pub fn print_terminal_size() {
|
||||||
let mut terminal = terminal();
|
let terminal = terminal();
|
||||||
|
|
||||||
// Get terminal size
|
// Get terminal size
|
||||||
let (width, height) = terminal.terminal_size();
|
let (width, height) = terminal.terminal_size();
|
||||||
@ -87,14 +87,14 @@ pub fn print_terminal_size() {
|
|||||||
|
|
||||||
/// Set the terminal size to width 10, height: 10 | demonstration.
|
/// Set the terminal size to width 10, height: 10 | demonstration.
|
||||||
pub fn set_terminal_size() {
|
pub fn set_terminal_size() {
|
||||||
let mut terminal = terminal();
|
let terminal = terminal();
|
||||||
|
|
||||||
terminal.set_size(10, 10);
|
terminal.set_size(10, 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Scroll down 10 lines | demonstration.
|
/// Scroll down 10 lines | demonstration.
|
||||||
pub fn scroll_down() {
|
pub fn scroll_down() {
|
||||||
let mut terminal = terminal();
|
let terminal = terminal();
|
||||||
|
|
||||||
print_test_data();
|
print_test_data();
|
||||||
|
|
||||||
@ -104,7 +104,7 @@ pub fn scroll_down() {
|
|||||||
|
|
||||||
/// Scroll down 10 lines | demonstration.
|
/// Scroll down 10 lines | demonstration.
|
||||||
pub fn scroll_up() {
|
pub fn scroll_up() {
|
||||||
let mut terminal = terminal();
|
let terminal = terminal();
|
||||||
|
|
||||||
print_test_data();
|
print_test_data();
|
||||||
|
|
||||||
@ -114,7 +114,7 @@ pub fn scroll_up() {
|
|||||||
|
|
||||||
/// Resize the terminal to X: 10, Y: 10 | demonstration.
|
/// Resize the terminal to X: 10, Y: 10 | demonstration.
|
||||||
pub fn resize_terminal() {
|
pub fn resize_terminal() {
|
||||||
let mut terminal = terminal();
|
let terminal = terminal();
|
||||||
|
|
||||||
// Get terminal size
|
// Get terminal size
|
||||||
terminal.set_size(10, 10);
|
terminal.set_size(10, 10);
|
||||||
@ -122,6 +122,6 @@ pub fn resize_terminal() {
|
|||||||
|
|
||||||
/// exit the current proccess.
|
/// exit the current proccess.
|
||||||
pub fn exit() {
|
pub fn exit() {
|
||||||
let mut terminal = terminal();
|
let terminal = terminal();
|
||||||
terminal.exit();
|
terminal.exit();
|
||||||
}
|
}
|
||||||
|
@ -18,8 +18,8 @@ pub trait IStateCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub trait IEnableAnsiCommand {
|
pub trait IEnableAnsiCommand {
|
||||||
fn enable(&self) -> bool;
|
fn enable(&self) -> io::Result<bool>;
|
||||||
fn disable(&self) -> bool;
|
fn disable(&self) -> io::Result<()>;
|
||||||
}
|
}
|
||||||
|
|
||||||
// This trait provides an interface for switching to alternate screen and back.
|
// This trait provides an interface for switching to alternate screen and back.
|
||||||
|
@ -2,12 +2,12 @@
|
|||||||
|
|
||||||
use super::{IAlternateScreenCommand, IEnableAnsiCommand, TerminalOutput};
|
use super::{IAlternateScreenCommand, IEnableAnsiCommand, TerminalOutput};
|
||||||
|
|
||||||
use kernel::windows_kernel::{ansi_support, csbi, handle, kernel};
|
use kernel::windows_kernel::{ansi_support, ConsoleMode, Handle, ScreenBuffer};
|
||||||
use winapi::shared::minwindef::DWORD;
|
use winapi::shared::minwindef::DWORD;
|
||||||
use winapi::um::wincon;
|
use winapi::um::wincon;
|
||||||
use winapi::um::wincon::ENABLE_VIRTUAL_TERMINAL_PROCESSING;
|
use winapi::um::wincon::ENABLE_VIRTUAL_TERMINAL_PROCESSING;
|
||||||
|
|
||||||
use std::io::{Error, ErrorKind, Result};
|
use std::io::Result;
|
||||||
|
|
||||||
/// This command is used for enabling and disabling ANSI code support for windows systems,
|
/// This command is used for enabling and disabling ANSI code support for windows systems,
|
||||||
/// For more info check: https://docs.microsoft.com/en-us/windows/console/console-virtual-terminal-sequences.
|
/// For more info check: https://docs.microsoft.com/en-us/windows/console/console-virtual-terminal-sequences.
|
||||||
@ -26,43 +26,35 @@ impl EnableAnsiCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl IEnableAnsiCommand for EnableAnsiCommand {
|
impl IEnableAnsiCommand for EnableAnsiCommand {
|
||||||
fn enable(&self) -> bool {
|
fn enable(&self) -> Result<bool> {
|
||||||
// we need to check whether we tried to enable ansi before. If we have we can just return if that had succeeded.
|
// we need to check whether we tried to enable ansi before. If we have we can just return if that had succeeded.
|
||||||
if ansi_support::has_been_tried_to_enable_ansi() && ansi_support::ansi_enabled() {
|
if ansi_support::has_been_tried_to_enable_ansi() && ansi_support::ansi_enabled() {
|
||||||
return ansi_support::windows_supportable();
|
return Ok(ansi_support::windows_supportable());
|
||||||
} else {
|
} else {
|
||||||
let output_handle = handle::get_output_handle().unwrap();
|
let console_mode = ConsoleMode::new()?;
|
||||||
|
|
||||||
let mut dw_mode: DWORD = 0;
|
let mut dw_mode = console_mode.mode()?;
|
||||||
if !kernel::get_console_mode(&output_handle, &mut dw_mode) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
dw_mode |= self.mask;
|
dw_mode |= self.mask;
|
||||||
if !kernel::set_console_mode(&output_handle, dw_mode) {
|
|
||||||
return false;
|
console_mode.set_mode(dw_mode)?;
|
||||||
}
|
Ok(true)
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn disable(&self) -> bool {
|
fn disable(&self) -> Result<()> {
|
||||||
if ansi_support::ansi_enabled() {
|
if ansi_support::ansi_enabled() {
|
||||||
let output_handle = handle::get_output_handle().unwrap();
|
let console_mode = ConsoleMode::new()?;
|
||||||
|
|
||||||
let mut dw_mode: DWORD = 0;
|
let mut dw_mode = console_mode.mode()?;
|
||||||
if !kernel::get_console_mode(&output_handle, &mut dw_mode) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
dw_mode &= !self.mask;
|
dw_mode &= !self.mask;
|
||||||
if !kernel::set_console_mode(&output_handle, dw_mode) {
|
|
||||||
return false;
|
console_mode.set_mode(dw_mode)?;
|
||||||
}
|
|
||||||
|
|
||||||
ansi_support::set_ansi_enabled(false);
|
ansi_support::set_ansi_enabled(false);
|
||||||
}
|
}
|
||||||
return true;
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -84,48 +76,26 @@ impl RawModeCommand {
|
|||||||
impl RawModeCommand {
|
impl RawModeCommand {
|
||||||
/// Enables raw mode.
|
/// Enables raw mode.
|
||||||
pub fn enable(&mut self) -> Result<()> {
|
pub fn enable(&mut self) -> Result<()> {
|
||||||
let mut dw_mode: DWORD = 0;
|
let console_mode = ConsoleMode::new()?;
|
||||||
let stdout = handle::get_output_handle().unwrap();
|
|
||||||
|
|
||||||
if !kernel::get_console_mode(&stdout, &mut dw_mode) {
|
let mut dw_mode = console_mode.mode()?;
|
||||||
return Err(Error::new(
|
|
||||||
ErrorKind::Other,
|
|
||||||
"Could not get console mode when enabling raw mode",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
let new_mode = dw_mode & !self.mask;
|
let new_mode = dw_mode & !self.mask;
|
||||||
|
|
||||||
if !kernel::set_console_mode(&stdout, new_mode) {
|
console_mode.set_mode(new_mode)?;
|
||||||
return Err(Error::new(
|
|
||||||
ErrorKind::Other,
|
|
||||||
"Could not set console mode when enabling raw mode",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Disables raw mode.
|
/// Disables raw mode.
|
||||||
pub fn disable(&self) -> Result<()> {
|
pub fn disable(&self) -> Result<()> {
|
||||||
let stdout = handle::get_output_handle().unwrap();
|
let console_mode = ConsoleMode::new()?;
|
||||||
|
|
||||||
let mut dw_mode: DWORD = 0;
|
let mut dw_mode = console_mode.mode()?;
|
||||||
if !kernel::get_console_mode(&stdout, &mut dw_mode) {
|
|
||||||
return Err(Error::new(
|
|
||||||
ErrorKind::Other,
|
|
||||||
"Could not get console mode when disabling raw mode",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
let new_mode = dw_mode | self.mask;
|
let new_mode = dw_mode | self.mask;
|
||||||
|
|
||||||
if !kernel::set_console_mode(&stdout, new_mode) {
|
console_mode.set_mode(new_mode)?;
|
||||||
return Err(Error::new(
|
|
||||||
ErrorKind::Other,
|
|
||||||
"Could not set console mode when disabling raw mode",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
@ -143,21 +113,14 @@ impl ToAlternateScreenCommand {
|
|||||||
|
|
||||||
impl IAlternateScreenCommand for ToAlternateScreenCommand {
|
impl IAlternateScreenCommand for ToAlternateScreenCommand {
|
||||||
fn enable(&self, _stdout: &mut TerminalOutput) -> Result<()> {
|
fn enable(&self, _stdout: &mut TerminalOutput) -> Result<()> {
|
||||||
let _handle = handle::get_output_handle()?;
|
let alternate_screen = ScreenBuffer::create();
|
||||||
|
alternate_screen.show();
|
||||||
// create a new screen buffer to copy to.
|
|
||||||
let new_handle = csbi::create_console_screen_buffer();
|
|
||||||
|
|
||||||
// Make the new screen buffer the active screen buffer.
|
|
||||||
csbi::set_active_screen_buffer(new_handle)?;
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn disable(&self, _stdout: &TerminalOutput) -> Result<()> {
|
fn disable(&self, _stdout: &TerminalOutput) -> Result<()> {
|
||||||
let handle = handle::get_output_handle()?;
|
let screen_buffer = ScreenBuffer::from(Handle::output_handle()?);
|
||||||
csbi::set_active_screen_buffer(handle);
|
screen_buffer.show()?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,25 +8,49 @@ use std::sync::Arc;
|
|||||||
use kernel::windows_kernel::ansi_support::{try_enable_ansi_support, windows_supportable};
|
use kernel::windows_kernel::ansi_support::{try_enable_ansi_support, windows_supportable};
|
||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
use kernel::windows_kernel::terminal::{exit, terminal_size};
|
use kernel::windows_kernel::exit;
|
||||||
|
#[cfg(windows)]
|
||||||
|
use kernel::windows_kernel::ScreenBuffer;
|
||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
use kernel::windows_kernel::cursor::pos;
|
use kernel::windows_kernel::Cursor;
|
||||||
|
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
use kernel::unix_kernel::terminal::{exit, pos, terminal_size};
|
use kernel::unix_kernel::terminal::{exit, pos, terminal_size};
|
||||||
|
|
||||||
/// Get the terminal size based on the current platform.
|
/// Get the terminal size based on the current platform.
|
||||||
|
#[cfg(unix)]
|
||||||
pub fn get_terminal_size() -> (u16, u16) {
|
pub fn get_terminal_size() -> (u16, u16) {
|
||||||
terminal_size()
|
terminal_size()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the cursor position based on the current platform.
|
|
||||||
pub fn get_cursor_position() -> (u16, u16) {
|
|
||||||
#[cfg(unix)]
|
|
||||||
return pos().expect("Valide position");
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
return pos();
|
pub fn get_terminal_size() -> (u16, u16) {
|
||||||
|
if let Ok(buffer) = ScreenBuffer::current() {
|
||||||
|
let size = buffer.info().unwrap().terminal_size();
|
||||||
|
(size.width as u16, size.height as u16)
|
||||||
|
} else {
|
||||||
|
(0, 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the cursor position based on the current platform.
|
||||||
|
#[cfg(unix)]
|
||||||
|
pub fn get_cursor_position() -> (u16, u16) {
|
||||||
|
if let Ok(pos) = pos() {
|
||||||
|
pos
|
||||||
|
} else {
|
||||||
|
(0, 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(windows)]
|
||||||
|
pub fn get_cursor_position() -> (u16, u16) {
|
||||||
|
if let Ok(cursor) = Cursor::new() {
|
||||||
|
cursor.position().unwrap().into()
|
||||||
|
} else {
|
||||||
|
(0, 0)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// exit the current terminal.
|
/// exit the current terminal.
|
||||||
@ -40,18 +64,18 @@ pub fn exit_terminal() {
|
|||||||
/// If the current platform is unix it will return the ansi implementation.
|
/// If the current platform is unix it will return the ansi implementation.
|
||||||
pub fn get_module<T>(winapi_impl: T, unix_impl: T) -> Option<T> {
|
pub fn get_module<T>(winapi_impl: T, unix_impl: T) -> Option<T> {
|
||||||
let mut term: Option<T> = None;
|
let mut term: Option<T> = None;
|
||||||
let mut does_support = true;
|
let does_support = false;
|
||||||
|
|
||||||
if !windows_supportable() {
|
// if !windows_supportable() {
|
||||||
// Try to enable ansi on windows if not than use WINAPI.
|
// Try to enable ansi on windows if not than use WINAPI.
|
||||||
does_support = try_enable_ansi_support();
|
// does_support = try_enable_ansi_support();
|
||||||
|
|
||||||
// uncomment this line when you want to use the winapi implementation.
|
// uncomment this line when you want to use the winapi implementation.
|
||||||
// does_support = false;
|
// does_support = false;
|
||||||
if !does_support {
|
if !does_support {
|
||||||
term = Some(winapi_impl);
|
term = Some(winapi_impl);
|
||||||
}
|
}
|
||||||
}
|
// }
|
||||||
|
|
||||||
if does_support {
|
if does_support {
|
||||||
term = Some(unix_impl);
|
term = Some(unix_impl);
|
||||||
|
@ -13,7 +13,7 @@ use common::commands::IEnableAnsiCommand;
|
|||||||
pub fn try_enable_ansi_support() -> bool {
|
pub fn try_enable_ansi_support() -> bool {
|
||||||
ENABLE_ANSI.call_once(|| {
|
ENABLE_ANSI.call_once(|| {
|
||||||
let command = EnableAnsiCommand::new();
|
let command = EnableAnsiCommand::new();
|
||||||
let success = command.enable();
|
let success = command.enable().unwrap();
|
||||||
|
|
||||||
set_is_windows_ansi_supportable(success);
|
set_is_windows_ansi_supportable(success);
|
||||||
set_ansi_enabled(success);
|
set_ansi_enabled(success);
|
||||||
|
@ -1,117 +0,0 @@
|
|||||||
//! This contains the logic for working with the console buffer.
|
|
||||||
|
|
||||||
use winapi::shared::minwindef::TRUE;
|
|
||||||
use winapi::shared::ntdef::NULL;
|
|
||||||
use winapi::um::minwinbase::SECURITY_ATTRIBUTES;
|
|
||||||
use winapi::um::wincon::{
|
|
||||||
CreateConsoleScreenBuffer, GetConsoleScreenBufferInfo, SetConsoleActiveScreenBuffer,
|
|
||||||
SetConsoleScreenBufferSize, CONSOLE_SCREEN_BUFFER_INFO, CONSOLE_TEXTMODE_BUFFER, COORD,
|
|
||||||
};
|
|
||||||
|
|
||||||
use winapi::um::winnt::{FILE_SHARE_READ, FILE_SHARE_WRITE, GENERIC_READ, GENERIC_WRITE};
|
|
||||||
|
|
||||||
use super::{handle, kernel, Empty, HANDLE};
|
|
||||||
|
|
||||||
use std::io::{self, Result};
|
|
||||||
use std::mem::size_of;
|
|
||||||
use std::sync::{Once, ONCE_INIT};
|
|
||||||
|
|
||||||
/// Create a new console screen buffer info struct.
|
|
||||||
pub fn get_csbi() -> Result<CONSOLE_SCREEN_BUFFER_INFO> {
|
|
||||||
let mut csbi = CONSOLE_SCREEN_BUFFER_INFO::empty();
|
|
||||||
let success;
|
|
||||||
|
|
||||||
unsafe { success = GetConsoleScreenBufferInfo(handle::get_current_out_handle()?, &mut csbi) }
|
|
||||||
|
|
||||||
if success == 0 {
|
|
||||||
return Err(io::Error::new(
|
|
||||||
io::ErrorKind::Other,
|
|
||||||
"Could not get console screen buffer info",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(csbi)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get buffer info and handle of the current screen.
|
|
||||||
pub fn get_csbi_and_handle() -> Result<(CONSOLE_SCREEN_BUFFER_INFO, HANDLE)> {
|
|
||||||
let handle = handle::get_current_out_handle()?;
|
|
||||||
let csbi = get_csbi_by_handle(&handle)?;
|
|
||||||
|
|
||||||
return Ok((csbi, handle));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Create a new console screen buffer info struct.
|
|
||||||
pub fn get_csbi_by_handle(handle: &HANDLE) -> Result<CONSOLE_SCREEN_BUFFER_INFO> {
|
|
||||||
let mut csbi = CONSOLE_SCREEN_BUFFER_INFO::empty();
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
if !kernel::is_true(GetConsoleScreenBufferInfo(*handle, &mut csbi)) {
|
|
||||||
return Err(io::Error::new(
|
|
||||||
io::ErrorKind::Other,
|
|
||||||
"Could not get console screen buffer info",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(csbi)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Set the console screen buffer size
|
|
||||||
pub fn set_console_screen_buffer_size(size: COORD) -> bool {
|
|
||||||
let handle = handle::get_current_out_handle().unwrap();
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
if !kernel::is_true(SetConsoleScreenBufferSize(handle, size)) {
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Create new console screen buffer. This can be used for alternate screen.
|
|
||||||
pub fn create_console_screen_buffer() -> HANDLE {
|
|
||||||
let mut security_attr: SECURITY_ATTRIBUTES = SECURITY_ATTRIBUTES {
|
|
||||||
nLength: size_of::<SECURITY_ATTRIBUTES>() as u32,
|
|
||||||
lpSecurityDescriptor: NULL,
|
|
||||||
bInheritHandle: TRUE,
|
|
||||||
};
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
let new_screen_buffer = CreateConsoleScreenBuffer(
|
|
||||||
GENERIC_READ | // read/write access
|
|
||||||
GENERIC_WRITE,
|
|
||||||
FILE_SHARE_READ | FILE_SHARE_WRITE, // shared
|
|
||||||
&mut security_attr, // default security attributes
|
|
||||||
CONSOLE_TEXTMODE_BUFFER, // must be TEXTMODE
|
|
||||||
NULL,
|
|
||||||
);
|
|
||||||
new_screen_buffer
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Set the active screen buffer to the given handle. This can be used for alternate screen.
|
|
||||||
pub fn set_active_screen_buffer(new_buffer: HANDLE) -> Result<()> {
|
|
||||||
unsafe {
|
|
||||||
if !kernel::is_true(SetConsoleActiveScreenBuffer(new_buffer)) {
|
|
||||||
return Err(io::Error::new(
|
|
||||||
io::ErrorKind::Other,
|
|
||||||
"Could not set the active screen buffer",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
static GET_ORIGINAL_CONSOLE_COLOR: Once = ONCE_INIT;
|
|
||||||
static mut original_console_color: u16 = 0;
|
|
||||||
|
|
||||||
pub fn get_original_console_color() -> u16 {
|
|
||||||
GET_ORIGINAL_CONSOLE_COLOR.call_once(|| {
|
|
||||||
let handle = handle::get_output_handle().unwrap();
|
|
||||||
let csbi = get_csbi_by_handle(&handle).unwrap();
|
|
||||||
unsafe { original_console_color = csbi.wAttributes as u16 };
|
|
||||||
});
|
|
||||||
return unsafe { original_console_color };
|
|
||||||
}
|
|
@ -1,99 +1,123 @@
|
|||||||
//! This module handles some logic for cursor interaction in the windows console.
|
//! This module handles some logic for cursor interaction in the windows console.
|
||||||
|
|
||||||
use winapi::shared::minwindef::{FALSE, TRUE};
|
use crossterm_winapi::{is_true, Coord, Handle, HandleType, ScreenBuffer};
|
||||||
use winapi::um::wincon::{
|
|
||||||
SetConsoleCursorInfo, SetConsoleCursorPosition, CONSOLE_CURSOR_INFO, COORD,
|
use winapi::{
|
||||||
|
shared::minwindef::{FALSE, TRUE},
|
||||||
|
um::wincon::{SetConsoleCursorInfo, SetConsoleCursorPosition, CONSOLE_CURSOR_INFO, COORD},
|
||||||
|
um::winnt::HANDLE,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{csbi, handle, kernel};
|
use std::io::{self, Result};
|
||||||
use std::io;
|
|
||||||
|
|
||||||
/// This stores the cursor pos, at program level. So it can be recalled later.
|
/// This stores the cursor pos, at program level. So it can be recalled later.
|
||||||
static mut SAVED_CURSOR_POS: (u16, u16) = (0, 0);
|
static mut SAVED_CURSOR_POS: (u16, u16) = (0, 0);
|
||||||
|
|
||||||
/// Reset to saved cursor position
|
pub struct Cursor {
|
||||||
pub fn reset_to_saved_position() {
|
screen_buffer: ScreenBuffer,
|
||||||
unsafe {
|
|
||||||
set_console_cursor_position(SAVED_CURSOR_POS.0 as i16, SAVED_CURSOR_POS.1 as i16);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Save current cursor position to recall later.
|
impl Cursor {
|
||||||
pub fn save_cursor_pos() {
|
pub fn new() -> io::Result<Cursor> {
|
||||||
let position = pos();
|
Ok(Cursor {
|
||||||
|
screen_buffer: ScreenBuffer::from(Handle::new(HandleType::CurrentOutputHandle)?),
|
||||||
unsafe {
|
})
|
||||||
SAVED_CURSOR_POS = (position.0, position.1);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// get the current cursor position.
|
/// get the current cursor position.
|
||||||
pub fn pos() -> (u16, u16) {
|
pub fn position(&self) -> Result<Coord> {
|
||||||
let handle = handle::get_current_out_handle().unwrap();
|
Ok(self.screen_buffer.info()?.cursor_pos())
|
||||||
|
|
||||||
if let Ok(csbi) = csbi::get_csbi_by_handle(&handle) {
|
|
||||||
(
|
|
||||||
csbi.dwCursorPosition.X as u16,
|
|
||||||
csbi.dwCursorPosition.Y as u16,
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
(0, 0)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the cursor position to the given x and y. Note that this is 0 based.
|
/// Set the cursor position to the given x and y. Note that this is 0 based.
|
||||||
pub fn set_console_cursor_position(x: i16, y: i16) {
|
pub fn goto(&self, x: i16, y: i16) -> io::Result<()> {
|
||||||
if x < 0 || x >= <i16>::max_value() {
|
if x < 0 || x >= <i16>::max_value() {
|
||||||
panic!(
|
return Err(io::Error::new(
|
||||||
|
io::ErrorKind::Other,
|
||||||
|
format!(
|
||||||
"Argument Out of Range Exception when setting cursor position to X: {}",
|
"Argument Out of Range Exception when setting cursor position to X: {}",
|
||||||
x
|
x
|
||||||
);
|
),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
if y < 0 || y >= <i16>::max_value() {
|
if y < 0 || y >= <i16>::max_value() {
|
||||||
panic!(
|
return Err(io::Error::new(
|
||||||
|
io::ErrorKind::Other,
|
||||||
|
format!(
|
||||||
"Argument Out of Range Exception when setting cursor position to Y: {}",
|
"Argument Out of Range Exception when setting cursor position to Y: {}",
|
||||||
y
|
y
|
||||||
);
|
),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
let handle = handle::get_current_out_handle().unwrap();
|
|
||||||
|
|
||||||
let position = COORD { X: x, Y: y };
|
let position = COORD { X: x, Y: y };
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let success = SetConsoleCursorPosition(handle, position);
|
if !is_true(SetConsoleCursorPosition(
|
||||||
|
**self.screen_buffer.get_handle(),
|
||||||
if success == 0 {
|
position,
|
||||||
panic!("Argument out of range when trying to set cursor position.");
|
)) {
|
||||||
|
return Err(io::Error::last_os_error());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
//pub fn set_relative_cursor_pos(x: i16, y: i16)
|
|
||||||
//{
|
|
||||||
// let (cur_x, cur_y) = pos()?;
|
|
||||||
// let Relative(x, y) = *self;
|
|
||||||
// let (x, y) = (x + cur_x, y + cur_y);
|
|
||||||
// platform::set_cursor_pos(x, y)?;
|
|
||||||
//}
|
|
||||||
|
|
||||||
/// change the cursor visibility.
|
/// change the cursor visibility.
|
||||||
pub fn cursor_visibility(visable: bool) -> io::Result<()> {
|
pub fn set_visibility(&self, visable: bool) -> io::Result<()> {
|
||||||
let handle = handle::get_current_out_handle().unwrap();
|
|
||||||
|
|
||||||
let cursor_info = CONSOLE_CURSOR_INFO {
|
let cursor_info = CONSOLE_CURSOR_INFO {
|
||||||
dwSize: 100,
|
dwSize: 100,
|
||||||
bVisible: if visable { TRUE } else { FALSE },
|
bVisible: if visable { TRUE } else { FALSE },
|
||||||
};
|
};
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
if !kernel::is_true(SetConsoleCursorInfo(handle, &cursor_info)) {
|
if !is_true(SetConsoleCursorInfo(
|
||||||
return Err(io::Error::new(
|
**self.screen_buffer.get_handle(),
|
||||||
io::ErrorKind::Other,
|
&cursor_info,
|
||||||
"Could not get console screen buffer info",
|
)) {
|
||||||
));
|
return Err(io::Error::last_os_error());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Reset to saved cursor position
|
||||||
|
pub fn reset_to_saved_position() -> io::Result<()> {
|
||||||
|
let cursor = Cursor::new()?;
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
cursor.goto(SAVED_CURSOR_POS.0 as i16, SAVED_CURSOR_POS.1 as i16)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Save current cursor position to recall later.
|
||||||
|
pub fn save_cursor_pos() -> io::Result<()> {
|
||||||
|
let cursor = Cursor::new()?;
|
||||||
|
let position = cursor.position()?;
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
SAVED_CURSOR_POS = (position.x as u16, position.y as u16);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Handle> for Cursor {
|
||||||
|
fn from(handle: Handle) -> Self {
|
||||||
|
Cursor {
|
||||||
|
screen_buffer: ScreenBuffer::from(handle),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<HANDLE> for Cursor {
|
||||||
|
fn from(handle: HANDLE) -> Self {
|
||||||
|
Cursor {
|
||||||
|
screen_buffer: ScreenBuffer::from(handle),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,99 +0,0 @@
|
|||||||
//! This module contains some logic for working with the console handle.
|
|
||||||
|
|
||||||
use super::*;
|
|
||||||
use winapi::um::fileapi::{CreateFileW, OPEN_EXISTING};
|
|
||||||
use winapi::um::handleapi::INVALID_HANDLE_VALUE;
|
|
||||||
use winapi::um::processenv::GetStdHandle;
|
|
||||||
use winapi::um::winbase::{STD_INPUT_HANDLE, STD_OUTPUT_HANDLE};
|
|
||||||
use winapi::um::winnt::{FILE_SHARE_READ, FILE_SHARE_WRITE, GENERIC_READ, GENERIC_WRITE};
|
|
||||||
|
|
||||||
use std::io::{self, Result};
|
|
||||||
use std::ptr::null_mut;
|
|
||||||
|
|
||||||
/// Get the handle of the active screen.
|
|
||||||
pub fn get_current_out_handle() -> Result<HANDLE> {
|
|
||||||
let utf16: Vec<u16> = "CONOUT$\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 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
|
|
||||||
pub fn get_output_handle() -> Result<HANDLE> {
|
|
||||||
unsafe {
|
|
||||||
let handle = GetStdHandle(STD_OUTPUT_HANDLE);
|
|
||||||
|
|
||||||
if !is_valid_handle(&handle) {
|
|
||||||
return Err(io::Error::new(
|
|
||||||
io::ErrorKind::Other,
|
|
||||||
"Could not get output handle!",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
Ok(handle)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the std_input_handle of the console
|
|
||||||
pub fn get_input_handle() -> Result<HANDLE> {
|
|
||||||
unsafe {
|
|
||||||
let handle = GetStdHandle(STD_INPUT_HANDLE);
|
|
||||||
|
|
||||||
if !is_valid_handle(&handle) {
|
|
||||||
return Err(io::Error::new(
|
|
||||||
io::ErrorKind::Other,
|
|
||||||
"Could not get input handle",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(handle)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Checks if the console handle is an invalid handle value.
|
|
||||||
fn is_valid_handle(handle: &HANDLE) -> bool {
|
|
||||||
if *handle == INVALID_HANDLE_VALUE {
|
|
||||||
false
|
|
||||||
} else {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,60 +0,0 @@
|
|||||||
//! This module contains some basic winapi calls.
|
|
||||||
|
|
||||||
use winapi::um::consoleapi::{GetConsoleMode, SetConsoleMode};
|
|
||||||
use winapi::um::wincon::{
|
|
||||||
GetLargestConsoleWindowSize, SetConsoleTextAttribute, SetConsoleWindowInfo, COORD, SMALL_RECT,
|
|
||||||
};
|
|
||||||
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
/// Get the largest console window size possible.
|
|
||||||
pub fn get_largest_console_window_size() -> COORD {
|
|
||||||
let output_handle = handle::get_output_handle().unwrap();
|
|
||||||
|
|
||||||
unsafe { GetLargestConsoleWindowSize(output_handle) }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Set the console mode to the given console mode.
|
|
||||||
pub fn set_console_mode(handle: &HANDLE, console_mode: u32) -> bool {
|
|
||||||
unsafe {
|
|
||||||
return is_true(SetConsoleMode(*handle, console_mode));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the console mode.
|
|
||||||
pub fn get_console_mode(handle: &HANDLE, current_mode: &mut u32) -> bool {
|
|
||||||
unsafe {
|
|
||||||
return is_true(GetConsoleMode(*handle, &mut *current_mode));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Change the console text attribute.
|
|
||||||
pub fn set_console_text_attribute(value: u16) -> bool {
|
|
||||||
let handle = handle::get_current_out_handle().unwrap();
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
return is_true(SetConsoleTextAttribute(handle, value));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Change console info.
|
|
||||||
pub fn set_console_info(absolute: bool, rect: &SMALL_RECT) -> bool {
|
|
||||||
let handle = handle::get_current_out_handle().unwrap();
|
|
||||||
|
|
||||||
let absolute = match absolute {
|
|
||||||
true => 1,
|
|
||||||
false => 0,
|
|
||||||
};
|
|
||||||
unsafe {
|
|
||||||
return is_true(SetConsoleWindowInfo(handle, absolute, rect));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Parse integer to an bool
|
|
||||||
pub fn is_true(value: i32) -> bool {
|
|
||||||
if value == 0 {
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,44 +1,22 @@
|
|||||||
//! This module contains the `windows` (unsafe) logic.
|
//! This module contains the `windows` (unsafe) logic.
|
||||||
|
|
||||||
pub mod ansi_support;
|
pub mod ansi_support;
|
||||||
pub mod csbi;
|
mod cursor;
|
||||||
pub mod cursor;
|
|
||||||
pub mod handle;
|
|
||||||
pub mod kernel;
|
|
||||||
pub mod reading;
|
pub mod reading;
|
||||||
pub mod terminal;
|
|
||||||
pub mod writing;
|
pub mod writing;
|
||||||
|
|
||||||
use winapi::um::wincon::{CONSOLE_SCREEN_BUFFER_INFO, COORD, SMALL_RECT};
|
use winapi::um::{
|
||||||
use winapi::um::winnt::HANDLE;
|
wincon::{CONSOLE_SCREEN_BUFFER_INFO, COORD, SMALL_RECT},
|
||||||
|
winnt::HANDLE,
|
||||||
|
};
|
||||||
|
|
||||||
use common::traits::Empty;
|
pub use self::cursor::Cursor;
|
||||||
|
pub use crossterm_winapi::{
|
||||||
|
Console, ConsoleMode, Coord, Handle, HandleType, ScreenBuffer, ScreenBufferInfo, Size,
|
||||||
|
WindowPositions,
|
||||||
|
};
|
||||||
|
|
||||||
impl Empty for COORD {
|
/// Exit the current process.
|
||||||
fn empty() -> COORD {
|
pub fn exit() {
|
||||||
COORD { X: 0, Y: 0 }
|
::std::process::exit(256);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Empty for SMALL_RECT {
|
|
||||||
fn empty() -> SMALL_RECT {
|
|
||||||
SMALL_RECT {
|
|
||||||
Top: 0,
|
|
||||||
Right: 0,
|
|
||||||
Bottom: 0,
|
|
||||||
Left: 0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Empty for CONSOLE_SCREEN_BUFFER_INFO {
|
|
||||||
fn empty() -> CONSOLE_SCREEN_BUFFER_INFO {
|
|
||||||
CONSOLE_SCREEN_BUFFER_INFO {
|
|
||||||
dwSize: COORD::empty(),
|
|
||||||
dwCursorPosition: COORD::empty(),
|
|
||||||
wAttributes: 0,
|
|
||||||
srWindow: SMALL_RECT::empty(),
|
|
||||||
dwMaximumWindowSize: COORD::empty(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,24 +1,22 @@
|
|||||||
use super::handle::get_current_in_handle;
|
use crossterm_winapi::{Handle, HandleType};
|
||||||
use std::io::{self, Error, Result};
|
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
mem::{self, zeroed},
|
io::{self, Write},
|
||||||
ptr::{null, null_mut},
|
mem,
|
||||||
};
|
};
|
||||||
|
|
||||||
use winapi::{
|
use winapi::{
|
||||||
shared::minwindef::{LPVOID, ULONG},
|
shared::minwindef::{LPVOID, ULONG},
|
||||||
um::consoleapi::{ReadConsoleInputW, ReadConsoleW},
|
um::{
|
||||||
um::wincon::CONSOLE_READCONSOLE_CONTROL,
|
consoleapi::ReadConsoleW,
|
||||||
um::wincon::{CHAR_INFO, CONSOLE_FONT_INFOEX, INPUT_RECORD, PCONSOLE_READCONSOLE_CONTROL},
|
wincon::{CONSOLE_READCONSOLE_CONTROL, PCONSOLE_READCONSOLE_CONTROL},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
use std::io::Write;
|
|
||||||
|
|
||||||
/// Could be used to read a line from the stdin.
|
/// Could be used to read a line from the stdin.
|
||||||
/// Note that this is a blocking call and it continues when user pressed enter.
|
/// 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> {
|
pub fn read_line(buf: &mut Vec<u8>) -> io::Result<usize> {
|
||||||
let handle = get_current_in_handle()?;
|
let handle = Handle::current_in_handle()?;
|
||||||
|
|
||||||
let mut utf16 = vec![0u16; 0x1000];
|
let mut utf16 = vec![0u16; 0x1000];
|
||||||
let mut num = 0;
|
let mut num = 0;
|
||||||
|
@ -1,36 +0,0 @@
|
|||||||
//! This module contains terminal specific logic.
|
|
||||||
|
|
||||||
use super::{csbi, handle};
|
|
||||||
|
|
||||||
/// Get the terminal size
|
|
||||||
pub fn terminal_size() -> (u16, u16) {
|
|
||||||
let handle = handle::get_output_handle().unwrap();
|
|
||||||
|
|
||||||
// if let Ok(csbi) = csbi::get_csbi_by_handle(&handle) {
|
|
||||||
// println!("right: {} left: {} bottom: {}, top: {} window top {} windows width {} csbi.dwCursorPosition.X {} csbi.dwCursorPosition.Y {}", csbi.srWindow.Right, csbi.srWindow.Left, csbi.srWindow.Bottom, csbi.srWindow.Top, csbi.dwSize.X,csbi.dwSize.Y, csbi.dwCursorPosition.X, csbi.dwCursorPosition.Y);
|
|
||||||
// }
|
|
||||||
|
|
||||||
if let Ok(csbi) = csbi::get_csbi_by_handle(&handle) {
|
|
||||||
(
|
|
||||||
(csbi.srWindow.Right - csbi.srWindow.Left) as u16,
|
|
||||||
(csbi.srWindow.Bottom - csbi.srWindow.Top) as u16,
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
return (0, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn buffer_size() -> (u16, u16) {
|
|
||||||
let handle = handle::get_output_handle().unwrap();
|
|
||||||
|
|
||||||
if let Ok(csbi) = csbi::get_csbi_by_handle(&handle) {
|
|
||||||
((csbi.dwSize.X) as u16, (csbi.dwSize.Y) as u16)
|
|
||||||
} else {
|
|
||||||
return (0, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Exit the current process.
|
|
||||||
pub fn exit() {
|
|
||||||
::std::process::exit(256);
|
|
||||||
}
|
|
@ -3,62 +3,14 @@
|
|||||||
use winapi::ctypes::c_void;
|
use winapi::ctypes::c_void;
|
||||||
use winapi::shared::ntdef::NULL;
|
use winapi::shared::ntdef::NULL;
|
||||||
use winapi::um::consoleapi::WriteConsoleW;
|
use winapi::um::consoleapi::WriteConsoleW;
|
||||||
use winapi::um::wincon::{
|
use winapi::um::wincon::{WriteConsoleOutputA, CHAR_INFO, COORD, PSMALL_RECT};
|
||||||
FillConsoleOutputAttribute, FillConsoleOutputCharacterA, WriteConsoleOutputA, CHAR_INFO, COORD,
|
use winapi::um::winnt::HANDLE;
|
||||||
PSMALL_RECT,
|
|
||||||
};
|
|
||||||
|
|
||||||
use super::{csbi, handle, kernel, HANDLE};
|
use crossterm_winapi::{is_true, ScreenBuffer};
|
||||||
|
|
||||||
use std::io::{self, Result};
|
use std::io::{self, Result};
|
||||||
use std::str;
|
use std::str;
|
||||||
|
|
||||||
/// Fill a certain block with characters.
|
|
||||||
pub fn fill_console_output_character(
|
|
||||||
cells_written: &mut u32,
|
|
||||||
start_location: COORD,
|
|
||||||
cells_to_write: u32,
|
|
||||||
) -> bool {
|
|
||||||
let handle = handle::get_current_out_handle().unwrap();
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
// fill the cells in console with blanks
|
|
||||||
let success = FillConsoleOutputCharacterA(
|
|
||||||
handle,
|
|
||||||
' ' as i8,
|
|
||||||
cells_to_write,
|
|
||||||
start_location,
|
|
||||||
cells_written,
|
|
||||||
);
|
|
||||||
kernel::is_true(success)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Set console ouput attribute for certain block.
|
|
||||||
pub fn fill_console_output_attribute(
|
|
||||||
cells_written: &mut u32,
|
|
||||||
start_location: COORD,
|
|
||||||
cells_to_write: u32,
|
|
||||||
) -> bool {
|
|
||||||
// Get the position of the current console window
|
|
||||||
|
|
||||||
let (csbi, handle) = csbi::get_csbi_and_handle().unwrap();
|
|
||||||
|
|
||||||
let success;
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
success = FillConsoleOutputAttribute(
|
|
||||||
handle,
|
|
||||||
csbi.wAttributes,
|
|
||||||
cells_to_write,
|
|
||||||
start_location,
|
|
||||||
cells_written,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
kernel::is_true(success)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Write console output.
|
/// Write console output.
|
||||||
pub fn write_console_output(
|
pub fn write_console_output(
|
||||||
write_buffer: &HANDLE,
|
write_buffer: &HANDLE,
|
||||||
@ -68,7 +20,7 @@ pub fn write_console_output(
|
|||||||
source_buffer: PSMALL_RECT,
|
source_buffer: PSMALL_RECT,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
unsafe {
|
unsafe {
|
||||||
if !kernel::is_true(
|
if !is_true(
|
||||||
WriteConsoleOutputA(
|
WriteConsoleOutputA(
|
||||||
*write_buffer, // screen buffer to write to
|
*write_buffer, // screen buffer to write to
|
||||||
copy_buffer.as_mut_ptr(), // buffer to copy into
|
copy_buffer.as_mut_ptr(), // buffer to copy into
|
||||||
@ -77,10 +29,7 @@ pub fn write_console_output(
|
|||||||
source_buffer,
|
source_buffer,
|
||||||
), // screen buffer source rectangle
|
), // screen buffer source rectangle
|
||||||
) {
|
) {
|
||||||
return Err(io::Error::new(
|
return Err(io::Error::last_os_error());
|
||||||
io::ErrorKind::Other,
|
|
||||||
"Could not write to terminal",
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -88,15 +37,15 @@ pub fn write_console_output(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Write utf8 buffer to console.
|
/// Write utf8 buffer to console.
|
||||||
pub fn write_char_buffer(handle: &HANDLE, buf: &[u8]) -> ::std::io::Result<usize> {
|
pub fn write_char_buffer(handle: &HANDLE, buf: &[u8]) -> io::Result<usize> {
|
||||||
// get string from u8[] and parse it to an c_str
|
// get string from u8[] and parse it to an c_str
|
||||||
let utf8 = match str::from_utf8(buf) {
|
let utf8 = match str::from_utf8(buf) {
|
||||||
Ok(string) => string,
|
Ok(string) => string,
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
return Err(io::Error::new(
|
return Err(io::Error::new(
|
||||||
io::ErrorKind::Other,
|
io::ErrorKind::Other,
|
||||||
"Could not parse input to utf8 string.",
|
"Could not parse to utf8 string",
|
||||||
))
|
));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -104,30 +53,29 @@ pub fn write_char_buffer(handle: &HANDLE, buf: &[u8]) -> ::std::io::Result<usize
|
|||||||
let utf16_ptr: *const c_void = utf16.as_ptr() as *const _ as *const c_void;
|
let utf16_ptr: *const c_void = utf16.as_ptr() as *const _ as *const c_void;
|
||||||
|
|
||||||
// get buffer info
|
// get buffer info
|
||||||
let csbi = csbi::get_csbi_by_handle(handle)?;
|
match ScreenBuffer::from(*handle).info() {
|
||||||
|
Ok(csbi) => {
|
||||||
// get current position
|
// get current position
|
||||||
let _current_pos = COORD {
|
let _current_pos = COORD {
|
||||||
X: csbi.dwCursorPosition.X,
|
X: csbi.cursor_pos().x,
|
||||||
Y: csbi.dwCursorPosition.Y,
|
Y: csbi.cursor_pos().y,
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut cells_written: u32 = 0;
|
let mut cells_written: u32 = 0;
|
||||||
let mut success = false;
|
|
||||||
// write to console
|
// write to console
|
||||||
unsafe {
|
unsafe {
|
||||||
success = kernel::is_true(WriteConsoleW(
|
if !is_true(WriteConsoleW(
|
||||||
*handle,
|
*handle,
|
||||||
utf16_ptr,
|
utf16_ptr,
|
||||||
utf16.len() as u32,
|
utf16.len() as u32,
|
||||||
&mut cells_written,
|
&mut cells_written,
|
||||||
NULL,
|
NULL,
|
||||||
));
|
)) {
|
||||||
}
|
return Err(io::Error::last_os_error());
|
||||||
|
}
|
||||||
match success {
|
}
|
||||||
// think this is wrong could be done better!
|
Ok(utf8.as_bytes().len())
|
||||||
true => Ok(utf8.as_bytes().len()),
|
}
|
||||||
false => Ok(0),
|
Err(e) => Err(e),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
18
src/lib.rs
18
src/lib.rs
@ -6,6 +6,16 @@
|
|||||||
//!
|
//!
|
||||||
//! This crate supports all UNIX and Windows terminals down to windows 7 (not all terminals are tested see [Tested Terminals] in the README.
|
//! This crate supports all UNIX and Windows terminals down to windows 7 (not all terminals are tested see [Tested Terminals] in the README.
|
||||||
|
|
||||||
|
#[cfg(unix)]
|
||||||
|
extern crate libc;
|
||||||
|
#[cfg(unix)]
|
||||||
|
extern crate termios;
|
||||||
|
|
||||||
|
#[cfg(windows)]
|
||||||
|
extern crate winapi;
|
||||||
|
#[cfg(windows)]
|
||||||
|
extern crate crossterm_winapi;
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
mod common;
|
mod common;
|
||||||
|
|
||||||
@ -28,11 +38,3 @@ pub use self::style::{
|
|||||||
pub use self::terminal::{terminal, Terminal};
|
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;
|
||||||
|
|
||||||
#[cfg(unix)]
|
|
||||||
extern crate libc;
|
|
||||||
#[cfg(unix)]
|
|
||||||
extern crate termios;
|
|
||||||
|
|
||||||
#[cfg(windows)]
|
|
||||||
extern crate winapi;
|
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
//! This module is used for Windows terminals that do not support ANSI escape codes.
|
//! This module is used for Windows terminals that do not support ANSI escape codes.
|
||||||
//! Note that the cursor position is 0 based. This means that we start counting at 0 when setting the cursor position.
|
//! Note that the cursor position is 0 based. This means that we start counting at 0 when setting the cursor position.
|
||||||
|
|
||||||
use kernel::windows_kernel::cursor;
|
use kernel::windows_kernel::Cursor;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
@ -11,17 +11,19 @@ pub struct WinApiCursor;
|
|||||||
|
|
||||||
impl WinApiCursor {
|
impl WinApiCursor {
|
||||||
pub fn new() -> Box<WinApiCursor> {
|
pub fn new() -> Box<WinApiCursor> {
|
||||||
Box::from(WinApiCursor {})
|
Box::from(WinApiCursor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ITerminalCursor for WinApiCursor {
|
impl ITerminalCursor for WinApiCursor {
|
||||||
fn goto(&self, x: u16, y: u16, _stdout: &Option<&Arc<TerminalOutput>>) {
|
fn goto(&self, x: u16, y: u16, _stdout: &Option<&Arc<TerminalOutput>>) {
|
||||||
cursor::set_console_cursor_position(x as i16, y as i16);
|
let cursor = Cursor::new().unwrap();
|
||||||
|
cursor.goto(x as i16, y as i16);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pos(&self) -> (u16, u16) {
|
fn pos(&self) -> (u16, u16) {
|
||||||
cursor::pos()
|
let cursor = Cursor::new().unwrap();
|
||||||
|
cursor.position().unwrap().into()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn move_up(&self, count: u16, _stdout: &Option<&Arc<TerminalOutput>>) {
|
fn move_up(&self, count: u16, _stdout: &Option<&Arc<TerminalOutput>>) {
|
||||||
@ -45,19 +47,19 @@ impl ITerminalCursor for WinApiCursor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn save_position(&self, _stdout: &Option<&Arc<TerminalOutput>>) {
|
fn save_position(&self, _stdout: &Option<&Arc<TerminalOutput>>) {
|
||||||
cursor::save_cursor_pos();
|
Cursor::save_cursor_pos();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn reset_position(&self, _stdout: &Option<&Arc<TerminalOutput>>) {
|
fn reset_position(&self, _stdout: &Option<&Arc<TerminalOutput>>) {
|
||||||
cursor::reset_to_saved_position();
|
Cursor::reset_to_saved_position();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn hide(&self, _stdout: &Option<&Arc<TerminalOutput>>) {
|
fn hide(&self, _stdout: &Option<&Arc<TerminalOutput>>) {
|
||||||
cursor::cursor_visibility(false);
|
Cursor::new().unwrap().set_visibility(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn show(&self, _stdout: &Option<&Arc<TerminalOutput>>) {
|
fn show(&self, _stdout: &Option<&Arc<TerminalOutput>>) {
|
||||||
cursor::cursor_visibility(true);
|
Cursor::new().unwrap().set_visibility(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn blink(&self, _blink: bool, _stdout: &Option<&Arc<TerminalOutput>>) {}
|
fn blink(&self, _blink: bool, _stdout: &Option<&Arc<TerminalOutput>>) {}
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
use kernel::windows_kernel::reading::read_line;
|
|
||||||
use std::char;
|
use std::char;
|
||||||
use std::thread;
|
use std::thread;
|
||||||
use winapi::um::winnt::INT;
|
use winapi::um::winnt::INT;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use super::IStdout;
|
use super::IStdout;
|
||||||
use kernel::windows_kernel::{handle, writing};
|
use kernel::windows_kernel::{writing, Handle};
|
||||||
|
|
||||||
use std::io;
|
use std::io;
|
||||||
|
|
||||||
@ -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_out_handle().unwrap();
|
let handle = Handle::current_out_handle().unwrap();
|
||||||
writing::write_char_buffer(&handle, buf)
|
writing::write_char_buffer(&handle, buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,32 +2,34 @@
|
|||||||
//! This module is used for non supporting `ANSI` Windows terminals.
|
//! This module is used for non supporting `ANSI` Windows terminals.
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use kernel::windows_kernel::{csbi, kernel};
|
use kernel::windows_kernel::{Console, Handle, HandleType, ScreenBuffer};
|
||||||
|
use std::io;
|
||||||
|
use std::sync::{Once, ONCE_INIT};
|
||||||
use winapi::um::wincon;
|
use winapi::um::wincon;
|
||||||
|
|
||||||
/// This struct is a WinApi implementation for color related actions.
|
/// This struct is a WinApi implementation for color related actions.
|
||||||
pub struct WinApiColor {
|
pub struct WinApiColor;
|
||||||
original_color: u16,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WinApiColor {
|
impl WinApiColor {
|
||||||
pub fn new() -> WinApiColor {
|
pub fn new() -> WinApiColor {
|
||||||
WinApiColor {
|
WinApiColor
|
||||||
original_color: csbi::get_original_console_color(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ITerminalColor for WinApiColor {
|
impl ITerminalColor for WinApiColor {
|
||||||
fn set_fg(&self, fg_color: Color, _stdout: &Option<&Arc<TerminalOutput>>) {
|
fn set_fg(&self, fg_color: Color, _stdout: &Option<&Arc<TerminalOutput>>) {
|
||||||
|
// init the original color in case it is not set.
|
||||||
|
let _ = init_console_color().unwrap();
|
||||||
|
|
||||||
let color_value = &self.color_value(fg_color, ColorType::Foreground);
|
let color_value = &self.color_value(fg_color, ColorType::Foreground);
|
||||||
|
|
||||||
let csbi = csbi::get_csbi().unwrap();
|
let screen_buffer = ScreenBuffer::current().unwrap();
|
||||||
|
let csbi = screen_buffer.info().unwrap();
|
||||||
|
|
||||||
// Notice that the color values are stored in wAttribute.
|
// Notice that the color values are stored in wAttribute.
|
||||||
// So we need to use bitwise operators to check if the values exists or to get current console colors.
|
// So we need to use bitwise operators to check if the values exists or to get current console colors.
|
||||||
let mut color: u16;
|
let mut color: u16;
|
||||||
let attrs = csbi.wAttributes;
|
let attrs = csbi.attributes();
|
||||||
let bg_color = attrs & 0x0070;
|
let bg_color = attrs & 0x0070;
|
||||||
color = color_value.parse::<u16>().unwrap() | bg_color;
|
color = color_value.parse::<u16>().unwrap() | bg_color;
|
||||||
|
|
||||||
@ -37,18 +39,24 @@ impl ITerminalColor for WinApiColor {
|
|||||||
color = color | wincon::BACKGROUND_INTENSITY as u16;
|
color = color | wincon::BACKGROUND_INTENSITY as u16;
|
||||||
}
|
}
|
||||||
|
|
||||||
kernel::set_console_text_attribute(color);
|
Console::from(**screen_buffer.get_handle())
|
||||||
|
.set_text_attribute(color)
|
||||||
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_bg(&self, bg_color: Color, _stdout: &Option<&Arc<TerminalOutput>>) {
|
fn set_bg(&self, bg_color: Color, _stdout: &Option<&Arc<TerminalOutput>>) {
|
||||||
|
// init the original color in case it is not set.
|
||||||
|
let _ = init_console_color().unwrap();
|
||||||
|
|
||||||
let color_value = &self.color_value(bg_color, ColorType::Background);
|
let color_value = &self.color_value(bg_color, ColorType::Background);
|
||||||
|
|
||||||
let (csbi, _handle) = csbi::get_csbi_and_handle().unwrap();
|
let screen_buffer = ScreenBuffer::current().unwrap();
|
||||||
|
let csbi = screen_buffer.info().unwrap();
|
||||||
|
|
||||||
// Notice that the color values are stored in wAttribute.
|
// Notice that the color values are stored in wAttribute.
|
||||||
// So wee need to use bitwise operators to check if the values exists or to get current console colors.
|
// So wee need to use bitwise operators to check if the values exists or to get current console colors.
|
||||||
let mut color: u16;
|
let mut color: u16;
|
||||||
let attrs = csbi.wAttributes;
|
let attrs = csbi.attributes();
|
||||||
let fg_color = attrs & 0x0007;
|
let fg_color = attrs & 0x0007;
|
||||||
color = fg_color | color_value.parse::<u16>().unwrap();
|
color = fg_color | color_value.parse::<u16>().unwrap();
|
||||||
|
|
||||||
@ -58,11 +66,17 @@ impl ITerminalColor for WinApiColor {
|
|||||||
color = color | wincon::FOREGROUND_INTENSITY as u16;
|
color = color | wincon::FOREGROUND_INTENSITY as u16;
|
||||||
}
|
}
|
||||||
|
|
||||||
kernel::set_console_text_attribute(color);
|
Console::from(**screen_buffer.get_handle())
|
||||||
|
.set_text_attribute(color)
|
||||||
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn reset(&self, _stdout: &Option<&Arc<TerminalOutput>>) {
|
fn reset(&self, _stdout: &Option<&Arc<TerminalOutput>>) {
|
||||||
kernel::set_console_text_attribute(self.original_color);
|
// init the original color in case it is not set.
|
||||||
|
let original_color = original_console_color();
|
||||||
|
Console::from(Handle::new(HandleType::CurrentOutputHandle).unwrap())
|
||||||
|
.set_text_attribute(original_color)
|
||||||
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This will get the winapi color value from the Color and ColorType struct
|
/// This will get the winapi color value from the Color and ColorType struct
|
||||||
@ -133,3 +147,21 @@ impl ITerminalColor for WinApiColor {
|
|||||||
winapi_color.to_string()
|
winapi_color.to_string()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn init_console_color() -> io::Result<()> {
|
||||||
|
let screen_buffer = ScreenBuffer::current()?;
|
||||||
|
|
||||||
|
let attr = screen_buffer.info()?.attributes();
|
||||||
|
|
||||||
|
GET_ORIGINAL_CONSOLE_COLOR.call_once(|| {
|
||||||
|
unsafe { ORIGINAL_CONSOLE_COLOR = attr };
|
||||||
|
});
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn original_console_color() -> u16 {
|
||||||
|
return unsafe { ORIGINAL_CONSOLE_COLOR };
|
||||||
|
}
|
||||||
|
|
||||||
|
static GET_ORIGINAL_CONSOLE_COLOR: Once = ONCE_INIT;
|
||||||
|
static mut ORIGINAL_CONSOLE_COLOR: u16 = 0;
|
||||||
|
@ -16,11 +16,11 @@ mod winapi_tests {
|
|||||||
let stdout = Some(&screen.stdout);
|
let stdout = Some(&screen.stdout);
|
||||||
let terminal = WinApiTerminal::new();
|
let terminal = WinApiTerminal::new();
|
||||||
|
|
||||||
terminal.set_size(10, 10, &stdout);
|
terminal.set_size(20, 10, &stdout);
|
||||||
|
|
||||||
let (x, y) = terminal.terminal_size(&stdout);
|
let (x, y) = terminal.terminal_size(&stdout);
|
||||||
|
|
||||||
assert_eq!(x, 10);
|
assert_eq!(x, 20);
|
||||||
assert_eq!(y, 10);
|
assert_eq!(y, 10);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,10 +4,8 @@
|
|||||||
//! Windows versions lower then windows 10 are not supporting ANSI codes. Those versions will use this implementation instead.
|
//! Windows versions lower then windows 10 are not supporting ANSI codes. Those versions will use this implementation instead.
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use cursor::TerminalCursor;
|
|
||||||
|
|
||||||
use kernel::windows_kernel::{csbi, kernel, terminal, writing};
|
use kernel::windows_kernel::{Console, Coord, Cursor, Handle, ScreenBuffer, Size};
|
||||||
use winapi::um::wincon::{CONSOLE_SCREEN_BUFFER_INFO, COORD, SMALL_RECT};
|
|
||||||
|
|
||||||
/// This struct is an winapi implementation for terminal related actions.
|
/// This struct is an winapi implementation for terminal related actions.
|
||||||
pub struct WinApiTerminal;
|
pub struct WinApiTerminal;
|
||||||
@ -19,57 +17,60 @@ impl WinApiTerminal {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ITerminal for WinApiTerminal {
|
impl ITerminal for WinApiTerminal {
|
||||||
fn clear(&self, clear_type: ClearType, stdout: &Option<&Arc<TerminalOutput>>) {
|
fn clear(&self, clear_type: ClearType, _stdout: &Option<&Arc<TerminalOutput>>) {
|
||||||
let csbi = csbi::get_csbi().unwrap();
|
let screen_buffer = ScreenBuffer::current().unwrap();
|
||||||
let pos = TerminalCursor::new().pos();
|
let csbi = screen_buffer.info().unwrap();
|
||||||
|
|
||||||
|
let pos = csbi.cursor_pos();
|
||||||
|
let buffer_size = csbi.buffer_size();
|
||||||
|
let current_attribute = csbi.attributes();
|
||||||
|
|
||||||
match clear_type {
|
match clear_type {
|
||||||
ClearType::All => {
|
ClearType::All => {
|
||||||
clear_entire_screen(csbi, stdout);
|
clear_entire_screen(buffer_size, current_attribute);
|
||||||
}
|
}
|
||||||
ClearType::FromCursorDown => clear_after_cursor(pos, csbi, stdout),
|
ClearType::FromCursorDown => clear_after_cursor(pos, buffer_size, current_attribute),
|
||||||
ClearType::FromCursorUp => clear_before_cursor(pos, csbi, stdout),
|
ClearType::FromCursorUp => clear_before_cursor(pos, buffer_size, current_attribute),
|
||||||
ClearType::CurrentLine => clear_current_line(pos, csbi, stdout),
|
ClearType::CurrentLine => clear_current_line(pos, buffer_size, current_attribute),
|
||||||
ClearType::UntilNewLine => clear_until_line(pos, csbi, stdout),
|
ClearType::UntilNewLine => clear_until_line(pos, buffer_size, current_attribute),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn terminal_size(&self, _stdout: &Option<&Arc<TerminalOutput>>) -> (u16, u16) {
|
fn terminal_size(&self, _stdout: &Option<&Arc<TerminalOutput>>) -> (u16, u16) {
|
||||||
terminal::terminal_size()
|
let csbi = ScreenBuffer::current().unwrap();
|
||||||
|
csbi.info().unwrap().terminal_size().into()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn scroll_up(&self, count: i16, _stdout: &Option<&Arc<TerminalOutput>>) {
|
fn scroll_up(&self, count: i16, _stdout: &Option<&Arc<TerminalOutput>>) {
|
||||||
let csbi = csbi::get_csbi().unwrap();
|
let csbi = ScreenBuffer::current().unwrap();
|
||||||
|
let mut window = csbi.info().unwrap().terminal_window();
|
||||||
// Set srctWindow to the current window size and location.
|
|
||||||
let mut srct_window = csbi.srWindow;
|
|
||||||
|
|
||||||
// Check whether the window is too close to the screen buffer top
|
// Check whether the window is too close to the screen buffer top
|
||||||
if srct_window.Top >= count {
|
if window.top >= count {
|
||||||
srct_window.Top -= count; // move top down
|
window.top -= count; // move top down
|
||||||
srct_window.Bottom = count; // move bottom down
|
window.bottom = count; // move bottom down
|
||||||
|
|
||||||
let success = kernel::set_console_info(false, &mut srct_window);
|
Console::new()
|
||||||
if success {
|
.unwrap()
|
||||||
panic!("Something went wrong when scrolling down");
|
.set_console_info(false, window)
|
||||||
}
|
.unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn scroll_down(&self, count: i16, _stdout: &Option<&Arc<TerminalOutput>>) {
|
fn scroll_down(&self, count: i16, _stdout: &Option<&Arc<TerminalOutput>>) {
|
||||||
let csbi = csbi::get_csbi().unwrap();
|
let csbi = ScreenBuffer::current().unwrap();
|
||||||
// Set srctWindow to the current window size and location.
|
let mut window = csbi.info().unwrap().terminal_window();
|
||||||
let mut srct_window = csbi.srWindow;
|
let buffer_size = csbi.info().unwrap().buffer_size();
|
||||||
|
|
||||||
// Check whether the window is too close to the screen buffer top
|
// Check whether the window is too close to the screen buffer top
|
||||||
if srct_window.Bottom < csbi.dwSize.Y - count {
|
if window.bottom < buffer_size.height - count {
|
||||||
srct_window.Top += count; // move top down
|
window.top += count; // move top down
|
||||||
srct_window.Bottom += count; // move bottom down
|
window.bottom += count; // move bottom down
|
||||||
|
|
||||||
let success = kernel::set_console_info(true, &mut srct_window);
|
Console::new()
|
||||||
if success {
|
.unwrap()
|
||||||
panic!("Something went wrong when scrolling down");
|
.set_console_info(false, window)
|
||||||
}
|
.unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -84,71 +85,70 @@ impl ITerminal for WinApiTerminal {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get the position of the current console window
|
// Get the position of the current console window
|
||||||
let csbi = csbi::get_csbi().unwrap();
|
let screen_buffer = ScreenBuffer::current().unwrap();
|
||||||
let mut success = false;
|
let console = Console::from(**screen_buffer.get_handle());
|
||||||
|
let csbi = screen_buffer.info().unwrap();
|
||||||
|
|
||||||
|
let current_size = csbi.buffer_size();
|
||||||
|
let window = csbi.terminal_window();
|
||||||
|
|
||||||
|
let mut new_size = Size::new(current_size.width, current_size.height);
|
||||||
|
|
||||||
// If the buffer is smaller than this new window size, resize the
|
// If the buffer is smaller than this new window size, resize the
|
||||||
// buffer to be large enough. Include window position.
|
// buffer to be large enough. Include window position.
|
||||||
let mut resize_buffer = false;
|
let mut resize_buffer = false;
|
||||||
let mut size = COORD {
|
|
||||||
X: csbi.dwSize.X,
|
|
||||||
Y: csbi.dwSize.Y,
|
|
||||||
};
|
|
||||||
|
|
||||||
if csbi.dwSize.X < csbi.srWindow.Left + width {
|
if current_size.width < window.left + width {
|
||||||
if csbi.srWindow.Left >= i16::max_value() - width {
|
if window.left >= i16::max_value() - width {
|
||||||
panic!("Argument out of range when setting terminal width.");
|
panic!("Argument out of range when setting terminal width.");
|
||||||
}
|
}
|
||||||
|
|
||||||
size.X = csbi.srWindow.Left + width;
|
new_size.width = window.left + width;
|
||||||
resize_buffer = true;
|
resize_buffer = true;
|
||||||
}
|
}
|
||||||
if csbi.dwSize.Y < csbi.srWindow.Top + height {
|
if current_size.height < window.top + height {
|
||||||
if csbi.srWindow.Top >= i16::max_value() - height {
|
if window.top >= i16::max_value() - height {
|
||||||
panic!("Argument out of range when setting terminal height");
|
panic!("Argument out of range when setting terminal height");
|
||||||
}
|
}
|
||||||
|
|
||||||
size.Y = csbi.srWindow.Top + height;
|
new_size.height = window.top + height;
|
||||||
resize_buffer = true;
|
resize_buffer = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if resize_buffer {
|
if resize_buffer {
|
||||||
success = csbi::set_console_screen_buffer_size(size);
|
if let Err(_) = screen_buffer.set_size(new_size.width, new_size.height) {
|
||||||
|
|
||||||
if !success {
|
|
||||||
panic!("Something went wrong when setting screen buffer size.");
|
panic!("Something went wrong when setting screen buffer size.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut fsr_window: SMALL_RECT = csbi.srWindow;
|
let mut window = window.clone();
|
||||||
// Preserve the position, but change the size.
|
// Preserve the position, but change the size.
|
||||||
fsr_window.Bottom = fsr_window.Top + height;
|
window.bottom = window.top + height;
|
||||||
fsr_window.Right = fsr_window.Left + width;
|
window.right = window.left + width;
|
||||||
|
console.set_console_info(true, window).unwrap();
|
||||||
|
|
||||||
let success = kernel::set_console_info(true, &fsr_window);
|
|
||||||
|
|
||||||
if success {
|
|
||||||
// If we resized the buffer, un-resize it.
|
// If we resized the buffer, un-resize it.
|
||||||
if resize_buffer {
|
if resize_buffer {
|
||||||
csbi::set_console_screen_buffer_size(csbi.dwSize);
|
if let Err(_) = screen_buffer.set_size(current_size.width, current_size.height) {
|
||||||
|
panic!("Something went wrong when setting screen buffer size.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let bounds = kernel::get_largest_console_window_size();
|
let bounds = console.largest_window_size();
|
||||||
|
|
||||||
if width > bounds.X {
|
if width > bounds.x {
|
||||||
panic!(
|
panic!(
|
||||||
"Argument width: {} out of range when setting terminal width.",
|
"Argument width: {} out of range when setting terminal width.",
|
||||||
width
|
width
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if height > bounds.Y {
|
if height > bounds.y {
|
||||||
panic!(
|
panic!(
|
||||||
"Argument height: {} out of range when setting terminal height",
|
"Argument height: {} out of range when setting terminal height",
|
||||||
height
|
height
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
fn exit(&self, stdout: &Option<&Arc<TerminalOutput>>) {
|
fn exit(&self, stdout: &Option<&Arc<TerminalOutput>>) {
|
||||||
if let Some(output) = stdout {
|
if let Some(output) = stdout {
|
||||||
@ -160,36 +160,26 @@ impl ITerminal for WinApiTerminal {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn clear_after_cursor(
|
pub fn clear_after_cursor(location: Coord, buffer_size: Size, current_attribute: u16) {
|
||||||
pos: (u16, u16),
|
let (mut x, mut y) = (location.x, location.y);
|
||||||
csbi: CONSOLE_SCREEN_BUFFER_INFO,
|
|
||||||
_stdout: &Option<&Arc<TerminalOutput>>,
|
|
||||||
) {
|
|
||||||
let (mut x, mut y) = pos;
|
|
||||||
|
|
||||||
// if cursor position is at the outer right position
|
// if cursor position is at the outer right position
|
||||||
if x as i16 > csbi.dwSize.X {
|
if x as i16 > buffer_size.width {
|
||||||
y += 1;
|
y += 1;
|
||||||
x = 0;
|
x = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// location where to start clearing
|
// location where to start clearing
|
||||||
let start_location = COORD {
|
let start_location = Coord::new(x, y);
|
||||||
X: x as i16,
|
|
||||||
Y: y as i16,
|
|
||||||
};
|
|
||||||
// get sum cells before cursor
|
|
||||||
let cells_to_write = csbi.dwSize.X as u32 * csbi.dwSize.Y as u32;
|
|
||||||
|
|
||||||
clear(start_location, cells_to_write);
|
// get sum cells before cursor
|
||||||
|
let cells_to_write = buffer_size.width as u32 * buffer_size.height as u32;
|
||||||
|
|
||||||
|
clear(start_location, cells_to_write, current_attribute);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn clear_before_cursor(
|
pub fn clear_before_cursor(location: Coord, buffer_size: Size, current_attribute: u16) {
|
||||||
pos: (u16, u16),
|
let (xpos, ypos) = (location.x, location.y);
|
||||||
csbi: CONSOLE_SCREEN_BUFFER_INFO,
|
|
||||||
_stdout: &Option<&Arc<TerminalOutput>>,
|
|
||||||
) {
|
|
||||||
let (xpos, ypos) = pos;
|
|
||||||
|
|
||||||
// one cell after cursor position
|
// one cell after cursor position
|
||||||
let x = 0;
|
let x = 0;
|
||||||
@ -197,129 +187,68 @@ pub fn clear_before_cursor(
|
|||||||
let y = 0;
|
let y = 0;
|
||||||
|
|
||||||
// location where to start clearing
|
// location where to start clearing
|
||||||
let start_location = COORD {
|
let start_location = Coord::new(x, y);
|
||||||
X: x as i16,
|
|
||||||
Y: y as i16,
|
|
||||||
};
|
|
||||||
// get sum cells before cursor
|
|
||||||
let cells_to_write = (csbi.dwSize.X as u32 * ypos as u32) + (xpos as u32 + 1);
|
|
||||||
|
|
||||||
clear(start_location, cells_to_write);
|
// get sum cells before cursor
|
||||||
|
let cells_to_write = (buffer_size.width as u32 * ypos as u32) + (xpos as u32 + 1);
|
||||||
|
|
||||||
|
// clear everything before cursor position
|
||||||
|
clear(start_location, cells_to_write, current_attribute);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn clear_entire_screen(
|
pub fn clear_entire_screen(buffer_size: Size, current_attribute: u16) {
|
||||||
csbi: CONSOLE_SCREEN_BUFFER_INFO,
|
// get sum cells before cursor
|
||||||
stdout: &Option<&Arc<TerminalOutput>>,
|
let cells_to_write = buffer_size.width as u32 * buffer_size.height as u32;
|
||||||
) {
|
|
||||||
// position x at start
|
|
||||||
let x = 0;
|
|
||||||
// position y at start
|
|
||||||
let y = 0;
|
|
||||||
|
|
||||||
// location where to start clearing
|
// location where to start clearing
|
||||||
let start_location = COORD {
|
let start_location = Coord::new(0, 0);
|
||||||
X: x as i16,
|
|
||||||
Y: y as i16,
|
// clear the entire screen
|
||||||
};
|
clear(start_location, cells_to_write, current_attribute);
|
||||||
|
|
||||||
|
// put the cursor back at cell 0,0
|
||||||
|
let cursor = Cursor::new().unwrap();
|
||||||
|
cursor.goto(0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn clear_current_line(location: Coord, buffer_size: Size, current_attribute: u16) {
|
||||||
|
// location where to start clearing
|
||||||
|
let start_location = Coord::new(0, location.y);
|
||||||
|
|
||||||
// get sum cells before cursor
|
// get sum cells before cursor
|
||||||
|
let cells_to_write = buffer_size.width as u32;
|
||||||
|
|
||||||
let cells_to_write = csbi.dwSize.X as u32 * csbi.dwSize.Y as u32;
|
// clear the whole current line
|
||||||
|
clear(start_location, cells_to_write, current_attribute);
|
||||||
|
|
||||||
clear(start_location, cells_to_write);
|
// put the cursor back at cell 1 on current row
|
||||||
|
let cursor = Cursor::new().unwrap();
|
||||||
match stdout {
|
cursor.goto(0, location.y);
|
||||||
Some(ref output) => {
|
|
||||||
// put the cursor back at (0, 0)
|
|
||||||
TerminalCursor::from_output(output).goto(0, 0);
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
// put the cursor back at (0, 0)
|
|
||||||
TerminalCursor::new().goto(0, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn clear_current_line(
|
pub fn clear_until_line(location: Coord, buffer_size: Size, current_attribute: u16) {
|
||||||
pos: (u16, u16),
|
let (x, y) = (location.x, location.y);
|
||||||
csbi: CONSOLE_SCREEN_BUFFER_INFO,
|
|
||||||
stdout: &Option<&Arc<TerminalOutput>>,
|
|
||||||
) {
|
|
||||||
// position x at start
|
|
||||||
let x = 0;
|
|
||||||
// position y at start
|
|
||||||
let y = pos.1;
|
|
||||||
|
|
||||||
// location where to start clearing
|
// location where to start clearing
|
||||||
let start_location = COORD {
|
let start_location = Coord::new(x, y);
|
||||||
X: x as i16,
|
|
||||||
Y: y as i16,
|
|
||||||
};
|
|
||||||
// get sum cells before cursor
|
// get sum cells before cursor
|
||||||
|
let cells_to_write = (buffer_size.width - x as i16) as u32;
|
||||||
|
|
||||||
let cells_to_write = csbi.dwSize.X as u32;
|
// clear until the current line
|
||||||
|
clear(start_location, cells_to_write, current_attribute);
|
||||||
|
|
||||||
clear(start_location, cells_to_write);
|
// put the cursor back at original cursor position before we did the clearing
|
||||||
|
let cursor = Cursor::new().unwrap();
|
||||||
// put the cursor back at 1 cell on current row
|
cursor.goto(x, y);
|
||||||
match stdout {
|
|
||||||
Some(ref output) => {
|
|
||||||
// put the cursor back at (0, 0)
|
|
||||||
TerminalCursor::from_output(output).goto(0, y);
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
// put the cursor back at (0, 0)
|
|
||||||
TerminalCursor::new().goto(0, y);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn clear_until_line(
|
fn clear(start_location: Coord, cells_to_write: u32, current_attribute: u16) {
|
||||||
pos: (u16, u16),
|
let console = Console::from(Handle::current_out_handle().unwrap());
|
||||||
csbi: CONSOLE_SCREEN_BUFFER_INFO,
|
let _ = console
|
||||||
stdout: &Option<&Arc<TerminalOutput>>,
|
.fill_whit_character(start_location, cells_to_write, ' ')
|
||||||
) {
|
.unwrap();
|
||||||
let (x, y) = pos;
|
console
|
||||||
|
.fill_whit_attribute(start_location, cells_to_write, current_attribute)
|
||||||
// location where to start clearing
|
.unwrap();
|
||||||
let start_location = COORD {
|
|
||||||
X: x as i16,
|
|
||||||
Y: y as i16,
|
|
||||||
};
|
|
||||||
// get sum cells before cursor
|
|
||||||
let cells_to_write = (csbi.dwSize.X - x as i16) as u32;
|
|
||||||
|
|
||||||
clear(start_location, cells_to_write);
|
|
||||||
|
|
||||||
// put the cursor back at original cursor position
|
|
||||||
match stdout {
|
|
||||||
Some(ref output) => {
|
|
||||||
// put the cursor back at (0, 0)
|
|
||||||
TerminalCursor::from_output(output).goto(x, y);
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
// put the cursor back at (0, 0)
|
|
||||||
TerminalCursor::new().goto(x, y);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn clear(start_location: COORD, cells_to_write: u32) {
|
|
||||||
let mut cells_written = 0;
|
|
||||||
let mut success = false;
|
|
||||||
|
|
||||||
success =
|
|
||||||
writing::fill_console_output_character(&mut cells_written, start_location, cells_to_write);
|
|
||||||
|
|
||||||
if !success {
|
|
||||||
panic!("Could not clear screen after cursor");
|
|
||||||
}
|
|
||||||
|
|
||||||
cells_written = 0;
|
|
||||||
|
|
||||||
success =
|
|
||||||
writing::fill_console_output_attribute(&mut cells_written, start_location, cells_to_write);
|
|
||||||
|
|
||||||
if !success {
|
|
||||||
panic!("Could not reset attributes after cursor");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user