c++winapidirectxdirectinput

GetRawInputData vs GetAsyncKeyState()


Well, I'm trying to avoid using the deprecated DirectInput.

But I need, at each "frame" or "iteration" of the game to snatch ALL KEY STATES so that I can act accordingly. For example, if the player is down on the VK_RIGHT key then he will move just a smidgen right on that frame.

The problem with WM_INPUT messages is they can appear an unpredictable number of times per frame, because of the way the game loop is written:

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

So if more than one WM_INPUT message is stacked there then they will all get processed before Update()/Draw().

I resolved this issue by using an array of BOOL to remember what keys were down:


    bool array_of_keys_that_are_down[ 256 ] ;

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

That works fine because the Update() function checks


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

BUT the problem is now that WM_INPUT messages don't get generated often enough. There's a delay of about 1 second between the first press of VK_RIGHT and subsequent VK_RIGHT messages, even if the player had his finger down on it the whole time. Its not like DirectInput where you can keyboard->GetDeviceState( 256, (void*)array_of_keys_that_are_down ); (snatch out all key states each frame with a single call)

So I'm lost. Other than resorting to GetAsyncKeystate() function calls for each key I need to monitor, I see no way to avoid using DirectInput if you can't snatch out all key states each frame reliably.

It seems to me that DirectInput was a very good solution to this problem, but if it was deprecated, then there really must be some way to do this conveniently using Win32 api only.

Currently array_of_keys_that_are_down gets reset back to all FALSE's every frame.

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

*EDIT

I've been working on this problem and one solution is to only reset a key state, once its been released

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

I don't like this solution though because it seems flimsy. If the user switches away from the application while down on a key, then that key will be "stuck" until he switches back and presses that same key again because we'll never get the upstroke WM_INPUT message. It makes for weird "sticky key" bugs.


Solution

  • You can use GetKeyboardState instead. What you generally want is two arrays; one stores the previous frames' input state, and one stores the current. This allows things like differentiating between being held and being triggered.

    // 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
    

    And you're done.