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}