mirror of
https://github.com/crossterm-rs/crossterm.git
synced 2025-09-30 14:32:09 +00:00
214 lines
7.1 KiB
Rust
214 lines
7.1 KiB
Rust
use super::{is_true, Coord, Handle, HandleType, WindowPositions};
|
|
use std::io::{self, Error, Result};
|
|
use std::str;
|
|
|
|
use winapi::ctypes::c_void;
|
|
use winapi::shared::minwindef::DWORD;
|
|
use winapi::shared::ntdef::NULL;
|
|
use winapi::um::consoleapi::{GetNumberOfConsoleInputEvents, ReadConsoleInputW, WriteConsoleW};
|
|
use winapi::um::{
|
|
wincon::{
|
|
FillConsoleOutputAttribute, FillConsoleOutputCharacterA, GetLargestConsoleWindowSize,
|
|
SetConsoleTextAttribute, SetConsoleWindowInfo, COORD, INPUT_RECORD, SMALL_RECT,
|
|
},
|
|
winnt::HANDLE,
|
|
};
|
|
use InputRecord;
|
|
|
|
/// Could be used to do some basic things with the console.
|
|
pub struct Console {
|
|
handle: Handle,
|
|
}
|
|
|
|
impl Console {
|
|
/// Create new instance of `Console`.
|
|
///
|
|
/// This created instance will use the default output handle (STD_OUTPUT_HANDLE) as handle for the function call it wraps.
|
|
pub fn new() -> Result<Console> {
|
|
Ok(Console {
|
|
handle: Handle::new(HandleType::OutputHandle)?,
|
|
})
|
|
}
|
|
|
|
/// Sets the attributes of characters written to the console screen buffer by the WriteFile or WriteConsole function, or echoed by the ReadFile or ReadConsole function.
|
|
/// This function affects text written after the function call.
|
|
///
|
|
/// parameter: [wAttributes]
|
|
/// Wraps the underlying function call: [SetConsoleTextAttribute]
|
|
/// link: [https://docs.microsoft.com/en-us/windows/console/setconsoletextattribute]
|
|
pub fn set_text_attribute(&self, value: u16) -> Result<()> {
|
|
unsafe {
|
|
if !is_true(SetConsoleTextAttribute(*self.handle, value)) {
|
|
return Err(Error::last_os_error());
|
|
}
|
|
}
|
|
Ok(())
|
|
}
|
|
|
|
/// Sets the current size and position of a console screen buffer's window.
|
|
///
|
|
/// Wraps the underlying function call: [SetConsoleTextAttribute]
|
|
/// link: [https://docs.microsoft.com/en-us/windows/console/setconsoletextattribute]
|
|
pub fn set_console_info(&self, absolute: bool, rect: WindowPositions) -> Result<()> {
|
|
let absolute = match absolute {
|
|
true => 1,
|
|
false => 0,
|
|
};
|
|
let a = SMALL_RECT::from(rect);
|
|
|
|
unsafe {
|
|
if !is_true(SetConsoleWindowInfo(*self.handle, absolute, &a)) {
|
|
return Err(Error::last_os_error());
|
|
}
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
|
|
/// Writes a character to the console screen buffer a specified number of times, beginning at the specified coordinates
|
|
///
|
|
/// Wraps the underlying function call: [FillConsoleOutputCharacterA]
|
|
/// link: [https://docs.microsoft.com/en-us/windows/console/fillconsoleoutputcharacter]
|
|
pub fn fill_whit_character(
|
|
&self,
|
|
start_location: Coord,
|
|
cells_to_write: u32,
|
|
filling_char: char,
|
|
) -> Result<u32> {
|
|
let mut chars_written = 0;
|
|
unsafe {
|
|
// fill the cells in console with blanks
|
|
if !is_true(FillConsoleOutputCharacterA(
|
|
*self.handle,
|
|
filling_char as i8,
|
|
cells_to_write,
|
|
COORD::from(start_location),
|
|
&mut chars_written,
|
|
)) {
|
|
return Err(Error::last_os_error());
|
|
}
|
|
|
|
Ok(chars_written)
|
|
}
|
|
}
|
|
|
|
/// Sets the character attributes for a specified number of character cells, beginning at the specified coordinates in a screen buffer.
|
|
///
|
|
/// Wraps the underlying function call: [FillConsoleOutputAttribute]
|
|
/// link: [https://docs.microsoft.com/en-us/windows/console/fillconsoleoutputattribute]
|
|
pub fn fill_whit_attribute(
|
|
&self,
|
|
start_location: Coord,
|
|
cells_to_write: u32,
|
|
dw_attribute: u16,
|
|
) -> Result<u32> {
|
|
let mut cells_written = 0;
|
|
// Get the position of the current console window
|
|
unsafe {
|
|
if !is_true(FillConsoleOutputAttribute(
|
|
*self.handle,
|
|
dw_attribute,
|
|
cells_to_write,
|
|
COORD::from(start_location),
|
|
&mut cells_written,
|
|
)) {
|
|
return Err(Error::last_os_error());
|
|
}
|
|
}
|
|
|
|
Ok(cells_written)
|
|
}
|
|
|
|
/// Retrieves the size of the largest possible console window, based on the current font and the size of the display.
|
|
///
|
|
/// Wraps the underlying function call: [GetLargestConsoleWindowSize]
|
|
/// link: [https://docs.microsoft.com/en-us/windows/console/getlargestconsolewindowsize]
|
|
pub fn largest_window_size(&self) -> Coord {
|
|
Coord::from(unsafe { GetLargestConsoleWindowSize(*self.handle) })
|
|
}
|
|
|
|
/// Writes a character string to a console screen buffer beginning at the current cursor location.
|
|
///
|
|
/// Wraps the underlying function call: [WriteConsoleW]
|
|
/// link: [https://docs.microsoft.com/en-us/windows/console/writeconsole]
|
|
pub fn write_char_buffer(&self, buf: &[u8]) -> Result<usize> {
|
|
// get string from u8[] and parse it to an c_str
|
|
let utf8 = match str::from_utf8(buf) {
|
|
Ok(string) => string,
|
|
Err(_) => {
|
|
return Err(io::Error::new(
|
|
io::ErrorKind::Other,
|
|
"Could not parse to utf8 string",
|
|
));
|
|
}
|
|
};
|
|
|
|
let utf16: Vec<u16> = utf8.encode_utf16().collect();
|
|
let utf16_ptr: *const c_void = utf16.as_ptr() as *const _ as *const c_void;
|
|
|
|
let mut cells_written: u32 = 0;
|
|
// write to console
|
|
unsafe {
|
|
if !is_true(WriteConsoleW(
|
|
*self.handle,
|
|
utf16_ptr,
|
|
utf16.len() as u32,
|
|
&mut cells_written,
|
|
NULL,
|
|
)) {
|
|
return Err(io::Error::last_os_error());
|
|
}
|
|
}
|
|
Ok(utf8.as_bytes().len())
|
|
}
|
|
|
|
pub fn read_console_input(&self) -> Result<(u32, Vec<InputRecord>)> {
|
|
let mut buf_len: DWORD = 0;
|
|
if !is_true(unsafe { GetNumberOfConsoleInputEvents(*self.handle, &mut buf_len) }) {
|
|
return Err(Error::last_os_error());
|
|
}
|
|
|
|
// Fast-skipping all the code below if there is nothing to read at all
|
|
if buf_len == 0 {
|
|
return Ok((0, vec![]));
|
|
}
|
|
|
|
let mut buf: Vec<INPUT_RECORD> = Vec::with_capacity(buf_len as usize);
|
|
let mut size = 0;
|
|
|
|
if !is_true(unsafe {
|
|
ReadConsoleInputW(*self.handle, buf.as_mut_ptr(), buf_len, &mut size)
|
|
}) {
|
|
return Err(Error::last_os_error());
|
|
} else {
|
|
unsafe {
|
|
buf.set_len(size as usize);
|
|
}
|
|
}
|
|
|
|
Ok((
|
|
size,
|
|
buf[..(size as usize)]
|
|
.iter()
|
|
.map(|x| InputRecord::from(*x))
|
|
.collect::<Vec<InputRecord>>(),
|
|
))
|
|
}
|
|
}
|
|
|
|
impl From<Handle> for Console {
|
|
/// Create a `Console` instance who's functions will be executed on the the given `Handle`
|
|
fn from(handle: Handle) -> Self {
|
|
Console { handle }
|
|
}
|
|
}
|
|
|
|
impl From<HANDLE> for Console {
|
|
/// Create a `Console` instance who's functions will be executed on the the given `HANDLE`
|
|
fn from(handle: HANDLE) -> Self {
|
|
Console {
|
|
handle: Handle::from(handle),
|
|
}
|
|
}
|
|
}
|