decoding input events

parse-tree
Jordan Orelli 2 years ago
parent ee7f8a7db3
commit 1f46fe5bb7

63
Cargo.lock generated

@ -2,10 +2,73 @@
# It is not intended for manual editing. # It is not intended for manual editing.
version = 3 version = 3
[[package]]
name = "anyhow"
version = "1.0.69"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "224afbd727c3d6e4b90103ece64b8d1b67fbb1973b1046c2281eed3f3803f800"
[[package]]
name = "proc-macro2"
version = "1.0.51"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5d727cae5b39d21da60fa540906919ad737832fe0b1c165da3a34d6548c849d6"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b"
dependencies = [
"proc-macro2",
]
[[package]]
name = "syn"
version = "1.0.107"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "thiserror"
version = "1.0.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "unicode-ident"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc"
[[package]] [[package]]
name = "wash" name = "wash"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"anyhow",
"thiserror",
"windows", "windows",
] ]

@ -6,6 +6,8 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
anyhow = "1.0"
thiserror = "1.0"
[dependencies.windows] [dependencies.windows]
version = "0.44.0" version = "0.44.0"

@ -0,0 +1,22 @@
use thiserror::Error;
use windows::Win32::Foundation::{GetLastError, BOOL};
#[derive(Error, Debug)]
pub enum Error {
#[error("windows error: {0}")]
WindowsError(String),
}
impl Error {
pub fn last_error() -> Self {
unsafe { Error::WindowsError(GetLastError().to_hresult().message().to_string()) }
}
pub fn check(b: BOOL) -> Result<(), Self> {
if b.as_bool() {
Ok(())
} else {
Err(Error::last_error())
}
}
}

@ -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;
// 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(())
}
let handle = Console::GetStdHandle(Console::STD_OUTPUT_HANDLE).unwrap(); 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))?;
}
let n = n as usize;
println!("read: {:?}", n);
for rec in &buf[0..n] {
println!("Event Type: {}", rec.EventType);
match rec.EventType as u32 {
Console::FOCUS_EVENT => {
// The Event member contains a FOCUS_EVENT_RECORD structure. These events are
// used internally and should be ignored.
unsafe {
let event = rec.Event.FocusEvent;
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);
} }
if let Err(_) = stdout.flush() {
break;
} }
match stdin.read_line(&mut line) { Console::KEY_EVENT => {
Ok(_) => { // The Event member contains a KEY_EVENT_RECORD structure with information
if let Err(_) = stdout.write( // about a keyboard event.
String::from("\u{001b}[31m ok \u{001b}[0m\n") unsafe {
.as_str() let event = rec.Event.KeyEvent;
.as_bytes(), let down = event.bKeyDown;
) { let repeats = event.wRepeatCount;
break; 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,
} }
} }
} }

Loading…
Cancel
Save