在Windows控制台中获取按键输入

5

我在网上找到了这段代码

CHAR getch() {
    DWORD mode, cc;
    HANDLE h = GetStdHandle( STD_INPUT_HANDLE );

    if (h == NULL) {
        return 0; // console not found
    }

    GetConsoleMode( h, &mode );
    SetConsoleMode( h, mode & ~(ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT) );
    TCHAR c = 0;
    ReadConsole( h, &c, 1, &cc, NULL );
    SetConsoleMode( h, mode );
    return c;
}

如何使用:

while(1) {
    TCHAR key = getch();
}

我能够获取数字、字母甚至回车键的按键信息,但无法获取像Esc或其他功能键(如Ctrl、Alt)的按键信息。是否有可能修改程序以侦测这些键的按下?

3个回答

12
如果涉及到类似控制键和Alt键这样的内容,它们是虚拟按键,它们是字符的补充。您将需要使用ReadConsoleInput。但是您将得到所有的内容,包括鼠标。因此,您真的需要过滤并从调用中返回一个结构,以便您知道它是否是ctrl-A Alt-A之类的内容。如果您不想要重复项,请过滤它们。
这可能需要进一步的工作,不知道您的具体需求...
bool getconchar( KEY_EVENT_RECORD& krec )
{
    DWORD cc;
    INPUT_RECORD irec;
    HANDLE h = GetStdHandle( STD_INPUT_HANDLE );

    if (h == NULL)
    {
        return false; // console not found
    }

    for( ; ; )
    {
        ReadConsoleInput( h, &irec, 1, &cc );
        if( irec.EventType == KEY_EVENT
            &&  ((KEY_EVENT_RECORD&)irec.Event).bKeyDown
            )//&& ! ((KEY_EVENT_RECORD&)irec.Event).wRepeatCount )
        {
            krec= (KEY_EVENT_RECORD&)irec.Event;
            return true;
        }
    }
    return false; //future ????
}

int main( )
{
    KEY_EVENT_RECORD key;
    for( ; ; )
    {
        getconchar( key );
        std::cout << "key: " << key.uChar.AsciiChar
            << " code:  " << key.wVirtualKeyCode << std::endl;
    }
}

ReadConsoleInput函数

INPUT_RECORD结构体

KEY_EVENT_RECORD结构体

虚拟键代码


0
以下代码可以捕获任何按键。它用于从函数中返回。
文档:

https://learn.microsoft.com/en-us/windows/console/readconsoleinput?redirectedfrom=MSDN

https://learn.microsoft.com/en-us/windows/console/input-record-str?redirectedfrom=MSDN

https://learn.microsoft.com/en-us/windows/console/key-event-record-str?redirectedfrom=MSDN

目的 该函数执行一些计算,其进度在控制台上向用户显示。当所有操作完成后,用户希望从函数中返回。她可以通过按任意键来实现这一点。在我所有的其他应用程序中,用户可以使用Esc键返回,因此在这里也能够使用它是很好的。

它通过分配控制台并设置控制台输出和输入的句柄来工作。标志OKflg_out和OKflg_in被设置为在结束时验证操作。在向用户显示消息“按任意键”之后的for (; ;)循环将在用户按下键时结束。

按下键的数字代码是(((irec.Event).KeyEvent).uChar).AsciiChar,但在这里没有使用它。当然,它可以用作返回代码,以确定调用函数中的后续操作。

#include <windows.h>
// Various other includes.
void wrintf0(HANDLE stdOut, unsigned char *message)
{
    DWORD written=0;
    WriteConsoleA(stdOut, message, strleni(message), &written, NULL);
}
#define wrintf(message) wrintf0(stdOut,message)
// Various code lines.
void Myfunction(void)
{
    unsigned char OKflg_in=0,OKflg_out=0;
    HANDLE stdIn,stdOut;
    // Various code lines.
    AllocConsole();
    stdOut = GetStdHandle(STD_OUTPUT_HANDLE);
    if (stdOut != NULL && stdOut != INVALID_HANDLE_VALUE)
    {
        OKflg_out = 1;
        stdIn = GetStdHandle(STD_INPUT_HANDLE);
        if (stdIn != NULL && stdIn != INVALID_HANDLE_VALUE) OKflg_in = 1;
    }
    // Various code lines.
    if (OKflg_out)
    {
        if (OKflg_in)
        {
          DWORD cc;
          INPUT_RECORD irec;
          wrintf("Press any key.");
          for(; ;) {
              ReadConsoleInput(stdIn, &irec, 1, &cc );
              if (irec.EventType == KEY_EVENT && ((irec.Event).KeyEvent).bKeyDown) break;
          }
          CloseHandle(stdIn);
        }
        CloseHandle(stdOut);
    }
    FreeConsole();
    return;
}

1
“仅有代码的答案并不是高质量的答案”(https://meta.stackoverflow.com/questions/392712/explaining-entirely-code-based-answers)。虽然这段代码可能很有用,但您可以通过解释它为什么有效、如何有效、何时应该使用以及其限制是什么来改进它。请编辑您的答案,包括解释和相关文档链接。 - Muhammad Mohsin Khan

-2

3
这些是用于GUI应用程序,而不是控制台应用程序。您将获得的结果将不会与控制台输入缓冲区的状态同步。 - Matteo Italia
1
你将会获得字符,但它们不会与控制台输入函数、Win32标准输入和CRT标准输入同步(使用GetAsyncKeyState甚至不能与线程的输入队列同步)。这有微妙的影响,因此除非你完全理解,否则应避免使用这些东西。 - Matteo Italia

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接