[PATCH 0/1] MR7586: cmd: Handle cntl-c events correctly
https://bugs.winehq.org/show_bug.cgi?id=27605 describes how cntl-c is not handled well in cmd.exe, this patch allows the cntl-c to be returned in the buffer so that it can processed. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/7586
From: Jeff Latimer <jeff_lats(a)hotmail.com> --- programs/cmd/batch.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/programs/cmd/batch.c b/programs/cmd/batch.c index 20ae894dbfd..1cd883c0621 100644 --- a/programs/cmd/batch.c +++ b/programs/cmd/batch.c @@ -223,17 +223,32 @@ WCHAR *WCMD_fgets(WCHAR *buf, DWORD noChars, HANDLE h) DWORD charsRead; BOOL status; DWORD i; + DWORD conmode, oldconmode; + CONSOLE_READCONSOLE_CONTROL control; + + GetConsoleMode(h, &oldconmode); + conmode = oldconmode & ~ENABLE_PROCESSED_INPUT; + SetConsoleMode(h, conmode); + control.nLength = sizeof(CONSOLE_READCONSOLE_CONTROL); + control.nInitialChars = 0; + control.dwCtrlWakeupMask = 0x0008; + control.dwConsoleKeyState = 0; /* We can't use the native f* functions because of the filename syntax differences between DOS and Unix. Also need to lose the LF (or CRLF) from the line. */ - if (VerifyConsoleIoHandle(h) && ReadConsoleW(h, buf, noChars, &charsRead, NULL) && charsRead) { + if (VerifyConsoleIoHandle(h) && ReadConsoleW(h, buf, noChars, &charsRead, &control) && charsRead) { + SetConsoleMode(h, oldconmode); if (!charsRead) return NULL; /* Find first EOL */ for (i = 0; i < charsRead; i++) { if (buf[i] == '\n' || buf[i] == '\r') break; + if (buf[i] == 0x03) { + WCMD_output(L"^C\n"); + i = 0; + break;} } } else { @@ -242,6 +257,7 @@ WCHAR *WCMD_fgets(WCHAR *buf, DWORD noChars, HANDLE h) UINT cp; const char *p; + SetConsoleMode(h, oldconmode); cp = GetOEMCP(); bufA = xalloc(noChars); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/7586
eric pouech (@epo) commented about programs/cmd/batch.c:
DWORD charsRead; BOOL status; DWORD i; + DWORD conmode, oldconmode; + CONSOLE_READCONSOLE_CONTROL control; + + GetConsoleMode(h, &oldconmode); I think this would be better handled by rewriting the code as:
`if (GetConsoleMode(h, &oldmode)) {` `/* put all console related code here */` `SetConsoleMode(h, oldmode);` `}` `else` `{` `/* other handles (file, pipe) */` -- https://gitlab.winehq.org/wine/wine/-/merge_requests/7586#note_98052
eric pouech (@epo) commented about programs/cmd/batch.c:
DWORD charsRead; BOOL status; DWORD i; + DWORD conmode, oldconmode; + CONSOLE_READCONSOLE_CONTROL control; + + GetConsoleMode(h, &oldconmode); + conmode = oldconmode & ~ENABLE_PROCESSED_INPUT; + SetConsoleMode(h, conmode); + control.nLength = sizeof(CONSOLE_READCONSOLE_CONTROL); + control.nInitialChars = 0; + control.dwCtrlWakeupMask = 0x0008; perhaps use 1u \<\< 0x03 instead (to make it clearer that the intent in ctrl-c) (note one day we might even add tab/shift tab here)
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/7586#note_98055
eric pouech (@epo) commented about programs/cmd/batch.c:
/* We can't use the native f* functions because of the filename syntax differences between DOS and Unix. Also need to lose the LF (or CRLF) from the line. */
- if (VerifyConsoleIoHandle(h) && ReadConsoleW(h, buf, noChars, &charsRead, NULL) && charsRead) { + if (VerifyConsoleIoHandle(h) && ReadConsoleW(h, buf, noChars, &charsRead, &control) && charsRead) { + SetConsoleMode(h, oldconmode); if (!charsRead) return NULL;
/* Find first EOL */ for (i = 0; i < charsRead; i++) { if (buf[i] == '\n' || buf[i] == '\r') break; + if (buf[i] == 0x03) { + WCMD_output(L"^C\n"); + i = 0; + break;} misplaced curly bracket
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/7586#note_98056
eric pouech (@epo) commented about programs/cmd/batch.c:
+ control.dwConsoleKeyState = 0;
/* We can't use the native f* functions because of the filename syntax differences between DOS and Unix. Also need to lose the LF (or CRLF) from the line. */
- if (VerifyConsoleIoHandle(h) && ReadConsoleW(h, buf, noChars, &charsRead, NULL) && charsRead) { + if (VerifyConsoleIoHandle(h) && ReadConsoleW(h, buf, noChars, &charsRead, &control) && charsRead) { + SetConsoleMode(h, oldconmode); if (!charsRead) return NULL;
/* Find first EOL */ for (i = 0; i < charsRead; i++) { if (buf[i] == '\n' || buf[i] == '\r') break; + if (buf[i] == 0x03) { + WCMD_output(L"^C\n"); I don't see ^C printed on native (Win10)
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/7586#note_98054
eric pouech (@epo) commented about programs/cmd/batch.c:
DWORD i; + DWORD conmode, oldconmode; + CONSOLE_READCONSOLE_CONTROL control; + + GetConsoleMode(h, &oldconmode); + conmode = oldconmode & ~ENABLE_PROCESSED_INPUT; + SetConsoleMode(h, conmode); + control.nLength = sizeof(CONSOLE_READCONSOLE_CONTROL); + control.nInitialChars = 0; + control.dwCtrlWakeupMask = 0x0008; + control.dwConsoleKeyState = 0;
/* We can't use the native f* functions because of the filename syntax differences between DOS and Unix. Also need to lose the LF (or CRLF) from the line. */
- if (VerifyConsoleIoHandle(h) && ReadConsoleW(h, buf, noChars, &charsRead, NULL) && charsRead) { we can get rid of VerifyConsoleHandle() as GetConsoleMode() succeeded
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/7586#note_98053
only works as expected under user32 console but complely breaks the unix console culprit is not the patch, is that conhost is closed with ctrl-c when processed input is turned off (without the patch on unix console, there are unwanted cursor movement, but after hitting ctrl-c one can still do something; with the patch cmd is "frozen") there at least two issues to consider: 1. ReadConsole with control on unix console doesn't report ctrl-c 2. cmd shouldn't freeze when the console has been closed either one of 1 or 2 must be supplied before accepting this patch apart from that, mostly stylistic remarks -- https://gitlab.winehq.org/wine/wine/-/merge_requests/7586#note_98057
On Thu Mar 20 00:49:02 2025 +0000, eric pouech wrote:
only works as expected under user32 console but complely breaks the unix console culprit is not the patch, is that conhost is closed with ctrl-c when processed input is turned off (without the patch on unix console, there are unwanted cursor movement, but after hitting ctrl-c one can still do something; with the patch cmd is "frozen") there at least two issues to consider: 1. ReadConsole with control on unix console doesn't report ctrl-c 2. cmd shouldn't freeze when the console has been closed either one of 1 or 2 must be supplied before accepting this patch apart from that, mostly stylistic remarks Thanks, I will look more closely at it.
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/7586#note_98488
This merge request was closed by Jeff Latimer. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/7586
participants (3)
-
eric pouech (@epo) -
Jeff Latimer -
Jeff Latimer (@greyghoster)