summaryrefslogtreecommitdiff
path: root/runtime/permissions.rs
diff options
context:
space:
mode:
authorDavid Sherret <dsherret@users.noreply.github.com>2021-09-14 08:37:27 -0400
committerGitHub <noreply@github.com>2021-09-14 08:37:27 -0400
commit5e2c5d0afa785b15c654b08409f0500ef9b96365 (patch)
tree7af144f634c2273590da30859d781b9230d49166 /runtime/permissions.rs
parentbb7ee4f4450882419ac46378df882d243eb150da (diff)
fix: permission prompt stuffing on Windows (#11969)
Diffstat (limited to 'runtime/permissions.rs')
-rw-r--r--runtime/permissions.rs98
1 files changed, 89 insertions, 9 deletions
diff --git a/runtime/permissions.rs b/runtime/permissions.rs
index d1ee7f999..c6fcfc58c 100644
--- a/runtime/permissions.rs
+++ b/runtime/permissions.rs
@@ -16,8 +16,6 @@ use log::debug;
use std::collections::HashSet;
use std::fmt;
use std::hash::Hash;
-#[cfg(not(test))]
-use std::io;
use std::path::{Path, PathBuf};
#[cfg(test)]
use std::sync::atomic::AtomicBool;
@@ -1203,13 +1201,95 @@ fn permission_prompt(message: &str) -> bool {
#[cfg(not(unix))]
fn clear_stdin() {
+ use winapi::shared::minwindef::TRUE;
+ use winapi::shared::minwindef::UINT;
+ use winapi::shared::minwindef::WORD;
+ use winapi::shared::ntdef::WCHAR;
+ use winapi::um::processenv::GetStdHandle;
+ use winapi::um::winbase::STD_INPUT_HANDLE;
+ use winapi::um::wincon::FlushConsoleInputBuffer;
+ use winapi::um::wincon::PeekConsoleInputW;
+ use winapi::um::wincon::WriteConsoleInputW;
+ use winapi::um::wincontypes::INPUT_RECORD;
+ use winapi::um::wincontypes::KEY_EVENT;
+ use winapi::um::winnt::HANDLE;
+ use winapi::um::winuser::MapVirtualKeyW;
+ use winapi::um::winuser::MAPVK_VK_TO_VSC;
+ use winapi::um::winuser::VK_RETURN;
+
unsafe {
- let stdin = winapi::um::processenv::GetStdHandle(
- winapi::um::winbase::STD_INPUT_HANDLE,
- );
- let flags =
- winapi::um::winbase::PURGE_TXCLEAR | winapi::um::winbase::PURGE_RXCLEAR;
- winapi::um::commapi::PurgeComm(stdin, flags);
+ let stdin = GetStdHandle(STD_INPUT_HANDLE);
+ // emulate an enter key press to clear any line buffered console characters
+ emulate_enter_key_press(stdin);
+ // read the buffered line or enter key press
+ read_stdin_line();
+ // check if our emulated key press was executed
+ if is_input_buffer_empty(stdin) {
+ // if so, move the cursor up to prevent a blank line
+ move_cursor_up();
+ } else {
+ // the emulated key press is still pending, so a buffered line was read
+ // and we can flush the emulated key press
+ flush_input_buffer(stdin);
+ }
+ }
+
+ unsafe fn flush_input_buffer(stdin: HANDLE) {
+ let success = FlushConsoleInputBuffer(stdin);
+ if success != TRUE {
+ panic!(
+ "Error flushing console input buffer: {}",
+ std::io::Error::last_os_error().to_string()
+ )
+ }
+ }
+
+ unsafe fn emulate_enter_key_press(stdin: HANDLE) {
+ // https://github.com/libuv/libuv/blob/a39009a5a9252a566ca0704d02df8dabc4ce328f/src/win/tty.c#L1121-L1131
+ let mut input_record: INPUT_RECORD = std::mem::zeroed();
+ input_record.EventType = KEY_EVENT;
+ input_record.Event.KeyEvent_mut().bKeyDown = TRUE;
+ input_record.Event.KeyEvent_mut().wRepeatCount = 1;
+ input_record.Event.KeyEvent_mut().wVirtualKeyCode = VK_RETURN as WORD;
+ input_record.Event.KeyEvent_mut().wVirtualScanCode =
+ MapVirtualKeyW(VK_RETURN as UINT, MAPVK_VK_TO_VSC) as WORD;
+ *input_record.Event.KeyEvent_mut().uChar.UnicodeChar_mut() =
+ '\r' as WCHAR;
+
+ let mut record_written = 0;
+ let success =
+ WriteConsoleInputW(stdin, &input_record, 1, &mut record_written);
+ if success != TRUE {
+ panic!(
+ "Error emulating enter key press: {}",
+ std::io::Error::last_os_error().to_string()
+ )
+ }
+ }
+
+ unsafe fn is_input_buffer_empty(stdin: HANDLE) -> bool {
+ let mut buffer = Vec::with_capacity(1);
+ let mut events_read = 0;
+ let success =
+ PeekConsoleInputW(stdin, buffer.as_mut_ptr(), 1, &mut events_read);
+ if success != TRUE {
+ panic!(
+ "Error peeking console input buffer: {}",
+ std::io::Error::last_os_error().to_string()
+ )
+ }
+ events_read == 0
+ }
+
+ fn move_cursor_up() {
+ use std::io::Write;
+ write!(std::io::stderr(), "\x1B[1A").expect("expected to move cursor up");
+ }
+
+ fn read_stdin_line() {
+ let mut input = String::new();
+ let stdin = std::io::stdin();
+ stdin.read_line(&mut input).expect("expected to read line");
}
}
@@ -1226,7 +1306,7 @@ fn permission_prompt(message: &str) -> bool {
eprint!("{}", colors::bold(&msg));
loop {
let mut input = String::new();
- let stdin = io::stdin();
+ let stdin = std::io::stdin();
let result = stdin.read_line(&mut input);
if result.is_err() {
return false;