Skip to content

Commit

Permalink
fix(runtime): (WinOS) console raw mode off repair (fixes #17866)
Browse files Browse the repository at this point in the history
  • Loading branch information
rivy committed Mar 8, 2023
1 parent 92ba46c commit 1e02efa
Showing 1 changed file with 50 additions and 5 deletions.
55 changes: 50 additions & 5 deletions runtime/ops/tty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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]))
);
}
}

0 comments on commit 1e02efa

Please sign in to comment.