I want to read a line from stdin with timeout on Windows. The following code uses WaitForSingleObject without success. Creating a blocking thread seems only transfer the problem to canceling the thread. Is there a way to read a line with timeout, other than peeking from time to time?
#include <assert.h>
#include <stdio.h>
#include <windows.h>
#define TIMEOUT_MS 5000
static void PrintByteArray(const void *b, size_t len) {
const unsigned char *u = (const unsigned char *)b;
printf("len %zu [", len);
for (size_t i = 0; i < len; ++i) {
printf(" %02x", u[i]);
}
puts(" ]");
}
int main() {
const HANDLE hStdIn = GetStdHandle(STD_INPUT_HANDLE);
assert(hStdIn != INVALID_HANDLE_VALUE);
DWORD r;
BOOL ok = GetConsoleMode(hStdIn, &r);
assert(ok);
printf("ConsoleMode %lx\n", r); // mode is 1f7, flag ENABLE_LINE_INPUT 0x0002 is set
r = WaitForSingleObject(hStdIn, TIMEOUT_MS);
switch (r) {
case WAIT_OBJECT_0: {
puts("WAIT_OBJECT_0");
char buf[8];
DWORD readLen;
BOOL ok = ReadConsoleA(hStdIn, buf, sizeof(buf), &readLen, NULL);
if (!ok) {
puts("ReadConsole fail");
return 1;
}
PrintByteArray(buf, readLen);
break;
}
case WAIT_TIMEOUT:
puts("Timeout");
break;
default:
printf("WaitForSingleObject err: %lu\n", r);
return 1;
}
return 0;
}
Using Windows Terminal with cmd: WaitForSingleObject returns WAIT_OBJECT_0 immediately when there is no input, then ReadConsole blocks forever.
Using conhost with cmd: if there is no input, WaitForSingleObject timeouts correctly. If there is input, WaitForSingleObject returns WAIT_OBJECT_0 as soon as one character is available, rather than one line. After WaitForSingleObject returns WAIT_OBJECT_0, ReadConsole blocks forever.
Expected behavior: if there is a line within timeout, return the line; if there isn't a line within timeout, return timeout.