One-shot key press

Hello all.
Imagine you’re coding a game in which you have a spaceship and want it shoots only once every time you press the spacebar. If you want to shoot again you have to release and press the spacebar again. For what I know MonoGame doesn’t have a practical and easy way to handle the keyboard input for such a situation, so I coded this simple class:

using Microsoft.Xna.Framework.Input;

public class Keyboard
{
    static KeyboardState currentKeyState;
    static KeyboardState previousKeyState;

    public static KeyboardState GetState()
    {
        previousKeyState = currentKeyState;
        currentKeyState = Microsoft.Xna.Framework.Input.Keyboard.GetState();
        return currentKeyState;
    }

    public static bool IsPressed(Keys key)
    {
        return currentKeyState.IsKeyDown(key);
    }

    public static bool HasBeenPressed(Keys key)
    {
        return currentKeyState.IsKeyDown(key) && !previousKeyState.IsKeyDown(key);
    }
}

The class has a HasBeenPressed method that returns true only the first time a key is pressed.
Usage:

using Microsoft.Xna.Framework.Input;
...
        Keyboard.GetState();
        if (Keyboard.HasBeenPressed(Keys.Space))
        {
            Shoot(); // Shoot only once. To shoot again release/press the spacebar
        }
        if (Keyboard.IsPressed(Keys.Right))
        {
            MoveShipToRight(); // Move the ship to right while the right arrow key is pressed
        }

What do you think about it? Is there a simpler way to do the same?
I think future versions of MonoGame should implement a similar feature…

2 Likes

Nope, this is pretty much how it’s done. Though, more clear names will be CheckKey, CheckKeyPress, CheckKeyRelease.

I don’t think the names you suggested make the idea any better because they don’t “say” if a key is pressed at that moment or if it has been pressed before and therefore it should no longer be considered. However I think there are more suitable names than those I used. Other suggestions are welcome …

Actually, the IsPressed and HasBeenPressed methods could be replaced with the following one:

public static bool IsKeyPressed(Keys key, bool oneShot)
{
    if(!oneShot) return currentKeyState.IsKeyDown(key);
    return currentKeyState.IsKeyDown(key) && !previousKeyState.IsKeyDown(key);
}

Is this better?

For what it’s worth, I named mine PositiveEdge and NegativeEdge.

After all, they’re just names. What matters is the substance.

In my case they are named
Trigger (for a new keypress),
Press (to know if it’s currently pressed)
Hold (to know if and how long it’s being pressed)
and Release (for keys that are no longer pressed starting this update)

No. You’re just mashing together two different methods. And you still need to check key release.

// these two are relatively clear
IsKeyDown
IsKeyUp

// this could be mistaken to just mean the key is down
IsKeyPressed

// this could be mistaken to just mean the key is up
IsKeyReleased

// seems to be clear that the key has been pressed and released but not to clear what the key state is now.
HasBeenPressed

I guess you could name it

HasTheKeyBeenReleasedAndHasJustNowBeenRePressedThisFrame()

lol

God naming conventions are seriously rough.

Nice.
Or you could use this

and do:
input.Keyboard().Is.Press(Keys.Space);

In the situation I described at the beginning, I don’t need at all to check if/when a key is up/released. I only need to check if a key is down at that moment and/or if a key has “just” been pressed. So I would exclude the names IsKeyUp and IsKeyReleased. I also would exclude names as CheckKey, CheckKeyPress and CheckKeyRelease since they don’t “ask” a “question” expecting an answer (true=yes, false=no). I would exclude the names PositiveEdge and NegativeEdge too since they don’t contains a verb (generally, method names should be verbs or verb phrases) and they are not meaningfull to me. So I think I’ll use the names IsKeyDown (ok, let’s use the XNA/MonoGame default name) and HasJustBeenPressed (a compromise between HasBeenPressed and HasTheKeyBeenReleasedAndHasJustNowBeenRePressedThisFrame :slight_smile:).
But a question remains… Will future versions of MonoGame have a similar feature?..

In fact, I wondered if someone had created a class like this, but this is even too complex for my purpose, so I’ll use mine. I also don’t like that the method names in this class are not verbs or verb phrases. Thanks anyway for reporting.

1 Like

Np. Keep on coding. Looking forward to whatever you’re creating.

They way you are handling it is how most people handle it but something you might want to fix before releasing your game, if your game ever lags long enough for an entire key press to happen between two times when you call Keyboard,GetState() then IsKeyDown will return false for both and you will have missed the key press. Ideally you wont ever get that much lag but it certainly happened to me during development with debug builds and you never know what windows is trying to do in the background. Unfortunately monogame doesn’t have a way of fixing this as it doesn’t store all the information coming in about key presses, I fixed it in windows by modifying monogame to pass directx events straight to my game and doing my own input handling but you have to do that for every platform you want to release on. Source code for what I did http://hernblog.com/blogs/fixingInputInWindowsMonogame.html

Looks like you’ve done a big job here. It deserves to be taken into consideration. To be honest, I haven’t noticed any problems with system lags yet, and I would like to hear the opinion and experience of someone else about it…