Fix up vendor for... linux?

This commit is contained in:
John Doty 2022-12-20 01:02:23 +00:00
parent b799fedeec
commit 81de013103
114 changed files with 21002 additions and 21002 deletions

View file

@ -1,236 +1,236 @@
use std::io::{self, Result};
use std::iter;
use std::slice;
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,
};
use super::{result, Coord, Handle, HandleType, InputRecord, WindowPositions};
/// A wrapper around a screen buffer.
#[derive(Debug, Clone)]
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 output() -> 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` functions, or echoed by the `ReadFile` or `ReadConsole` functions.
/// This function affects text written after the function call.
///
/// The attributes is a bitmask of possible [character
/// attributes](https://docs.microsoft.com/en-us/windows/console/console-screen-buffers#character-attributes).
///
/// This wraps
/// [`SetConsoleTextAttribute`](https://docs.microsoft.com/en-us/windows/console/setconsoletextattribute).
pub fn set_text_attribute(&self, value: u16) -> Result<()> {
result(unsafe { SetConsoleTextAttribute(*self.handle, value) })?;
Ok(())
}
/// Sets the current size and position of a console screen buffer's window.
///
/// This wraps
/// [`SetConsoleWindowInfo`](https://docs.microsoft.com/en-us/windows/console/setconsolewindowinfo).
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);
result(unsafe { SetConsoleWindowInfo(*self.handle, absolute, &a) })?;
Ok(())
}
/// Writes a character to the console screen buffer a specified number of times, beginning at the specified coordinates.
/// Returns the number of characters that have been written.
///
/// This wraps
/// [`FillConsoleOutputCharacterA`](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;
result(unsafe {
// fill the cells in console with blanks
FillConsoleOutputCharacterA(
*self.handle,
filling_char as i8,
cells_to_write,
COORD::from(start_location),
&mut chars_written,
)
})?;
Ok(chars_written)
}
/// Sets the character attributes for a specified number of character cells, beginning at the specified coordinates in a screen buffer.
/// Returns the number of cells that have been modified.
///
/// This wraps
/// [`FillConsoleOutputAttribute`](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
result(unsafe {
FillConsoleOutputAttribute(
*self.handle,
dw_attribute,
cells_to_write,
COORD::from(start_location),
&mut cells_written,
)
})?;
Ok(cells_written)
}
/// Retrieves the size of the largest possible console window, based on the current text and the size of the display.
///
/// This wraps [`GetLargestConsoleWindowSize`](https://docs.microsoft.com/en-us/windows/console/getlargestconsolewindowsize)
pub fn largest_window_size(&self) -> Result<Coord> {
crate::coord_result(unsafe { GetLargestConsoleWindowSize(*self.handle) })
}
/// Writes a character string to a console screen buffer beginning at the current cursor location.
///
/// This wraps
/// [`WriteConsoleW`](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;
result(unsafe {
WriteConsoleW(
*self.handle,
utf16_ptr,
utf16.len() as u32,
&mut cells_written,
NULL,
)
})?;
Ok(utf8.as_bytes().len())
}
/// Read one input event.
///
/// This wraps
/// [`ReadConsoleInputW`](https://docs.microsoft.com/en-us/windows/console/readconsoleinput).
pub fn read_single_input_event(&self) -> Result<InputRecord> {
let mut record: INPUT_RECORD = INPUT_RECORD::default();
{
// Convert an INPUT_RECORD to an &mut [INPUT_RECORD] of length 1
let buf = slice::from_mut(&mut record);
let num_read = self.read_input(buf)?;
// The windows API promises that ReadConsoleInput returns at least
// 1 element
debug_assert!(num_read == 1);
}
Ok(record.into())
}
/// Read all available input events without blocking.
///
/// This wraps
/// [`ReadConsoleInputW`](https://docs.microsoft.com/en-us/windows/console/readconsoleinput).
pub fn read_console_input(&self) -> Result<Vec<InputRecord>> {
let buf_len = self.number_of_console_input_events()?;
// Fast-skipping all the code below if there is nothing to read at all
if buf_len == 0 {
return Ok(vec![]);
}
let mut buf: Vec<INPUT_RECORD> = iter::repeat_with(INPUT_RECORD::default)
.take(buf_len as usize)
.collect();
let num_read = self.read_input(buf.as_mut_slice())?;
Ok(buf
.into_iter()
.take(num_read)
.map(InputRecord::from)
.collect())
}
/// Get the number of available input events that can be read without blocking.
///
/// This wraps
/// [`GetNumberOfConsoleInputEvents`](https://docs.microsoft.com/en-us/windows/console/getnumberofconsoleinputevents).
pub fn number_of_console_input_events(&self) -> Result<u32> {
let mut buf_len: DWORD = 0;
result(unsafe { GetNumberOfConsoleInputEvents(*self.handle, &mut buf_len) })?;
Ok(buf_len)
}
/// Read input (via ReadConsoleInputW) into buf and return the number
/// of events read. ReadConsoleInputW guarantees that at least one event
/// is read, even if it means blocking the thread. buf.len() must fit in
/// a u32.
fn read_input(&self, buf: &mut [INPUT_RECORD]) -> Result<usize> {
let mut num_records = 0;
debug_assert!(buf.len() < std::u32::MAX as usize);
result(unsafe {
ReadConsoleInputW(
*self.handle,
buf.as_mut_ptr(),
buf.len() as u32,
&mut num_records,
)
})?;
Ok(num_records as usize)
}
}
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 }
}
}
use std::io::{self, Result};
use std::iter;
use std::slice;
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,
};
use super::{result, Coord, Handle, HandleType, InputRecord, WindowPositions};
/// A wrapper around a screen buffer.
#[derive(Debug, Clone)]
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 output() -> 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` functions, or echoed by the `ReadFile` or `ReadConsole` functions.
/// This function affects text written after the function call.
///
/// The attributes is a bitmask of possible [character
/// attributes](https://docs.microsoft.com/en-us/windows/console/console-screen-buffers#character-attributes).
///
/// This wraps
/// [`SetConsoleTextAttribute`](https://docs.microsoft.com/en-us/windows/console/setconsoletextattribute).
pub fn set_text_attribute(&self, value: u16) -> Result<()> {
result(unsafe { SetConsoleTextAttribute(*self.handle, value) })?;
Ok(())
}
/// Sets the current size and position of a console screen buffer's window.
///
/// This wraps
/// [`SetConsoleWindowInfo`](https://docs.microsoft.com/en-us/windows/console/setconsolewindowinfo).
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);
result(unsafe { SetConsoleWindowInfo(*self.handle, absolute, &a) })?;
Ok(())
}
/// Writes a character to the console screen buffer a specified number of times, beginning at the specified coordinates.
/// Returns the number of characters that have been written.
///
/// This wraps
/// [`FillConsoleOutputCharacterA`](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;
result(unsafe {
// fill the cells in console with blanks
FillConsoleOutputCharacterA(
*self.handle,
filling_char as i8,
cells_to_write,
COORD::from(start_location),
&mut chars_written,
)
})?;
Ok(chars_written)
}
/// Sets the character attributes for a specified number of character cells, beginning at the specified coordinates in a screen buffer.
/// Returns the number of cells that have been modified.
///
/// This wraps
/// [`FillConsoleOutputAttribute`](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
result(unsafe {
FillConsoleOutputAttribute(
*self.handle,
dw_attribute,
cells_to_write,
COORD::from(start_location),
&mut cells_written,
)
})?;
Ok(cells_written)
}
/// Retrieves the size of the largest possible console window, based on the current text and the size of the display.
///
/// This wraps [`GetLargestConsoleWindowSize`](https://docs.microsoft.com/en-us/windows/console/getlargestconsolewindowsize)
pub fn largest_window_size(&self) -> Result<Coord> {
crate::coord_result(unsafe { GetLargestConsoleWindowSize(*self.handle) })
}
/// Writes a character string to a console screen buffer beginning at the current cursor location.
///
/// This wraps
/// [`WriteConsoleW`](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;
result(unsafe {
WriteConsoleW(
*self.handle,
utf16_ptr,
utf16.len() as u32,
&mut cells_written,
NULL,
)
})?;
Ok(utf8.as_bytes().len())
}
/// Read one input event.
///
/// This wraps
/// [`ReadConsoleInputW`](https://docs.microsoft.com/en-us/windows/console/readconsoleinput).
pub fn read_single_input_event(&self) -> Result<InputRecord> {
let mut record: INPUT_RECORD = INPUT_RECORD::default();
{
// Convert an INPUT_RECORD to an &mut [INPUT_RECORD] of length 1
let buf = slice::from_mut(&mut record);
let num_read = self.read_input(buf)?;
// The windows API promises that ReadConsoleInput returns at least
// 1 element
debug_assert!(num_read == 1);
}
Ok(record.into())
}
/// Read all available input events without blocking.
///
/// This wraps
/// [`ReadConsoleInputW`](https://docs.microsoft.com/en-us/windows/console/readconsoleinput).
pub fn read_console_input(&self) -> Result<Vec<InputRecord>> {
let buf_len = self.number_of_console_input_events()?;
// Fast-skipping all the code below if there is nothing to read at all
if buf_len == 0 {
return Ok(vec![]);
}
let mut buf: Vec<INPUT_RECORD> = iter::repeat_with(INPUT_RECORD::default)
.take(buf_len as usize)
.collect();
let num_read = self.read_input(buf.as_mut_slice())?;
Ok(buf
.into_iter()
.take(num_read)
.map(InputRecord::from)
.collect())
}
/// Get the number of available input events that can be read without blocking.
///
/// This wraps
/// [`GetNumberOfConsoleInputEvents`](https://docs.microsoft.com/en-us/windows/console/getnumberofconsoleinputevents).
pub fn number_of_console_input_events(&self) -> Result<u32> {
let mut buf_len: DWORD = 0;
result(unsafe { GetNumberOfConsoleInputEvents(*self.handle, &mut buf_len) })?;
Ok(buf_len)
}
/// Read input (via ReadConsoleInputW) into buf and return the number
/// of events read. ReadConsoleInputW guarantees that at least one event
/// is read, even if it means blocking the thread. buf.len() must fit in
/// a u32.
fn read_input(&self, buf: &mut [INPUT_RECORD]) -> Result<usize> {
let mut num_records = 0;
debug_assert!(buf.len() < std::u32::MAX as usize);
result(unsafe {
ReadConsoleInputW(
*self.handle,
buf.as_mut_ptr(),
buf.len() as u32,
&mut num_records,
)
})?;
Ok(num_records as usize)
}
}
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 }
}
}

