minicrossterm/src/kernel/windows_kernel/kernel.rs
2018-06-26 18:56:34 +00:00

365 lines
9.7 KiB
Rust

//! This module is the core of all the `WINAPI` actions. All unsafe `WINAPI` function call are done here.
use winapi::um::winnt::HANDLE;
use winapi::um::winbase::{STD_OUTPUT_HANDLE, STD_INPUT_HANDLE };
use winapi::um::handleapi::INVALID_HANDLE_VALUE;
use winapi::um::processenv::{GetStdHandle};
use winapi::um::consoleapi::{SetConsoleMode,GetConsoleMode, };
use winapi::shared::ntdef::{NULL};
use winapi::shared::minwindef::{TRUE, FALSE};
use winapi::um::wincon;
use winapi::um::wincon::
{
SetConsoleWindowInfo, SetConsoleCursorPosition, SetConsoleTextAttribute, SetConsoleScreenBufferSize, CreateConsoleScreenBuffer,SetConsoleActiveScreenBuffer, SetConsoleCursorInfo,
GetLargestConsoleWindowSize, GetConsoleScreenBufferInfo,
FillConsoleOutputCharacterA, FillConsoleOutputAttribute,WriteConsoleOutputCharacterA,WriteConsoleOutputAttribute,
CONSOLE_SCREEN_BUFFER_INFO, SMALL_RECT, COORD, CHAR_INFO, PSMALL_RECT, CONSOLE_CURSOR_INFO
};
use super::{Empty};
static mut CONSOLE_OUTPUT_HANDLE: Option<HANDLE> = None;
static mut CONSOLE_INPUT_HANDLE: Option<HANDLE> = None;
/// Get the std_output_handle of the console
pub fn get_output_handle() -> HANDLE {
unsafe {
if let Some(handle) = CONSOLE_OUTPUT_HANDLE {
handle
} else {
let handle = GetStdHandle(STD_OUTPUT_HANDLE);
if !is_valid_handle(&handle)
{
panic!("Cannot get output handle")
}
CONSOLE_OUTPUT_HANDLE = Some(handle);
handle
}
}
}
/// Get the std_input_handle of the console
pub fn get_input_handle() -> HANDLE {
unsafe {
if let Some(handle) = CONSOLE_INPUT_HANDLE {
handle
} else {
let handle = GetStdHandle(STD_INPUT_HANDLE);
if !is_valid_handle(&handle)
{
panic!("Cannot get input handle")
}
CONSOLE_INPUT_HANDLE = Some(handle);
handle
}
}
}
/// Checks if the console handle is an invalid handle value.
fn is_valid_handle(handle: &HANDLE) -> bool {
if *handle == INVALID_HANDLE_VALUE {
false
} else {
true
}
}
pub fn get_console_screen_buffer_info() -> CONSOLE_SCREEN_BUFFER_INFO {
let output_handle = get_output_handle();
let mut csbi = CONSOLE_SCREEN_BUFFER_INFO::empty();
let success;
unsafe { success = GetConsoleScreenBufferInfo(output_handle, &mut csbi) }
if success == 0 {
panic!("Cannot get console screen buffer info");
}
csbi
}
pub fn get_largest_console_window_size() -> COORD
{
let output_handle = get_output_handle();
unsafe {
GetLargestConsoleWindowSize(output_handle)
}
}
pub fn get_original_console_color() -> u16 {
let console_buffer_info = get_console_screen_buffer_info();
console_buffer_info.wAttributes as u16
}
pub fn set_console_mode(handle: &HANDLE, console_mode: u32) -> bool
{
unsafe {
let success = SetConsoleMode(*handle, console_mode);
return is_true(success);
}
}
pub fn get_console_mode(handle: &HANDLE, current_mode: &mut u32) -> bool
{
unsafe {
let success = GetConsoleMode(*handle, &mut *current_mode);
return is_true(success);
}
}
pub fn set_console_cursor_position(x: i16, y: i16)
{
if x < 0 || x >= <i16>::max_value() {
panic!("X: {}, Argument Out of Range Exception", x);
}
if y < 0 || y >= <i16>::max_value() {
panic!("Y: {}, Argument Out of Range Exception", y);
}
let output_handle = get_output_handle();
let position = COORD { X: x, Y: y };
unsafe {
let success = SetConsoleCursorPosition(output_handle, position);
if success == 0 {
panic!("Argument out of range.");
}
}
}
pub fn cursor_visibility(visable: bool)
{
let handle = get_output_handle();
let cursor_info = CONSOLE_CURSOR_INFO
{
dwSize: 1,
bVisible: if visable { TRUE } else {FALSE}
};
unsafe
{
SetConsoleCursorInfo(handle, &cursor_info);
}
}
pub fn set_console_text_attribute(value: u16)
{
let output_handle = get_output_handle();
unsafe {
SetConsoleTextAttribute(output_handle, value);
}
}
pub fn set_console_info(absolute: bool, rect: &SMALL_RECT) -> bool
{
let output_handle = get_output_handle();
let absolute = match absolute { true => 1, false => 0, };
unsafe
{
let success = SetConsoleWindowInfo(output_handle,absolute ,rect);
is_true(success)
}
}
pub fn set_console_screen_buffer_size( size: COORD) -> bool
{
let output_handle = get_output_handle();
unsafe
{
let success = SetConsoleScreenBufferSize(output_handle, size);
is_true(success)
}
}
pub fn fill_console_output_character(cells_written: &mut u32, start_location: COORD, cells_to_write: u32) -> bool
{
let output_handle = get_output_handle();
unsafe {
// fill the cells in console with blanks
let success = FillConsoleOutputCharacterA (
output_handle,
' ' as i8,
cells_to_write,
start_location,
cells_written,
);
is_true(success)
}
}
pub fn fill_console_output_attribute(cells_written: &mut u32, start_location: COORD, cells_to_write: u32) -> bool
{
// Get the position of the current console window
let csbi = get_console_screen_buffer_info();
let output_handle = get_output_handle();
let success;
unsafe {
success = FillConsoleOutputAttribute (
output_handle,
csbi.wAttributes,
cells_to_write,
start_location,
cells_written,
);
}
is_true(success)
}
pub fn create_console_screen_buffer() -> HANDLE
{
use winapi::shared::ntdef::NULL;
use winapi::um::wincon::CONSOLE_TEXTMODE_BUFFER;
use winapi::um::winnt::{GENERIC_READ, GENERIC_WRITE, FILE_SHARE_READ, FILE_SHARE_WRITE};
use winapi::um::minwinbase::SECURITY_ATTRIBUTES;
use std::mem::size_of;
unsafe
{
let mut security_attr: SECURITY_ATTRIBUTES = SECURITY_ATTRIBUTES
{
nLength: size_of::<SECURITY_ATTRIBUTES>() as u32,
lpSecurityDescriptor: NULL,
bInheritHandle: TRUE
};
let new_screen_buffer = CreateConsoleScreenBuffer(
GENERIC_READ | // read/write access
GENERIC_WRITE,
FILE_SHARE_READ |
FILE_SHARE_WRITE, // shared
&mut security_attr, // default security attributes
CONSOLE_TEXTMODE_BUFFER, // must be TEXTMODE
NULL
);
new_screen_buffer
}
}
pub fn set_active_screen_buffer(new_buffer: HANDLE)
{
unsafe
{
if !is_true(SetConsoleActiveScreenBuffer(new_buffer))
{
panic!("Cannot set active screen buffer");
}
}
}
pub fn read_console_output(read_buffer: &HANDLE, copy_buffer: &mut [CHAR_INFO;160], buffer_size: COORD, buffer_coord: COORD, source_buffer: PSMALL_RECT)
{
use self::wincon::ReadConsoleOutputA;
unsafe
{
if !is_true(ReadConsoleOutputA(
*read_buffer, // screen buffer to read from
copy_buffer.as_mut_ptr(), // buffer to copy into
buffer_size, // col-row size of chiBuffer
buffer_coord, // top left dest. cell in chiBuffer
source_buffer) // screen buffer source rectangle
){
panic!("Cannot read console output");
}
}
}
pub fn write_console_output(write_buffer: &HANDLE, copy_buffer: &mut [CHAR_INFO;160], buffer_size: COORD, buffer_coord: COORD, source_buffer: PSMALL_RECT)
{
use self::wincon::WriteConsoleOutputA;
unsafe
{
if !is_true(WriteConsoleOutputA(
*write_buffer, // screen buffer to write to
copy_buffer.as_mut_ptr(), // buffer to copy into
buffer_size, // col-row size of chiBuffer
buffer_coord, // top left dest. cell in chiBuffer
source_buffer)// screen buffer source rectangle
){
panic!("Cannot write to console output");
}
}
}
pub fn write_char_buffer(handle: HANDLE, buf: &[u8])
{
use std::ffi::{ NulError, CString };
use std::str;
// get string from u8[] and parse it to an c_str
let mut utf8 = match str::from_utf8(buf)
{
Ok(string) => string,
Err(_) => "",
};
let utf16_bytes: Vec<u16> = utf8.encode_utf16().collect();
let mut utf16 = match String::from_utf16(&utf16_bytes)
{
Ok(string) => string,
Err(_) => String::new()
};
let str_length = utf16.len() as u32;
let c_str = match CString::new(utf16)
{
Ok(c) => c,
Err(_) => CString::new("").unwrap()
};
let ptr: *const i8 = c_str.as_ptr() as *const i8;
// get buffer info
let csbi = get_console_screen_buffer_info();
// get current position
let current_pos = COORD {X: csbi.dwCursorPosition.X, Y: csbi.dwCursorPosition.Y};
let mut cells_written: u32 = 0;
// write to console
unsafe
{
::winapi::um::consoleapi::WriteConsoleW(handle, utf16.as_ptr(), utf16.len() as u32, &mut cells_written, NULL);
WriteConsoleOutputCharacterA(handle, ptr, str_length, current_pos, &mut cells_written);
}
// get buffer info
let csbi = get_console_screen_buffer_info();
// get current position
let new_pos = COORD {X: csbi.dwCursorPosition.X, Y: csbi.dwCursorPosition.Y};
set_console_cursor_position(new_pos.X, new_pos.Y + 1);
}
/// Parse integer to an bool
fn is_true(value: i32) -> bool
{
if value == 0{
return false;
}
else{
return true;
}
}