Player Input : Getting multiple triggers on the same frame when one InputAction enables another

Hello,

I was wondering if this was expected behaviour.

Say I have the following code (see below), where m_reference1 and m_reference2 are both buttons, and are bound to the same keyboard input (in this case, the ‘B’ button).

My expected flow would be :

  • m_reference1 is enabled
  • User presses ‘B’ button
  • m_reference1 is triggered
  • m_reference1 is disabled
  • m_reference2 is enabled
  • the end.

But what actually happens is :

  • m_reference1 is enabled
  • User presses ‘B’ button
  • m_reference1 is triggered
  • m_reference1 is disabled
  • m_reference2 is enabled
  • m_reference2 is triggered…

It seems that if one action enables another, and if they both have the same binding, the second action will automatically get triggered with the same input. Seems like a bug to me, right ?

It is causing some issues for me where I have a UI Map with ‘B’ to close a menu, which returns to my player’s action map which has ‘B’ to perform another action. It ultimately means that when I press ‘B’ both actions happen at once, which is definitely not what I want.

To me, any actions that are enabled after a button action has been registered should be ignored.

Is this something in my setup I can fix? or is this just a limitation of the Input system?

using System;
using UnityEngine;
using UnityEngine.InputSystem;

public class InputTest : MonoBehaviour
{
    [SerializeField]
    private PlayerInput m_playerInput;
    
    [SerializeField]
    private InputActionReference m_reference1;
    
    [SerializeField]
    private InputActionReference m_reference2;
    
    private void Awake()
    {
        m_playerInput.onActionTriggered += EVENT_OnTriggered;

        m_playerInput.actions.FindActionMap("TestMap").Enable();

        EnableAction(m_reference1);
    }

    private static void Log(string a_prefix, string a_text)
    {
        Debug.Log($"[{Time.frameCount}: {a_prefix}] {a_text}");
    }

    private void EnableAction(InputActionReference a_ref)
    {
        Log("EnableAction", a_ref.name);
        
        var action1 = m_playerInput.actions.FindAction(a_ref.action.id);
        action1.Enable();
    }

    private void DisableAction(InputActionReference a_ref)
    {
        Log("DisableAction", a_ref.name);
        
        var action1 = m_playerInput.actions.FindAction(a_ref.action.id);
        action1.Disable();
    }

    private void OnDestroy()
    {
        m_playerInput.onActionTriggered -= EVENT_OnTriggered;
    }

    private void EVENT_OnTriggered(InputAction.CallbackContext a_obj)
    {
        if (a_obj.action.id != m_reference1.action.id &&
            a_obj.action.id != m_reference2.action.id)
            return;
                
        Log("EVENT_OnTriggered", $"{a_obj.action.name}: {a_obj.phase}");

        if (a_obj.phase != InputActionPhase.Performed)
            return;
        
        if (a_obj.action.id == m_reference1.action.id)
        {
            DisableAction(m_reference1);
            EnableAction(m_reference2);
        }
    }
}

For those curious, the exact output from the Log is:

[0: EnableAction] TestMap/Action1
[307: EVENT_OnTriggered] Action1: Started
[307: EVENT_OnTriggered] Action1: Performed
[307: DisableAction] TestMap/Action1
[307: EVENT_OnTriggered] Action1: Canceled
[307: EnableAction] TestMap/Action2
[307: EVENT_OnTriggered] Action2: Started
[307: EVENT_OnTriggered] Action2: Performed
[315: EVENT_OnTriggered] Action2: Canceled

To further clarify, both of the inputs are set to ‘Button’, Given this documentation text, I assume what I’m seeing is an error ?

I’ve ended up submitting a bug report. We’ll see what happens!