View file

@ -1,75 +1,75 @@
use std::io::Result;
use winapi::um::consoleapi::{GetConsoleMode, SetConsoleMode};
use super::{result, Handle, HandleType};
/// A wrapper around a screen buffer, focusing on calls to get and set the console mode.
///
/// This wraps [`SetConsoleMode`](https://docs.microsoft.com/en-us/windows/console/setconsolemode)
/// and [`GetConsoleMode`](https://docs.microsoft.com/en-us/windows/console/getconsolemode).
#[derive(Debug, Clone)]
pub struct ConsoleMode {
// the handle used for the functions of this type.
handle: Handle,
}
impl ConsoleMode {
/// Create a new `ConsoleMode` instance.
///
/// This will use the standard output as its handle.
/// When you explicitly want to specify the handle used for the function calls use `ConsoleMode::from(handle)` instead.
pub fn new() -> Result<ConsoleMode> {
Ok(ConsoleMode {
handle: Handle::new(HandleType::OutputHandle)?,
})
}
/// Set the console mode to the given console mode.
///
/// This function sets the `dwMode`.
///
/// This wraps
/// [`SetConsoleMode`](https://docs.microsoft.com/en-us/windows/console/setconsolemode).
pub fn set_mode(&self, console_mode: u32) -> Result<()> {
result(unsafe { SetConsoleMode(*self.handle, console_mode) })
}
/// Get the console mode.
///
/// This function returns the `lpMode`.
///
/// This wraps
/// [`GetConsoleMode`](https://docs.microsoft.com/en-us/windows/console/getconsolemode).
pub fn mode(&self) -> Result<u32> {
let mut console_mode = 0;
result(unsafe { GetConsoleMode(*self.handle, &mut console_mode) })?;
Ok(console_mode)
}
}
impl From<Handle> for ConsoleMode {
fn from(handle: Handle) -> Self {
ConsoleMode { handle }
}
}
#[cfg(test)]
mod tests {
use super::ConsoleMode;
// TODO - Test is ignored, because it's failing on Travis CI
#[test]
#[ignore]
fn test_set_get_mode() {
let mode = ConsoleMode::new().unwrap();
let original_mode = mode.mode().unwrap();
mode.set_mode(0x0004).unwrap();
let console_mode = mode.mode().unwrap();
assert_eq!(console_mode & 0x0004, mode.mode().unwrap());
mode.set_mode(original_mode).unwrap();
}
}
use std::io::Result;
use winapi::um::consoleapi::{GetConsoleMode, SetConsoleMode};
use super::{result, Handle, HandleType};
/// A wrapper around a screen buffer, focusing on calls to get and set the console mode.
///
/// This wraps [`SetConsoleMode`](https://docs.microsoft.com/en-us/windows/console/setconsolemode)
/// and [`GetConsoleMode`](https://docs.microsoft.com/en-us/windows/console/getconsolemode).
#[derive(Debug, Clone)]
pub struct ConsoleMode {
// the handle used for the functions of this type.
handle: Handle,
}
impl ConsoleMode {
/// Create a new `ConsoleMode` instance.
///
/// This will use the standard output as its handle.
/// When you explicitly want to specify the handle used for the function calls use `ConsoleMode::from(handle)` instead.
pub fn new() -> Result<ConsoleMode> {
Ok(ConsoleMode {
handle: Handle::new(HandleType::OutputHandle)?,
})
}
/// Set the console mode to the given console mode.
///
/// This function sets the `dwMode`.
///
/// This wraps
/// [`SetConsoleMode`](https://docs.microsoft.com/en-us/windows/console/setconsolemode).
pub fn set_mode(&self, console_mode: u32) -> Result<()> {
result(unsafe { SetConsoleMode(*self.handle, console_mode) })
}
/// Get the console mode.
///
/// This function returns the `lpMode`.
///
/// This wraps
/// [`GetConsoleMode`](https://docs.microsoft.com/en-us/windows/console/getconsolemode).
pub fn mode(&self) -> Result<u32> {
let mut console_mode = 0;
result(unsafe { GetConsoleMode(*self.handle, &mut console_mode) })?;
Ok(console_mode)
}
}
impl From<Handle> for ConsoleMode {
fn from(handle: Handle) -> Self {
ConsoleMode { handle }
}
}
#[cfg(test)]
mod tests {
use super::ConsoleMode;
// TODO - Test is ignored, because it's failing on Travis CI
#[test]
#[ignore]
fn test_set_get_mode() {
let mode = ConsoleMode::new().unwrap();
let original_mode = mode.mode().unwrap();
mode.set_mode(0x0004).unwrap();
let console_mode = mode.mode().unwrap();
assert_eq!(console_mode & 0x0004, mode.mode().unwrap());
mode.set_mode(original_mode).unwrap();
}
}

View file

@ -1,82 +1,82 @@
use std::fmt;
use std::mem::zeroed;
use winapi::um::wincon::CONSOLE_SCREEN_BUFFER_INFO;
use super::{Coord, Size, WindowPositions};
/// Information about a console screen buffer.
///
/// This wraps
/// [`CONSOLE_SCREEN_BUFFER_INFO`](https://docs.microsoft.com/en-us/windows/console/console-screen-buffer-info-str).
// TODO: replace the innards of this type with our own, more friendly types, like Coord.
// This will obviously be a breaking change.
#[derive(Clone)]
pub struct ScreenBufferInfo(pub CONSOLE_SCREEN_BUFFER_INFO);
// TODO: replace this with a derive ASAP
impl fmt::Debug for ScreenBufferInfo {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("ScreenBufferInfo")
.field("dwSize", &self.buffer_size())
.field("dwCursorPosition", &self.cursor_pos())
.field("wAttributes", &self.attributes()) // TODO: hex print this
.field("srWindow", &self.terminal_window())
.field(
"dwMaximumWindowSize",
&Size::from(self.0.dwMaximumWindowSize),
)
.finish()
}
}
impl ScreenBufferInfo {
/// Create a new console screen buffer without all zeroed properties.
pub fn new() -> ScreenBufferInfo {
ScreenBufferInfo(unsafe { zeroed() })
}
/// Get the size of the screen buffer.
///
/// Will take `dwSize` from the current screen buffer and convert it into a [`Size`].
pub fn buffer_size(&self) -> Size {
Size::from(self.0.dwSize)
}
/// Get the size of the terminal display window.
///
/// Will calculate the width and height from `srWindow` and convert it into a [`Size`].
pub fn terminal_size(&self) -> Size {
Size::new(
self.0.srWindow.Right - self.0.srWindow.Left,
self.0.srWindow.Bottom - self.0.srWindow.Top,
)
}
/// Get the position and size of the terminal display window.
///
/// Will take `srWindow` and convert it into the `WindowPositions` type.
pub fn terminal_window(&self) -> WindowPositions {
WindowPositions::from(self.0)
}
/// Get the current attributes of the characters that are being written to the console.
///
/// Will take `wAttributes` from the current screen buffer.
pub fn attributes(&self) -> u16 {
self.0.wAttributes
}
/// Get the current column and row of the terminal cursor in the screen buffer.
///
/// Will take `dwCursorPosition` from the current screen buffer.
pub fn cursor_pos(&self) -> Coord {
Coord::from(self.0.dwCursorPosition)
}
}
impl From<CONSOLE_SCREEN_BUFFER_INFO> for ScreenBufferInfo {
fn from(csbi: CONSOLE_SCREEN_BUFFER_INFO) -> Self {
ScreenBufferInfo(csbi)
}
}
use std::fmt;
use std::mem::zeroed;
use winapi::um::wincon::CONSOLE_SCREEN_BUFFER_INFO;
use super::{Coord, Size, WindowPositions};
/// Information about a console screen buffer.
///
/// This wraps
/// [`CONSOLE_SCREEN_BUFFER_INFO`](https://docs.microsoft.com/en-us/windows/console/console-screen-buffer-info-str).
// TODO: replace the innards of this type with our own, more friendly types, like Coord.
// This will obviously be a breaking change.
#[derive(Clone)]
pub struct ScreenBufferInfo(pub CONSOLE_SCREEN_BUFFER_INFO);
// TODO: replace this with a derive ASAP
impl fmt::Debug for ScreenBufferInfo {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("ScreenBufferInfo")
.field("dwSize", &self.buffer_size())
.field("dwCursorPosition", &self.cursor_pos())
.field("wAttributes", &self.attributes()) // TODO: hex print this
.field("srWindow", &self.terminal_window())
.field(
"dwMaximumWindowSize",
&Size::from(self.0.dwMaximumWindowSize),
)
.finish()
}
}
impl ScreenBufferInfo {
/// Create a new console screen buffer without all zeroed properties.
pub fn new() -> ScreenBufferInfo {
ScreenBufferInfo(unsafe { zeroed() })
}
/// Get the size of the screen buffer.
///
/// Will take `dwSize` from the current screen buffer and convert it into a [`Size`].
pub fn buffer_size(&self) -> Size {
Size::from(self.0.dwSize)
}
/// Get the size of the terminal display window.
///
/// Will calculate the width and height from `srWindow` and convert it into a [`Size`].
pub fn terminal_size(&self) -> Size {
Size::new(
self.0.srWindow.Right - self.0.srWindow.Left,
self.0.srWindow.Bottom - self.0.srWindow.Top,
)
}
/// Get the position and size of the terminal display window.
///
/// Will take `srWindow` and convert it into the `WindowPositions` type.
pub fn terminal_window(&self) -> WindowPositions {
WindowPositions::from(self.0)
}
/// Get the current attributes of the characters that are being written to the console.
///
/// Will take `wAttributes` from the current screen buffer.
pub fn attributes(&self) -> u16 {
self.0.wAttributes
}
/// Get the current column and row of the terminal cursor in the screen buffer.
///
/// Will take `dwCursorPosition` from the current screen buffer.
pub fn cursor_pos(&self) -> Coord {
Coord::from(self.0.dwCursorPosition)
}
}
impl From<CONSOLE_SCREEN_BUFFER_INFO> for ScreenBufferInfo {
fn from(csbi: CONSOLE_SCREEN_BUFFER_INFO) -> Self {
ScreenBufferInfo(csbi)
}
}

