diff --git a/src/main.rs b/src/main.rs index 4e73258..cd63ffc 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,37 +1,39 @@ mod error; mod log; +use std::ffi::OsString; use windows::Win32::{Foundation::HANDLE, System::Console}; +use windows::{h, s, w}; use anyhow::{Context, Result}; use crate::{error::Error, log::*}; -fn print_input_mode(mode: Console::CONSOLE_MODE) { +fn log_input_mode(mode: Console::CONSOLE_MODE) { // Characters read by the ReadFile or ReadConsole function are written to the active screen // buffer as they are typed into the console. This mode can be used only if the // ENABLE_LINE_INPUT mode is also enabled. if (mode & Console::ENABLE_ECHO_INPUT).0 > 0 { - println!("Echo Input: Enabled"); + debug!("Echo Input: Enabled"); } else { - println!("Echo Input: Disabled"); + debug!("Echo Input: Disabled"); } // When enabled, text entered in a console window will be inserted at the current cursor // location and all text following that location will not be overwritten. When disabled, all // following text will be overwritten. if (mode & Console::ENABLE_INSERT_MODE).0 > 0 { - println!("Insert Mode: Enabled"); + debug!("Insert Mode: Enabled"); } else { - println!("Insert Mode: Disabled"); + debug!("Insert Mode: Disabled"); } // The ReadFile or ReadConsole function returns only when a carriage return character is read. // If this mode is disabled, the functions return when one or more characters are available. if (mode & Console::ENABLE_LINE_INPUT).0 > 0 { - println!("Line Input Mode: Enabled"); + debug!("Line Input Mode: Enabled"); } else { - println!("Line Input Mode: Disabled"); + debug!("Line Input Mode: Disabled"); } // If the mouse pointer is within the borders of the console window and the window has the @@ -40,9 +42,9 @@ fn print_input_mode(mode: Console::CONSOLE_MODE) { // is enabled. The ReadConsoleInput function can be used to read MOUSE_EVENT input records from // the input buffer. if (mode & Console::ENABLE_MOUSE_INPUT).0 > 0 { - println!("Mouse Input: Enabled"); + debug!("Mouse Input: Enabled"); } else { - println!("Mouse Input: Disabled"); + debug!("Mouse Input: Disabled"); } // CTRL+C is processed by the system and is not placed in the input buffer. If the input buffer @@ -51,18 +53,18 @@ fn print_input_mode(mode: Console::CONSOLE_MODE) { // also enabled, backspace, carriage return, and line feed characters are handled by the // system. if (mode & Console::ENABLE_PROCESSED_INPUT).0 > 0 { - println!("Processed Input: Enabled"); + debug!("Processed Input: Enabled"); } else { - println!("Processed Input: Disabled"); + debug!("Processed Input: Disabled"); } // This flag enables the user to use the mouse to select and edit text. To enable this mode, // use ENABLE_QUICK_EDIT_MODE | ENABLE_EXTENDED_FLAGS. To disable this mode, use // ENABLE_EXTENDED_FLAGS without this flag. if (mode & Console::ENABLE_QUICK_EDIT_MODE).0 > 0 { - println!("Quick Edit Mode: Enabled"); + debug!("Quick Edit Mode: Enabled"); } else { - println!("Quick Edit Mode: Disabled"); + debug!("Quick Edit Mode: Disabled"); } // User interactions that change the size of the console screen buffer are reported in the @@ -70,9 +72,9 @@ fn print_input_mode(mode: Console::CONSOLE_MODE) { // applications using the ReadConsoleInput function, but not by those using ReadFile or // ReadConsole. if (mode & Console::ENABLE_WINDOW_INPUT).0 > 0 { - println!("Window Input: Enabled"); + debug!("Window Input: Enabled"); } else { - println!("Window Input: Disabled"); + debug!("Window Input: Disabled"); } // Setting this flag directs the Virtual Terminal processing engine to convert user input @@ -83,22 +85,22 @@ fn print_input_mode(mode: Console::CONSOLE_MODE) { // ENABLE_VIRTUAL_TERMINAL_PROCESSING on the output handle to connect to an application that // communicates exclusively via virtual terminal sequences. if (mode & Console::ENABLE_VIRTUAL_TERMINAL_INPUT).0 > 0 { - println!("Virtual Terminal Input: Enabled"); + debug!("Virtual Terminal Input: Enabled"); } else { - println!("Virtual Terminal Input: Disabled"); + debug!("Virtual Terminal Input: Disabled"); } } -fn print_output_mode(mode: Console::CONSOLE_MODE) { +fn log_output_mode(mode: Console::CONSOLE_MODE) { // Characters written by the WriteFile or WriteConsole function or echoed by the ReadFile or // ReadConsole function are parsed for ASCII control sequences, and the correct action is // performed. Backspace, tab, bell, carriage return, and line feed characters are processed. It // should be enabled when using control sequences or when ENABLE_VIRTUAL_TERMINAL_PROCESSING is // set. if (mode & Console::ENABLE_PROCESSED_OUTPUT).0 > 0 { - println!("Processed Output: Enabled"); + debug!("Processed Output: Enabled"); } else { - println!("Processed Output: Disabled"); + debug!("Processed Output: Disabled"); } // When writing with WriteFile or WriteConsole or echoing with ReadFile or ReadConsole, the @@ -109,9 +111,9 @@ fn print_output_mode(mode: Console::CONSOLE_MODE) { // when the cursor advances beyond the last row in the console screen buffer. If this mode is // disabled, the last character in the row is overwritten with any subsequent characters. if (mode & Console::ENABLE_WRAP_AT_EOL_OUTPUT).0 > 0 { - println!("Wrap at EOL: Enabled"); + debug!("Wrap at EOL: Enabled"); } else { - println!("Wrap at EOL: Disabled"); + debug!("Wrap at EOL: Disabled"); } // When writing with WriteFile or WriteConsole, characters are parsed for VT100 and similar @@ -121,9 +123,9 @@ fn print_output_mode(mode: Console::CONSOLE_MODE) { // // Ensure ENABLE_PROCESSED_OUTPUT is set when using this flag. if (mode & Console::ENABLE_VIRTUAL_TERMINAL_PROCESSING).0 > 0 { - println!("Terminal Processing: Enabled"); + debug!("Terminal Processing: Enabled"); } else { - println!("Terminal Processing: Disabled"); + debug!("Terminal Processing: Disabled"); } // When writing with WriteFile or WriteConsole, this adds an additional state to end-of-line @@ -144,9 +146,9 @@ fn print_output_mode(mode: Console::CONSOLE_MODE) { // final character on the screen (../in the bottom right corner) without triggering an // immediate scroll is the desired behavior. if (mode & Console::DISABLE_NEWLINE_AUTO_RETURN).0 > 0 { - println!("Newline Auto Return: Enabled"); + debug!("Newline Auto Return: Enabled"); } else { - println!("Newline Auto Return: Disabled"); + debug!("Newline Auto Return: Disabled"); } // The APIs for writing character attributes including WriteConsoleOutput and @@ -170,9 +172,9 @@ fn print_output_mode(mode: Console::CONSOLE_MODE) { // reverse video flags being set while this flag is still off if the attached application // requests underlining or inverse video via Console Virtual Terminal Sequences. if (mode & Console::ENABLE_LVB_GRID_WORLDWIDE).0 > 0 { - println!("LVB Grid: Enabled"); + debug!("LVB Grid: Enabled"); } else { - println!("LVB Grid: Disabled"); + debug!("LVB Grid: Disabled"); } } @@ -215,19 +217,23 @@ fn setup_stdin() -> Result<()> { Error::check(Console::SetConsoleMode(handle, mode))?; Error::check(Console::GetConsoleMode(handle, &mut mode))?; - println!("Stdin details:"); - print_input_mode(mode); + debug!("Stdin details:"); + log_input_mode(mode); } Ok(()) } fn setup_stdout() -> Result<()> { + unsafe { + Console::SetConsoleOutputCP(65001); + } + let mut mode = Console::CONSOLE_MODE(0); unsafe { let handle = stdout_handle()?; if Console::GetConsoleMode(handle, &mut mode).as_bool() { - println!("Stdout details:"); - print_output_mode(mode); + debug!("Stdout details:"); + log_output_mode(mode); } else { return Err(Error::last_error().into()); } @@ -241,23 +247,24 @@ fn main() -> Result<()> { setup_stdout()?; let stdin = stdin_handle()?; + let stdout = stdout_handle()?; let mut buf = [Console::INPUT_RECORD::default(); 100]; + loop { let mut n: u32 = 0; unsafe { Error::check(Console::ReadConsoleInputW(stdin, &mut buf, &mut n))?; } let n = n as usize; - println!("read: {:?}", n); for rec in &buf[0..n] { - println!("Event Type: {}", rec.EventType); + debug!("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); + debug!("Focus Event: {:?}", event); } } Console::MENU_EVENT => { @@ -265,7 +272,7 @@ fn main() -> Result<()> { // used internally and should be ignored. unsafe { let event = rec.Event.MenuEvent; - println!("Menu Event: {:?}", event); + debug!("Menu Event: {:?}", event); } } Console::KEY_EVENT => { @@ -273,13 +280,72 @@ fn main() -> Result<()> { // about a keyboard event. unsafe { let event = rec.Event.KeyEvent; - let down = event.bKeyDown; + let down = event.bKeyDown.as_bool(); let repeats = event.wRepeatCount; let key_code = event.wVirtualKeyCode; let scan_code = event.wVirtualScanCode; let c = event.uChar.UnicodeChar; let modifiers = event.dwControlKeyState; - println!( + // handle key presses on key up, not key down. This is a little weird but + // it's sending both down and up events when you hit the key anyway. I + // dunno if this is right. But for some reason, the down events don't have + // the modifiers + if !down { + // Carriage Return (Enter key) + if c == 13 { + let mask = Console::LEFT_ALT_PRESSED + | Console::RIGHT_ALT_PRESSED + | Console::LEFT_CTRL_PRESSED + | Console::RIGHT_CTRL_PRESSED + | Console::SHIFT_PRESSED; + if modifiers & mask == 0 { + Error::check(Console::WriteConsoleA( + stdout, + "\r\n".as_bytes(), + None, + None, + ))?; + } + } else if key_code == 74 && modifiers == 40 { + // key j modifier ctrl + // let text = "X"; + let text = "•"; + // let z = text.encode_utf16().map(|c| c.to_ne_bytes()); + //let t16: Vec = text + // .encode_utf16() + // .chain(std::iter::once(0 as u16)) + // .collect(); + // t16.as_ptr() + // let (_, k, _) = t16.align_to::(); + // let x: &[u8] = &[0x20, 0x22, 0x00, 0x00]; + //let x: &[u16] = &[0x2022]; + //let mut z = x[0].to_ne_bytes(); + //let z: [u8] = [(0x2022 as u16).to_ne_bytes()]; + //let mut z = Vec::new(); + //text.as_bytes() + + Error::check(Console::WriteConsoleA( + stdout, + text.as_bytes(), + None, + None, + ))?; + } else { + if let Some(c) = char::from_u32(event.uChar.UnicodeChar as u32) { + if !c.is_control() { + let mut buf = [0 as u8; 2]; + let s = c.encode_utf8(&mut buf); + Error::check(Console::WriteConsoleW( + stdout, + s.as_bytes(), + None, + None, + ))?; + } + } + } + } + debug!( "Key Event: down: {down:?} repeats: {repeats} key-code: {key_code} scan-code: {scan_code} char: {c} modifiers: {modifiers}" ); } @@ -289,7 +355,7 @@ fn main() -> Result<()> { // about a mouse movement or button press event. unsafe { let event = rec.Event.MouseEvent; - println!("Mouse Event: {:?}", event); + debug!("Mouse Event: {:?}", event); } } Console::WINDOW_BUFFER_SIZE_EVENT => { @@ -297,7 +363,7 @@ fn main() -> Result<()> { // information about the new size of the console screen buffer. unsafe { let event = rec.Event.WindowBufferSizeEvent; - println!("Window Buffer Event: {:?}", event); + debug!("Window Buffer Event: {:?}", event); } } _ => {}