The “Any” Key Problem with the New Input System for Simultaneous Input Detection in Unity 2023.1
In the new Input System, the “Any Key” does not pass the name of the key that was pressed, which sucks.
The “Any Key” also fails to work accurately for detecting simultaneous keypresses when used as the trigger for checking keypress input.
As shown above when the Y, U, I, and O keys were pressed simultaneously, button states and entire buttons were missed!
The Solution is Brute Force
If you absolutely *MUST* detect all keyboard input, including up to 4 simultaneous keypresses or more, you have to accept the performance trade off of checking every key’s state every Update() frame.
It is probably best to use a for loop rather than a foreach loop to regain some of the lost performance.
For the details on how I came to this conclusion, please read on.
In this article I want to briefly cover an issue I ran into while working with the new input system.
But first, why was I using the “Any key” binding in the first place?
I thought that this binding would pass the name of the key pressed.
It did not.
What was the alternative then?
Bind every key individually?
Yep, but that still had issues with simultaneous keypresses and their button states registering.
So that ended my attempts to address simultaneous keypress input through the Input Action Asset.
From now on, it would be code only using the new Input System’s functions.
The Event Driven Input Actions Asset Approach
I originally took the Input Actions Asset approach with an Action that was bound to “Any key” for detecting all keyboard input.
Apologies that I don’t have a screenshot of the Input Actions Asset in the Unity Editor, but the related code is shown above.
This is where the issue first cropped up.
You cannot get what key was pressed from an “Any Key” binding in the Input Actions Asset.
The InputAction.CallbackContext simply does not pass the name of the key when the binding is “Any key”.
Why, Unity, why?!
So, as a workaround, when the “Any Key” binding was triggered in the Input Actions Asset, I checked what key was pressed that frame by checking literally every key with a foreach loop.
While this worked for one key at a time or maybe two simultaneously, anything beyond that started to miss either button phase events (Start, Cancelled) or entire buttons.
The results were as shown above.
When pressing Y, U, I, and O keys simultaneously, the debug logs from the InputDataCollection class only showed that Y was pressed (started) and that O was released (cancelled).
It missed a button state for both of the 2 keys it did register, and it didn’t register 2 other keys entirely!
This can be seen by the debug logs being reported of keypresses from the old Input System class that was being phased out for the new Input System.
Note that the old input system did not report released / canceled states so we only get logs of the keypress in general for comparison’s sake.
The new input system debug logs are shown as full width above, while the old input system starts with “OnKeyPressDown”.
The Update() Approach with “Any key”
At this point, I was still hoping to make use of the “Any key” as a trigger in order to avoid checking all keypress input on frames when none has occurred.
Using “Keyboard.current” functionality from the new Input System, I checked the “Any key” every Update() frame.
This had the same issues shown in the debug logs earlier in this article with hit or miss detection.
Testing the Check Every Key Every Update() Frame Approach
At this point I tested whether individual checking every Update() frame would correctly report simultaneous input.
I had avoided this up until now with the hopes of not impacting performance with so many keypress checks since one of my use-case requirements is getting literally all keypress input on any keyboard.
For this testing though, I only set up the Y, U, I, and O keys which I then tested with simultaneous keypresses.
Sometimes Brute Force is What it Takes
As mentioned at the beginning of this article, when you absolutely have to catch all keyboard input including simultaneous input of up to 4 keys (perhaps more), than you just have to bite the performance bullet.
Keyboard.current functions from the new Input System do the trick, but only have to button states.
These are pressed and released which correlate to Started and Canceled when using the Input Action Asset’s bindings.
I hope this saves someone else a day or more’s work trying to work out issues with simultaneous keypress tracking!