Search code examples
c++eventskeyboardsfml

Key Repetition in SFML 2.0


Is there a way to receive if a key has just been pressed (not held) in SFML, or a way to mimic such an effect?

I poll my event here,

while (window.pollEvent(event));

And then later in the loop, out of scope but with the same event, I read:

if (event.type == sf::Event::KeyPressed)
{
    if (event.key.code == sf::Keyboard::Up)
    {
        decision--;
        if (decision < 0)
        decision = CHARACTER_MAX - 1;
    }
}

This makes decision decrement continuously when the up arrow is held down. Using sf::events, can I read the first time it is pressed and not when it is held down?

Also, if its not possible or you're not familiar with sfml, what would be the best way to mimic such with little or no globalized variables? (such as is_already_held), e.g. https://gamedev.stackexchange.com/questions/30826/action-button-only-true-once-per-press

I realize that such may be the only way (declaring a variable in a wider scope) but I would prefer not to, because I exit the scope continuously and try to steer clear from global variables as often as possible.


Solution

  • You can disable key repetition with sf::Window::setKeyRepeatEnabled:

    window.setKeyRepeatEnabled(false);
    

    Call it once (that's enough) after creating your window.

    The documentation is here.


    If, for any reason, you don't want to use this function, you can have a table of boolean to store the state of each key. Here is a pseudo code that shows how to keep the table up-to-date and integrates your 'decision' code.

    // Init the table of state. true means down, false means up.
    std::array<bool, sf::Keyboard::KeyCount> keyState;
    keyState.fill(true);
    
    // :
    // :
    
    // In the event loop:
    if (event.type == sf::Event::KeyPressed)
    {
        // If the key is UP and was not previously pressed:
        if (event.key.code == sf::Keyboard::Up && !keyState[event.key.code])
        {
            decision--;
            if (decision < 0)
                decision = CHARACTER_MAX - 1;
        }
    
        // Here comes the rest of your code and at the end of the if-body:
    
        // Update state of current key:
        keyState[event.key.code] = true;
    }
    else if (event.type == sf::Event::KeyReleased)
    {
        // Update state of current key:
        keyState[event.key.code] = false;
    }
    

    A third alternative is to use a third-party library such as Thor. It's still under development so you can expect some changes from the author. And here you'll find a tutorial on Action – that is, exactly what you need.