0
votes

I'm coding a simple 3D game engine with DirectX11 and I'm using Win32 API to read user input (for the time being, later I'll switch to DirectInput). To read the state of keys on the keyboard I use the following API function:

void Game::ProcessInput()
{
    unsigned char keys[256];
    GetKeyboardState(keys);
    Input::GetInstance()->ProcessKeyboardInput(keys, mCamera, *mEntity, *mRenderer);
}

I call it in my game loop and pass the array of key states to my Input class:

void Input::ProcessKeyboardInput(unsigned char *keys, Camera &camera, Entity &player, Renderer &renderer)
{
    static bool pressed = false;

    /* update camera position - translate camera */
    if (keys['A'] & 0x80)
        camera.MoveRight(-speed);
    if (keys['D'] & 0x80)
        camera.MoveRight(speed);
    if (keys['W'] & 0x80)
        camera.MoveForward(speed);
    if (keys['S'] & 0x80)
        camera.MoveForward(-speed);
    if (keys['Q'] & 0x80)
        camera.MoveUp(speed);
    if (keys['E'] & 0x80)
        camera.MoveUp(-speed);
    if (keys['P'] & 0x80)
        speed == SLOW ? speed = FAST : speed = SLOW;

    /* move player */
    if (keys[VK_LEFT] & 0x80)
        player.Rotate(-playerSpeed * 10.0);
    if (keys[VK_RIGHT] & 0x80)
        player.Rotate(playerSpeed * 10.0);
    if (keys[VK_UP] & 0x80)
        player.MoveForward(playerSpeed);
    if (keys[VK_DOWN] & 0x80)
        player.MoveForward(-playerSpeed);
    if (keys[VK_SPACE] & 0x80)
        player.Jump();

    /* control rendering */
    if (keys['O'] & 0x80 && !pressed)
    {
        renderer.TogglePostProcessing();
        pressed = true;
    }
    else
        pressed = false;

}

I thought that I can detect if a key is hold down by checking the topmost bit (0x80 bit mask), and this works for the movement keys, but I want the 'O' key to toggle my renderer when I press it and re-toggle it when I press it again after releasing it, but the code continuously detect the key. What am I doing wrong?

1
An application can call this function to retrieve the current status of all the virtual keys. The status changes as a thread removes keyboard messages from its message queue. The status does not change as keyboard messages are posted to the thread's message queue, nor does it change as keyboard messages are posted to or retrieved from message queues of other threads.Jonathan Potter

1 Answers

1
votes

You need to move your !pressed check inside of the if block, rather than in the if itself:

if (keys['O'] & 0x80) {
    if (!pressed) {
        renderer.TogglePostProcessing();
        pressed = true;
    }
}
else
    pressed = false;

In your original code:

if (keys['O'] & 0x80 && !pressed)
{
    renderer.TogglePostProcessing();
    pressed = true;
}
else
    pressed = false;

While 'O' is held down, you are continuously toggling pressed back and forth, and thus toggling the renderer:

Pass #1: pressed==false, so (keys['O'] & 0x80 && !pressed) == true, so the renderer is toggled and pressed is set to true.

Pass #2: pressed==true, so (keys['O'] & 0x80 && !pressed) == false, so pressed is set to false.

Pass #3: pressed==false, so (keys['O'] & 0x80 && !pressed) == true, so the renderer is toggled and pressed is set to true.

And so on, until you eventually release 'O'...

In the new code, pressed is set to true only when keys['O'] & 0x80 evaluates as true for the first time, and remains set as true until keys['O'] & 0x80 evaluates as false. Then toggles one time when keys['O'] & 0x80 evaluates as true again. And so on...