win_term/
lib.rs

1use windows_sys::Win32::{
2    Foundation::HANDLE,
3    System::Console::{
4        GetConsoleScreenBufferInfo, GetConsoleWindow, GetStdHandle, CONSOLE_SCREEN_BUFFER_INFO,
5        SMALL_RECT, STD_OUTPUT_HANDLE,
6    },
7    UI::HiDpi::GetDpiForWindow,
8};
9
10/// Struct to hold terminal size information in terms of width and height.
11#[derive(Debug)]
12pub struct TerminalSize {
13    pub width: i32,  // Width of the terminal in pixels
14    pub height: i32, // Height of the terminal in pixels
15}
16
17/// Struct to hold font size information in terms of width and height.
18#[derive(Debug)]
19pub struct FontSize {
20    pub width: i32,  // Width of a single character in pixels
21    pub height: i32, // Height of a single character in pixels
22}
23
24/// Enum to represent possible errors that can occur while getting terminal or font size.
25#[derive(Debug)]
26pub enum TerminalError {
27    NoStdHandle,        // Standard output handle not found
28    NoScreenBufferInfo, // Failed to retrieve console screen buffer information
29    UnsupportedDpi,     // DPI setting is unsupported (not 96, 120, or 144)
30}
31
32/// This function retrieves the font size used by the terminal in pixels.
33///
34/// ## Assumptions:
35/// - The font size is set to 12 points, and the font type is "Consolas".
36/// - No zooming in or out has been done.
37/// - The DPI is set to either 100%, 125%, or 150% scaling (175% is not supported).
38///
39/// ## Returns:
40/// - `Ok(FontSize)` with the font width and height in pixels.
41/// - `Err(TerminalError)` if there's an issue obtaining the standard handle or the DPI is unsupported.
42///
43/// ## Note:
44/// - The DPI values used are approximations for common scaling settings:
45///   - 96 DPI (100% scaling)
46///   - 120 DPI (125% scaling)
47///   - 144 DPI (150% scaling)
48pub fn get_size_of_the_font() -> Result<FontSize, TerminalError> {
49    unsafe {
50        let h_console: HANDLE = GetStdHandle(STD_OUTPUT_HANDLE);
51        if h_console.is_null() {
52            return Err(TerminalError::NoStdHandle);
53        }
54        let pixel_size = match GetDpiForWindow(GetConsoleWindow()) {
55            96 => FontSize {
56                width: 9,
57                height: 20,
58            },
59            120 => FontSize {
60                width: 12,
61                height: 25,
62            },
63            144 => FontSize {
64                width: 14,
65                height: 32,
66            },
67            _ => return Err(TerminalError::UnsupportedDpi),
68        };
69        return Ok(pixel_size);
70    }
71}
72
73/// This function retrieves the size of the terminal window in pixels.
74///
75/// ## Assumptions:
76/// - The font size is set to 12 points, and the font type is "Consolas".
77/// - No zooming in or out has been done.
78/// - The DPI is set to either 100%, 125%, or 150% scaling (175% is not supported).
79///
80/// ## Returns:
81/// - `Ok(TerminalSize)` with the terminal's width and height in pixels.
82/// - `Err(TerminalError)` if there's an issue obtaining the standard handle, retrieving screen buffer info, or the DPI is unsupported.
83///
84/// ## Note:
85/// - The DPI values used are approximations for common scaling settings:
86///   - 96 DPI (100% scaling)
87///   - 120 DPI (125% scaling)
88///   - 144 DPI (150% scaling)
89pub fn get_size_of_the_terminal() -> Result<TerminalSize, TerminalError> {
90    unsafe {
91        let h_console: HANDLE = GetStdHandle(STD_OUTPUT_HANDLE);
92        if h_console.is_null() {
93            return Err(TerminalError::NoStdHandle);
94        }
95
96        let mut info = CONSOLE_SCREEN_BUFFER_INFO {
97            dwSize: windows_sys::Win32::System::Console::COORD { X: 0, Y: 0 },
98            dwCursorPosition: windows_sys::Win32::System::Console::COORD { X: 0, Y: 0 },
99            wAttributes: 0,
100            srWindow: SMALL_RECT {
101                Left: 0,
102                Top: 0,
103                Right: 0,
104                Bottom: 0,
105            },
106            dwMaximumWindowSize: windows_sys::Win32::System::Console::COORD { X: 0, Y: 0 },
107        };
108        if GetConsoleScreenBufferInfo(h_console, &mut info) == 0 {
109            return Err(TerminalError::NoScreenBufferInfo);
110        }
111        let pixel_size = match GetDpiForWindow(GetConsoleWindow()) {
112            96 => TerminalSize {
113                width: 9 * info.dwSize.X as i32,
114                height: 20 * info.dwSize.Y as i32,
115            },
116            120 => TerminalSize {
117                width: 12 * info.dwSize.X as i32,
118                height: 25 * info.dwSize.Y as i32,
119            },
120            144 => TerminalSize {
121                width: 14 * info.dwSize.X as i32,
122                height: 32 * info.dwSize.Y as i32,
123            },
124            _ => return Err(TerminalError::UnsupportedDpi),
125        };
126        return Ok(pixel_size);
127    }
128}