minicrossterm/src/common/commands/win_commands.rs

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(())
}
}