View file

@ -1,219 +1,219 @@
//! This module contains some logic for working with the console handle.
use std::io::Result;
use std::ops::Deref;
use std::ptr::null_mut;
use std::sync::Arc;
use winapi::shared::minwindef::DWORD;
use winapi::um::{
fileapi::{CreateFileW, OPEN_EXISTING},
handleapi::{CloseHandle, INVALID_HANDLE_VALUE},
processenv::GetStdHandle,
winbase::{STD_INPUT_HANDLE, STD_OUTPUT_HANDLE},
winnt::{FILE_SHARE_READ, FILE_SHARE_WRITE, GENERIC_READ, GENERIC_WRITE, HANDLE},
};
use super::handle_result;
/// The standard handles of a process.
///
/// See [the Windows documentation on console
/// handles](https://docs.microsoft.com/en-us/windows/console/console-handles) for more info.
#[derive(Debug, Clone, Copy)]
pub enum HandleType {
/// The process' standard output.
OutputHandle,
/// The process' standard input.
InputHandle,
/// The process' active console screen buffer, `CONOUT$`.
CurrentOutputHandle,
/// The process' console input buffer, `CONIN$`.
CurrentInputHandle,
}
/// Inner structure for closing a handle on Drop.
///
/// The second parameter indicates if the HANDLE is exclusively owned or not.
/// A non-exclusive handle can be created using for example
/// `Handle::input_handle` or `Handle::output_handle`, which corresponds to
/// stdin and stdout respectively.
#[derive(Debug)]
struct Inner {
handle: HANDLE,
is_exclusive: bool,
}
impl Inner {
fn new_exclusive(handle: HANDLE) -> Self {
Inner {
handle,
is_exclusive: true,
}
}
fn new_shared(handle: HANDLE) -> Self {
Inner {
handle,
is_exclusive: false,
}
}
}
impl Drop for Inner {
fn drop(&mut self) {
if self.is_exclusive {
assert!(
unsafe { CloseHandle(self.handle) != 0 },
"failed to close handle"
)
}
}
}
unsafe impl Send for Inner {}
unsafe impl Sync for Inner {}
/// This abstracts away some WinAPI calls to set and get some console handles.
///
/// It wraps WinAPI's [`HANDLE`] type.
#[derive(Debug, Clone)]
pub struct Handle {
handle: Arc<Inner>,
}
impl Handle {
/// Create a new handle of a certaint type.
pub fn new(handle: HandleType) -> Result<Handle> {
match handle {
HandleType::OutputHandle => Handle::output_handle(),
HandleType::InputHandle => Handle::input_handle(),
HandleType::CurrentOutputHandle => Handle::current_out_handle(),
HandleType::CurrentInputHandle => Handle::current_in_handle(),
}
}
/// Construct a handle from a raw handle.
///
/// # Safety
///
/// This is unsafe since there is not guarantee that the underlying HANDLE is thread-safe to implement `Send` and `Sync`.
/// Most HANDLE's however, are thread safe.
pub unsafe fn from_raw(handle: HANDLE) -> Self {
Self {
handle: Arc::new(Inner::new_exclusive(handle)),
}
}
/// Get the handle of the active screen buffer.
/// When using multiple screen buffers this will always point to the to the current screen output buffer.
///
/// This function uses `CONOUT$` to create a file handle to the current output buffer.
///
/// This wraps
/// [`CreateFileW`](https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilew).
pub fn current_out_handle() -> Result<Handle> {
let utf16: Vec<u16> = "CONOUT$\0".encode_utf16().collect();
let utf16_ptr: *const u16 = utf16.as_ptr();
let handle = handle_result(unsafe {
CreateFileW(
utf16_ptr,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
null_mut(),
OPEN_EXISTING,
0,
null_mut(),
)
})?;
Ok(Handle {
handle: Arc::new(Inner::new_exclusive(handle)),
})
}
/// Get the handle of the console input buffer.
///
/// This function uses `CONIN$` to create a file handle to the current input buffer.
///
/// This wraps
/// [`CreateFileW`](https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilew).
pub fn current_in_handle() -> Result<Handle> {
let utf16: Vec<u16> = "CONIN$\0".encode_utf16().collect();
let utf16_ptr: *const u16 = utf16.as_ptr();
let handle = handle_result(unsafe {
CreateFileW(
utf16_ptr,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
null_mut(),
OPEN_EXISTING,
0,
null_mut(),
)
})?;
Ok(Handle {
handle: Arc::new(Inner::new_exclusive(handle)),
})
}
/// Get the handle of the standard output.
///
/// On success this function returns the `HANDLE` to `STD_OUTPUT_HANDLE`.
///
/// This wraps [`GetStdHandle`](https://docs.microsoft.com/en-us/windows/console/getstdhandle)
/// called with `STD_OUTPUT_HANDLE`.
pub fn output_handle() -> Result<Handle> {
Self::std_handle(STD_OUTPUT_HANDLE)
}
/// Get the handle of the input screen buffer.
///
/// On success this function returns the `HANDLE` to `STD_INPUT_HANDLE`.
///
/// This wraps [`GetStdHandle`](https://docs.microsoft.com/en-us/windows/console/getstdhandle)
/// called with `STD_INPUT_HANDLE`.
pub fn input_handle() -> Result<Handle> {
Self::std_handle(STD_INPUT_HANDLE)
}
fn std_handle(which_std: DWORD) -> Result<Handle> {
let handle = handle_result(unsafe { GetStdHandle(which_std) })?;
Ok(Handle {
handle: Arc::new(Inner::new_shared(handle)),
})
}
/// Checks if the console handle is an invalid handle value.
///
/// This is done by checking if the passed `HANDLE` is equal to `INVALID_HANDLE_VALUE`.
pub fn is_valid_handle(handle: &HANDLE) -> bool {
*handle != INVALID_HANDLE_VALUE
}
}
impl Deref for Handle {
type Target = HANDLE;
fn deref(&self) -> &HANDLE {
&self.handle.handle
}
}
#[cfg(test)]
mod tests {
use super::{Handle, HandleType};
#[test]
fn test_get_handle() {
assert!(Handle::new(HandleType::OutputHandle).is_ok());
assert!(Handle::new(HandleType::InputHandle).is_ok());
assert!(Handle::new(HandleType::CurrentOutputHandle).is_ok());
assert!(Handle::new(HandleType::CurrentInputHandle).is_ok());
}
}
//! This module contains some logic for working with the console handle.
use std::io::Result;
use std::ops::Deref;
use std::ptr::null_mut;
use std::sync::Arc;
use winapi::shared::minwindef::DWORD;
use winapi::um::{
fileapi::{CreateFileW, OPEN_EXISTING},
handleapi::{CloseHandle, INVALID_HANDLE_VALUE},
processenv::GetStdHandle,
winbase::{STD_INPUT_HANDLE, STD_OUTPUT_HANDLE},
winnt::{FILE_SHARE_READ, FILE_SHARE_WRITE, GENERIC_READ, GENERIC_WRITE, HANDLE},
};
use super::handle_result;
/// The standard handles of a process.
///
/// See [the Windows documentation on console
/// handles](https://docs.microsoft.com/en-us/windows/console/console-handles) for more info.
#[derive(Debug, Clone, Copy)]
pub enum HandleType {
/// The process' standard output.
OutputHandle,
/// The process' standard input.
InputHandle,
/// The process' active console screen buffer, `CONOUT$`.
CurrentOutputHandle,
/// The process' console input buffer, `CONIN$`.
CurrentInputHandle,
}
/// Inner structure for closing a handle on Drop.
///
/// The second parameter indicates if the HANDLE is exclusively owned or not.
/// A non-exclusive handle can be created using for example
/// `Handle::input_handle` or `Handle::output_handle`, which corresponds to
/// stdin and stdout respectively.
#[derive(Debug)]
struct Inner {
handle: HANDLE,
is_exclusive: bool,
}
impl Inner {
fn new_exclusive(handle: HANDLE) -> Self {
Inner {
handle,
is_exclusive: true,
}
}
fn new_shared(handle: HANDLE) -> Self {
Inner {
handle,
is_exclusive: false,
}
}
}
impl Drop for Inner {
fn drop(&mut self) {
if self.is_exclusive {
assert!(
unsafe { CloseHandle(self.handle) != 0 },
"failed to close handle"
)
}
}
}
unsafe impl Send for Inner {}
unsafe impl Sync for Inner {}
/// This abstracts away some WinAPI calls to set and get some console handles.
///
/// It wraps WinAPI's [`HANDLE`] type.
#[derive(Debug, Clone)]
pub struct Handle {
handle: Arc<Inner>,
}
impl Handle {
/// Create a new handle of a certaint type.
pub fn new(handle: HandleType) -> Result<Handle> {
match handle {
HandleType::OutputHandle => Handle::output_handle(),
HandleType::InputHandle => Handle::input_handle(),
HandleType::CurrentOutputHandle => Handle::current_out_handle(),
HandleType::CurrentInputHandle => Handle::current_in_handle(),
}
}
/// Construct a handle from a raw handle.
///
/// # Safety
///
/// This is unsafe since there is not guarantee that the underlying HANDLE is thread-safe to implement `Send` and `Sync`.
/// Most HANDLE's however, are thread safe.
pub unsafe fn from_raw(handle: HANDLE) -> Self {
Self {
handle: Arc::new(Inner::new_exclusive(handle)),
}
}
/// Get the handle of the active screen buffer.
/// When using multiple screen buffers this will always point to the to the current screen output buffer.
///
/// This function uses `CONOUT$` to create a file handle to the current output buffer.
///
/// This wraps
/// [`CreateFileW`](https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilew).
pub fn current_out_handle() -> Result<Handle> {
let utf16: Vec<u16> = "CONOUT$\0".encode_utf16().collect();
let utf16_ptr: *const u16 = utf16.as_ptr();
let handle = handle_result(unsafe {
CreateFileW(
utf16_ptr,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
null_mut(),
OPEN_EXISTING,
0,
null_mut(),
)
})?;
Ok(Handle {
handle: Arc::new(Inner::new_exclusive(handle)),
})
}
/// Get the handle of the console input buffer.
///
/// This function uses `CONIN$` to create a file handle to the current input buffer.
///
/// This wraps
/// [`CreateFileW`](https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilew).
pub fn current_in_handle() -> Result<Handle> {
let utf16: Vec<u16> = "CONIN$\0".encode_utf16().collect();
let utf16_ptr: *const u16 = utf16.as_ptr();
let handle = handle_result(unsafe {
CreateFileW(
utf16_ptr,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
null_mut(),
OPEN_EXISTING,
0,
null_mut(),
)
})?;
Ok(Handle {
handle: Arc::new(Inner::new_exclusive(handle)),
})
}
/// Get the handle of the standard output.
///
/// On success this function returns the `HANDLE` to `STD_OUTPUT_HANDLE`.
///
/// This wraps [`GetStdHandle`](https://docs.microsoft.com/en-us/windows/console/getstdhandle)
/// called with `STD_OUTPUT_HANDLE`.
pub fn output_handle() -> Result<Handle> {
Self::std_handle(STD_OUTPUT_HANDLE)
}
/// Get the handle of the input screen buffer.
///
/// On success this function returns the `HANDLE` to `STD_INPUT_HANDLE`.
///
/// This wraps [`GetStdHandle`](https://docs.microsoft.com/en-us/windows/console/getstdhandle)
/// called with `STD_INPUT_HANDLE`.
pub fn input_handle() -> Result<Handle> {
Self::std_handle(STD_INPUT_HANDLE)
}
fn std_handle(which_std: DWORD) -> Result<Handle> {
let handle = handle_result(unsafe { GetStdHandle(which_std) })?;
Ok(Handle {
handle: Arc::new(Inner::new_shared(handle)),
})
}
/// Checks if the console handle is an invalid handle value.
///
/// This is done by checking if the passed `HANDLE` is equal to `INVALID_HANDLE_VALUE`.
pub fn is_valid_handle(handle: &HANDLE) -> bool {
*handle != INVALID_HANDLE_VALUE
}
}
impl Deref for Handle {
type Target = HANDLE;
fn deref(&self) -> &HANDLE {
&self.handle.handle
}
}
#[cfg(test)]
mod tests {
use super::{Handle, HandleType};
#[test]
fn test_get_handle() {
assert!(Handle::new(HandleType::OutputHandle).is_ok());
assert!(Handle::new(HandleType::InputHandle).is_ok());
assert!(Handle::new(HandleType::CurrentOutputHandle).is_ok());
assert!(Handle::new(HandleType::CurrentInputHandle).is_ok());
}
}

