diff options
author | Roy Ivy III <rivy.dev@gmail.com> | 2023-03-08 13:56:49 -0600 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-03-08 19:56:49 +0000 |
commit | f2e5e01832a40eb71be82f1b46304c56aa2e8dba (patch) | |
tree | f0637a981aa0f22500ab667a6b187c20a2b5fb1c | |
parent | 23e1ba7e2dba1b9453e064f6c92c10b64071b708 (diff) |
fix(runtime/windows): ensure `Deno.stdin.setRaw(false)` properly disables raw mode (#17983)
-rw-r--r-- | runtime/ops/tty.rs | 55 |
1 files changed, 50 insertions, 5 deletions
diff --git a/runtime/ops/tty.rs b/runtime/ops/tty.rs index bd9331d4f..d577a6755 100644 --- a/runtime/ops/tty.rs +++ b/runtime/ops/tty.rs @@ -43,6 +43,26 @@ pub fn init() -> Extension { .build() } +// ref: <https://learn.microsoft.com/en-us/windows/console/setconsolemode> +#[cfg(windows)] +const COOKED_MODE: DWORD = + // enable line-by-line input (returns input only after CR is read) + wincon::ENABLE_LINE_INPUT + // enables real-time character echo to console display (requires ENABLE_LINE_INPUT) + | wincon::ENABLE_ECHO_INPUT + // system handles CTRL-C (with ENABLE_LINE_INPUT, also handles BS, CR, and LF) and other control keys (when using `ReadFile` or `ReadConsole`) + | wincon::ENABLE_PROCESSED_INPUT; + +#[cfg(windows)] +fn mode_raw_input_on(original_mode: DWORD) -> DWORD { + original_mode & !COOKED_MODE | wincon::ENABLE_VIRTUAL_TERMINAL_INPUT +} + +#[cfg(windows)] +fn mode_raw_input_off(original_mode: DWORD) -> DWORD { + original_mode & !wincon::ENABLE_VIRTUAL_TERMINAL_INPUT | COOKED_MODE +} + #[op(fast)] fn op_stdin_set_raw( state: &mut OpState, @@ -83,13 +103,10 @@ fn op_stdin_set_raw( return Err(Error::last_os_error().into()); } - const RAW_MODE_MASK: DWORD = wincon::ENABLE_LINE_INPUT - | wincon::ENABLE_ECHO_INPUT - | wincon::ENABLE_PROCESSED_INPUT; let new_mode = if is_raw { - original_mode & !RAW_MODE_MASK | wincon::ENABLE_VIRTUAL_TERMINAL_INPUT + mode_raw_input_on(original_mode) } else { - original_mode | RAW_MODE_MASK & !wincon::ENABLE_VIRTUAL_TERMINAL_INPUT + mode_raw_input_off(original_mode) }; // SAFETY: winapi call @@ -271,3 +288,31 @@ pub fn console_size( } } } + +#[cfg(all(test, windows))] +mod tests { + #[test] + fn test_winos_raw_mode_transitions() { + use crate::ops::tty::mode_raw_input_off; + use crate::ops::tty::mode_raw_input_on; + + let known_off_modes = + [0xf7 /* Win10/CMD */, 0x1f7 /* Win10/WinTerm */]; + let known_on_modes = + [0x2f0 /* Win10/CMD */, 0x3f0 /* Win10/WinTerm */]; + + // assert known transitions + assert_eq!(known_on_modes[0], mode_raw_input_on(known_off_modes[0])); + assert_eq!(known_on_modes[1], mode_raw_input_on(known_off_modes[1])); + + // assert ON-OFF round-trip is neutral + assert_eq!( + known_off_modes[0], + mode_raw_input_off(mode_raw_input_on(known_off_modes[0])) + ); + assert_eq!( + known_off_modes[1], + mode_raw_input_off(mode_raw_input_on(known_off_modes[1])) + ); + } +} |