|
|
@ -1,6 +1,11 @@
|
|
|
|
use std::io;
|
|
|
|
mod error;
|
|
|
|
use std::io::Write;
|
|
|
|
|
|
|
|
use windows::Win32::{Foundation::GetLastError, System::Console};
|
|
|
|
use std::io::{self, Write};
|
|
|
|
|
|
|
|
use windows::Win32::{Foundation::HANDLE, System::Console};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
use anyhow::{Context, Result};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
use crate::error::Error;
|
|
|
|
|
|
|
|
|
|
|
|
fn print_input_mode(mode: Console::CONSOLE_MODE) {
|
|
|
|
fn print_input_mode(mode: Console::CONSOLE_MODE) {
|
|
|
|
// Characters read by the ReadFile or ReadConsole function are written to the active screen
|
|
|
|
// Characters read by the ReadFile or ReadConsole function are written to the active screen
|
|
|
@ -171,56 +176,130 @@ fn print_output_mode(mode: Console::CONSOLE_MODE) {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
fn main() {
|
|
|
|
fn stdin_handle() -> Result<HANDLE> {
|
|
|
|
let mut stdout = io::stdout();
|
|
|
|
unsafe {
|
|
|
|
|
|
|
|
let handle = Console::GetStdHandle(Console::STD_INPUT_HANDLE)
|
|
|
|
|
|
|
|
.context("unable to get stdin handle")?;
|
|
|
|
|
|
|
|
Ok(handle)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fn stdout_handle() -> Result<HANDLE> {
|
|
|
|
|
|
|
|
unsafe {
|
|
|
|
|
|
|
|
let handle = Console::GetStdHandle(Console::STD_OUTPUT_HANDLE)
|
|
|
|
|
|
|
|
.context("unable to get stdin handle")?;
|
|
|
|
|
|
|
|
Ok(handle)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fn setup_stdin() -> Result<()> {
|
|
|
|
let mut mode = Console::CONSOLE_MODE(0);
|
|
|
|
let mut mode = Console::CONSOLE_MODE(0);
|
|
|
|
unsafe {
|
|
|
|
unsafe {
|
|
|
|
let handle = Console::GetStdHandle(Console::STD_INPUT_HANDLE).unwrap();
|
|
|
|
let handle = stdin_handle()?;
|
|
|
|
if Console::GetConsoleMode(handle, &mut mode).as_bool() {
|
|
|
|
Error::check(Console::GetConsoleMode(handle, &mut mode))?;
|
|
|
|
println!("Stdin details:");
|
|
|
|
println!("Stdin details:");
|
|
|
|
print_input_mode(mode);
|
|
|
|
print_input_mode(mode);
|
|
|
|
} else {
|
|
|
|
|
|
|
|
let err = GetLastError();
|
|
|
|
// allow terminal input characters
|
|
|
|
println!(
|
|
|
|
mode |= Console::ENABLE_VIRTUAL_TERMINAL_INPUT;
|
|
|
|
"Unable to get console mode: {:?}",
|
|
|
|
|
|
|
|
err.to_hresult().message()
|
|
|
|
// disable automatic processing of CTRL+C, we'll handle it ourselves
|
|
|
|
);
|
|
|
|
mode &= !Console::ENABLE_PROCESSED_INPUT;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let handle = Console::GetStdHandle(Console::STD_OUTPUT_HANDLE).unwrap();
|
|
|
|
// disable line mode to get every input as its pressed
|
|
|
|
|
|
|
|
mode &= !Console::ENABLE_LINE_INPUT;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// disable automatic echoing of inputs
|
|
|
|
|
|
|
|
mode &= !Console::ENABLE_ECHO_INPUT;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// enable mouse input
|
|
|
|
|
|
|
|
mode |= Console::ENABLE_MOUSE_INPUT;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Error::check(Console::SetConsoleMode(handle, mode))?;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fn setup_stdout() -> Result<()> {
|
|
|
|
|
|
|
|
let mut mode = Console::CONSOLE_MODE(0);
|
|
|
|
|
|
|
|
unsafe {
|
|
|
|
|
|
|
|
let handle = stdout_handle()?;
|
|
|
|
if Console::GetConsoleMode(handle, &mut mode).as_bool() {
|
|
|
|
if Console::GetConsoleMode(handle, &mut mode).as_bool() {
|
|
|
|
println!("Stdout details:");
|
|
|
|
println!("Stdout details:");
|
|
|
|
print_output_mode(mode);
|
|
|
|
print_output_mode(mode);
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
let err = GetLastError();
|
|
|
|
return Err(Error::last_error().into());
|
|
|
|
println!(
|
|
|
|
|
|
|
|
"Unable to get console mode: {:?}",
|
|
|
|
|
|
|
|
err.to_hresult().message()
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fn main() -> Result<()> {
|
|
|
|
|
|
|
|
setup_stdin()?;
|
|
|
|
|
|
|
|
setup_stdout()?;
|
|
|
|
|
|
|
|
|
|
|
|
let stdin = io::stdin();
|
|
|
|
let stdin = stdin_handle()?;
|
|
|
|
let mut line = String::new();
|
|
|
|
let mut buf = [Console::INPUT_RECORD::default(); 100];
|
|
|
|
loop {
|
|
|
|
loop {
|
|
|
|
if let Err(_) = stdout.write(b"> ") {
|
|
|
|
let mut n: u32 = 0;
|
|
|
|
break;
|
|
|
|
unsafe {
|
|
|
|
|
|
|
|
Error::check(Console::ReadConsoleInputA(stdin, &mut buf, &mut n))?;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if let Err(_) = stdout.flush() {
|
|
|
|
let n = n as usize;
|
|
|
|
break;
|
|
|
|
println!("read: {:?}", n);
|
|
|
|
}
|
|
|
|
for rec in &buf[0..n] {
|
|
|
|
match stdin.read_line(&mut line) {
|
|
|
|
println!("Event Type: {}", rec.EventType);
|
|
|
|
Ok(_) => {
|
|
|
|
match rec.EventType as u32 {
|
|
|
|
if let Err(_) = stdout.write(
|
|
|
|
Console::FOCUS_EVENT => {
|
|
|
|
String::from("\u{001b}[31m ok \u{001b}[0m\n")
|
|
|
|
// The Event member contains a FOCUS_EVENT_RECORD structure. These events are
|
|
|
|
.as_str()
|
|
|
|
// used internally and should be ignored.
|
|
|
|
.as_bytes(),
|
|
|
|
unsafe {
|
|
|
|
) {
|
|
|
|
let event = rec.Event.FocusEvent;
|
|
|
|
break;
|
|
|
|
println!("Focus Event: {:?}", event);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
Console::MENU_EVENT => {
|
|
|
|
|
|
|
|
// The Event member contains a MENU_EVENT_RECORD structure. These events are
|
|
|
|
|
|
|
|
// used internally and should be ignored.
|
|
|
|
|
|
|
|
unsafe {
|
|
|
|
|
|
|
|
let event = rec.Event.MenuEvent;
|
|
|
|
|
|
|
|
println!("Menu Event: {:?}", event);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
Console::KEY_EVENT => {
|
|
|
|
|
|
|
|
// The Event member contains a KEY_EVENT_RECORD structure with information
|
|
|
|
|
|
|
|
// about a keyboard event.
|
|
|
|
|
|
|
|
unsafe {
|
|
|
|
|
|
|
|
let event = rec.Event.KeyEvent;
|
|
|
|
|
|
|
|
let down = event.bKeyDown;
|
|
|
|
|
|
|
|
let repeats = event.wRepeatCount;
|
|
|
|
|
|
|
|
let key_code = event.wVirtualKeyCode;
|
|
|
|
|
|
|
|
let scan_code = event.wVirtualScanCode;
|
|
|
|
|
|
|
|
let c = event.uChar.UnicodeChar;
|
|
|
|
|
|
|
|
let modifiers = event.dwControlKeyState;
|
|
|
|
|
|
|
|
println!(
|
|
|
|
|
|
|
|
"Key Event: down: {down:?} repeats: {repeats} key-code: {key_code} scan-code: {scan_code} char: {c} modifiers: {modifiers}"
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
Console::MOUSE_EVENT => {
|
|
|
|
|
|
|
|
// The Event member contains a MOUSE_EVENT_RECORD structure with information
|
|
|
|
|
|
|
|
// about a mouse movement or button press event.
|
|
|
|
|
|
|
|
unsafe {
|
|
|
|
|
|
|
|
let event = rec.Event.MouseEvent;
|
|
|
|
|
|
|
|
println!("Mouse Event: {:?}", event);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
Console::WINDOW_BUFFER_SIZE_EVENT => {
|
|
|
|
|
|
|
|
// The Event member contains a WINDOW_BUFFER_SIZE_RECORD structure with
|
|
|
|
|
|
|
|
// information about the new size of the console screen buffer.
|
|
|
|
|
|
|
|
unsafe {
|
|
|
|
|
|
|
|
let event = rec.Event.WindowBufferSizeEvent;
|
|
|
|
|
|
|
|
println!("Window Buffer Event: {:?}", event);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Err(_) => break,
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|