crossterm_winapi-0.3.0/.github/CODEOWNERS000064400000000000000000000000161354265064500162320ustar0000000000000000* @TimonPost crossterm_winapi-0.3.0/.gitignore000064400000000000000000000000771354265064500152760ustar0000000000000000**/target/ **/.idea/ **/.vscode/ **/*.rs.bk **/Cargo.lock crossterm_winapi-0.3.0/.travis.yml000064400000000000000000000010051354712331000153740ustar0000000000000000language: rust rust: - stable - nightly os: - linux - windows - osx git: depth: 1 quiet: true matrix: allow_failures: - rust: nightly before_script: - export PATH=$PATH:/home/travis/.cargo/bin - rustup component add rustfmt script: - cargo fmt --version - rustup --version - rustc --version - if [ "$TRAVIS_RUST_VERSION" = "stable" ]; then cargo fmt --all -- --check; fi - cargo build - cargo test --all-features -- --nocapture --test-threads 1 crossterm_winapi-0.3.0/Cargo.toml.orig000064400000000000000000000012531355337176600162000ustar0000000000000000[package] name = "crossterm_winapi" version = "0.3.0" authors = ["T. Post"] description = "An WinApi wrapper that provides some basic simple abstractions aground common WinApi calls" repository = "https://github.com/crossterm-rs/crossterm" documentation = "https://docs.rs/crossterm_winapi/" license = "MIT" keywords = ["winapi", "abstractions", "crossterm", "windows", "screen_buffer"] exclude = ["target", "Cargo.lock"] readme = "README.md" edition = "2018" [target.'cfg(windows)'.dependencies] winapi = { version = "0.3.8", features = ["winbase", "consoleapi", "processenv", "handleapi"] } [package.metadata.docs.rs] default-target = "x86_64-pc-windows-msvc" crossterm_winapi-0.3.0/Cargo.toml0000644000000022340000000000000124620ustar00# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies # # If you believe there's an error in this file please file an # issue against the rust-lang/cargo repository. If you're # editing this file be aware that the upstream Cargo.toml # will likely look very different (and much more reasonable) [package] edition = "2018" name = "crossterm_winapi" version = "0.3.0" authors = ["T. Post"] exclude = ["target", "Cargo.lock"] description = "An WinApi wrapper that provides some basic simple abstractions aground common WinApi calls" documentation = "https://docs.rs/crossterm_winapi/" readme = "README.md" keywords = ["winapi", "abstractions", "crossterm", "windows", "screen_buffer"] license = "MIT" repository = "https://github.com/crossterm-rs/crossterm" [package.metadata.docs.rs] default-target = "x86_64-pc-windows-msvc" [target."cfg(windows)".dependencies.winapi] version = "0.3.8" features = ["winbase", "consoleapi", "processenv", "handleapi"] crossterm_winapi-0.3.0/CHANGELOG.md000064400000000000000000000005141355337176600151210ustar0000000000000000# Version 0.3.0 - Make read sync block for windows systems ([PR #2](https://github.com/crossterm-rs/crossterm-winapi/pull/2)) # Version 0.2.1 - Maintenance release only - Moved to a [separate repository](https://github.com/crossterm-rs/crossterm-winapi) # Version 0.2.0 - `Console::get_handle` to `Console::handle` crossterm_winapi-0.3.0/docs/CONTRIBUTING.md000064400000000000000000000002311354265064500164570ustar0000000000000000# Contributing The `crossterm` crate [contributing guidelines](https://github.com/crossterm-rs/crossterm/blob/master/docs/CONTRIBUTING.md) applies. crossterm_winapi-0.3.0/docs/known-problems.md000064400000000000000000000010301354265064500175230ustar0000000000000000# Known problems There are some problems I discovered during development. I don't think it has to do anything with the crossterm, but it has to do whit how terminals handle ANSI or WinAPI. ## WinAPI - Power shell does not interpreter 'DarkYellow' and is instead using gray instead, cmd is working perfectly fine. - Power shell inserts an '\n' (enter) when the program starts, this enter is the one you pressed when running the command. - After the program ran, power shell will reset the background and foreground colors. crossterm_winapi-0.3.0/examples/coloring_example.rs000064400000000000000000000036341354265064500210230ustar0000000000000000#[cfg(windows)] use std::io::Result; #[cfg(windows)] use crossterm_winapi::{Console, ScreenBuffer}; #[cfg(windows)] fn set_background_color() -> Result<()> { // background value const BLUE_BACKGROUND: u16 = 0x0010; let screen_buffer = ScreenBuffer::current()?; let csbi = screen_buffer.info()?; // Notice that the color values are stored in wAttribute. // So wee need to use bitwise operators to check if the values exists or to get current console colors. let attrs = csbi.attributes(); let fg_color = attrs & 0x0007; // apply the blue background flag to the current attributes let new_color = fg_color | BLUE_BACKGROUND; // set the console text attribute to the new color value. Console::from(**screen_buffer.handle()).set_text_attribute(new_color)?; Ok(()) } #[cfg(windows)] fn set_foreground_color() -> Result<()> { // background value const BLUE_FOREGROUND: u16 = 0x0001; let screen_buffer = ScreenBuffer::current()?; let csbi = screen_buffer.info()?; // Notice that the color values are stored in wAttribute. // So we need to use bitwise operators to check if the values exists or to get current console colors. let attrs = csbi.attributes(); let bg_color = attrs & 0x0070; let mut color = BLUE_FOREGROUND | bg_color; // background intensity is a separate value in attrs, // wee need to check if this was applied to the current bg color. if (attrs & 0x0080 as u16) != 0 { color = color | 0x0080 as u16; } // set the console text attribute to the new color value. Console::from(**screen_buffer.handle()).set_text_attribute(color)?; Ok(()) } #[cfg(windows)] fn main() -> Result<()> { set_background_color()?; set_foreground_color() } #[cfg(not(windows))] fn main() { println!("This example is for the Windows platform only."); } crossterm_winapi-0.3.0/examples/console.rs000064400000000000000000000010731354265064500171310ustar0000000000000000#[cfg(windows)] use std::io::Result; #[cfg(windows)] use crossterm_winapi::ConsoleMode; #[cfg(windows)] fn change_console_mode() -> Result<()> { let console_mode = ConsoleMode::new()?; // get the current console mode: let _mode: u32 = console_mode.mode()?; // set the console mode (not sure if this is an actual value xp) console_mode.set_mode(10) } #[cfg(windows)] fn main() -> Result<()> { change_console_mode() } #[cfg(not(windows))] fn main() { println!("This example is for the Windows platform only."); } crossterm_winapi-0.3.0/examples/handle.rs000064400000000000000000000017221354265064500167230ustar0000000000000000#[cfg(windows)] use std::io::Result; #[cfg(windows)] use crossterm_winapi::{Handle, HandleType}; #[cfg(windows)] #[allow(unused_variables)] fn main() -> Result<()> { // see the description of the types to see what they do. let out_put_handle = Handle::new(HandleType::OutputHandle)?; let out_put_handle = Handle::new(HandleType::InputHandle)?; let curr_out_put_handle = Handle::new(HandleType::CurrentOutputHandle)?; let curr_out_put_handle = Handle::new(HandleType::CurrentInputHandle)?; // now you have this handle you might want to get the WinApi `HANDLE` it is wrapping. // you can do this by defencing. let handle /*:HANDLE*/ = *out_put_handle; // you can also pass you own `HANDLE` to create an instance of `Handle` let handle = Handle::from(handle); /* winapi::um::winnt::HANDLE */ Ok(()) } #[cfg(not(windows))] fn main() { println!("This example is for the Windows platform only."); } crossterm_winapi-0.3.0/examples/screen_buffer.rs000064400000000000000000000017461354265064500203060ustar0000000000000000#![allow(dead_code)] #[cfg(windows)] use std::io::Result; #[cfg(windows)] use crossterm_winapi::ScreenBuffer; #[cfg(windows)] fn print_screen_buffer_information() -> Result<()> { let screen_buffer = ScreenBuffer::current()?; // get console screen buffer information let csbi = screen_buffer.info()?; println!("cursor post: {:?}", csbi.cursor_pos()); println!("attributes: {:?}", csbi.attributes()); println!("terminal window dimentions {:?}", csbi.terminal_window()); println!("terminal size {:?}", csbi.terminal_size()); Ok(()) } #[cfg(windows)] fn multiple_screen_buffers() -> Result<()> { // create new screen buffer let screen_buffer = ScreenBuffer::create(); // which to this screen buffer screen_buffer.show() } #[cfg(windows)] fn main() -> Result<()> { print_screen_buffer_information() } #[cfg(not(windows))] fn main() { println!("This example is for the Windows platform only."); } crossterm_winapi-0.3.0/LICENSE000064400000000000000000000020731354265064500143110ustar0000000000000000MIT License Copyright (c) 2019 Timon Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. crossterm_winapi-0.3.0/README.md000064400000000000000000000050321354265064500145610ustar0000000000000000![Lines of Code][s7] [![Latest Version][s1]][l1] [![MIT][s2]][l2] [![docs][s3]][l3] # Crossterm Windows API Abstractions This crate provides some wrappers aground common used WinAPI functions. The purpose of this library is originally meant for the [crossterm](https://github.com/crossterm-rs/crossterm), but could be used apart from it. Although, notice that it unstable right because some changes to the API could be expected. # Features This crate provides some abstractions over reading input, console screen buffer, and handle. The following WinApi calls: - CONSOLE_SCREEN_BUFFER_INFO (used to extract information like cursor pos, terminal size etc.) - HANDLE (the handle needed to run functions from WinApi) - SetConsoleActiveScreenBuffer (activate an other screen buffer) - Set/GetConsoleMode (e.g. console modes like disabling output) - SetConsoleTextAttribute (eg. coloring) - SetConsoleWindowInfo (changing the buffer location e.g. scrolling) - FillConsoleOutputAttribute, FillConsoleOutputCharacter (used to replace some block of cells with a color or character.) - SetConsoleInfo - ReadConsoleW # Example The [examples](https://github.com/crossterm-rs/examples) repository has more complete and verbose examples. ## Screen buffer information ```rust use crossterm_winapi::{ScreenBuffer, Handle}; fn print_screen_buffer_information() { let screen_buffer = ScreenBuffer::current().unwrap(); // get console screen buffer information let csbi = screen_buffer.info().unwrap(); println!("cursor post: {:?}", csbi.cursor_pos()); println!("attributes: {:?}", csbi.attributes()); println!("terminal window dimentions {:?}", csbi.terminal_window()); println!("terminal size {:?}", csbi.terminal_size()); } ``` ## Handle ```rust use crossterm_winapi::{HandleType, Handle}; fn get_different_handle_types() { let out_put_handle = Handle::new(HandleType::OutputHandle).unwrap(); let out_put_handle = Handle::new(HandleType::InputHandle).unwrap(); let curr_out_put_handle = Handle::new(HandleType::CurrentOutputHandle).unwrap(); let curr_out_put_handle = Handle::new(HandleType::CurrentInputHandle).unwrap(); } ``` [s1]: https://img.shields.io/crates/v/crossterm_winapi.svg [l1]: https://crates.io/crates/crossterm_winapi [s2]: https://img.shields.io/badge/license-MIT-blue.svg [l2]: LICENSE [s3]: https://docs.rs/crossterm_winapi/badge.svg [l3]: https://docs.rs/crossterm_winapi/ [s7]: https://travis-ci.org/crossterm-rs/crossterm.svg?branch=master crossterm_winapi-0.3.0/src/console.rs000064400000000000000000000200331354712331000160640ustar0000000000000000use std::borrow::ToOwned; 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 super::{is_true, Coord, Handle, HandleType, InputRecord, WindowPositions}; /// 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 { 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 { 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 { 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 text 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 { // 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 = 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_single_input_event(&self) -> Result { let mut buf: Vec = Vec::with_capacity(1); let mut size = 0; return Ok(self.read_input(&mut buf, 1, &mut size)?.1[0].to_owned()); } pub fn read_console_input(&self) -> Result<(u32, Vec)> { 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((0, vec![])); } let mut buf: Vec = Vec::with_capacity(buf_len as usize); let mut size = 0; self.read_input(&mut buf, buf_len, &mut size) } pub fn number_of_console_input_events(&self) -> Result { let mut buf_len: DWORD = 0; if !is_true(unsafe { GetNumberOfConsoleInputEvents(*self.handle, &mut buf_len) }) { return Err(Error::last_os_error()); } Ok(buf_len) } fn read_input( &self, buf: &mut Vec, buf_len: u32, bytes_written: &mut u32, ) -> Result<(u32, Vec)> { if !is_true(unsafe { ReadConsoleInputW(*self.handle, buf.as_mut_ptr(), buf_len, bytes_written) }) { return Err(Error::last_os_error()); } else { unsafe { buf.set_len(buf_len as usize); } } Ok(( buf_len, buf[..(buf_len as usize)] .iter() .map(|x| InputRecord::from(*x)) .collect::>(), )) } } impl From 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 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), } } } crossterm_winapi-0.3.0/src/console_mode.rs000064400000000000000000000055671354265064500171220ustar0000000000000000use std::io::{Error, Result}; use winapi::um::consoleapi::{GetConsoleMode, SetConsoleMode}; use winapi::um::winnt::HANDLE; use super::{is_true, Handle, HandleType}; /// This abstracts away some WinaApi calls to set and get the console mode. /// /// Wraps the underlying function call: [SetConsoleMode] /// link: [https://docs.microsoft.com/en-us/windows/console/setconsolemode] /// /// Wraps the underlying function call: [GetConsoleMode] /// link: [https://docs.microsoft.com/en-us/windows/console/getconsolemode] 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 `STD_OUTPUT_HANDLE` as default handle. /// When you explicitly want to specify the handle used for the function calls use `ConsoleMode::from(handle)` instead. pub fn new() -> Result { Ok(ConsoleMode { handle: Handle::new(HandleType::OutputHandle)?, }) } /// Set the console mode to the given console mode. /// /// This function sets the `dwMode`. /// /// Wraps the underlying function call: [SetConsoleMode] /// link: [https://docs.microsoft.com/en-us/windows/console/setconsolemode] pub fn set_mode(&self, console_mode: u32) -> Result<()> { unsafe { if !is_true(SetConsoleMode(*self.handle, console_mode)) { return Err(Error::last_os_error()); } } Ok(()) } /// Get the console mode. /// /// This function returns the `lpMode`. /// /// Wraps the underlying function call: [GetConsoleMode] /// link: [https://docs.microsoft.com/en-us/windows/console/getconsolemode] pub fn mode(&self) -> Result { let mut console_mode = 0; unsafe { if !is_true(GetConsoleMode(*self.handle, &mut console_mode)) { println!("Getting mode failed"); return Err(Error::last_os_error()); } } Ok(console_mode) } } impl From for ConsoleMode { fn from(handle: HANDLE) -> Self { ConsoleMode { handle: Handle::from(handle), } } } impl From 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(); } } crossterm_winapi-0.3.0/src/csbi.rs000064400000000000000000000037331354265064500153650ustar0000000000000000use std::mem::zeroed; use winapi::um::wincon::CONSOLE_SCREEN_BUFFER_INFO; use super::{Coord, Size, WindowPositions}; /// This type is a wrapper for `CONSOLE_SCREEN_BUFFER_INFO` and has some methods to extract information from it. /// /// Wraps the underlying type: [CONSOLE_SCREEN_BUFFER_INFO] /// link: [https://docs.microsoft.com/en-us/windows/console/console-screen-buffer-info-str] pub struct ScreenBufferInfo(pub CONSOLE_SCREEN_BUFFER_INFO); impl ScreenBufferInfo { pub fn new() -> ScreenBufferInfo { ScreenBufferInfo(unsafe { zeroed() }) } /// This will return the buffer size. /// /// Will take `dwSize` from the current screen buffer and convert it into the `Size`. pub fn buffer_size(&self) -> Size { Size::from(self.0.dwSize) } /// This will return the terminal size. /// /// 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, )) } /// This will return the terminal window properties. /// /// Will take `srWindow` and convert it into the `WindowPositions` type. pub fn terminal_window(&self) -> WindowPositions { WindowPositions::from(self.0) } /// This will return the terminal window properties. /// /// Will take `wAttributes` from the current screen buffer. pub fn attributes(&self) -> u16 { self.0.wAttributes } /// This will return the current cursor position. /// /// Will take `dwCursorPosition` from the current screen buffer. pub fn cursor_pos(&self) -> Coord { Coord::from(self.0.dwCursorPosition) } } impl From for ScreenBufferInfo { fn from(csbi: CONSOLE_SCREEN_BUFFER_INFO) -> Self { ScreenBufferInfo(csbi) } } crossterm_winapi-0.3.0/src/handle.rs000064400000000000000000000143541354265064500157010ustar0000000000000000//! This module contains some logic for working with the console handle. use std::io::{self, Result}; use std::ops::Deref; use std::ptr::null_mut; use winapi::um::{ fileapi::{CreateFileW, OPEN_EXISTING}, handleapi::INVALID_HANDLE_VALUE, processenv::GetStdHandle, winbase::{STD_INPUT_HANDLE, STD_OUTPUT_HANDLE}, winnt::{FILE_SHARE_READ, FILE_SHARE_WRITE, GENERIC_READ, GENERIC_WRITE, HANDLE}, }; /// This enum represents the different handles that could be requested. /// /// Some more details could be found [here](https://docs.microsoft.com/en-us/windows/console/getstdhandle#parameters) pub enum HandleType { /// This represents the `STD_OUTPUT_HANDLE` OutputHandle, /// This represents the `STD_INPUT_HANDLE` InputHandle, /// This represents the `CONOUT$` file handle /// When using multiple screen buffers this will always point to the to the current screen output buffer. CurrentOutputHandle, /// This represents the `CONIN$` file handle. /// When using multiple screen buffers this will always point to the to the current screen input buffer. CurrentInputHandle, } /// This abstracts away some WinaApi calls to set and get some console handles. /// // Wraps the underlying WinApi type: [HANDLE] pub struct Handle { handle: HANDLE, } impl Handle { pub fn new(handle: HandleType) -> Result { let 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(), }?; Ok(Handle { 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. /// /// On success this function returns the `HANDLE` to `STD_OUTPUT_HANDLE`. /// /// This function uses `CONOUT$` to create a file handle to the current output buffer. /// /// Wraps the underlying function call: [CreateFileW] /// link: [https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-createfilew] pub fn current_out_handle() -> Result { let utf16: Vec = "CONOUT$\0".encode_utf16().collect(); let utf16_ptr: *const u16 = utf16.as_ptr(); let handle = unsafe { CreateFileW( utf16_ptr, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, null_mut(), OPEN_EXISTING, 0, null_mut(), ) }; if !Handle::is_valid_handle(&handle) { println!("invalid!!"); return Err(io::Error::last_os_error()); } Ok(handle) } /// Get the handle of the active input screen buffer. /// When using multiple screen buffers this will always point to the to the current screen input buffer. /// /// On success this function returns the `HANDLE` to `STD_INPUT_HANDLE`. /// /// This function uses `CONIN$` to create a file handle to the current input buffer. /// /// Wraps the underlying function call: [CreateFileW] /// link: [https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-createfilew] pub fn current_in_handle() -> Result { let utf16: Vec = "CONIN$\0".encode_utf16().collect(); let utf16_ptr: *const u16 = utf16.as_ptr(); let handle = unsafe { CreateFileW( utf16_ptr, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, null_mut(), OPEN_EXISTING, 0, null_mut(), ) }; if !Handle::is_valid_handle(&handle) { return Err(io::Error::last_os_error()); } Ok(handle) } /// Get the handle of the output screen buffer. /// /// On success this function returns the `HANDLE` to `STD_OUTPUT_HANDLE`. /// /// Wraps the underlying function call: [GetStdHandle] whit argument `STD_OUTPUT_HANDLE` /// link: [https://docs.microsoft.com/en-us/windows/console/getstdhandle] pub fn output_handle() -> Result { unsafe { let handle = GetStdHandle(STD_OUTPUT_HANDLE); if !Handle::is_valid_handle(&handle) { return Err(io::Error::last_os_error()); } Ok(handle) } } /// Get the handle of the input screen buffer. /// /// On success this function returns the `HANDLE` to `STD_INPUT_HANDLE`. /// /// Wraps the underlying function call: [GetStdHandle] whit argument `STD_INPUT_HANDLE` /// link: [https://docs.microsoft.com/en-us/windows/console/getstdhandle] pub fn input_handle() -> Result { unsafe { let handle = GetStdHandle(STD_INPUT_HANDLE); if !Handle::is_valid_handle(&handle) { return Err(io::Error::last_os_error()); } Ok(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 { if *handle == INVALID_HANDLE_VALUE { false } else { true } } } impl Deref for Handle { type Target = HANDLE; fn deref(&self) -> &::Target { &self.handle } } impl From for Handle { fn from(handle: 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()); } } crossterm_winapi-0.3.0/src/lib.rs000064400000000000000000000015131354265064500152050ustar0000000000000000#![cfg(windows)] #![deny(unused_imports)] pub use self::{ console::Console, console_mode::ConsoleMode, csbi::ScreenBufferInfo, handle::{Handle, HandleType}, screen_buffer::ScreenBuffer, structs::{ ButtonState, ControlKeyState, Coord, EventFlags, InputEventType, InputRecord, KeyEventRecord, MouseEvent, Size, WindowPositions, }, }; mod console; mod console_mode; mod csbi; mod handle; mod screen_buffer; mod structs; /// Parses the given integer to an bool by checking if the value is 0 or 1. /// This is currently used for checking if a WinApi called succeeded, this might be moved into a macro at some time. /// So please don't use this :(. pub fn is_true(value: i32) -> bool { if value == 0 { return false; } else { return true; } } crossterm_winapi-0.3.0/src/screen_buffer.rs000064400000000000000000000105301354265064500172460ustar0000000000000000//! This contains the logic for working with the console buffer. use std::io::{Error, 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, HANDLE}, }, }; use super::{is_true, Handle, HandleType, ScreenBufferInfo}; pub struct ScreenBuffer { handle: Handle, } impl ScreenBuffer { /// Create an instance of `ScreenBuffer` where the `HANDLE`, used for the functions this type wraps, is the current output handle. pub fn current() -> Result { Ok(ScreenBuffer { handle: Handle::new(HandleType::CurrentOutputHandle)?, }) } /// Create new console screen buffer. /// /// Wraps the underlying function call: [CreateConsoleScreenBuffer] /// link: [https://docs.microsoft.com/en-us/windows/console/createconsolescreenbuffer] pub fn create() -> ScreenBuffer { let mut security_attr: SECURITY_ATTRIBUTES = SECURITY_ATTRIBUTES { nLength: size_of::() as u32, lpSecurityDescriptor: NULL, bInheritHandle: TRUE, }; unsafe { 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, ); ScreenBuffer { handle: Handle::from(new_screen_buffer), } } } /// This will make this `ScreenBuffer` the active one. /// /// Wraps the underlying function call: [SetConsoleActiveScreenBuffer] /// link: [https://docs.microsoft.com/en-us/windows/console/setconsoleactivescreenbuffer] pub fn show(&self) -> Result<()> { unsafe { if !is_true(SetConsoleActiveScreenBuffer(*self.handle)) { return Err(Error::last_os_error()); } } Ok(()) } /// Get the screen buffer information like terminal size, cursor position, buffer size. /// /// Wraps the underlying function call: [GetConsoleScreenBufferInfo] /// link: [https://docs.microsoft.com/en-us/windows/console/getconsolescreenbufferinfo] pub fn info(&self) -> Result { let mut csbi = ScreenBufferInfo::new(); unsafe { if !is_true(GetConsoleScreenBufferInfo(*self.handle, &mut csbi.0)) { return Err(Error::last_os_error()); } } Ok(csbi) } /// Set the console screen buffer size to the given size. /// /// Wraps the underlying function call: [SetConsoleScreenBufferSize] /// link: [https://docs.microsoft.com/en-us/windows/console/setconsolescreenbuffersize] pub fn set_size(&self, x: i16, y: i16) -> Result<()> { unsafe { if !is_true(SetConsoleScreenBufferSize( *self.handle, COORD { X: x, Y: y }, )) { return Err(Error::last_os_error()); } } Ok(()) } /// Get the underlining raw `HANDLE` used by this type to execute whit. pub fn handle(&self) -> &Handle { return &self.handle; } } impl From for ScreenBuffer { fn from(handle: Handle) -> Self { ScreenBuffer { handle } } } impl From for ScreenBuffer { fn from(handle: HANDLE) -> Self { ScreenBuffer { handle: Handle::from(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(); } } crossterm_winapi-0.3.0/src/structs.rs000064400000000000000000000004511354265064500161460ustar0000000000000000pub use self::coord::Coord; pub use self::input::{ ButtonState, ControlKeyState, EventFlags, InputEventType, InputRecord, KeyEventRecord, MouseEvent, }; pub use self::size::Size; pub use self::window_coords::WindowPositions; mod coord; mod input; mod size; mod window_coords; crossterm_winapi-0.3.0/src/structs/coord.rs000064400000000000000000000022011354265064500172470ustar0000000000000000//! 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 whit `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, PartialOrd, PartialEq)] 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 size instance by passing in the width and height. pub fn new(x: i16, y: i16) -> Coord { Coord { x, y } } } impl From for Coord { fn from(coord: COORD) -> Self { Coord::new(coord.X, coord.Y) } } impl From 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) } } crossterm_winapi-0.3.0/src/structs/input.rs000064400000000000000000000215021354265064500173050ustar0000000000000000//! 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, WORD}; use winapi::um::wincon::{ INPUT_RECORD_Event, KEY_EVENT_RECORD_uChar, FOCUS_EVENT, INPUT_RECORD, KEY_EVENT, KEY_EVENT_RECORD, MENU_EVENT, MOUSE_EVENT, MOUSE_EVENT_RECORD, WINDOW_BUFFER_SIZE_EVENT, }; use super::coord::Coord; /// Describes a keyboard input event in a console INPUT_RECORD structure. /// link: [https://docs.microsoft.com/en-us/windows/console/key-event-record-str] 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: WORD, /// The virtual scan code of the given key that represents the device-dependent value generated by the keyboard hardware. pub virtual_scan_code: u16, /// A union of the following members. /// /// - UnicodeChar /// Translated Unicode character. /// /// - AsciiChar /// Translated ASCII character. /// TODO, make this a rust type. pub u_char: KEY_EVENT_RECORD_uChar, /// The state of the control keys. pub control_key_state: ControlKeyState, } impl KeyEventRecord {} impl From for KeyEventRecord { fn from(event: KEY_EVENT_RECORD) -> Self { KeyEventRecord { key_down: event.bKeyDown == 1, repeat_count: event.wRepeatCount, virtual_key_code: event.wVirtualKeyCode, virtual_scan_code: event.wVirtualScanCode, u_char: event.uChar, control_key_state: ControlKeyState(event.dwControlKeyState), } } } #[derive(PartialOrd, PartialEq, Debug, Copy, Clone)] pub struct MouseEvent { pub mouse_position: Coord, pub button_state: ButtonState, pub control_key_state: ControlKeyState, pub event_flags: EventFlags, } impl From for MouseEvent { fn from(event: MOUSE_EVENT_RECORD) -> Self { MouseEvent { mouse_position: Coord::from(event.dwMousePosition), button_state: ButtonState::from(event.dwButtonState), control_key_state: ControlKeyState(event.dwControlKeyState), event_flags: EventFlags::from(event.dwEventFlags), } } } /// 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. /// /// [Ms Docs](https://docs.microsoft.com/en-us/windows/console/mouse-event-record-str#members) #[derive(PartialOrd, PartialEq, Debug, Copy, Clone)] pub enum ButtonState { 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, } impl From for ButtonState { fn from(event: DWORD) -> Self { let e = event as i32; match e { 0x0000 => ButtonState::Release, 0x0001 => ButtonState::FromLeft1stButtonPressed, 0x0004 => ButtonState::FromLeft2ndButtonPressed, 0x0008 => ButtonState::FromLeft3rdButtonPressed, 0x0010 => ButtonState::FromLeft4thButtonPressed, 0x0002 => ButtonState::RightmostButtonPressed, _ if e < 0 => ButtonState::Negative, _ => ButtonState::Unknown, } } } #[derive(PartialOrd, PartialEq, Debug, Copy, Clone)] pub struct ControlKeyState(u32); impl ControlKeyState { 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(PartialOrd, PartialEq, Debug, Copy, Clone)] 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, } impl From for EventFlags { fn from(event: DWORD) -> Self { match event { 0x0000 => EventFlags::PressOrRelease, 0x0002 => EventFlags::DoubleClick, 0x0008 => EventFlags::MouseHwheeled, 0x0001 => EventFlags::MouseMoved, 0x0004 => EventFlags::MouseWheeled, _ => panic!("Event flag {} does not exist.", event), } } } /// Describes an input event in the console input buffer. /// 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. /// /// [Ms Docs](https://docs.microsoft.com/en-us/windows/console/input-record-str) #[derive(Clone)] pub struct InputRecord { /// A handle to the type of input event and the event record stored in the Event member. pub event_type: InputEventType, /// The event information. The format of this member depends on the event type specified by the EventType member. /// Todo: wrap with rust type. pub event: INPUT_RECORD_Event, } impl From for InputRecord { fn from(event: INPUT_RECORD) -> Self { InputRecord { event_type: InputEventType::from(event.EventType), event: event.Event, } } } /// A handle to the type of input event and the event record stored in the Event member. /// /// [Ms Docs](https://docs.microsoft.com/en-us/windows/console/input-record-str#members) #[derive(PartialOrd, PartialEq, Debug, Copy, Clone)] pub enum InputEventType { /// The Event member contains a `KEY_EVENT_RECORD` structure with information about a keyboard event. KeyEvent = KEY_EVENT as isize, /// The Event member contains a `MOUSE_EVENT_RECORD` structure with information about a mouse movement or button press event. MouseEvent = MOUSE_EVENT as isize, /// The Event member contains a `WINDOW_BUFFER_SIZE_RECORD` structure with information about the new size of the console screen buffer. WindowBufferSizeEvent = WINDOW_BUFFER_SIZE_EVENT as isize, /// The Event member contains a `FOCUS_EVENT_RECORD` structure. These events are used internally and should be ignored. FocusEvent = FOCUS_EVENT as isize, /// The Event member contains a `MENU_EVENT_RECORD` structure. These events are used internally and should be ignored. MenuEvent = MENU_EVENT as isize, } impl From for InputEventType { fn from(event: WORD) -> Self { match event { KEY_EVENT => InputEventType::KeyEvent, MOUSE_EVENT => InputEventType::MouseEvent, WINDOW_BUFFER_SIZE_EVENT => InputEventType::WindowBufferSizeEvent, FOCUS_EVENT => InputEventType::FocusEvent, MENU_EVENT => InputEventType::MenuEvent, _ => panic!("Input event type {} does not exist.", event), } } } crossterm_winapi-0.3.0/src/structs/size.rs000064400000000000000000000016441354265064500171250ustar0000000000000000//! 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 whit `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 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) } } crossterm_winapi-0.3.0/src/structs/window_coords.rs000064400000000000000000000023411354265064500210260ustar0000000000000000//! 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 whit `COORD` easier. use winapi::um::wincon::{CONSOLE_SCREEN_BUFFER_INFO, SMALL_RECT}; /// This is a wrapper for the locations of a rectangle. /// /// It has left, right, bottom, top attributes. #[derive(Copy, Clone, Debug, Default, Eq, PartialEq)] pub struct WindowPositions { pub left: i16, pub right: i16, pub bottom: i16, pub top: i16, } impl From for WindowPositions { fn from(csbi: CONSOLE_SCREEN_BUFFER_INFO) -> Self { WindowPositions { left: csbi.srWindow.Left, right: csbi.srWindow.Right, bottom: csbi.srWindow.Bottom, top: csbi.srWindow.Top, } } } impl From for SMALL_RECT { fn from(positions: WindowPositions) -> Self { SMALL_RECT { Top: positions.top, Right: positions.right, Bottom: positions.bottom, Left: positions.left, } } } crossterm_winapi-0.3.0/.cargo_vcs_info.json0000644000000001120000000000000144550ustar00{ "git": { "sha1": "3b8ec59ece78176eb632ca366d60fec701094540" } } crossterm_winapi-0.3.0/Cargo.lock0000644000000024550000000000000124440ustar00# This file is automatically @generated by Cargo. # It is not intended for manual editing. [[package]] name = "crossterm_winapi" version = "0.3.0" dependencies = [ "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "winapi" version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "winapi-i686-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" [metadata] "checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"