View file

@ -1,71 +1,71 @@
#![cfg(windows)]
#![deny(unused_imports)]
use std::io;
use winapi::shared::minwindef::BOOL;
use winapi::um::handleapi::INVALID_HANDLE_VALUE;
use winapi::um::wincontypes::COORD;
use winapi::um::winnt::HANDLE;
pub use self::{
console::Console,
console_mode::ConsoleMode,
csbi::ScreenBufferInfo,
handle::{Handle, HandleType},
screen_buffer::ScreenBuffer,
semaphore::Semaphore,
structs::{
ButtonState, ControlKeyState, Coord, EventFlags, InputRecord, KeyEventRecord, MouseEvent,
Size, WindowPositions,
},
};
mod console;
mod console_mode;
mod csbi;
mod handle;
mod screen_buffer;
mod semaphore;
mod structs;
/// Get the result of a call to WinAPI as an [`io::Result`].
#[inline]
pub fn result(return_value: BOOL) -> io::Result<()> {
if return_value != 0 {
Ok(())
} else {
Err(io::Error::last_os_error())
}
}
/// Get the result of a call to WinAPI that returns a
/// [`COORD`](https://docs.microsoft.com/en-us/windows/console/coord-str) as an [`io::Result`].
#[inline]
pub fn coord_result(return_value: COORD) -> io::Result<Coord> {
if return_value.X != 0 && return_value.Y != 0 {
Ok(Coord::from(return_value))
} else {
Err(io::Error::last_os_error())
}
}
/// Get the result of a call to WinAPI that returns a handle or `INVALID_HANDLE_VALUE`.
#[inline]
pub fn handle_result(return_value: HANDLE) -> io::Result<HANDLE> {
if return_value != INVALID_HANDLE_VALUE {
Ok(return_value)
} else {
Err(io::Error::last_os_error())
}
}
/// Get the result of a call to WinAPI that returns a handle or `NULL`.
#[inline]
pub fn nonnull_handle_result(return_value: HANDLE) -> io::Result<HANDLE> {
if return_value.is_null() {
Err(io::Error::last_os_error())
} else {
Ok(return_value)
}
}
#![cfg(windows)]
#![deny(unused_imports)]
use std::io;
use winapi::shared::minwindef::BOOL;
use winapi::um::handleapi::INVALID_HANDLE_VALUE;
use winapi::um::wincontypes::COORD;
use winapi::um::winnt::HANDLE;
pub use self::{
console::Console,
console_mode::ConsoleMode,
csbi::ScreenBufferInfo,
handle::{Handle, HandleType},
screen_buffer::ScreenBuffer,
semaphore::Semaphore,
structs::{
ButtonState, ControlKeyState, Coord, EventFlags, InputRecord, KeyEventRecord, MouseEvent,
Size, WindowPositions,
},
};
mod console;
mod console_mode;
mod csbi;
mod handle;
mod screen_buffer;
mod semaphore;
mod structs;
/// Get the result of a call to WinAPI as an [`io::Result`].
#[inline]
pub fn result(return_value: BOOL) -> io::Result<()> {
if return_value != 0 {
Ok(())
} else {
Err(io::Error::last_os_error())
}
}
/// Get the result of a call to WinAPI that returns a
/// [`COORD`](https://docs.microsoft.com/en-us/windows/console/coord-str) as an [`io::Result`].
#[inline]
pub fn coord_result(return_value: COORD) -> io::Result<Coord> {
if return_value.X != 0 && return_value.Y != 0 {
Ok(Coord::from(return_value))
} else {
Err(io::Error::last_os_error())
}
}
/// Get the result of a call to WinAPI that returns a handle or `INVALID_HANDLE_VALUE`.
#[inline]
pub fn handle_result(return_value: HANDLE) -> io::Result<HANDLE> {
if return_value != INVALID_HANDLE_VALUE {
Ok(return_value)
} else {
Err(io::Error::last_os_error())
}
}
/// Get the result of a call to WinAPI that returns a handle or `NULL`.
#[inline]
pub fn nonnull_handle_result(return_value: HANDLE) -> io::Result<HANDLE> {
if return_value.is_null() {
Err(io::Error::last_os_error())
} else {
Ok(return_value)
}
}

View file

