1
votes

I've written a program that starts another process and redirects its standard I/O to pipes using the windows API (CreateProcess, CreatePipe, etc.)

The program should start multiple different console programs and communicate with them using stdio.

This was all working well (I could write to the stdin of the process and read from the process using the pipes) until I tried to start and communicate with a program that was using kbhit.

To simplify it what that program I'd like to start does with the standard input:

while(1)
{
    if(kbhit())
    {
        fgets(line, sizeof(line), stdin);
        //do something with line
    }
    Sleep(100);
 } 

The result is that fgets gets never called because kbhit doesn't return true even though I've written to the pipe that I've redirected stdin to. I know that because I've debugged into the other program. I've tried to remove the call of kbhit and then it does work but I can't change that code.

Is there a way to send something to the process so that that kbhit in the child process returns true?

1
I suppose kbhit reads the keyboard directly instead of reading via stdin. Why do you need kbhit here? Is this an XY Problem?Jabberwocky
The other program that I didn't make uses kbhit and I can't change thatJimmy T.
kbhit() is not a standard function in C++. You'll need to read the documentation for the compiler/library used to build the "other program" in order to know how to interact with it - assuming that is even possible.Peter
_kbhit read from console ( CONIN$ device). it ignore stdin. what you write to stdin will be ignoredRbMm
Is there no way to write something there?Jimmy T.

1 Answers

2
votes

The _kbhit function checks the console for a recent keystroke. it never check stdin, but open CONIN$ (console input) and read always from here.

so redirect stdin here nothing give. if we share same console with child we can use WriteConsoleInput for this task. example for write string to child:

void write_to_conin(PCWSTR msg)
{
    if (ULONG len = (ULONG)wcslen(msg))
    {
        if (INPUT_RECORD* lpBuffer = new INPUT_RECORD[len])
        {
            INPUT_RECORD* pir = lpBuffer;
            ULONG n = len;
            do 
            {
                WCHAR UnicodeChar = *msg++;
                WORD wVirtualKeyCode = UnicodeChar;
                DWORD dwControlKeyState = CAPSLOCK_ON;

                if ((USHORT)(UnicodeChar - 'a') <= (USHORT)('z' - 'a'))
                {
                    dwControlKeyState = 0;
                    wVirtualKeyCode &= ~0x20;
                }

                pir->Event.KeyEvent.bKeyDown = TRUE;
                pir->Event.KeyEvent.dwControlKeyState = dwControlKeyState;
                pir->Event.KeyEvent.wRepeatCount = 1;
                pir->Event.KeyEvent.uChar.UnicodeChar = UnicodeChar;
                pir->Event.KeyEvent.wVirtualKeyCode = wVirtualKeyCode;
                pir->Event.KeyEvent.wVirtualScanCode = (WORD)MapVirtualKey(wVirtualKeyCode, MAPVK_VK_TO_VSC);
                pir++->EventType = KEY_EVENT;
            } while (--n);

            HANDLE hcon = CreateFileW(L"CONIN$", FILE_GENERIC_WRITE, FILE_SHARE_VALID_FLAGS, 0, OPEN_EXISTING, 0, 0);

            if (hcon != INVALID_HANDLE_VALUE) 
            { 
                WriteConsoleInput(hcon, lpBuffer, len, &n); 
                CloseHandle(hcon); 
            }

            delete [] lpBuffer;
        }
    }
}