Skip to content

Commit 2b4538a

Browse files
authored
Merge pull request #15 from sitiom/patch-1
Fix Ctrl+C, Ctrl+Z, and Window resize handling
2 parents 165331a + 6f274b7 commit 2b4538a

1 file changed

Lines changed: 67 additions & 10 deletions

File tree

main.c

Lines changed: 67 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,9 @@ typedef struct {
3838
HANDLE stdOut;
3939

4040
HANDLE events[2];
41+
HANDLE inputHandler;
42+
DWORD originalConsoleMode;
43+
HPCON hpcon;
4144
} Context;
4245

4346
static void ParseArgs(int argc, const wchar_t** wargv, char** argv, Context* ctx);
@@ -47,6 +50,8 @@ static HRESULT InitializeStartupInfoAttachedToPseudoConsole(STARTUPINFOEXW* star
4750
HPCON hpcon);
4851
static void __cdecl PipeListener(LPVOID);
4952
static void __cdecl InputHandlerThread(LPVOID);
53+
static void __cdecl ResizeHandlerThread(LPVOID);
54+
static void CloseInputHandler(Context* ctx);
5055

5156
static wchar_t* ToUtf16(const char* utf8) {
5257
if (utf8 == NULL) {
@@ -127,11 +132,15 @@ int wmain(int argc, const wchar_t* argv[]) {
127132
ctx.pipeIn = INVALID_HANDLE_VALUE;
128133
ctx.pipeOut = INVALID_HANDLE_VALUE;
129134
ctx.stdOut = GetStdHandle(STD_OUTPUT_HANDLE);
135+
ctx.inputHandler = INVALID_HANDLE_VALUE;
130136
ctx.events[0] = CreateEvent(NULL, FALSE, FALSE, NULL);
131137
if (ctx.events[0] == NULL) {
132138
return EXIT_FAILURE;
133139
}
134140

141+
HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE);
142+
GetConsoleMode(hStdin, &ctx.originalConsoleMode);
143+
135144
DWORD consoleMode = 0;
136145
GetConsoleMode(ctx.stdOut, &consoleMode);
137146
SetConsoleMode(ctx.stdOut, consoleMode | ENABLE_VIRTUAL_TERMINAL_PROCESSING);
@@ -140,6 +149,7 @@ int wmain(int argc, const wchar_t* argv[]) {
140149

141150
hr = CreatePseudoConsoleAndPipes(&hpcon, &ctx);
142151
if (S_OK == hr) {
152+
ctx.hpcon = hpcon;
143153
HANDLE pipeListener = (HANDLE) _beginthread(PipeListener, 0, &ctx);
144154

145155
STARTUPINFOEXW startupInfo = {0};
@@ -154,11 +164,14 @@ int wmain(int argc, const wchar_t* argv[]) {
154164
if (S_OK == hr) {
155165
ctx.events[1] = cmdProc.hThread;
156166

157-
HANDLE inputHandler = (HANDLE) _beginthread(InputHandlerThread, 0, &ctx);
167+
ctx.inputHandler = (HANDLE) _beginthread(InputHandlerThread, 0, &ctx);
168+
_beginthread(ResizeHandlerThread, 0, &ctx);
158169

159170
WaitForMultipleObjects(sizeof(ctx.events) / sizeof(HANDLE), ctx.events, FALSE,
160171
INFINITE);
161172

173+
CloseInputHandler(&ctx);
174+
162175
GetExitCodeProcess(cmdProc.hProcess, &childExitCode);
163176
}
164177

@@ -335,6 +348,7 @@ typedef enum { INIT, VERIFY, EXEC, END } State;
335348

336349
static State ProcessOutput(Context* ctx, const char* buffer, DWORD len, State state) {
337350
State nextState;
351+
DWORD written;
338352
switch (state) {
339353
case INIT: {
340354
if (!IsWaitInputPass(ctx, buffer, len)) {
@@ -349,12 +363,12 @@ static State ProcessOutput(Context* ctx, const char* buffer, DWORD len, State st
349363
fprintf(stderr, "Password is error!");
350364
nextState = END;
351365
} else {
352-
fprintf(stdout, "%s", buffer);
366+
WriteFile(ctx->stdOut, buffer, len, &written, NULL);
353367
nextState = EXEC;
354368
}
355369
} break;
356370
case EXEC: {
357-
fprintf(stdout, "%s", buffer);
371+
WriteFile(ctx->stdOut, buffer, len, &written, NULL);
358372
nextState = EXEC;
359373
} break;
360374
case END: {
@@ -443,22 +457,65 @@ static void __cdecl InputHandlerThread(LPVOID arg) {
443457
DWORD mode;
444458

445459
GetConsoleMode(hStdin, &mode);
446-
mode &= ~(ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT);
460+
mode &= ~(ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT | ENABLE_PROCESSED_INPUT);
447461
mode |= ENABLE_VIRTUAL_TERMINAL_INPUT;
448462
SetConsoleMode(hStdin, mode);
449463

450-
char buffer;
451-
DWORD bytesRead, bytesWritten;
464+
wchar_t buffer[64];
465+
DWORD charsRead, bytesWritten;
452466

453467
while (1) {
454-
if (!ReadFile(hStdin, &buffer, 1, &bytesRead, NULL) || bytesRead == 0) {
468+
if (!ReadConsoleW(hStdin, buffer, sizeof(buffer) / sizeof(wchar_t), &charsRead, NULL) || charsRead == 0) {
455469
break;
456470
}
457471

458-
if (!WriteFile(ctx->pipeOut, &buffer, 1, &bytesWritten, NULL)) {
459-
break;
472+
char utf8Buffer[256];
473+
int utf8Len = WideCharToMultiByte(CP_UTF8, 0, buffer, charsRead, utf8Buffer, sizeof(utf8Buffer), NULL, NULL);
474+
if (utf8Len > 0) {
475+
if (!WriteFile(ctx->pipeOut, utf8Buffer, utf8Len, &bytesWritten, NULL)) {
476+
break;
477+
}
460478
}
461479
}
480+
}
462481

463-
SetConsoleMode(hStdin, mode);
482+
static void CloseInputHandler(Context* ctx) {
483+
HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE);
484+
485+
if (ctx->pipeOut != INVALID_HANDLE_VALUE) {
486+
CloseHandle(ctx->pipeOut);
487+
ctx->pipeOut = INVALID_HANDLE_VALUE;
488+
}
489+
490+
if (ctx->inputHandler != INVALID_HANDLE_VALUE) {
491+
WaitForSingleObject(ctx->inputHandler, 1000);
492+
}
493+
494+
SetConsoleMode(hStdin, ctx->originalConsoleMode);
495+
}
496+
497+
static void __cdecl ResizeHandlerThread(LPVOID arg) {
498+
Context* ctx = arg;
499+
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
500+
COORD currentSize = {0, 0};
501+
CONSOLE_SCREEN_BUFFER_INFO csbi;
502+
503+
if (GetConsoleScreenBufferInfo(hConsole, &csbi)) {
504+
currentSize.X = csbi.srWindow.Right - csbi.srWindow.Left + 1;
505+
currentSize.Y = csbi.srWindow.Bottom - csbi.srWindow.Top + 1;
506+
}
507+
508+
while (WaitForMultipleObjects(sizeof(ctx->events) / sizeof(HANDLE), ctx->events, FALSE, 100) ==
509+
WAIT_TIMEOUT) {
510+
if (GetConsoleScreenBufferInfo(hConsole, &csbi)) {
511+
COORD newSize;
512+
newSize.X = csbi.srWindow.Right - csbi.srWindow.Left + 1;
513+
newSize.Y = csbi.srWindow.Bottom - csbi.srWindow.Top + 1;
514+
515+
if (newSize.X != currentSize.X || newSize.Y != currentSize.Y) {
516+
currentSize = newSize;
517+
ResizePseudoConsole(ctx->hpcon, currentSize);
518+
}
519+
}
520+
}
464521
}

0 commit comments

Comments
 (0)