@ -1,117 +1,117 @@
//! This contains the logic for working with the console buffer.
use std::io::Result;
use std::mem::size_of;
use winapi::{
shared::minwindef::TRUE,
shared::ntdef::NULL,
um::{
minwinbase::SECURITY_ATTRIBUTES,
wincon::{
CreateConsoleScreenBuffer, GetConsoleScreenBufferInfo, SetConsoleActiveScreenBuffer,
SetConsoleScreenBufferSize, CONSOLE_TEXTMODE_BUFFER, COORD,
},
winnt::{FILE_SHARE_READ, FILE_SHARE_WRITE, GENERIC_READ, GENERIC_WRITE},
},
};
use super::{handle_result, result, Handle, HandleType, ScreenBufferInfo};
/// A wrapper around a screen buffer.
#[derive(Clone, Debug)]
pub struct ScreenBuffer {
handle: Handle,
}
impl ScreenBuffer {
/// Create a wrapper around a screen buffer from its handle.
pub fn new(handle: Handle) -> Self {
Self { handle }
}
/// Get the current console screen buffer
pub fn current() -> Result<ScreenBuffer> {
Ok(ScreenBuffer {
handle: Handle::new(HandleType::CurrentOutputHandle)?,
})
}
/// Create new console screen buffer.
///
/// This wraps
/// [`CreateConsoleScreenBuffer`](https://docs.microsoft.com/en-us/windows/console/createconsolescreenbuffer)
pub fn create() -> Result<ScreenBuffer> {
let security_attr: SECURITY_ATTRIBUTES = SECURITY_ATTRIBUTES {
nLength: size_of::<SECURITY_ATTRIBUTES>() as u32,
lpSecurityDescriptor: NULL,
bInheritHandle: TRUE,
};
let new_screen_buffer = handle_result(unsafe {
CreateConsoleScreenBuffer(
GENERIC_READ | // read/write access
GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE, // shared
&security_attr, // default security attributes
CONSOLE_TEXTMODE_BUFFER, // must be TEXTMODE
NULL,
)
})?;
Ok(ScreenBuffer {
handle: unsafe { Handle::from_raw(new_screen_buffer) },
})
}
/// Set this screen buffer to the current one.
///
/// This wraps
/// [`SetConsoleActiveScreenBuffer`](https://docs.microsoft.com/en-us/windows/console/setconsoleactivescreenbuffer).
pub fn show(&self) -> Result<()> {
result(unsafe { SetConsoleActiveScreenBuffer(*self.handle) })
}
/// Get the screen buffer information like terminal size, cursor position, buffer size.
///
/// This wraps
/// [`GetConsoleScreenBufferInfo`](https://docs.microsoft.com/en-us/windows/console/getconsolescreenbufferinfo).
pub fn info(&self) -> Result<ScreenBufferInfo> {
let mut csbi = ScreenBufferInfo::new();
result(unsafe { GetConsoleScreenBufferInfo(*self.handle, &mut csbi.0) })?;
Ok(csbi)
}
/// Set the console screen buffer size to the given size.
///
/// This wraps
/// [`SetConsoleScreenBufferSize`](https://docs.microsoft.com/en-us/windows/console/setconsolescreenbuffersize).
pub fn set_size(&self, x: i16, y: i16) -> Result<()> {
result(unsafe { SetConsoleScreenBufferSize(*self.handle, COORD { X: x, Y: y }) })
}
/// Get the underlying raw `HANDLE` used by this type to execute with.
pub fn handle(&self) -> &Handle {
&self.handle
}
}
impl From<Handle> for ScreenBuffer {
fn from(handle: Handle) -> Self {
ScreenBuffer { handle }
}
}
#[cfg(test)]
mod tests {
use super::ScreenBuffer;
#[test]
fn test_screen_buffer_info() {
let buffer = ScreenBuffer::current().unwrap();
let info = buffer.info().unwrap();
info.terminal_size();
info.terminal_window();
info.attributes();
info.cursor_pos();
}
}
//! This contains the logic for working with the console buffer.
use std::io::Result;
use std::mem::size_of;
use winapi::{
shared::minwindef::TRUE,
shared::ntdef::NULL,
um::{
minwinbase::SECURITY_ATTRIBUTES,
wincon::{
CreateConsoleScreenBuffer, GetConsoleScreenBufferInfo, SetConsoleActiveScreenBuffer,
SetConsoleScreenBufferSize, CONSOLE_TEXTMODE_BUFFER, COORD,
},
winnt::{FILE_SHARE_READ, FILE_SHARE_WRITE, GENERIC_READ, GENERIC_WRITE},
},
};
use super::{handle_result, result, Handle, HandleType, ScreenBufferInfo};
/// A wrapper around a screen buffer.
#[derive(Clone, Debug)]
pub struct ScreenBuffer {
handle: Handle,
}
impl ScreenBuffer {
/// Create a wrapper around a screen buffer from its handle.
pub fn new(handle: Handle) -> Self {
Self { handle }
}
/// Get the current console screen buffer
pub fn current() -> Result<ScreenBuffer> {
Ok(ScreenBuffer {
handle: Handle::new(HandleType::CurrentOutputHandle)?,
})
}
/// Create new console screen buffer.
///
/// This wraps
/// [`CreateConsoleScreenBuffer`](https://docs.microsoft.com/en-us/windows/console/createconsolescreenbuffer)
pub fn create() -> Result<ScreenBuffer> {
let security_attr: SECURITY_ATTRIBUTES = SECURITY_ATTRIBUTES {
nLength: size_of::<SECURITY_ATTRIBUTES>() as u32,
lpSecurityDescriptor: NULL,
bInheritHandle: TRUE,
};
let new_screen_buffer = handle_result(unsafe {
CreateConsoleScreenBuffer(
GENERIC_READ | // read/write access
GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE, // shared
&security_attr, // default security attributes
CONSOLE_TEXTMODE_BUFFER, // must be TEXTMODE
NULL,
)
})?;
Ok(ScreenBuffer {
handle: unsafe { Handle::from_raw(new_screen_buffer) },
})
}
/// Set this screen buffer to the current one.
///
/// This wraps
/// [`SetConsoleActiveScreenBuffer`](https://docs.microsoft.com/en-us/windows/console/setconsoleactivescreenbuffer).
pub fn show(&self) -> Result<()> {
result(unsafe { SetConsoleActiveScreenBuffer(*self.handle) })
}
/// Get the screen buffer information like terminal size, cursor position, buffer size.
///
/// This wraps
/// [`GetConsoleScreenBufferInfo`](https://docs.microsoft.com/en-us/windows/console/getconsolescreenbufferinfo).
pub fn info(&self) -> Result<ScreenBufferInfo> {
let mut csbi = ScreenBufferInfo::new();
result(unsafe { GetConsoleScreenBufferInfo(*self.handle, &mut csbi.0) })?;
Ok(csbi)
}
/// Set the console screen buffer size to the given size.
///
/// This wraps
/// [`SetConsoleScreenBufferSize`](https://docs.microsoft.com/en-us/windows/console/setconsolescreenbuffersize).
pub fn set_size(&self, x: i16, y: i16) -> Result<()> {
result(unsafe { SetConsoleScreenBufferSize(*self.handle, COORD { X: x, Y: y }) })
}
/// Get the underlying raw `HANDLE` used by this type to execute with.
pub fn handle(&self) -> &Handle {
&self.handle
}
}
impl From<Handle> for ScreenBuffer {
fn from(handle: Handle) -> Self {
ScreenBuffer { handle }
}
}
#[cfg(test)]
mod tests {
use super::ScreenBuffer;
#[test]
fn test_screen_buffer_info() {
let buffer = ScreenBuffer::current().unwrap();
let info = buffer.info().unwrap();
info.terminal_size();
info.terminal_window();
info.attributes();
info.cursor_pos();
}
}

View file

@ -1,41 +1,41 @@
use std::{io, ptr};
use winapi::um::synchapi::{CreateSemaphoreW, ReleaseSemaphore};
use crate::{nonnull_handle_result, result, Handle};
/// A [Windows semaphore](https://docs.microsoft.com/en-us/windows/win32/sync/semaphore-objects).
#[derive(Clone, Debug)]
pub struct Semaphore(Handle);
impl Semaphore {
/// Construct a new semaphore.
///
/// This wraps
/// [`CreateSemaphoreW`](https://docs.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-createsemaphorew).
pub fn new() -> io::Result<Self> {
let handle = nonnull_handle_result(unsafe {
CreateSemaphoreW(ptr::null_mut(), 0, 1, ptr::null_mut())
})?;
let handle = unsafe { Handle::from_raw(handle) };
Ok(Self(handle))
}
/// Release a permit on the semaphore.
///
/// This wraps
/// [`ReleaseSemaphore`](https://docs.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-releasesemaphore).
pub fn release(&self) -> io::Result<()> {
result(unsafe { ReleaseSemaphore(*self.0, 1, ptr::null_mut()) })
}
/// Access the underlying handle to the semaphore.
pub fn handle(&self) -> &Handle {
&self.0
}
}
unsafe impl Send for Semaphore {}
unsafe impl Sync for Semaphore {}
use std::{io, ptr};
use winapi::um::synchapi::{CreateSemaphoreW, ReleaseSemaphore};
use crate::{nonnull_handle_result, result, Handle};
/// A [Windows semaphore](https://docs.microsoft.com/en-us/windows/win32/sync/semaphore-objects).
#[derive(Clone, Debug)]
pub struct Semaphore(Handle);
impl Semaphore {
/// Construct a new semaphore.
///
/// This wraps
/// [`CreateSemaphoreW`](https://docs.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-createsemaphorew).
pub fn new() -> io::Result<Self> {
let handle = nonnull_handle_result(unsafe {
CreateSemaphoreW(ptr::null_mut(), 0, 1, ptr::null_mut())
})?;
let handle = unsafe { Handle::from_raw(handle) };
Ok(Self(handle))
}
/// Release a permit on the semaphore.
///
/// This wraps
/// [`ReleaseSemaphore`](https://docs.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-releasesemaphore).
pub fn release(&self) -> io::Result<()> {
result(unsafe { ReleaseSemaphore(*self.0, 1, ptr::null_mut()) })
}
/// Access the underlying handle to the semaphore.
pub fn handle(&self) -> &Handle {
&self.0
}
}
unsafe impl Send for Semaphore {}
unsafe impl Sync for Semaphore {}

View file

@ -1,11 +1,11 @@
pub use self::coord::Coord;
pub use self::input::{
ButtonState, ControlKeyState, EventFlags, InputRecord, KeyEventRecord, MouseEvent,
};
pub use self::size::Size;
pub use self::window_coords::WindowPositions;
mod coord;
mod input;
mod size;
mod window_coords;
pub use self::coord::Coord;
pub use self::input::{
ButtonState, ControlKeyState, EventFlags, InputRecord, KeyEventRecord, MouseEvent,
};
pub use self::size::Size;
pub use self::window_coords::WindowPositions;
mod coord;
mod input;
mod size;
mod window_coords;

View file

