diff --git a/Cargo.lock b/Cargo.lock index d6f2291..941c6f8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5,3 +5,72 @@ version = 3 [[package]] name = "wash" version = "0.1.0" +dependencies = [ + "windows", +] + +[[package]] +name = "windows" +version = "0.44.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e745dab35a0c4c77aa3ce42d595e13d2003d6902d6b08c9ef5fc326d08da12b" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e2522491fbfcd58cc84d47aeb2958948c4b8982e9a2d8a2a35bbaed431390e7" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7" + +[[package]] +name = "windows_i686_gnu" +version = "0.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640" + +[[package]] +name = "windows_i686_msvc" +version = "0.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1040f221285e17ebccbc2591ffdc2d44ee1f9186324dd3e84e99ac68d699c45" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd" diff --git a/Cargo.toml b/Cargo.toml index e766507..b0c20cb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,3 +6,10 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] + +[dependencies.windows] +version = "0.44.0" +features = [ + "Win32_Foundation", + "Win32_System_Console", +] diff --git a/src/main.rs b/src/main.rs index e42e36a..96f963f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,10 +1,207 @@ use std::io; use std::io::Write; +use windows::Win32::{Foundation::GetLastError, System::Console}; + +fn print_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"); + } else { + println!("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"); + } else { + println!("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"); + } else { + println!("Line Input Mode: Disabled"); + } + + // If the mouse pointer is within the borders of the console window and the window has the + // keyboard focus, mouse events generated by mouse movement and button presses are placed in + // the input buffer. These events are discarded by ReadFile or ReadConsole, even when this 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"); + } else { + println!("Mouse Input: Disabled"); + } + + // CTRL+C is processed by the system and is not placed in the input buffer. If the input buffer + // is being read by ReadFile or ReadConsole, other control keys are processed by the system and + // are not returned in the ReadFile or ReadConsole buffer. If the ENABLE_LINE_INPUT mode is + // 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"); + } else { + println!("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"); + } else { + println!("Quick Edit Mode: Disabled"); + } + + // User interactions that change the size of the console screen buffer are reported in the + // console's input buffer. Information about these events can be read from the input buffer by + // 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"); + } else { + println!("Window Input: Disabled"); + } + + // Setting this flag directs the Virtual Terminal processing engine to convert user input + // received by the console window into Console Virtual Terminal Sequences that can be retrieved + // by a supporting application through ReadFile or ReadConsole functions. + // + // The typical usage of this flag is intended in conjunction with + // 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"); + } else { + println!("Virtual Terminal Input: Disabled"); + } +} + +fn print_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"); + } else { + println!("Processed Output: Disabled"); + } + + // When writing with WriteFile or WriteConsole or echoing with ReadFile or ReadConsole, the + // cursor moves to the beginning of the next row when it reaches the end of the current row. + // This causes the rows displayed in the console window to scroll up automatically when the + // cursor advances beyond the last row in the window. It also causes the contents of the + // console screen buffer to scroll up (../discarding the top row of the console screen buffer) + // 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"); + } else { + println!("Wrap at EOL: Disabled"); + } + + // When writing with WriteFile or WriteConsole, characters are parsed for VT100 and similar + // control character sequences that control cursor movement, color/font mode, and other + // operations that can also be performed via the existing Console APIs. For more information, + // see Console Virtual Terminal Sequences. + // + // Ensure ENABLE_PROCESSED_OUTPUT is set when using this flag. + if (mode & Console::ENABLE_VIRTUAL_TERMINAL_PROCESSING).0 > 0 { + println!("Terminal Processing: Enabled"); + } else { + println!("Terminal Processing: Disabled"); + } + + // When writing with WriteFile or WriteConsole, this adds an additional state to end-of-line + // wrapping that can delay the cursor move and buffer scroll operations. + // + // Normally when ENABLE_WRAP_AT_EOL_OUTPUT is set and text reaches the end of the line, the + // cursor will immediately move to the next line and the contents of the buffer will scroll up + // by one line. In contrast with this flag set, the cursor does not move to the next line, and + // the scroll operation is not performed. The written character will be printed in the final + // position on the line and the cursor will remain above this character as if + // ENABLE_WRAP_AT_EOL_OUTPUT was off, but the next printable character will be printed as if + // ENABLE_WRAP_AT_EOL_OUTPUT is on. No overwrite will occur. Specifically, the cursor quickly + // advances down to the following line, a scroll is performed if necessary, the character is + // printed, and the cursor advances one more position. + // + // The typical usage of this flag is intended in conjunction with setting + // ENABLE_VIRTUAL_TERMINAL_PROCESSING to better emulate a terminal emulator where writing the + // 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"); + } else { + println!("Newline Auto Return: Disabled"); + } + + // The APIs for writing character attributes including WriteConsoleOutput and + // WriteConsoleOutputAttribute allow the usage of flags from character attributes to adjust the + // color of the foreground and background of text. Additionally, a range of DBCS flags was + // specified with the COMMON_LVB prefix. Historically, these flags only functioned in DBCS code + // pages for Chinese, Japanese, and Korean languages. + // + // With exception of the leading byte and trailing byte flags, the remaining flags describing + // line drawing and reverse video (../swap foreground and background colors) can be useful for + // other languages to emphasize portions of output. + // + // Setting this console mode flag will allow these attributes to be used in every code page on + // every language. + // + // It is off by default to maintain compatibility with known applications that have + // historically taken advantage of the console ignoring these flags on non-CJK machines to + // store bits in these fields for their own purposes or by accident. + // + // Note that using the ENABLE_VIRTUAL_TERMINAL_PROCESSING mode can result in LVB grid and + // 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"); + } else { + println!("LVB Grid: Disabled"); + } +} fn main() { - let stdin = io::stdin(); let mut stdout = io::stdout(); + let mut mode = Console::CONSOLE_MODE(0); + unsafe { + let handle = Console::GetStdHandle(Console::STD_INPUT_HANDLE).unwrap(); + if Console::GetConsoleMode(handle, &mut mode).as_bool() { + println!("Stdin details:"); + print_input_mode(mode); + } else { + let err = GetLastError(); + println!( + "Unable to get console mode: {:?}", + err.to_hresult().message() + ); + } + + let handle = Console::GetStdHandle(Console::STD_OUTPUT_HANDLE).unwrap(); + if Console::GetConsoleMode(handle, &mut mode).as_bool() { + println!("Stdout details:"); + print_output_mode(mode); + } else { + let err = GetLastError(); + println!( + "Unable to get console mode: {:?}", + err.to_hresult().message() + ); + } + } + + let stdin = io::stdin(); let mut line = String::new(); loop { if let Err(_) = stdout.write(b"> ") { @@ -15,7 +212,11 @@ fn main() { } match stdin.read_line(&mut line) { Ok(_) => { - if let Err(_) = stdout.write(b"ok\n") { + if let Err(_) = stdout.write( + String::from("\u{001b}[31m ok \u{001b}[0m\n") + .as_str() + .as_bytes(), + ) { break; } }