summaryrefslogtreecommitdiff
path: root/runtime/ops
diff options
context:
space:
mode:
authorRoy Ivy III <rivy.dev@gmail.com>2023-03-08 13:56:49 -0600
committerGitHub <noreply@github.com>2023-03-08 19:56:49 +0000
commitf2e5e01832a40eb71be82f1b46304c56aa2e8dba (patch)
treef0637a981aa0f22500ab667a6b187c20a2b5fb1c /runtime/ops
parent23e1ba7e2dba1b9453e064f6c92c10b64071b708 (diff)
fix(runtime/windows): ensure `Deno.stdin.setRaw(false)` properly disables raw mode (#17983)
Diffstat (limited to 'runtime/ops')
-rw-r--r--runtime/ops/tty.rs55
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]))
+ );
+ }
+}