@ -1,42 +1,42 @@
//! This module provides a type that represents some location/coordination.
//! For example, in WinAPI we have `COORD` which looks and feels inconvenient.
//! This module provides also some trait implementations who will make parsing and working with `COORD` easier.
use winapi::um::wincon::COORD;
/// This is type represents the position of something on a certain 'x' and 'y'.
#[derive(Copy, Clone, Debug, Default, Eq, PartialEq, PartialOrd)]
pub struct Coord {
/// the position on the x axis
pub x: i16,
/// the position on the y axis
pub y: i16,
}
impl Coord {
/// Create a new coordinate from its x and y position.
pub fn new(x: i16, y: i16) -> Coord {
Coord { x, y }
}
}
impl From<COORD> for Coord {
fn from(coord: COORD) -> Self {
Coord::new(coord.X, coord.Y)
}
}
impl From<Coord> for COORD {
fn from(location: Coord) -> Self {
COORD {
X: location.x,
Y: location.y,
}
}
}
impl Into<(u16, u16)> for Coord {
fn into(self) -> (u16, u16) {
(self.x as u16, self.y as u16)
}
}
//! This module provides a type that represents some location/coordination.
//! For example, in WinAPI we have `COORD` which looks and feels inconvenient.
//! This module provides also some trait implementations who will make parsing and working with `COORD` easier.
use winapi::um::wincon::COORD;
/// This is type represents the position of something on a certain 'x' and 'y'.
#[derive(Copy, Clone, Debug, Default, Eq, PartialEq, PartialOrd)]
pub struct Coord {
/// the position on the x axis
pub x: i16,
/// the position on the y axis
pub y: i16,
}
impl Coord {
/// Create a new coordinate from its x and y position.
pub fn new(x: i16, y: i16) -> Coord {
Coord { x, y }
}
}
impl From<COORD> for Coord {
fn from(coord: COORD) -> Self {
Coord::new(coord.X, coord.Y)
}
}
impl From<Coord> for COORD {
fn from(location: Coord) -> Self {
COORD {
X: location.x,
Y: location.y,
}
}
}
impl Into<(u16, u16)> for Coord {
fn into(self) -> (u16, u16) {
(self.x as u16, self.y as u16)
}
}

View file

