185 lines
5.7 KiB
Rust
185 lines
5.7 KiB
Rust
//! This module contains the commands that can be used for windows systems.
|
|
|
|
use super::{IAlternateScreenCommand, IEnableAnsiCommand, IRawScreenCommand, ScreenManager};
|
|
|
|
use kernel::windows_kernel::{ansi_support, csbi, handle, kernel};
|
|
use std::mem;
|
|
use winapi::shared::minwindef::DWORD;
|
|
use winapi::um::wincon;
|
|
use winapi::um::wincon::{CHAR_INFO, COORD, ENABLE_VIRTUAL_TERMINAL_PROCESSING, SMALL_RECT};
|
|
|
|
use std::io::{Error, ErrorKind, Result};
|
|
|
|
/// 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 EnableAnsiCommand {
|
|
pub fn new() -> EnableAnsiCommand {
|
|
let command = EnableAnsiCommand {
|
|
mask: ENABLE_VIRTUAL_TERMINAL_PROCESSING,
|
|
};
|
|
command
|
|
}
|
|
}
|
|
|
|
impl IEnableAnsiCommand for EnableAnsiCommand {
|
|
fn enable(&mut self) -> bool {
|
|
// 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 = handle::get_output_handle().unwrap();
|
|
|
|
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;
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
|
|
fn disable(&mut self) -> bool {
|
|
if ansi_support::ansi_enabled() {
|
|
let output_handle = handle::get_output_handle().unwrap();
|
|
|
|
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 RawModeCommand {
|
|
mask: DWORD,
|
|
}
|
|
|
|
impl RawModeCommand {
|
|
pub fn new() -> Self {
|
|
use self::wincon::{ENABLE_ECHO_INPUT, ENABLE_LINE_INPUT, ENABLE_PROCESSED_INPUT};
|
|
|
|
RawModeCommand {
|
|
mask: ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT | ENABLE_ECHO_INPUT,
|
|
}
|
|
}
|
|
|
|
/// Enables raw mode.
|
|
pub fn enable(&mut self) -> Result<()> {
|
|
let input_handle = handle::get_input_handle()?;
|
|
|
|
let mut dw_mode: DWORD = 0;
|
|
if !kernel::get_console_mode(&input_handle, &mut dw_mode) {
|
|
return Err(Error::new(
|
|
ErrorKind::Other,
|
|
"Could not get console mode when enabling raw mode",
|
|
));
|
|
}
|
|
|
|
let new_mode = dw_mode & !self.mask;
|
|
|
|
if !kernel::set_console_mode(&input_handle, new_mode) {
|
|
return Err(Error::new(
|
|
ErrorKind::Other,
|
|
"Could not set console mode when enabling raw mode",
|
|
));
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
|
|
/// Disables raw mode.
|
|
pub fn disable(&mut self) -> Result<()> {
|
|
let output_handle = handle::get_input_handle()?;
|
|
|
|
let mut dw_mode: DWORD = 0;
|
|
if !kernel::get_console_mode(&output_handle, &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;
|
|
|
|
if !kernel::set_console_mode(&output_handle, new_mode) {
|
|
return Err(Error::new(
|
|
ErrorKind::Other,
|
|
"Could not set console mode when disabling raw mode",
|
|
));
|
|
}
|
|
|
|
return Ok(());
|
|
}
|
|
}
|
|
|
|
/// 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
|
|
pub struct ToAlternateScreenCommand;
|
|
|
|
impl ToAlternateScreenCommand {
|
|
pub fn new() -> ToAlternateScreenCommand {
|
|
return ToAlternateScreenCommand {};
|
|
}
|
|
}
|
|
|
|
impl IAlternateScreenCommand for ToAlternateScreenCommand {
|
|
fn enable(&self, screen_manager: &mut ScreenManager) -> Result<()> {
|
|
use super::super::super::manager::WinApiScreenManager;
|
|
|
|
let handle = handle::get_output_handle()?;
|
|
|
|
// 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)?;
|
|
|
|
match screen_manager
|
|
.as_any_mut()
|
|
.downcast_mut::<WinApiScreenManager>()
|
|
{
|
|
Some(b) => b.set_alternate_handle(new_handle),
|
|
None => return Err(Error::new(ErrorKind::Other, "Invalid cast exception")),
|
|
};
|
|
|
|
let b: &mut WinApiScreenManager = match screen_manager
|
|
.as_any_mut()
|
|
.downcast_mut::<WinApiScreenManager>()
|
|
{
|
|
Some(b) => b,
|
|
None => return Err(Error::new(ErrorKind::Other, "Invalid cast exception")),
|
|
};
|
|
|
|
b.set_alternate_handle(new_handle);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
fn disable(&self, screen_manager: &mut ScreenManager) -> Result<()> {
|
|
let handle = handle::get_output_handle()?;
|
|
csbi::set_active_screen_buffer(handle);
|
|
|
|
Ok(())
|
|
}
|
|
}
|