GetKeyDown triggering more than intended

Hello there. I’m making a user interface for a game.
When calling GetKeyDown(KeyCode.E) the active element becomes disabled and another window opens and becomes active. When Pressing E again to close this window however the newly made active element becomes disabled and the previous one active again, only because of the way the Update method is structured the first GetKeyDown method is called again, making it appear as though the window was never closed.

Sorry for the massive amount of code below, you don’t have to read it. Basically I’m wondering if there’s a way I can stop GetKeyDown from firing twice.

public class Inventory : UserInterface {
   
    // Update is called once per frame
    void Update()
    {
        //Inventory is out of focus while handling options
        if (m_handlingOptions)
            return;

        //Inventory is out of focus if inventory is not enabled, obviously...
        if (!m_enabled)
            return;
    ....

        //interact
        if (Input.GetKeyDown(KeyCode.E) && !m_options.m_enabled)
        {
            //I recognise this is an awful way to call a method, don't judge me.
            m_handlingOptions = m_options.Send(m_inventorySlots[m_choiceIndex].GetComponentInChildren<Item>());
        }
    }

    ....

    private void InventoryOptions_OnClosed()
    {
        m_handlingOptions = false;
    }

}
public class InventoryOptions : UserInterface {

    ....   

    // Update is called once per frame
    void Update ()
    {
        if (!m_enabled)
            return;
    ....

        if (Input.GetKeyDown(KeyCode.E))
        {
            Disable();
            ToggleInventoryOptions();

            if (OnClosed != null)
                OnClosed();
        }
    }
}

To fix this I created a UserInterface class which is inherited by all windows. The class has a Disable and Enable method which basically toggles a bool and has an IEnumorator yield return WaitForNextFrame. I’d hoped that this would prevent GetKeyDown from being called a second time, but regrettably that isn’t the case.

public class UserInterface : MonoBehaviour {

    public bool m_enabled = false;

    /// <summary>
    /// sets the active user interface to enabled
    /// </summary>
    public void Enable() { StartCoroutine(pEnable()); }
    private IEnumerator pEnable()
    {
        m_enabled = true;
        Debug.Log(transform.name + " set to " + (m_enabled ? "Enabled" : "Disabled"));
        yield return new WaitForEndOfFrame();
    }

    ....

}

Can you use FixedUpdate instead of Update?

You could do something as simple as not allowing key press to do anything until a small amount of time has passed after the window is displayed.

public class InventoryOptions : UserInterface {

    private float timeSinceOpened = 0f;
    private float timeToWaitForKeyInput = 0.5f;
    ....

    // Update is called once per frame
    void Update ()
    {
        if (!m_enabled)
            return;
    ....
        timeSinceOpened = timeSinceOpened + Time.deltaTime;
        if ((Input.GetKeyDown(KeyCode.E)) && (timeSinceOpened >= timeToWaitForKeyInput))
        {
            timeSinceOpened = 0f;
            Disable();
            ToggleInventoryOptions();

            if (OnClosed != null)
                OnClosed();
        }
    }
}
1 Like

Just tried but sadly it didn’t work. As a result some of the key presses didn’t go through and both GetKeyDown E still went through like before.

This worked beautifully, thank you both.

Glad its working for you. I just noticed I messed up the parameter declaration (left out “float”) :stuck_out_tongue: but I guess you figured out my screw up.