游戏键盘输入和事件

Game keyboard input and events

我正在开发一个小游戏引擎,无法决定如何处理键盘输入。到目前为止,我一直在通过捕获来自 window 过程的 WM_KEYDOWNWM_KEYUP 消息来处理键盘输入,但是在我看来这并不是处理键盘输入的好方法。

我真的很喜欢 Infinity Ward 3.0 引擎,您可以在其中使用简单的配置文件或使用游戏控制台轻松更改每个关键操作。我也想做类似的。

这是 IW 3.0 引擎的配置文件片段:

bind TAB "+scores"
bind ESCAPE "togglemenu"
bind SPACE "+gostand"
bind ALT "gocrouch"
bind CTRL "goprone"
bind SHIFT "+breath_sprint"
bind 1 "weapnext"
bind 2 "weapnext"
bind 4 "+smoke"
bind 5 "+actionslot 3"
bind 6 "+actionslot 4"
bind 7 "+actionslot 2"
bind ` "toggleconsole"
bind A "+moveleft"
bind B "mp_QuickMessage"
bind D "+moveright"
bind E "+leanright"

您甚至可以为按键分配其他操作,例如在聊天中说些什么:

bind F3 "say Hello, World!"

我已经有了我在游戏启动时从中读取的配置文件,之后我初始化了所有操作键。它可以工作,但是将所有键分配给所有操作真的很不舒服。对于像 A, B, C, D, E 这样的键,这很容易,因为每个字符的 ASCII 码对应于 WM_KEYDOWN/UP 消息,但是对于像 SPACE, CTRL, SHIFT 这样的键,它不是。

所以我的问题是:

有很多方法。捕获键的一个好方法是使用 ReadConsoleInput() 然后 在 switch 语句中处理键码。正如您在下面的代码中看到的 您还可以 "bind" switch 语句本身中的键。

#include <stdio.h>
#include <windows.h>
#include <iostream>
using namespace std;




int main()
{
    DWORD        mode;          /* Preserved console mode */
    INPUT_RECORD event;         /* Input event */
    BOOL         EXITGAME = FALSE;  /* Program termination flag */
    unsigned int counter = 0;   /* The number of times 'Esc' is pressed */


    /* Get the console input handle */
    HANDLE hstdin = GetStdHandle( STD_INPUT_HANDLE );

    /* Preserve the original console mode */
    GetConsoleMode( hstdin, &mode );

    /* Set to no line-buffering, no echo, no special-key-processing */
    SetConsoleMode( hstdin, 0 );




    while (!EXITGAME)
    {           


        if (WaitForSingleObject( hstdin, 0 ) == WAIT_OBJECT_0)  /* if kbhit */
        {
            DWORD count;  /* ignored */

            /* Get the input event */
            ReadConsoleInput( hstdin, &event, 1, &count );
            cout<<"Key Code   = "<<event.Event.KeyEvent.wVirtualKeyCode <<" \n";

        }

            /* Only respond to key release events */
            if ((event.EventType == KEY_EVENT)
            &&  !event.Event.KeyEvent.bKeyDown)
            {        


                    switch (event.Event.KeyEvent.wVirtualKeyCode)
                    {
                        case VK_ESCAPE:
                           EXITGAME = TRUE;
                         break;

                        case VK_SPACE:

                         break;


                        case VK_RETURN:

                         break;

                        case VK_LEFT:
                            // left key   move player left
                            cout<<"VK_LEFT   = "<<event.Event.KeyEvent.wVirtualKeyCode <<" \n";

                         break;

                        case VK_RIGHT:
                            // right key   move player right
                            cout<<"VK_RIGHT   = "<<event.Event.KeyEvent.wVirtualKeyCode <<" \n";

                         break;    

                        case VK_UP:
                            // up key   move player up
                            cout<<"VK_UP   = "<<event.Event.KeyEvent.wVirtualKeyCode <<" \n";


                         break;

                        case VK_DOWN:
                            // up key   move player down
                            cout<<"VK_DOWN   = "<<event.Event.KeyEvent.wVirtualKeyCode <<" \n";


                         break;



                    }//switch

                   event.Event.KeyEvent.wVirtualKeyCode=-1;             


        }
    }

 return 0; 
}

虚拟键列表:https://msdn.microsoft.com/en-us/library/windows/desktop/dd375731(v=vs.85).aspx

读取控制台输入:https://msdn.microsoft.com/en-us/library/windows/desktop/ms685035(v=vs.85).aspx

抱歉回复晚了,我最近 2 天没在家。 我已经解决了这个问题。根据我的第一个问题,我选择原始键盘输入,如果有人感兴趣,这里是代码:

std::map<string, bool> myKey;
bool KEYBOARD_INPUT::GetRawKeyboardData(LPARAM lParam)
{
    char buffer[sizeof(RAWINPUT)];
    UINT size = sizeof(RAWINPUT);
    GetRawInputData(reinterpret_cast<HRAWINPUT>(lParam), RID_INPUT, buffer, &size, sizeof(RAWINPUTHEADER));

    RAWINPUT* raw = reinterpret_cast<RAWINPUT*>(buffer);
    if(raw->header.dwType == RIM_TYPEKEYBOARD)
    {
        const RAWKEYBOARD& rawKeyboard = raw->data.keyboard;

        unsigned int scanCode = rawKeyboard.MakeCode;
        unsigned int flags = rawKeyboard.Flags;
        const bool E0 = ((flags & RI_KEY_E0) != 0);
        const bool E1 = ((flags & RI_KEY_E1) != 0);
        const bool KeyDown = !((flags & RI_KEY_BREAK) != 0);

        UINT key = (scanCode << 16) | (E0 << 24);
        char buffer[32];
        GetKeyNameText((LONG)key, buffer, 32);
        if(KeyDown) // Press
        {
            myKey[buffer] = true;
        }
        else // Release
        {
            myKey[buffer] = false;
        }
    }
    return true;
}

这是获取实际按键状态的函数:

bool KEYBOARD_INPUT::KeyPressed(string key, int mode)
{
    if(mode == ONLYONCE)
    {
        if(myKey[key] && pressed_onlyonce[key] == false)
        {
            pressed_onlyonce[key] = true;
            return true;
        }
        if(!myKey[key])
        {
            pressed_onlyonce[key] = false;
            return false;
        }
    }

    else if(mode == CONTINUOUS)
    {
        if(myKey[key] == true)
        {
            return true;
        }
        else
        {
            return false;
        }
    }

    else if(mode == TOGGLE)
    {
        if(myKey[key] && pressed_toggle[key] == false)
        {
            pressed_toggle[key] = true;
            released_toggle[key] = !released_toggle[key];
            return released_toggle[key];
        }
        else if(!myKey[key])
        {
            pressed_toggle[key] = false;
            return released_toggle[key];
        }
    }
    return false;
}

我认为该代码也是我其他问题的答案。 如果有人对此 class 的完整源代码感兴趣,请在评论部分告诉我。

我想,我可以关闭这个线程了,特别感谢@IInspectabl,非常感谢!