2018-03-11 03:33:06 +11:00
|
|
|
//! This is an `WINAPI` specific implementation for terminal related action.
|
2018-06-17 04:10:51 +10:00
|
|
|
//! This module is used for non supporting `ANSI` windows terminals.
|
2018-03-11 03:33:06 +11:00
|
|
|
|
2018-06-19 06:10:41 +10:00
|
|
|
use Context;
|
2018-03-11 03:33:06 +11:00
|
|
|
use cursor::cursor;
|
2018-06-23 05:04:30 +10:00
|
|
|
use super::{ClearType, ITerminal, Rc};
|
2018-03-04 01:40:51 +11:00
|
|
|
use winapi::um::wincon::{SMALL_RECT, COORD, CONSOLE_SCREEN_BUFFER_INFO,};
|
|
|
|
use kernel::windows_kernel::{kernel, terminal};
|
2018-06-27 04:21:47 +10:00
|
|
|
use super::super::shared::functions;
|
2018-07-02 06:40:07 +10:00
|
|
|
use super::super::ScreenManager;
|
|
|
|
|
|
|
|
use std::sync::Mutex;
|
2018-01-18 09:06:45 +11:00
|
|
|
|
|
|
|
/// This struct is an windows implementation for terminal related actions.
|
2018-06-23 05:04:30 +10:00
|
|
|
pub struct WinApiTerminal
|
|
|
|
{
|
|
|
|
context: Rc<Context>
|
|
|
|
}
|
2018-01-07 07:31:14 +11:00
|
|
|
|
2018-06-19 06:10:41 +10:00
|
|
|
impl WinApiTerminal {
|
2018-06-23 05:04:30 +10:00
|
|
|
pub fn new(context: Rc<Context>) -> Box<WinApiTerminal> {
|
|
|
|
Box::from(WinApiTerminal { context })
|
2018-01-07 07:31:14 +11:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl ITerminal for WinApiTerminal {
|
2018-03-11 03:33:06 +11:00
|
|
|
|
2018-06-23 05:04:30 +10:00
|
|
|
fn clear(&self, clear_type: ClearType) {
|
2018-07-02 06:40:07 +10:00
|
|
|
let csbi = kernel::get_console_screen_buffer_info(&self.context.screen_manager);
|
2018-06-23 05:04:30 +10:00
|
|
|
let pos = cursor(self.context.clone()).pos();
|
2018-03-04 01:40:51 +11:00
|
|
|
|
2018-01-07 07:31:14 +11:00
|
|
|
match clear_type
|
|
|
|
{
|
2018-07-02 06:40:07 +10:00
|
|
|
ClearType::All => clear_entire_screen(csbi, &self.context),
|
|
|
|
ClearType::FromCursorDown => clear_after_cursor(pos,csbi, &self.context),
|
|
|
|
ClearType::FromCursorUp => clear_before_cursor(pos, csbi, &self.context),
|
|
|
|
ClearType::CurrentLine => clear_current_line(pos, csbi, &self.context),
|
|
|
|
ClearType::UntilNewLine => clear_until_line(pos, csbi, &self.context),
|
2018-01-07 07:31:14 +11:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2018-06-23 05:04:30 +10:00
|
|
|
fn terminal_size(&self) -> (u16, u16) {
|
2018-07-02 06:40:07 +10:00
|
|
|
terminal::terminal_size(&self.context.screen_manager)
|
2018-01-07 07:31:14 +11:00
|
|
|
}
|
|
|
|
|
2018-06-23 05:04:30 +10:00
|
|
|
fn scroll_up(&self, count: i16) {
|
2018-07-02 06:40:07 +10:00
|
|
|
// yet to be implemented
|
2018-01-07 07:31:14 +11:00
|
|
|
}
|
|
|
|
|
2018-06-23 05:04:30 +10:00
|
|
|
fn scroll_down(&self, count: i16) {
|
2018-07-02 06:40:07 +10:00
|
|
|
let csbi = kernel::get_console_screen_buffer_info(&self.context.screen_manager);
|
2018-03-04 01:40:51 +11:00
|
|
|
let mut srct_window;
|
|
|
|
|
|
|
|
// Set srctWindow to the current window size and location.
|
|
|
|
srct_window = csbi.srWindow;
|
|
|
|
|
|
|
|
// 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
|
|
|
|
|
2018-07-02 06:40:07 +10:00
|
|
|
let success = kernel::set_console_info(true, &mut srct_window, &self.context.screen_manager);
|
2018-03-04 01:40:51 +11:00
|
|
|
if success {
|
|
|
|
panic!("Something went wrong when scrolling down");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Set the current terminal size
|
2018-06-23 05:04:30 +10:00
|
|
|
fn set_size(&self, width: i16, height: i16) {
|
2018-03-04 01:40:51 +11:00
|
|
|
if width <= 0
|
|
|
|
{
|
|
|
|
panic!("Cannot set the terminal width lower than 1");
|
|
|
|
}
|
|
|
|
|
|
|
|
if height <= 0
|
|
|
|
{
|
|
|
|
panic!("Cannot set the terminal height lower then 1")
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get the position of the current console window
|
2018-07-02 06:40:07 +10:00
|
|
|
let csbi = kernel::get_console_screen_buffer_info(&self.context.screen_manager);
|
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;
|
|
|
|
let mut size = COORD { X: csbi.dwSize.X, Y: csbi.dwSize.Y };
|
|
|
|
|
|
|
|
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.");
|
|
|
|
}
|
|
|
|
|
|
|
|
size.X = csbi.srWindow.Left + width;
|
|
|
|
resize_buffer = true;
|
|
|
|
}
|
|
|
|
if csbi.dwSize.Y < csbi.srWindow.Top + height {
|
|
|
|
if csbi.srWindow.Top >= i16::max_value() - height
|
|
|
|
{
|
|
|
|
panic!("Argument out of range when setting terminal height");
|
|
|
|
}
|
|
|
|
|
|
|
|
size.Y = csbi.srWindow.Top + height;
|
|
|
|
resize_buffer = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if resize_buffer {
|
2018-07-02 06:40:07 +10:00
|
|
|
success = kernel::set_console_screen_buffer_size(size, &self.context.screen_manager);
|
2018-03-04 01:40:51 +11:00
|
|
|
|
|
|
|
if !success
|
|
|
|
{
|
|
|
|
panic!("Something went wrong when setting screen buffer size.");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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-02 06:40:07 +10:00
|
|
|
let success = kernel::set_console_info(true, &fsr_window, &self.context.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-02 06:40:07 +10:00
|
|
|
kernel::set_console_screen_buffer_size(csbi.dwSize, &self.context.screen_manager);
|
2018-03-04 01:40:51 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
let bounds = kernel::get_largest_console_window_size();
|
|
|
|
|
|
|
|
if width > bounds.X
|
|
|
|
{
|
|
|
|
panic!("Argument width: {} out of range when setting terminal width.", width);
|
|
|
|
}
|
|
|
|
if height > bounds.Y
|
|
|
|
{
|
|
|
|
panic!("Argument height: {} out of range when setting terminal height", height);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-06-24 03:48:22 +10:00
|
|
|
|
2018-06-27 04:21:47 +10:00
|
|
|
fn exit(&self)
|
|
|
|
{
|
|
|
|
functions::exit_terminal();
|
|
|
|
}
|
2018-03-04 01:40:51 +11:00
|
|
|
}
|
|
|
|
|
2018-07-02 06:40:07 +10:00
|
|
|
pub fn clear_after_cursor(pos: (u16,u16), csbi: CONSOLE_SCREEN_BUFFER_INFO, context: &Rc<Context>) {
|
2018-03-04 01:40:51 +11:00
|
|
|
let (mut x,mut y) = pos;
|
|
|
|
|
|
|
|
// if cursor position is at the outer right position
|
|
|
|
if x as i16 > csbi.dwSize.X
|
|
|
|
{
|
|
|
|
y += 1;
|
|
|
|
x = 0;
|
2018-01-07 07:31:14 +11:00
|
|
|
}
|
2018-01-26 04:26:08 +11:00
|
|
|
|
2018-03-04 01:40:51 +11:00
|
|
|
// location where to start clearing
|
|
|
|
let start_location = COORD { 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;
|
|
|
|
|
2018-07-02 06:40:07 +10:00
|
|
|
clear(start_location,cells_to_write, &context.screen_manager);
|
2018-01-07 07:31:14 +11:00
|
|
|
}
|
2018-03-04 01:40:51 +11:00
|
|
|
|
2018-07-02 06:40:07 +10:00
|
|
|
pub fn clear_before_cursor(pos: (u16,u16), csbi: CONSOLE_SCREEN_BUFFER_INFO, context: &Rc<Context>) {
|
2018-03-04 01:40:51 +11:00
|
|
|
let (xpos,ypos) = pos;
|
|
|
|
|
|
|
|
// one cell after cursor position
|
|
|
|
let x = 0;
|
|
|
|
// one at row of cursor position
|
|
|
|
let y = 0;
|
|
|
|
|
|
|
|
// location where to start clearing
|
|
|
|
let start_location = COORD { 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);
|
|
|
|
|
2018-07-02 06:40:07 +10:00
|
|
|
clear(start_location, cells_to_write, &context.screen_manager);
|
2018-03-04 01:40:51 +11:00
|
|
|
}
|
|
|
|
|
2018-07-02 06:40:07 +10:00
|
|
|
pub fn clear_entire_screen(csbi: CONSOLE_SCREEN_BUFFER_INFO, context: &Rc<Context>) {
|
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
|
|
|
|
let start_location = COORD { 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;
|
|
|
|
|
2018-07-02 06:40:07 +10:00
|
|
|
clear( start_location, cells_to_write, &context.screen_manager);
|
2018-03-04 01:40:51 +11:00
|
|
|
|
|
|
|
// put the cursor back at (0, 0)
|
2018-06-23 05:04:30 +10:00
|
|
|
cursor(context.clone()).goto(0, 0);
|
2018-03-04 01:40:51 +11:00
|
|
|
}
|
|
|
|
|
2018-07-02 06:40:07 +10:00
|
|
|
pub fn clear_current_line(pos: (u16,u16), csbi: CONSOLE_SCREEN_BUFFER_INFO, context: &Rc<Context>)
|
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
|
|
|
|
let start_location = COORD { X: x as i16, Y: y as i16};
|
|
|
|
// get sum cells before cursor
|
|
|
|
|
|
|
|
let cells_to_write = csbi.dwSize.X as u32;
|
|
|
|
|
2018-07-02 06:40:07 +10:00
|
|
|
clear(start_location, cells_to_write, &context.screen_manager);
|
2018-03-04 01:40:51 +11:00
|
|
|
|
|
|
|
// put the cursor back at 1 cell on current row
|
2018-06-23 05:04:30 +10:00
|
|
|
cursor(context.clone()).goto(0, y);
|
2018-03-04 01:40:51 +11:00
|
|
|
}
|
|
|
|
|
2018-07-02 06:40:07 +10:00
|
|
|
pub fn clear_until_line(pos: (u16,u16), csbi: CONSOLE_SCREEN_BUFFER_INFO, context: &Rc<Context>)
|
2018-03-04 01:40:51 +11:00
|
|
|
{
|
|
|
|
let (x,y) = pos;
|
|
|
|
|
|
|
|
// location where to start clearing
|
|
|
|
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;
|
|
|
|
|
2018-07-02 06:40:07 +10:00
|
|
|
clear(start_location, cells_to_write, &context.screen_manager);
|
2018-03-04 01:40:51 +11:00
|
|
|
|
|
|
|
// put the cursor back at original cursor position
|
2018-06-23 05:04:30 +10:00
|
|
|
cursor(context.clone()).goto(x,y);
|
2018-03-04 01:40:51 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
fn clear(
|
|
|
|
start_loaction: COORD,
|
2018-07-02 06:40:07 +10:00
|
|
|
cells_to_write: u32,
|
|
|
|
screen_manager: &Rc<Mutex<ScreenManager>>
|
2018-03-04 01:40:51 +11:00
|
|
|
) {
|
|
|
|
let mut cells_written = 0;
|
|
|
|
let mut success = false;
|
|
|
|
|
2018-07-02 06:40:07 +10:00
|
|
|
success = kernel::fill_console_output_character(&mut cells_written, start_loaction, cells_to_write, screen_manager);
|
2018-03-04 01:40:51 +11:00
|
|
|
|
|
|
|
if !success
|
|
|
|
{
|
|
|
|
panic!("Could not clear screen after cursor");
|
|
|
|
}
|
|
|
|
|
|
|
|
cells_written = 0;
|
|
|
|
|
2018-07-02 06:40:07 +10:00
|
|
|
success = kernel::fill_console_output_attribute(&mut cells_written, start_loaction, cells_to_write, screen_manager);
|
2018-03-04 01:40:51 +11:00
|
|
|
|
|
|
|
if !success {
|
|
|
|
panic!("Couldnot reset attributes after cursor");
|
|
|
|
}
|
|
|
|
}
|