GetRawInputData与GetAsyncKeyState()

bob*_*obo 3 c++ directx winapi directinput

好吧,我试图避免使用已弃用的DirectInput.

但是我需要在游戏的每个"框架"或"迭代"中抢夺所有关键状态,以便我可以采取相应的行动.例如,如果玩家在VK_RIGHT键上按下,那么他将在该帧上仅移动一个smidgen.

WM_INPUT消息的问题是它们每帧可能出现不可预测的次数,因为游戏循环的编写方式如下:

    MSG message ;
    while( 1 )
    {
        if( PeekMessage( &message, NULL, 0, 0, PM_REMOVE ) )
        {
            if( message.message == WM_QUIT )
            {
                break ;  // bail when WM_QUIT
            }

            TranslateMessage( &message ) ;
            DispatchMessage( &message ) ;
        }
        else
        {
            // No messages, so run the game.
            Update() ;
            Draw() ;
        }
    }

因此,如果堆叠了多个 WM_INPUT消息,那么它们将在Update()/ Draw()之前被处理.

我通过使用BOOL数组来解决这个问题,以记住关键是什么:


    bool array_of_keys_that_are_down[ 256 ] ;

    case WM_INPUT :
        if( its keyboard input )
        {
            array_of_keys_that_are_down[ VK_CODE ] = TRUE ;
        }

这工作正常,因为Update()函数检查


    void Update()
    {
        if( array_of_keys_that_are_down[ VK_RIGHT ] )
        {
            // Move the player right a bit
        }
    }

但现在的问题是,WM_INPUT消息不产生得到经常不够.在第一次按下VK_RIGHT和随后的VK_RIGHT消息之间会有大约1秒的延迟,即使玩家一直按下它的手指也是如此.它不像DirectInput,你可以keyboard->GetDeviceState( 256, (void*)array_of_keys_that_are_down );通过一次调用抢夺每一帧的所有关键状态

所以我迷路了.除了使用GetAsyncKeystate()函数调用我需要监视的每个键之外,如果你不能可靠地抢夺每个帧的所有关键状态,我认为没有办法避免使用DirectInput.

在我看来,DirectInput是解决这个问题的一个非常好的解决方案,但如果它被弃用了,那么必须有一些方法可以使用Win32 api方便地做到这一点.

目前array_of_keys_that_are_down每帧重置为所有FALSE.

    memset( array_of_keys_that_are_down, 0, sizeof( array_of_keys_that_are_down ) ) ;

*编辑

我一直在研究这个问题,一个解决方案是只在重置一个密钥状态后才会被释放

    case WM_INPUT :
        if( its keyboard input )
        {
            if( its a down press )
                array_of_keys_that_are_down[ VK_CODE ] = TRUE ;
            else
                array_of_keys_that_are_down[ VK_CODE ] = FALSE ;
        }

我不喜欢这个解决方案,因为它看起来很脆弱.如果用户在按下键的同时切换应用程序,那么该键将"卡住"直到他切换回并再次按下相同的键,因为我们永远不会得到上行WM_INPUT消息.它造成了奇怪的"粘键"错误.

GMa*_*ckG 6

你可以GetKeyboardState改用.你通常想要的是两个阵列; 一个存储先前帧的输入状态,一个存储当前帧.这允许区分被保持和被触发之类的事情.

// note, cannot use bool because of specialization
std::vector<unsigned char> previous(256);
std::vector<unsigned char> current(256);

// in update_keys or similar:
current.swap(previous); // constant time, yay
GetKeyboardState(&current[0]); // normally do error checking
Run Code Online (Sandbox Code Playgroud)

而且你已经完成了.