@ -1,327 +1,327 @@
//! This module provides a few structs to wrap common input struts to a rusty interface
//!
//! Types like:
//! - `KEY_EVENT_RECORD`
//! - `MOUSE_EVENT_RECORD`
//! - `ControlKeyState`
//! - `ButtonState`
//! - `EventFlags`
//! - `InputEventType`
//! - `INPUT_RECORD`
use winapi::shared::minwindef::DWORD;
use winapi::um::wincon::{
FOCUS_EVENT, FOCUS_EVENT_RECORD, FROM_LEFT_1ST_BUTTON_PRESSED, FROM_LEFT_2ND_BUTTON_PRESSED,
FROM_LEFT_3RD_BUTTON_PRESSED, FROM_LEFT_4TH_BUTTON_PRESSED, INPUT_RECORD, KEY_EVENT,
KEY_EVENT_RECORD, MENU_EVENT, MENU_EVENT_RECORD, MOUSE_EVENT, MOUSE_EVENT_RECORD,
RIGHTMOST_BUTTON_PRESSED, WINDOW_BUFFER_SIZE_EVENT, WINDOW_BUFFER_SIZE_RECORD,
};
use super::Coord;
use crate::ScreenBuffer;
/// A [keyboard input event](https://docs.microsoft.com/en-us/windows/console/key-event-record-str).
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct KeyEventRecord {
/// If the key is pressed, this member is true. Otherwise, this member is
/// false (the key is released).
pub key_down: bool,
/// The repeat count, which indicates that a key is being held down.
/// For example, when a key is held down, you might get five events with
/// this member equal to 1, one event with this member equal to 5, or
/// multiple events with this member greater than or equal to 1.
pub repeat_count: u16,
/// A virtual-key code that identifies the given key in a
/// device-independent manner.
pub virtual_key_code: u16,
/// The virtual scan code of the given key that represents the
/// device-dependent value generated by the keyboard hardware.
pub virtual_scan_code: u16,
/// The translated Unicode character (as a WCHAR, or utf-16 value)
pub u_char: u16,
/// The state of the control keys.
pub control_key_state: ControlKeyState,
}
impl KeyEventRecord {
/// Convert a `KEY_EVENT_RECORD` to KeyEventRecord. This function is private
/// because the `KEY_EVENT_RECORD` has several union fields for characters
/// (u8 vs u16) that we always interpret as u16. We always use the wide
/// versions of windows API calls to support this.
#[inline]
fn from_winapi(record: &KEY_EVENT_RECORD) -> Self {
KeyEventRecord {
key_down: record.bKeyDown != 0,
repeat_count: record.wRepeatCount,
virtual_key_code: record.wVirtualKeyCode,
virtual_scan_code: record.wVirtualScanCode,
u_char: unsafe { *record.uChar.UnicodeChar() },
control_key_state: ControlKeyState(record.dwControlKeyState),
}
}
}
/// A [mouse input event](https://docs.microsoft.com/en-us/windows/console/mouse-event-record-str).
#[derive(PartialEq, Debug, Copy, Clone, Eq)]
pub struct MouseEvent {
/// The position of the mouse when the event occurred in cell coordinates.
pub mouse_position: Coord,
/// The state of the mouse's buttons.
pub button_state: ButtonState,
/// The state of the control keys.
pub control_key_state: ControlKeyState,
/// What type of mouse event it is.
pub event_flags: EventFlags,
}
impl From<MOUSE_EVENT_RECORD> for MouseEvent {
#[inline]
fn from(event: MOUSE_EVENT_RECORD) -> Self {
MouseEvent {
mouse_position: event.dwMousePosition.into(),
button_state: event.dwButtonState.into(),
control_key_state: ControlKeyState(event.dwControlKeyState),
event_flags: event.dwEventFlags.into(),
}
}
}
/// The status of the mouse buttons.
/// The least significant bit corresponds to the leftmost mouse button.
/// The next least significant bit corresponds to the rightmost mouse button.
/// The next bit indicates the next-to-leftmost mouse button.
/// The bits then correspond left to right to the mouse buttons.
/// A bit is 1 if the button was pressed.
///
/// The state can be one of the following:
///
/// ```
/// # enum __ {
/// Release = 0x0000,
/// /// The leftmost mouse button.
/// FromLeft1stButtonPressed = 0x0001,
/// /// The second button from the left.
/// FromLeft2ndButtonPressed = 0x0004,
/// /// The third button from the left.
/// FromLeft3rdButtonPressed = 0x0008,
/// /// The fourth button from the left.
/// FromLeft4thButtonPressed = 0x0010,
/// /// The rightmost mouse button.
/// RightmostButtonPressed = 0x0002,
/// /// This button state is not recognized.
/// Unknown = 0x0021,
/// /// The wheel was rotated backward, toward the user; this will only be activated for `MOUSE_WHEELED ` from `dwEventFlags`
/// Negative = 0x0020,
/// # }
/// ```
///
/// [Ms Docs](https://docs.microsoft.com/en-us/windows/console/mouse-event-record-str#members)
#[derive(PartialEq, Debug, Copy, Clone, Eq)]
pub struct ButtonState {
state: i32,
}
impl From<DWORD> for ButtonState {
#[inline]
fn from(event: DWORD) -> Self {
let state = event as i32;
ButtonState { state }
}
}
impl ButtonState {
/// Get whether no buttons are being pressed.
pub fn release_button(&self) -> bool {
self.state == 0
}
/// Returns whether the left button was pressed.
pub fn left_button(&self) -> bool {
self.state as u32 & FROM_LEFT_1ST_BUTTON_PRESSED != 0
}
/// Returns whether the right button was pressed.
pub fn right_button(&self) -> bool {
self.state as u32
& (RIGHTMOST_BUTTON_PRESSED
| FROM_LEFT_3RD_BUTTON_PRESSED
| FROM_LEFT_4TH_BUTTON_PRESSED)
!= 0
}
/// Returns whether the right button was pressed.
pub fn middle_button(&self) -> bool {
self.state as u32 & FROM_LEFT_2ND_BUTTON_PRESSED != 0
}
/// Returns whether there is a down scroll.
pub fn scroll_down(&self) -> bool {
self.state < 0
}
/// Returns whether there is a up scroll.
pub fn scroll_up(&self) -> bool {
self.state > 0
}
/// Returns the raw state.
pub fn state(&self) -> i32 {
self.state
}
}
/// The state of the control keys.
///
/// This is a bitmask of the following values.
///
/// | Description | Value |
/// | --- | --- |
/// | The right alt key is pressed | `0x0001` |
/// | The left alt key is pressed | `x0002` |
/// | The right control key is pressed | `0x0004` |
/// | The left control key is pressed | `x0008` |
/// | The shift key is pressed | `0x0010` |
/// | The num lock light is on | `0x0020` |
/// | The scroll lock light is on | `0x0040` |
/// | The caps lock light is on | `0x0080` |
/// | The key is [enhanced](https://docs.microsoft.com/en-us/windows/console/key-event-record-str#remarks) | `0x0100` |
#[derive(PartialEq, Debug, Copy, Clone, Eq)]
pub struct ControlKeyState(u32);
impl ControlKeyState {
/// Whether the control key has a state.
pub fn has_state(&self, state: u32) -> bool {
(state & self.0) != 0
}
}
/// The type of mouse event.
/// If this value is zero, it indicates a mouse button being pressed or released.
/// Otherwise, this member is one of the following values.
///
/// [Ms Docs](https://docs.microsoft.com/en-us/windows/console/mouse-event-record-str#members)
#[derive(PartialEq, Debug, Copy, Clone, Eq)]
pub enum EventFlags {
PressOrRelease = 0x0000,
/// The second click (button press) of a double-click occurred. The first click is returned as a regular button-press event.
DoubleClick = 0x0002,
/// The horizontal mouse wheel was moved.
MouseHwheeled = 0x0008,
/// If the high word of the dwButtonState member contains a positive value, the wheel was rotated to the right. Otherwise, the wheel was rotated to the left.
MouseMoved = 0x0001,
/// A change in mouse position occurred.
/// The vertical mouse wheel was moved, if the high word of the dwButtonState member contains a positive value, the wheel was rotated forward, away from the user.
/// Otherwise, the wheel was rotated backward, toward the user.
MouseWheeled = 0x0004,
// This button state is not recognized.
Unknown = 0x0021,
}
// TODO: Replace with TryFrom.
impl From<DWORD> for EventFlags {
fn from(event: DWORD) -> Self {
match event {
0x0000 => EventFlags::PressOrRelease,
0x0002 => EventFlags::DoubleClick,
0x0008 => EventFlags::MouseHwheeled,
0x0001 => EventFlags::MouseMoved,
0x0004 => EventFlags::MouseWheeled,
_ => EventFlags::Unknown,
}
}
}
/// The [size of console screen
/// buffer](https://docs.microsoft.com/en-us/windows/console/window-buffer-size-record-str).
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct WindowBufferSizeRecord {
pub size: Coord,
}
impl From<WINDOW_BUFFER_SIZE_RECORD> for WindowBufferSizeRecord {
#[inline]
fn from(record: WINDOW_BUFFER_SIZE_RECORD) -> Self {
WindowBufferSizeRecord {
size: record.dwSize.into(),
}
}
}
/// A [focus event](https://docs.microsoft.com/en-us/windows/console/focus-event-record-str). This
/// is used only internally by Windows and should be ignored.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct FocusEventRecord {
/// Reserved; do not use.
pub set_focus: bool,
}
impl From<FOCUS_EVENT_RECORD> for FocusEventRecord {
#[inline]
fn from(record: FOCUS_EVENT_RECORD) -> Self {
FocusEventRecord {
set_focus: record.bSetFocus != 0,
}
}
}
/// A [menu event](https://docs.microsoft.com/en-us/windows/console/menu-event-record-str). This is
/// used only internally by Windows and should be ignored.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct MenuEventRecord {
/// Reserved; do not use.
pub command_id: u32,
}
impl From<MENU_EVENT_RECORD> for MenuEventRecord {
#[inline]
fn from(record: MENU_EVENT_RECORD) -> Self {
MenuEventRecord {
command_id: record.dwCommandId,
}
}
}
/// An [input event](https://docs.microsoft.com/en-us/windows/console/input-record-str).
///
/// These records can be read from the input buffer by using the `ReadConsoleInput`
/// or `PeekConsoleInput` function, or written to the input buffer by using the
/// `WriteConsoleInput` function.
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum InputRecord {
/// A keyboard event occurred.
KeyEvent(KeyEventRecord),
/// The mouse was moved or a mouse button was pressed.
MouseEvent(MouseEvent),
/// A console screen buffer was resized.
WindowBufferSizeEvent(WindowBufferSizeRecord),
/// A focus event occured. This is used only internally by Windows and should be ignored.
FocusEvent(FocusEventRecord),
/// A menu event occurred. This is used only internally by Windows and should be ignored.
MenuEvent(MenuEventRecord),
}
impl From<INPUT_RECORD> for InputRecord {
#[inline]
fn from(record: INPUT_RECORD) -> Self {
match record.EventType {
KEY_EVENT => InputRecord::KeyEvent(KeyEventRecord::from_winapi(unsafe {
record.Event.KeyEvent()
})),
MOUSE_EVENT => InputRecord::MouseEvent(unsafe { *record.Event.MouseEvent() }.into()),
WINDOW_BUFFER_SIZE_EVENT => InputRecord::WindowBufferSizeEvent({
let mut buffer =
unsafe { WindowBufferSizeRecord::from(*record.Event.WindowBufferSizeEvent()) };
let window = ScreenBuffer::current().unwrap().info().unwrap();
let screen_size = window.terminal_size();
buffer.size.y = screen_size.height;
buffer.size.x = screen_size.width;
buffer
}),
FOCUS_EVENT => InputRecord::FocusEvent(unsafe { *record.Event.FocusEvent() }.into()),
MENU_EVENT => InputRecord::MenuEvent(unsafe { *record.Event.MenuEvent() }.into()),
code => panic!("Unexpected INPUT_RECORD EventType: {}", code),
}
}
}
//! This module provides a few structs to wrap common input struts to a rusty interface
//!
//! Types like:
//! - `KEY_EVENT_RECORD`
//! - `MOUSE_EVENT_RECORD`
//! - `ControlKeyState`
//! - `ButtonState`
//! - `EventFlags`
//! - `InputEventType`
//! - `INPUT_RECORD`
use winapi::shared::minwindef::DWORD;
use winapi::um::wincon::{
FOCUS_EVENT, FOCUS_EVENT_RECORD, FROM_LEFT_1ST_BUTTON_PRESSED, FROM_LEFT_2ND_BUTTON_PRESSED,
FROM_LEFT_3RD_BUTTON_PRESSED, FROM_LEFT_4TH_BUTTON_PRESSED, INPUT_RECORD, KEY_EVENT,
KEY_EVENT_RECORD, MENU_EVENT, MENU_EVENT_RECORD, MOUSE_EVENT, MOUSE_EVENT_RECORD,
RIGHTMOST_BUTTON_PRESSED, WINDOW_BUFFER_SIZE_EVENT, WINDOW_BUFFER_SIZE_RECORD,
};
use super::Coord;
use crate::ScreenBuffer;
/// A [keyboard input event](https://docs.microsoft.com/en-us/windows/console/key-event-record-str).
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct KeyEventRecord {
/// If the key is pressed, this member is true. Otherwise, this member is
/// false (the key is released).
pub key_down: bool,
/// The repeat count, which indicates that a key is being held down.
/// For example, when a key is held down, you might get five events with
/// this member equal to 1, one event with this member equal to 5, or
/// multiple events with this member greater than or equal to 1.
pub repeat_count: u16,
/// A virtual-key code that identifies the given key in a
/// device-independent manner.
pub virtual_key_code: u16,
/// The virtual scan code of the given key that represents the
/// device-dependent value generated by the keyboard hardware.
pub virtual_scan_code: u16,
/// The translated Unicode character (as a WCHAR, or utf-16 value)
pub u_char: u16,
/// The state of the control keys.
pub control_key_state: ControlKeyState,
}
impl KeyEventRecord {
/// Convert a `KEY_EVENT_RECORD` to KeyEventRecord. This function is private
/// because the `KEY_EVENT_RECORD` has several union fields for characters
/// (u8 vs u16) that we always interpret as u16. We always use the wide
/// versions of windows API calls to support this.
#[inline]
fn from_winapi(record: &KEY_EVENT_RECORD) -> Self {
KeyEventRecord {
key_down: record.bKeyDown != 0,
repeat_count: record.wRepeatCount,
virtual_key_code: record.wVirtualKeyCode,
virtual_scan_code: record.wVirtualScanCode,
u_char: unsafe { *record.uChar.UnicodeChar() },
control_key_state: ControlKeyState(record.dwControlKeyState),
}
}
}
/// A [mouse input event](https://docs.microsoft.com/en-us/windows/console/mouse-event-record-str).
#[derive(PartialEq, Debug, Copy, Clone, Eq)]
pub struct MouseEvent {
/// The position of the mouse when the event occurred in cell coordinates.
pub mouse_position: Coord,
/// The state of the mouse's buttons.
pub button_state: ButtonState,
/// The state of the control keys.
pub control_key_state: ControlKeyState,
/// What type of mouse event it is.
pub event_flags: EventFlags,
}
impl From<MOUSE_EVENT_RECORD> for MouseEvent {
#[inline]
fn from(event: MOUSE_EVENT_RECORD) -> Self {
MouseEvent {
mouse_position: event.dwMousePosition.into(),
button_state: event.dwButtonState.into(),
control_key_state: ControlKeyState(event.dwControlKeyState),
event_flags: event.dwEventFlags.into(),
}
}
}
/// The status of the mouse buttons.
/// The least significant bit corresponds to the leftmost mouse button.
/// The next least significant bit corresponds to the rightmost mouse button.
/// The next bit indicates the next-to-leftmost mouse button.
/// The bits then correspond left to right to the mouse buttons.
/// A bit is 1 if the button was pressed.
///
/// The state can be one of the following:
///
/// ```
/// # enum __ {
/// Release = 0x0000,
/// /// The leftmost mouse button.
/// FromLeft1stButtonPressed = 0x0001,
/// /// The second button from the left.
/// FromLeft2ndButtonPressed = 0x0004,
/// /// The third button from the left.
/// FromLeft3rdButtonPressed = 0x0008,
/// /// The fourth button from the left.
/// FromLeft4thButtonPressed = 0x0010,
/// /// The rightmost mouse button.
/// RightmostButtonPressed = 0x0002,
/// /// This button state is not recognized.
/// Unknown = 0x0021,
/// /// The wheel was rotated backward, toward the user; this will only be activated for `MOUSE_WHEELED ` from `dwEventFlags`
/// Negative = 0x0020,
/// # }
/// ```
///
/// [Ms Docs](https://docs.microsoft.com/en-us/windows/console/mouse-event-record-str#members)
#[derive(PartialEq, Debug, Copy, Clone, Eq)]
pub struct ButtonState {
state: i32,
}
impl From<DWORD> for ButtonState {
#[inline]
fn from(event: DWORD) -> Self {
let state = event as i32;
ButtonState { state }
}
}
impl ButtonState {
/// Get whether no buttons are being pressed.
pub fn release_button(&self) -> bool {
self.state == 0
}
/// Returns whether the left button was pressed.
pub fn left_button(&self) -> bool {
self.state as u32 & FROM_LEFT_1ST_BUTTON_PRESSED != 0
}
/// Returns whether the right button was pressed.
pub fn right_button(&self) -> bool {
self.state as u32
& (RIGHTMOST_BUTTON_PRESSED
| FROM_LEFT_3RD_BUTTON_PRESSED
| FROM_LEFT_4TH_BUTTON_PRESSED)
!= 0
}
/// Returns whether the right button was pressed.
pub fn middle_button(&self) -> bool {
self.state as u32 & FROM_LEFT_2ND_BUTTON_PRESSED != 0
}
/// Returns whether there is a down scroll.
pub fn scroll_down(&self) -> bool {
self.state < 0
}
/// Returns whether there is a up scroll.
pub fn scroll_up(&self) -> bool {
self.state > 0
}
/// Returns the raw state.
pub fn state(&self) -> i32 {
self.state
}
}
/// The state of the control keys.
///
/// This is a bitmask of the following values.
///
/// | Description | Value |
/// | --- | --- |
/// | The right alt key is pressed | `0x0001` |
/// | The left alt key is pressed | `x0002` |
/// | The right control key is pressed | `0x0004` |
/// | The left control key is pressed | `x0008` |
/// | The shift key is pressed | `0x0010` |
/// | The num lock light is on | `0x0020` |
/// | The scroll lock light is on | `0x0040` |
/// | The caps lock light is on | `0x0080` |
/// | The key is [enhanced](https://docs.microsoft.com/en-us/windows/console/key-event-record-str#remarks) | `0x0100` |
#[derive(PartialEq, Debug, Copy, Clone, Eq)]
pub struct ControlKeyState(u32);
impl ControlKeyState {
/// Whether the control key has a state.
pub fn has_state(&self, state: u32) -> bool {
(state & self.0) != 0
}
}
/// The type of mouse event.
/// If this value is zero, it indicates a mouse button being pressed or released.
/// Otherwise, this member is one of the following values.
///
/// [Ms Docs](https://docs.microsoft.com/en-us/windows/console/mouse-event-record-str#members)
#[derive(PartialEq, Debug, Copy, Clone, Eq)]
pub enum EventFlags {
PressOrRelease = 0x0000,
/// The second click (button press) of a double-click occurred. The first click is returned as a regular button-press event.
DoubleClick = 0x0002,
/// The horizontal mouse wheel was moved.
MouseHwheeled = 0x0008,
/// If the high word of the dwButtonState member contains a positive value, the wheel was rotated to the right. Otherwise, the wheel was rotated to the left.
MouseMoved = 0x0001,
/// A change in mouse position occurred.
/// The vertical mouse wheel was moved, if the high word of the dwButtonState member contains a positive value, the wheel was rotated forward, away from the user.
/// Otherwise, the wheel was rotated backward, toward the user.
MouseWheeled = 0x0004,
// This button state is not recognized.
Unknown = 0x0021,
}
// TODO: Replace with TryFrom.
impl From<DWORD> for EventFlags {
fn from(event: DWORD) -> Self {
match event {
0x0000 => EventFlags::PressOrRelease,
0x0002 => EventFlags::DoubleClick,
0x0008 => EventFlags::MouseHwheeled,
0x0001 => EventFlags::MouseMoved,
0x0004 => EventFlags::MouseWheeled,
_ => EventFlags::Unknown,
}
}
}
/// The [size of console screen
/// buffer](https://docs.microsoft.com/en-us/windows/console/window-buffer-size-record-str).
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct WindowBufferSizeRecord {
pub size: Coord,
}
impl From<WINDOW_BUFFER_SIZE_RECORD> for WindowBufferSizeRecord {
#[inline]
fn from(record: WINDOW_BUFFER_SIZE_RECORD) -> Self {
WindowBufferSizeRecord {
size: record.dwSize.into(),
}
}
}
/// A [focus event](https://docs.microsoft.com/en-us/windows/console/focus-event-record-str). This
/// is used only internally by Windows and should be ignored.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct FocusEventRecord {
/// Reserved; do not use.
pub set_focus: bool,
}
impl From<FOCUS_EVENT_RECORD> for FocusEventRecord {
#[inline]
fn from(record: FOCUS_EVENT_RECORD) -> Self {
FocusEventRecord {
set_focus: record.bSetFocus != 0,
}
}
}
/// A [menu event](https://docs.microsoft.com/en-us/windows/console/menu-event-record-str). This is
/// used only internally by Windows and should be ignored.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct MenuEventRecord {
/// Reserved; do not use.
pub command_id: u32,
}
impl From<MENU_EVENT_RECORD> for MenuEventRecord {
#[inline]
fn from(record: MENU_EVENT_RECORD) -> Self {
MenuEventRecord {
command_id: record.dwCommandId,
}
}
}
/// An [input event](https://docs.microsoft.com/en-us/windows/console/input-record-str).
///
/// These records can be read from the input buffer by using the `ReadConsoleInput`
/// or `PeekConsoleInput` function, or written to the input buffer by using the
/// `WriteConsoleInput` function.
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum InputRecord {
/// A keyboard event occurred.
KeyEvent(KeyEventRecord),
/// The mouse was moved or a mouse button was pressed.
MouseEvent(MouseEvent),
/// A console screen buffer was resized.
WindowBufferSizeEvent(WindowBufferSizeRecord),
/// A focus event occured. This is used only internally by Windows and should be ignored.
FocusEvent(FocusEventRecord),
/// A menu event occurred. This is used only internally by Windows and should be ignored.
MenuEvent(MenuEventRecord),
}
impl From<INPUT_RECORD> for InputRecord {
#[inline]
fn from(record: INPUT_RECORD) -> Self {
match record.EventType {
KEY_EVENT => InputRecord::KeyEvent(KeyEventRecord::from_winapi(unsafe {
record.Event.KeyEvent()
})),
MOUSE_EVENT => InputRecord::MouseEvent(unsafe { *record.Event.MouseEvent() }.into()),
WINDOW_BUFFER_SIZE_EVENT => InputRecord::WindowBufferSizeEvent({
let mut buffer =
unsafe { WindowBufferSizeRecord::from(*record.Event.WindowBufferSizeEvent()) };
let window = ScreenBuffer::current().unwrap().info().unwrap();
let screen_size = window.terminal_size();
buffer.size.y = screen_size.height;
buffer.size.x = screen_size.width;
buffer
}),
FOCUS_EVENT => InputRecord::FocusEvent(unsafe { *record.Event.FocusEvent() }.into()),
MENU_EVENT => InputRecord::MenuEvent(unsafe { *record.Event.MenuEvent() }.into()),
code => panic!("Unexpected INPUT_RECORD EventType: {}", code),
}
}
}

