minicrossterm/src/modules/terminal/winapi_terminal.rs

302 lines
9.0 KiB
Rust
Raw Normal View History

//! This is an `WINAPI` specific implementation for terminal related action.
//! This module is used for non supporting `ANSI` windows terminals.
2018-07-30 05:30:09 +10:00
//!
//! Windows versions lower then windows 10 are not supporting ANSI codes. Those versions will use this implementation instead.
use super::super::super::cursor::TerminalCursor;
use super::*;
2018-07-22 22:55:14 +10:00
use kernel::windows_kernel::{csbi, kernel, terminal, writing};
2018-07-02 06:43:43 +10:00
use winapi::um::wincon::{CONSOLE_SCREEN_BUFFER_INFO, COORD, SMALL_RECT};
2018-07-30 05:30:09 +10:00
/// This struct is an winapi implementation for terminal related actions.
2018-07-28 17:54:05 +10:00
pub struct WinApiTerminal;
impl WinApiTerminal {
2018-07-28 17:54:05 +10:00
pub fn new() -> WinApiTerminal {
WinApiTerminal {}
}
}
impl ITerminal for WinApiTerminal {
fn clear(&self, clear_type: ClearType, screen_manager: &Arc<Stdout>) {
2018-07-28 17:54:05 +10:00
let csbi = csbi::get_csbi(screen_manager).unwrap();
let pos = TerminalCursor::new(screen_manager).pos();
2018-03-04 01:40:51 +11:00
2018-07-02 06:43:43 +10:00
match clear_type {
ClearType::All => {
clear_entire_screen(csbi, screen_manager);
}
2018-07-28 17:54:05 +10:00
ClearType::FromCursorDown => clear_after_cursor(pos, csbi, screen_manager),
ClearType::FromCursorUp => clear_before_cursor(pos, csbi, screen_manager),
ClearType::CurrentLine => clear_current_line(pos, csbi, screen_manager),
ClearType::UntilNewLine => clear_until_line(pos, csbi, screen_manager),
};
}
fn terminal_size(&self, screen_manager: &Arc<Stdout>) -> (u16, u16) {
terminal::terminal_size()
}
fn scroll_up(&self, count: i16, screen_manager: &Arc<Stdout>) {
2018-07-28 17:54:05 +10:00
let csbi = csbi::get_csbi(&screen_manager).unwrap();
2018-07-19 06:32:17 +10:00
// 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
if srct_window.Top >= count {
2018-07-22 22:55:14 +10:00
srct_window.Top -= count; // move top down
2018-07-19 06:32:17 +10:00
srct_window.Bottom = count; // move bottom down
let success = kernel::set_console_info(false, &mut srct_window, &screen_manager);
2018-07-19 06:32:17 +10:00
if success {
panic!("Something went wrong when scrolling down");
}
}
}
fn scroll_down(&self, count: i16, screen_manager: &Arc<Stdout>) {
2018-07-28 17:54:05 +10:00
let csbi = csbi::get_csbi(&screen_manager).unwrap();
2018-03-04 01:40:51 +11:00
// Set srctWindow to the current window size and location.
2018-07-19 06:32:17 +10:00
let mut srct_window = csbi.srWindow;
2018-07-22 22:55:14 +10:00
// Set srctWindow to the current window size and location.
srct_window = csbi.srWindow;
2018-03-04 01:40:51 +11:00
// Check whether the window is too close to the screen buffer top
if srct_window.Bottom < csbi.dwSize.Y - count {
srct_window.Top += count; // move top down
srct_window.Bottom += count; // move bottom down
let success = kernel::set_console_info(true, &mut srct_window, &screen_manager);
2018-03-04 01:40:51 +11:00
if success {
panic!("Something went wrong when scrolling down");
}
}
}
/// Set the current terminal size
fn set_size(&self, width: i16, height: i16, screen_manager: &Arc<Stdout>) {
2018-07-02 06:43:43 +10:00
if width <= 0 {
panic!("Cannot set the terminal width lower than 1");
}
2018-03-04 01:40:51 +11:00
2018-07-02 06:43:43 +10:00
if height <= 0 {
panic!("Cannot set the terminal height lower then 1")
}
2018-03-04 01:40:51 +11:00
// Get the position of the current console window
2018-07-28 17:54:05 +10:00
let csbi = csbi::get_csbi(&screen_manager).unwrap();
2018-03-04 01:40:51 +11:00
let mut success = false;
// If the buffer is smaller than this new window size, resize the
// buffer to be large enough. Include window position.
let mut resize_buffer = false;
2018-07-02 06:43:43 +10:00
let mut size = COORD {
X: csbi.dwSize.X,
Y: csbi.dwSize.Y,
};
2018-03-04 01:40:51 +11:00
2018-07-02 06:43:43 +10:00
if csbi.dwSize.X < csbi.srWindow.Left + width {
if csbi.srWindow.Left >= i16::max_value() - width {
panic!("Argument out of range when setting terminal width.");
2018-03-04 01:40:51 +11:00
}
2018-07-02 06:43:43 +10:00
size.X = csbi.srWindow.Left + width;
resize_buffer = true;
}
2018-03-04 01:40:51 +11:00
if csbi.dwSize.Y < csbi.srWindow.Top + height {
2018-07-02 06:43:43 +10:00
if csbi.srWindow.Top >= i16::max_value() - height {
panic!("Argument out of range when setting terminal height");
}
2018-03-04 01:40:51 +11:00
size.Y = csbi.srWindow.Top + height;
resize_buffer = true;
}
if resize_buffer {
2018-07-28 17:54:05 +10:00
success = csbi::set_console_screen_buffer_size(size, &screen_manager);
2018-03-04 01:40:51 +11:00
2018-07-02 06:43:43 +10:00
if !success {
panic!("Something went wrong when setting screen buffer size.");
}
2018-03-04 01:40:51 +11:00
}
let mut fsr_window: SMALL_RECT = csbi.srWindow;
// Preserve the position, but change the size.
fsr_window.Bottom = fsr_window.Top + height;
fsr_window.Right = fsr_window.Left + width;
2018-07-28 17:54:05 +10:00
let success = kernel::set_console_info(true, &fsr_window, &screen_manager);
2018-03-04 01:40:51 +11:00
if success {
// If we resized the buffer, un-resize it.
if resize_buffer {
2018-07-28 17:54:05 +10:00
csbi::set_console_screen_buffer_size(csbi.dwSize, &screen_manager);
2018-03-04 01:40:51 +11:00
}
let bounds = kernel::get_largest_console_window_size();
2018-07-02 06:43:43 +10:00
if width > bounds.X {
panic!(
"Argument width: {} out of range when setting terminal width.",
width
);
2018-03-04 01:40:51 +11:00
}
2018-07-02 06:43:43 +10:00
if height > bounds.Y {
panic!(
"Argument height: {} out of range when setting terminal height",
height
);
2018-03-04 01:40:51 +11:00
}
}
}
2018-07-02 06:43:43 +10:00
fn exit(&self) {
2018-06-27 04:21:47 +10:00
functions::exit_terminal();
}
2018-03-04 01:40:51 +11:00
}
2018-07-02 06:43:43 +10:00
pub fn clear_after_cursor(
pos: (u16, u16),
csbi: CONSOLE_SCREEN_BUFFER_INFO,
screen_manager: &Arc<Stdout>,
2018-07-02 06:43:43 +10:00
) {
let (mut x, mut y) = pos;
2018-03-04 01:40:51 +11:00
// if cursor position is at the outer right position
2018-07-02 06:43:43 +10:00
if x as i16 > csbi.dwSize.X {
2018-03-04 01:40:51 +11:00
y += 1;
x = 0;
}
2018-03-04 01:40:51 +11:00
// location where to start clearing
2018-07-02 06:43:43 +10:00
let start_location = COORD {
X: x as i16,
Y: y as i16,
};
2018-03-04 01:40:51 +11:00
// get sum cells before cursor
2018-07-02 06:43:43 +10:00
let cells_to_write = csbi.dwSize.X as u32 * csbi.dwSize.Y as u32;
2018-03-04 01:40:51 +11:00
2018-07-28 17:54:05 +10:00
clear(start_location, cells_to_write, screen_manager);
}
2018-03-04 01:40:51 +11:00
2018-07-02 06:43:43 +10:00
pub fn clear_before_cursor(
pos: (u16, u16),
csbi: CONSOLE_SCREEN_BUFFER_INFO,
screen_manager: &Arc<Stdout>,
2018-07-02 06:43:43 +10:00
) {
let (xpos, ypos) = pos;
2018-03-04 01:40:51 +11:00
// one cell after cursor position
let x = 0;
// one at row of cursor position
let y = 0;
// location where to start clearing
2018-07-02 06:43:43 +10:00
let start_location = COORD {
X: x as i16,
Y: y as i16,
};
2018-03-04 01:40:51 +11:00
// get sum cells before cursor
2018-07-02 06:43:43 +10:00
let cells_to_write = (csbi.dwSize.X as u32 * ypos as u32) + (xpos as u32 + 1);
2018-03-04 01:40:51 +11:00
2018-07-30 05:30:09 +10:00
clear(start_location, cells_to_write, screen_manager);
2018-03-04 01:40:51 +11:00
}
pub fn clear_entire_screen(csbi: CONSOLE_SCREEN_BUFFER_INFO, screen_manager: &Arc<Stdout>) {
2018-03-04 01:40:51 +11:00
// position x at start
let x = 0;
// position y at start
let y = 0;
// location where to start clearing
2018-07-02 06:43:43 +10:00
let start_location = COORD {
X: x as i16,
Y: y as i16,
};
2018-03-04 01:40:51 +11:00
// get sum cells before cursor
let cells_to_write = csbi.dwSize.X as u32 * csbi.dwSize.Y as u32;
2018-07-28 17:54:05 +10:00
clear(start_location, cells_to_write, &screen_manager);
2018-03-04 01:40:51 +11:00
// put the cursor back at (0, 0)
TerminalCursor::new(screen_manager).goto(0, 0);
2018-03-04 01:40:51 +11:00
}
2018-07-02 06:43:43 +10:00
pub fn clear_current_line(
pos: (u16, u16),
csbi: CONSOLE_SCREEN_BUFFER_INFO,
screen_manager: &Arc<Stdout>,
2018-07-02 06:43:43 +10:00
) {
2018-03-04 01:40:51 +11:00
// position x at start
let x = 0;
// position y at start
let y = pos.1;
// location where to start clearing
2018-07-02 06:43:43 +10:00
let start_location = COORD {
X: x as i16,
Y: y as i16,
};
2018-03-04 01:40:51 +11:00
// get sum cells before cursor
let cells_to_write = csbi.dwSize.X as u32;
2018-07-28 17:54:05 +10:00
clear(start_location, cells_to_write, screen_manager);
2018-03-04 01:40:51 +11:00
// put the cursor back at 1 cell on current row
TerminalCursor::new(screen_manager).goto(0, y);
2018-03-04 01:40:51 +11:00
}
pub fn clear_until_line(
pos: (u16, u16),
csbi: CONSOLE_SCREEN_BUFFER_INFO,
screen_manager: &Arc<Stdout>,
) {
2018-07-02 06:43:43 +10:00
let (x, y) = pos;
2018-03-04 01:40:51 +11:00
// location where to start clearing
2018-07-02 06:43:43 +10:00
let start_location = COORD {
X: x as i16,
Y: y as i16,
};
2018-03-04 01:40:51 +11:00
// get sum cells before cursor
2018-07-02 06:43:43 +10:00
let cells_to_write = (csbi.dwSize.X - x as i16) as u32;
2018-03-04 01:40:51 +11:00
2018-07-28 17:54:05 +10:00
clear(start_location, cells_to_write, &screen_manager);
2018-03-04 01:40:51 +11:00
// put the cursor back at original cursor position
TerminalCursor::new(screen_manager).goto(x, y);
2018-03-04 01:40:51 +11:00
}
fn clear(start_loaction: COORD, cells_to_write: u32, screen_manager: &Arc<Stdout>) {
2018-03-04 01:40:51 +11:00
let mut cells_written = 0;
let mut success = false;
success = writing::fill_console_output_character(
2018-07-02 06:43:43 +10:00
&mut cells_written,
start_loaction,
cells_to_write,
screen_manager,
);
2018-03-04 01:40:51 +11:00
2018-07-02 06:43:43 +10:00
if !success {
2018-03-04 01:40:51 +11:00
panic!("Could not clear screen after cursor");
}
cells_written = 0;
success = writing::fill_console_output_attribute(
2018-07-02 06:43:43 +10:00
&mut cells_written,
start_loaction,
cells_to_write,
screen_manager,
);
2018-03-04 01:40:51 +11:00
if !success {
2018-07-30 05:30:09 +10:00
panic!("Could not reset attributes after cursor");
2018-03-04 01:40:51 +11:00
}
2018-07-02 06:43:43 +10:00
}