mirror of
https://github.com/crossterm-rs/crossterm.git
synced 2025-09-30 06:21:48 +00:00

working for windows 10 terminals. Refactored usings. Rearanged usings. Raw Mode / alternate screeen windows yet to be tested. Added examples. Refactored code
224 lines
6.6 KiB
Rust
224 lines
6.6 KiB
Rust
//! This module contains the commands that can be used for windows systems.
|
|
|
|
use super::{ICommand, IContextCommand};
|
|
use super::super::Context;
|
|
|
|
use kernel::windows_kernel::{kernel, ansi_support};
|
|
use winapi::shared::minwindef::DWORD;
|
|
use winapi::um::wincon;
|
|
use winapi::um::wincon::{ENABLE_VIRTUAL_TERMINAL_PROCESSING ,SMALL_RECT, COORD, CHAR_INFO};
|
|
use std::mem;
|
|
|
|
/// 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.
|
|
#[derive(Clone, Copy)]
|
|
pub struct EnableAnsiCommand
|
|
{
|
|
mask: DWORD,
|
|
}
|
|
|
|
impl ICommand for EnableAnsiCommand
|
|
{
|
|
fn new() -> Box<EnableAnsiCommand> {
|
|
// println!("new EnableRawModeCommand winapi");
|
|
let key = super::generate_key();
|
|
let command = EnableAnsiCommand { mask: ENABLE_VIRTUAL_TERMINAL_PROCESSING };
|
|
Box::from(command)
|
|
}
|
|
|
|
fn execute(&mut self) -> bool
|
|
{
|
|
// println!("exucute EnableAnsiCommand winapi");
|
|
// 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()
|
|
{
|
|
return ansi_support::windows_supportable();
|
|
|
|
} else {
|
|
let output_handle = kernel::get_output_handle();
|
|
|
|
let mut dw_mode: DWORD = 0;
|
|
if !kernel::get_console_mode(&output_handle, &mut dw_mode)
|
|
{
|
|
panic!("Cannot get console mode");
|
|
return false;
|
|
}
|
|
|
|
dw_mode |= self.mask;
|
|
if !kernel::set_console_mode(&output_handle, dw_mode)
|
|
{
|
|
panic!("Cannot get console mode");
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
}
|
|
|
|
fn undo(&mut self) -> bool
|
|
{
|
|
// println!("undo EnableAnsiCommand winapi");
|
|
if ansi_support::ansi_enabled()
|
|
{
|
|
let output_handle = kernel::get_output_handle();
|
|
|
|
let mut dw_mode: DWORD = 0;
|
|
if !kernel::get_console_mode(&output_handle, &mut dw_mode)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
dw_mode &= !self.mask;
|
|
if !kernel::set_console_mode(&output_handle, dw_mode)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
ansi_support::set_ansi_enabled(false);
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
|
|
/// This command is used for enabling and disabling raw mode for windows systems.
|
|
/// For more info check: https://docs.microsoft.com/en-us/windows/console/high-level-console-modes.
|
|
#[derive(Clone, Copy)]
|
|
pub struct EnableRawModeCommand
|
|
{
|
|
mask: DWORD,
|
|
key: i16
|
|
}
|
|
|
|
impl IContextCommand for EnableRawModeCommand
|
|
{
|
|
fn new(context: &mut Context) -> (Box<EnableRawModeCommand>, i16) {
|
|
use self::wincon::{ENABLE_LINE_INPUT,ENABLE_PROCESSED_INPUT, ENABLE_PROCESSED_OUTPUT, ENABLE_WRAP_AT_EOL_OUTPUT, ENABLE_ECHO_INPUT};
|
|
|
|
// println!("new EnableRawModeCommand winapi");
|
|
let key = super::generate_key();
|
|
let command = EnableRawModeCommand { mask: ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT | ENABLE_ECHO_INPUT, key: key };
|
|
context.register_change(Box::from(command), key);
|
|
(Box::from(command),key)
|
|
}
|
|
|
|
fn execute(&mut self) -> bool
|
|
{
|
|
use self::wincon::{ENABLE_LINE_INPUT,ENABLE_PROCESSED_INPUT, ENABLE_ECHO_INPUT};
|
|
|
|
// println!("execute EnableRawModeCommand winapi");
|
|
let input_handle = kernel::get_input_handle();
|
|
|
|
let mut dw_mode: DWORD = 0;
|
|
if !kernel::get_console_mode(&input_handle, &mut dw_mode)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
let new_mode = dw_mode & !self.mask;
|
|
|
|
if !kernel::set_console_mode(&input_handle, new_mode)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
true
|
|
}
|
|
|
|
fn undo(&mut self) -> bool
|
|
{
|
|
// println!("undo EnableRawModeCommand winapi");
|
|
let output_handle = kernel::get_output_handle();
|
|
|
|
let mut dw_mode: DWORD = 0;
|
|
if !kernel::get_console_mode(&output_handle, &mut dw_mode)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
let new_mode = dw_mode | self.mask;
|
|
|
|
if !kernel::set_console_mode(&output_handle, new_mode)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
true
|
|
}
|
|
}
|
|
|
|
/// This command is used for switching to alternate screen and back to main screen.
|
|
/// check https://docs.microsoft.com/en-us/windows/console/reading-and-writing-blocks-of-characters-and-attributes for more info
|
|
#[derive(Clone, Copy)]
|
|
pub struct ToAlternateScreenBufferCommand;
|
|
|
|
impl ICommand for ToAlternateScreenBufferCommand
|
|
{
|
|
fn new() -> Box<ToAlternateScreenBufferCommand>
|
|
{
|
|
Box::from(ToAlternateScreenBufferCommand {})
|
|
}
|
|
|
|
fn execute(&mut self) -> bool
|
|
{
|
|
// println!("executte ToAlternateScreenBufferCommand winapi");
|
|
let mut chi_buffer: [CHAR_INFO;160] = unsafe {mem::zeroed() };
|
|
|
|
let handle = kernel::get_output_handle();
|
|
|
|
// create a new screen buffer to copy to.
|
|
let new_handle = kernel::create_console_screen_buffer();
|
|
|
|
// Make the new screen buffer the active screen buffer.
|
|
kernel::set_active_screen_buffer(new_handle);
|
|
|
|
// Set the source rectangle.
|
|
let mut srct_read_rect = SMALL_RECT
|
|
{
|
|
Top: 0,
|
|
Left: 0 ,
|
|
Bottom: 1,
|
|
Right: 79,
|
|
};
|
|
|
|
// The temporary buffer size is 2 rows x 80 columns.
|
|
let coord_buffer_size = COORD
|
|
{
|
|
X: 2,
|
|
Y: 80
|
|
};
|
|
|
|
// The top left destination cell of the temporary buffer is
|
|
// row 0, col 0.
|
|
let coord_buffer_coord = COORD
|
|
{
|
|
X: 0,
|
|
Y: 0,
|
|
};
|
|
|
|
// Copy the block from the screen buffer to the temp. buffer.
|
|
kernel::read_console_output(&handle, &mut chi_buffer, coord_buffer_size, coord_buffer_coord, &mut srct_read_rect);
|
|
|
|
// Set the destination rectangle.
|
|
let mut srct_write_rect = SMALL_RECT
|
|
{
|
|
Top: 10,
|
|
Left: 0,
|
|
Bottom: 11,
|
|
Right: 19,
|
|
};
|
|
|
|
// Copy from the temporary buffer to the new screen buffer.
|
|
kernel::write_console_output(&new_handle, &mut chi_buffer, coord_buffer_size, coord_buffer_coord, &mut srct_write_rect);
|
|
|
|
true
|
|
}
|
|
|
|
fn undo(&mut self) -> bool
|
|
{
|
|
// println!("undo ToAlternateScreenBufferCommand winapi");
|
|
let handle = kernel::get_output_handle();
|
|
kernel::set_active_screen_buffer(handle);
|
|
true
|
|
}
|
|
}
|