Skip to content

Commit

Permalink
Use windows crate instead of winapi
Browse files Browse the repository at this point in the history
This replaces crossterm-rs#26
Using the windows crate instead of the windows-sys crate simplifies the
code and avoids having to maintain code that handles errors, and various
other simplifications provided by the higher level crate.

From the windows crate documentation:

> The windows-sys crate is a zero-overhead fallback for the most
> demanding situations and primarily where the absolute best compile
> time is essential. It only includes function declarations (externs),
> structs, and constants. No convenience helpers, traits, or wrappers
> are provided.
  • Loading branch information
joshka committed Jun 22, 2024
1 parent d45a3bc commit f0200fc
Show file tree
Hide file tree
Showing 15 changed files with 159 additions and 224 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ jobs:
name: Test (${{ matrix.toolchain }})
strategy:
matrix:
# run on beta to ensure that tests won't break on the next version of the rust toolchain
# run on msrv to ensure that tests won't break on the minimum supported version of the rust
# run on stable and beta to ensure that tests won't break on the next version of the rust
# toolchain
toolchain: [1.62.0, stable, beta]
steps:
- name: Checkout
Expand Down
16 changes: 8 additions & 8 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,14 @@ edition = "2021"
rust-version = "1.62.0"

[target.'cfg(windows)'.dependencies]
winapi = { version = "0.3.8", features = [
"winbase",
"consoleapi",
"processenv",
"handleapi",
"synchapi",
"impl-default",
# Note that 0.56.0 is the last version that supports Rust 1.62.0, the next version requires Rust
# 1.70.0. This would prevent crossterm from being able to compile this on the stable version of
# Debian (which ships with Rust 1.63.0).
windows = { version = "0.56.0", features = [
"Win32_Security",
"Win32_Storage_FileSystem",
"Win32_System_Console",
"Win32_System_Threading",
] }

[package.metadata.docs.rs]
default-target = "x86_64-pc-windows-msvc"
4 changes: 2 additions & 2 deletions examples/coloring_example.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,8 @@ fn set_foreground_color() -> Result<()> {

// 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;
if (attrs & 0x0080_u16) != 0 {
color |= 0x0080_u16;
}

// set the console text attribute to the new color value.
Expand Down
13 changes: 9 additions & 4 deletions src/cfi.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use std::fmt;
use std::mem::zeroed;

use winapi::um::wincontypes::CONSOLE_FONT_INFO;
use windows::Win32::System::Console::CONSOLE_FONT_INFO;

use crate::Size;

Expand All @@ -23,9 +22,9 @@ impl fmt::Debug for FontInfo {
}

impl FontInfo {
/// Create a new font info without all zeroed properties.
/// Create a new font info with default (zeroed) properties.
pub fn new() -> FontInfo {
FontInfo(unsafe { zeroed() })
FontInfo(CONSOLE_FONT_INFO::default())
}

/// Get the size of the font.
Expand All @@ -40,3 +39,9 @@ impl FontInfo {
self.0.nFont
}
}

impl Default for FontInfo {
fn default() -> Self {
Self::new()
}
}
74 changes: 23 additions & 51 deletions src/console.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,16 @@
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::{
use std::{
io::{self, Result},
iter, slice, str,
};

use windows::Win32::System::Console::{
FillConsoleOutputAttribute, FillConsoleOutputCharacterA, GetLargestConsoleWindowSize,
SetConsoleTextAttribute, SetConsoleWindowInfo, COORD, INPUT_RECORD, SMALL_RECT,
GetNumberOfConsoleInputEvents, ReadConsoleInputW, SetConsoleTextAttribute,
SetConsoleWindowInfo, WriteConsoleW, CONSOLE_CHARACTER_ATTRIBUTES, COORD, INPUT_RECORD,
SMALL_RECT,
};

use super::{result, Coord, Handle, HandleType, InputRecord, WindowPositions};
use super::{Coord, Handle, HandleType, InputRecord, WindowPositions};

/// A wrapper around a screen buffer.
#[derive(Debug, Clone)]
Expand All @@ -39,7 +37,7 @@ impl Console {
/// 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) })?;
unsafe { SetConsoleTextAttribute(*self.handle, CONSOLE_CHARACTER_ATTRIBUTES(value)) }?;
Ok(())
}

Expand All @@ -48,14 +46,8 @@ impl Console {
/// 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) })?;

unsafe { SetConsoleWindowInfo(*self.handle, absolute, &a) }?;
Ok(())
}

Expand All @@ -64,14 +56,14 @@ impl Console {
///
/// This wraps
/// [`FillConsoleOutputCharacterA`](https://docs.microsoft.com/en-us/windows/console/fillconsoleoutputcharacter).
pub fn fill_whit_character(
pub fn fill_with_character(
&self,
start_location: Coord,
cells_to_write: u32,
filling_char: char,
) -> Result<u32> {
let mut chars_written = 0;
result(unsafe {
unsafe {
// fill the cells in console with blanks
FillConsoleOutputCharacterA(
*self.handle,
Expand All @@ -80,7 +72,7 @@ impl Console {
COORD::from(start_location),
&mut chars_written,
)
})?;
}?;

Ok(chars_written)
}
Expand All @@ -98,15 +90,15 @@ impl Console {
) -> Result<u32> {
let mut cells_written = 0;
// Get the position of the current console window
result(unsafe {
unsafe {
FillConsoleOutputAttribute(
*self.handle,
dw_attribute,
cells_to_write,
COORD::from(start_location),
&mut cells_written,
)
})?;
}?;

Ok(cells_written)
}
Expand Down Expand Up @@ -134,20 +126,9 @@ impl Console {
}
};

let utf16: Vec<u16> = utf8.encode_utf16().collect();
let utf16_ptr: *const c_void = utf16.as_ptr() as *const _ as *const c_void;
let cells_written: Option<*mut u32> = None;

let mut cells_written: u32 = 0;

result(unsafe {
WriteConsoleW(
*self.handle,
utf16_ptr,
utf16.len() as u32,
&mut cells_written,
NULL,
)
})?;
unsafe { WriteConsoleW(*self.handle, buf, cells_written, None) }?;

Ok(utf8.as_bytes().len())
}
Expand Down Expand Up @@ -202,8 +183,8 @@ impl Console {
/// 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) })?;
let mut buf_len = 0;
unsafe { GetNumberOfConsoleInputEvents(*self.handle, &mut buf_len) }?;
Ok(buf_len)
}

Expand All @@ -213,17 +194,8 @@ impl Console {
/// 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,
)
})?;

debug_assert!(buf.len() < u32::MAX as usize);
unsafe { ReadConsoleInputW(*self.handle, buf, &mut num_records) }?;
Ok(num_records as usize)
}
}
Expand Down
13 changes: 7 additions & 6 deletions src/console_mode.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use std::io::Result;

use winapi::um::consoleapi::{GetConsoleMode, SetConsoleMode};
use windows::Win32::System::Console::{GetConsoleMode, SetConsoleMode, CONSOLE_MODE};

use super::{result, Handle, HandleType};
use super::{Handle, HandleType};

/// A wrapper around a screen buffer, focusing on calls to get and set the console mode.
///
Expand Down Expand Up @@ -32,7 +32,8 @@ impl ConsoleMode {
/// 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) })
unsafe { SetConsoleMode(*self.handle, CONSOLE_MODE(console_mode)) }?;
Ok(())
}

/// Get the console mode.
Expand All @@ -42,9 +43,9 @@ impl ConsoleMode {
/// 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)
let mut console_mode = CONSOLE_MODE(0);
unsafe { GetConsoleMode(*self.handle, &mut console_mode) }?;
Ok(console_mode.0)
}
}

