Generic / Abstract way to check if an InputEvent is currently active?

Godot Version

v4.5.1.stable.mono.official [f62fdbde1]

Question

I’ve started setting up an input system for my game that uses commands that I bind to InputEvents, but I ran into a small problem.

In my current setup, I have the bindings set up like this:

Array<StringName> actions = InputMap.GetActions();
foreach (StringName action in actions)
{
    switch (action)
    {
        case "Up":
            BindInputEventToCommand(InputMap.ActionGetEvents(action), new MoveUpCommand(_player));
            break;
        case "Down":
            BindInputEventToCommand(InputMap.ActionGetEvents(action), new MoveDownCommand(_player));
            break;
        case "Left":
            BindInputEventToCommand(InputMap.ActionGetEvents(action), new MoveLeftCommand(_player));
            break;
        case "Right":
            BindInputEventToCommand(InputMap.ActionGetEvents(action), new MoveRightCommand(_player));
            break;
    }
}

BindInputEventToCommand simply does the following:

private void BindInputEventToCommand(Array<InputEvent> events, ICommand command)
{
    foreach (InputEvent inputEvent in events)
    {
        _bindings.Add(inputEvent, command);
    }
}

However, the problem comes up when it’s time to check if any of the inputs are actually active. In my Process function, I did the following:

foreach (InputEvent key in _bindings.Keys)
{
    if (key.IsPressed())
    {
        _bindings[key].Execute();
    }
}

But this doesn’t work at all. Not even for keyboard inputs, let alone joypad related things, since they’re technically not “pressed”, and I cannot for the life of me find a simple, abstract way to check if a specific InputEvent is currently active or not. Is the only way to achieve this is to type cast each InputEvent into a specific type and then handle it seperately?

That’s not how the input system works. The InputEvent in the InputMap are only used to check if a fired input event match with them or not internally. They don’t contain any other information and won’t update if they match.

Just use the action name as the key of your dictionary and check if the action is pressed or not in Node._input() or Node._unhandled_input() depending on what level you want your commands to work. Here’s how the input system work:

Something like:

extends Node


var _bindings: Dictionary[String, Command]


func _ready() -> void:
    # Fill the _bindings
    
    
func _input(event: InputEvent) -> void:
    for input_action in _bindings.keys():
        if event.is_action_pressed(input_action):
            _bindings[input_action].execute()
3 Likes