use std::io;
use std::ptr;
pub fn read_password() -> io::Result<String> {
const STD_INPUT_HANDLE: u32 = 0xFFFFFFF6;
const ENABLE_ECHO_INPUT: u32 = 0x0004;
#[link(name = "kernel32")]
unsafe extern "system" {
fn GetStdHandle(nStdHandle: u32) -> *mut core::ffi::c_void;
fn GetConsoleMode(hConsoleHandle: *mut core::ffi::c_void, lpMode: *mut u32) -> i32;
fn SetConsoleMode(hConsoleHandle: *mut core::ffi::c_void, dwMode: u32) -> i32;
fn ReadConsoleA(
hConsoleInput: *mut core::ffi::c_void,
lpBuffer: *mut u8,
nNumberOfCharsToRead: u32,
lpNumberOfCharsRead: *mut u32,
pInputControl: *mut core::ffi::c_void,
) -> i32;
}
unsafe {
let handle = GetStdHandle(STD_INPUT_HANDLE);
if handle.is_null() {
return Err(io::Error::last_os_error());
}
let mut original_mode: u32 = 0;
if GetConsoleMode(handle, &mut original_mode) == 0 {
return Err(io::Error::last_os_error());
}
let new_mode = original_mode & !ENABLE_ECHO_INPUT;
if SetConsoleMode(handle, new_mode) == 0 {
return Err(io::Error::last_os_error());
}
struct ConsoleResetter {
handle: *mut core::ffi::c_void,
mode: u32,
}
impl Drop for ConsoleResetter {
fn drop(&mut self) {
unsafe {
SetConsoleMode(self.handle, self.mode);
}
}
}
let _resetter = ConsoleResetter {
handle,
mode: original_mode,
};
const BUFFER_SIZE: usize = 1024;
let mut buffer = [0u8; BUFFER_SIZE];
let mut chars_read: u32 = 0;
if ReadConsoleA(
handle,
buffer.as_mut_ptr(),
(BUFFER_SIZE - 1) as u32,
&mut chars_read,
ptr::null_mut(),
) == 0
{
return Err(io::Error::last_os_error());
}
let mut password = String::new();
for &byte in buffer.iter().take(chars_read as usize) {
if byte == b'\r' || byte == b'\n' {
continue;
}
password.push(byte as char);
}
Ok(password)
}
}
pub fn get_terminal_size() -> Option<(u16, u16)> {
const STD_OUTPUT_HANDLE: u32 = 0xFFFFFFF5;
#[allow(non_camel_case_types, clippy::upper_case_acronyms)]
#[repr(C)]
struct COORD {
x: i16,
y: i16,
}
#[allow(non_camel_case_types, clippy::upper_case_acronyms)]
#[repr(C)]
struct SMALL_RECT {
left: i16,
top: i16,
right: i16,
bottom: i16,
}
#[allow(non_camel_case_types, clippy::upper_case_acronyms)]
#[repr(C)]
struct CONSOLE_SCREEN_BUFFER_INFO {
dw_size: COORD,
dw_cursor_position: COORD,
w_attributes: u16,
sr_window: SMALL_RECT,
dw_maximum_window_size: COORD,
}
#[link(name = "kernel32")]
unsafe extern "system" {
fn GetStdHandle(nStdHandle: u32) -> *mut core::ffi::c_void;
fn GetConsoleScreenBufferInfo(
hConsoleOutput: *mut core::ffi::c_void,
lpConsoleScreenBufferInfo: *mut CONSOLE_SCREEN_BUFFER_INFO,
) -> i32;
}
unsafe {
let handle = GetStdHandle(STD_OUTPUT_HANDLE);
if handle.is_null() {
return None;
}
let mut info: CONSOLE_SCREEN_BUFFER_INFO = std::mem::zeroed();
if GetConsoleScreenBufferInfo(handle, &mut info) == 0 {
return None;
}
let width = (info.sr_window.right - info.sr_window.left + 1) as u16;
let height = (info.sr_window.bottom - info.sr_window.top + 1) as u16;
Some((width, height))
}
}