Expand Down
15 changes: 10 additions & 5 deletions src/csbi.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use std::fmt;
use std::mem::zeroed;

use winapi::um::wincon::CONSOLE_SCREEN_BUFFER_INFO;
use windows::Win32::System::Console::CONSOLE_SCREEN_BUFFER_INFO;

use super::{Coord, Size, WindowPositions};

Expand Down Expand Up @@ -31,9 +30,9 @@ impl fmt::Debug for ScreenBufferInfo {
}

impl ScreenBufferInfo {
/// Create a new console screen buffer without all zeroed properties.
/// Create a new console screen buffer with default (zeroed) properties.
pub fn new() -> ScreenBufferInfo {
ScreenBufferInfo(unsafe { zeroed() })
ScreenBufferInfo(CONSOLE_SCREEN_BUFFER_INFO::default())
}

/// Get the size of the screen buffer.
Expand Down Expand Up @@ -64,7 +63,7 @@ impl ScreenBufferInfo {
///
/// Will take `wAttributes` from the current screen buffer.
pub fn attributes(&self) -> u16 {
self.0.wAttributes
self.0.wAttributes.0
}

/// Get the current column and row of the terminal cursor in the screen buffer.
Expand All @@ -75,6 +74,12 @@ impl ScreenBufferInfo {
}
}

impl Default for ScreenBufferInfo {
fn default() -> Self {
Self::new()
}
}

impl From<CONSOLE_SCREEN_BUFFER_INFO> for ScreenBufferInfo {
fn from(csbi: CONSOLE_SCREEN_BUFFER_INFO) -> Self {
ScreenBufferInfo(csbi)
Expand Down
Loading

0 comments on commit f0200fc

Please sign in to comment.