使用重定向的stdin处理子进程中的kbhit

时间:2018-09-04 13:41:11

标签: c++ windows winapi

我编写了一个程序,该程序可以启动另一个进程,并使用Windows API(CreateProcess,CreatePipe等)将其标准I / O重定向到管道。

该程序应启动多个不同的控制台程序,并使用stdio与它们通信。

一切运行良好(我可以写入进程的stdin并使用管道从进程中读取),直到尝试启动并与使用kbhit的程序进行通信为止。

为简化起见,我想使用标准输入启动该程序:

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

结果是fgets永远不会被调用,因为即使我已经将标准输入重定向到管道,kbhit也不返回true。我知道,因为我已经调试到另一个程序。我试图删除kbhit的调用,然后它确实起作用,但是我无法更改该代码。

是否有一种方法可以向进程发送内容,以便子进程中的kbhit返回true?

1 个答案:

答案 0 :(得分:2)

_kbhit函数检查控制台是否有最近的击键。它从不检查stdin,而是打开CONIN$(控制台输入)并始终从此处读取。

因此,重定向stdin此处无济于事。如果我们与孩子共享同一控制台,则可以使用WriteConsoleInput来完成此任务。将字符串写入子级的示例:

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;
        }
    }
}