Current code requires entering a newline character in order to continue past DIR /P prompts. This change allows any key to be pressed instead.
Code to handle this was similar to existing WCMD_pause() so we leveraged that code for this purpose as well. Key to the fix was the removal of ENABLE_LINE_INPUT from the console flags, and ENABLE_PROCESSED_INPUT was added in order to preserve the ability to abort the operation via Ctrl-C.
-- v24: cmd: Allow any key to continue past DIR /P pauses.
From: Joe Souza jsouza@yahoo.com
--- programs/cmd/builtins.c | 17 ++------- programs/cmd/directory.c | 4 +- programs/cmd/wcmd.h | 5 ++- programs/cmd/wcmdmain.c | 81 ++++++++++++++++++++++++++++++++++++---- 4 files changed, 81 insertions(+), 26 deletions(-)
diff --git a/programs/cmd/builtins.c b/programs/cmd/builtins.c index 5e084f9db92..b78ae9d293b 100644 --- a/programs/cmd/builtins.c +++ b/programs/cmd/builtins.c @@ -1954,21 +1954,10 @@ RETURN_CODE WCMD_move(void) RETURN_CODE WCMD_pause(void) { RETURN_CODE return_code = NO_ERROR; - DWORD oldmode; - BOOL have_console; - DWORD count; - WCHAR key; - HANDLE hIn = GetStdHandle(STD_INPUT_HANDLE); - - have_console = GetConsoleMode(hIn, &oldmode); - if (have_console) - SetConsoleMode(hIn, 0); - WCMD_output_asis(anykey); - if (!WCMD_ReadFile(hIn, &key, 1, &count) || !count) - return_code = ERROR_INVALID_FUNCTION; - if (have_console) - SetConsoleMode(hIn, oldmode); + return_code = WCMD_wait_for_input(GetStdHandle(STD_INPUT_HANDLE)); + WCMD_output_asis(L"\r\n"); + return return_code; }
diff --git a/programs/cmd/directory.c b/programs/cmd/directory.c index b7c036efd0d..a1efe0f20c9 100644 --- a/programs/cmd/directory.c +++ b/programs/cmd/directory.c @@ -305,7 +305,7 @@ static RETURN_CODE WCMD_list_directory (DIRECTORY_STACK *inputparms, int level,
/* Output the results */ if (!bare) { - if (level != 0 && (entry_count > 0)) WCMD_output_asis(L"\r\n"); + if (level != 0 && (entry_count > 0)) return_code = WCMD_output_asis(L"\r\n"); if (!recurse || ((entry_count > 0) && done_header==FALSE)) { WCMD_output (L"Directory of %1\n\n", real_path); done_header = TRUE; @@ -427,7 +427,7 @@ static RETURN_CODE WCMD_list_directory (DIRECTORY_STACK *inputparms, int level, } } } - if (addNewLine) WCMD_output_asis(L"\r\n"); + if (addNewLine) return_code = WCMD_output_asis(L"\r\n"); cur_width = 0;
/* Allow command to be aborted if user presses Ctrl-C. diff --git a/programs/cmd/wcmd.h b/programs/cmd/wcmd.h index 225ebd44310..d4adc7fd7c8 100644 --- a/programs/cmd/wcmd.h +++ b/programs/cmd/wcmd.h @@ -174,8 +174,8 @@ RETURN_CODE WCMD_move (void); WCHAR* WINAPIV WCMD_format_string (const WCHAR *format, ...); void WINAPIV WCMD_output (const WCHAR *format, ...); void WINAPIV WCMD_output_stderr (const WCHAR *format, ...); -void WCMD_output_asis (const WCHAR *message); -void WCMD_output_asis_stderr (const WCHAR *message); +RETURN_CODE WCMD_output_asis (const WCHAR *message); +RETURN_CODE WCMD_output_asis_stderr (const WCHAR *message); RETURN_CODE WCMD_pause(void); RETURN_CODE WCMD_popd(void); void WCMD_print_error (void); @@ -210,6 +210,7 @@ void WCMD_HandleTildeModifiers(WCHAR **start, BOOL atExecute); WCHAR *WCMD_strip_quotes(WCHAR *cmd); WCHAR *WCMD_LoadMessage(UINT id); WCHAR *WCMD_strsubstW(WCHAR *start, const WCHAR* next, const WCHAR* insert, int len); +RETURN_CODE WCMD_wait_for_input(HANDLE hIn); BOOL WCMD_ReadFile(const HANDLE hIn, WCHAR *intoBuf, const DWORD maxChars, LPDWORD charsRead);
enum read_parse_line {RPL_SUCCESS, RPL_EOF, RPL_SYNTAXERROR}; diff --git a/programs/cmd/wcmdmain.c b/programs/cmd/wcmdmain.c index 77f1112be23..3a35bded7f9 100644 --- a/programs/cmd/wcmdmain.c +++ b/programs/cmd/wcmdmain.c @@ -213,6 +213,67 @@ void WCMD_leave_paged_mode(void) pagedMessage = NULL; }
+static BOOL has_pending_char_events(HANDLE h) +{ + INPUT_RECORD ir; + DWORD count; + BOOL ret = FALSE; + + while (!ret && GetNumberOfConsoleInputEvents(h, &count) && count) + { + /* FIXME could be racy if another thread/process gets the input record */ + if (ReadConsoleInputA(h, &ir, 1, &count) && count) + ret = ir.EventType == KEY_EVENT && + ir.Event.KeyEvent.bKeyDown && + ir.Event.KeyEvent.uChar.AsciiChar; + } + return ret; +} + +/*************************************************************************** + * WCMD_wait_for_input + * + * Wait for input from a console/file. + * Used by commands like PAUSE and DIR /P that need to wait for user + * input before continuing. + */ +RETURN_CODE WCMD_wait_for_input(HANDLE hIn) +{ + RETURN_CODE return_code; + DWORD oldmode; + DWORD count; + WCHAR key; + + return_code = ERROR_INVALID_FUNCTION; + if (GetConsoleMode(hIn, &oldmode)) + { + HANDLE h[2] = {hIn, control_c_event}; + + SetConsoleMode(hIn, oldmode & ~ENABLE_LINE_INPUT); + FlushConsoleInputBuffer(hIn); + while (return_code == ERROR_INVALID_FUNCTION) + { + switch (WaitForMultipleObjects(2, h, FALSE, INFINITE)) + { + case WAIT_OBJECT_0: + if (has_pending_char_events(hIn)) + return_code = NO_ERROR; + /* will make both hIn no long signaled, and also process the pending input record */ + FlushConsoleInputBuffer(hIn); + break; + case WAIT_OBJECT_0 + 1: + return_code = STATUS_CONTROL_C_EXIT; + break; + default: break; + } + } + SetConsoleMode(hIn, oldmode); + } + else if (WCMD_ReadFile(hIn, &key, 1, &count)) + return_code = NO_ERROR; + return return_code; +} + /*************************************************************************** * WCMD_ReadFile * @@ -243,10 +304,9 @@ BOOL WCMD_ReadFile(const HANDLE hIn, WCHAR *intoBuf, const DWORD maxChars, LPDWO * * Send output to specified handle without formatting e.g. when message contains '%' */ -static void WCMD_output_asis_handle (DWORD std_handle, const WCHAR *message) { - DWORD count; +static RETURN_CODE WCMD_output_asis_handle (DWORD std_handle, const WCHAR *message) { + RETURN_CODE return_code = NO_ERROR; const WCHAR* ptr; - WCHAR string[1024]; HANDLE handle = GetStdHandle(std_handle);
if (paged_mode) { @@ -262,12 +322,17 @@ static void WCMD_output_asis_handle (DWORD std_handle, const WCHAR *message) { if (++line_count >= max_height - 1) { line_count = 0; WCMD_output_asis_len(pagedMessage, lstrlenW(pagedMessage), handle); - WCMD_ReadFile(GetStdHandle(STD_INPUT_HANDLE), string, ARRAY_SIZE(string), &count); + return_code = WCMD_wait_for_input(GetStdHandle(STD_INPUT_HANDLE)); + WCMD_output_asis(L"\r\n"); + if (return_code) + break; } } while (((message = ptr) != NULL) && (*ptr)); } else { WCMD_output_asis_len(message, lstrlenW(message), handle); } + + return return_code; }
/******************************************************************* @@ -276,8 +341,8 @@ static void WCMD_output_asis_handle (DWORD std_handle, const WCHAR *message) { * Send output to current standard output device, without formatting * e.g. when message contains '%' */ -void WCMD_output_asis (const WCHAR *message) { - WCMD_output_asis_handle(STD_OUTPUT_HANDLE, message); +RETURN_CODE WCMD_output_asis (const WCHAR *message) { + return WCMD_output_asis_handle(STD_OUTPUT_HANDLE, message); }
/******************************************************************* @@ -286,8 +351,8 @@ void WCMD_output_asis (const WCHAR *message) { * Send output to current standard error device, without formatting * e.g. when message contains '%' */ -void WCMD_output_asis_stderr (const WCHAR *message) { - WCMD_output_asis_handle(STD_ERROR_HANDLE, message); +RETURN_CODE WCMD_output_asis_stderr (const WCHAR *message) { + return WCMD_output_asis_handle(STD_ERROR_HANDLE, message); }
/****************************************************************************
On Thu Feb 27 22:13:41 2025 +0000, Joe Souza wrote:
Thanks for the patch. Will check it out here.
OK, merge request has been updated with your patch. Thanks for that.