View file

@ -1,31 +1,31 @@
//! This module provides a type that represents some size.
//! For example, in WinAPI we have `COORD` to represent screen/buffer size but this is a little inconvenient.
//! This module provides some trait implementations who will make parsing and working with `COORD` easier.
use winapi::um::wincon::COORD;
/// This is type represents the size of something in width and height.
#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
pub struct Size {
pub width: i16,
pub height: i16,
}
impl Size {
/// Create a new size instance by passing in the width and height.
pub fn new(width: i16, height: i16) -> Size {
Size { width, height }
}
}
impl From<COORD> for Size {
fn from(coord: COORD) -> Self {
Size::new(coord.X, coord.Y)
}
}
impl Into<(u16, u16)> for Size {
fn into(self) -> (u16, u16) {
(self.width as u16, self.height as u16)
}
}
//! This module provides a type that represents some size.
//! For example, in WinAPI we have `COORD` to represent screen/buffer size but this is a little inconvenient.
//! This module provides some trait implementations who will make parsing and working with `COORD` easier.
use winapi::um::wincon::COORD;
/// This is type represents the size of something in width and height.
#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
pub struct Size {
pub width: i16,
pub height: i16,
}
impl Size {
/// Create a new size instance by passing in the width and height.
pub fn new(width: i16, height: i16) -> Size {
Size { width, height }
}
}
impl From<COORD> for Size {
fn from(coord: COORD) -> Self {
Size::new(coord.X, coord.Y)
}
}
impl Into<(u16, u16)> for Size {
fn into(self) -> (u16, u16) {
(self.width as u16, self.height as u16)
}
}

View file

@ -1,46 +1,46 @@
//! This module provides a type that represents some rectangle.
//! For example, in WinAPI we have `SMALL_RECT` to represent a window size but this is a little inconvenient.
//! This module provides some trait implementations who will make parsing and working with `SMALL_RECT` easier.
use winapi::um::wincon::{CONSOLE_SCREEN_BUFFER_INFO, SMALL_RECT};
/// This is a wrapper for the locations of a rectangle.
#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
pub struct WindowPositions {
/// The rectangle's offset from the left.
pub left: i16,
/// The rectangle's offset from the right.
pub right: i16,
/// The rectangle's offset from the bottom.
pub bottom: i16,
/// The rectangle's offset from the top.
pub top: i16,
}
impl From<CONSOLE_SCREEN_BUFFER_INFO> for WindowPositions {
fn from(csbi: CONSOLE_SCREEN_BUFFER_INFO) -> Self {
csbi.srWindow.into()
}
}
impl From<WindowPositions> for SMALL_RECT {
fn from(positions: WindowPositions) -> Self {
SMALL_RECT {
Top: positions.top,
Right: positions.right,
Bottom: positions.bottom,
Left: positions.left,
}
}
}
impl From<SMALL_RECT> for WindowPositions {
fn from(rect: SMALL_RECT) -> Self {
WindowPositions {
left: rect.Left,
right: rect.Right,
bottom: rect.Bottom,
top: rect.Top,
}
}
}
//! This module provides a type that represents some rectangle.
//! For example, in WinAPI we have `SMALL_RECT` to represent a window size but this is a little inconvenient.
//! This module provides some trait implementations who will make parsing and working with `SMALL_RECT` easier.
use winapi::um::wincon::{CONSOLE_SCREEN_BUFFER_INFO, SMALL_RECT};
/// This is a wrapper for the locations of a rectangle.
#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
pub struct WindowPositions {
/// The rectangle's offset from the left.
pub left: i16,
/// The rectangle's offset from the right.
pub right: i16,
/// The rectangle's offset from the bottom.
pub bottom: i16,
/// The rectangle's offset from the top.
pub top: i16,
}
impl From<CONSOLE_SCREEN_BUFFER_INFO> for WindowPositions {
fn from(csbi: CONSOLE_SCREEN_BUFFER_INFO) -> Self {
csbi.srWindow.into()
}
}
impl From<WindowPositions> for SMALL_RECT {
fn from(positions: WindowPositions) -> Self {
SMALL_RECT {
Top: positions.top,
Right: positions.right,
Bottom: positions.bottom,
Left: positions.left,
}
}
}
impl From<SMALL_RECT> for WindowPositions {
fn from(rect: SMALL_RECT) -> Self {
WindowPositions {
left: rect.Left,
right: rect.Right,
bottom: rect.Bottom,
top: rect.Top,
}
}
}