Search Unity

Question Android: NotSupportedException while resolving binding 'Move:<Keyboard>/rightArrow[;Keyboard&Mouse]'

Discussion in 'Input System' started by Peter77, Jan 9, 2022.

  1. Peter77

    Peter77

    QA Jesus

    Joined:
    Jun 12, 2013
    Posts:
    6,609
    Unity 2019.4.20f1, Input System 1.1.1, Android

    According to Unity Cloud Diagnostics, my game randomly starts throwing the following exceptions after the game ran without error for several hours before.

    This problem occurs on Android phones and I'm unable to reproduce the problem locally.
    1. Any idea how to reproduce it?
    2. Any idea how to fix/workaround it?
    3. What is the error actually telling me and how severe is the problem?

    Code (CSharp):
    1. NotSupportedException while resolving binding 'Move:<Keyboard>/rightArrow[;Keyboard&Mouse]' in action map 'InputActions (UnityEngine.InputSystem.InputActionAsset):Player'
    2. NotSupportedException while resolving binding 'Navigate:<Keyboard>/rightArrow[Keyboard&Mouse]' in action map 'InputActions (UnityEngine.InputSystem.InputActionAsset):UI'
    3. NotSupportedException while resolving binding 'Move:<Keyboard>/rightArrow[;Keyboard&Mouse]' in action map 'InputActions (UnityEngine.InputSystem.InputActionAsset):Player'
    4. NotSupportedException while resolving binding 'Navigate:<Keyboard>/rightArrow[Keyboard&Mouse]' in action map 'InputActions (UnityEngine.InputSystem.InputActionAsset):UI'
    This is my "Player Input" configuration:
    upload_2022-1-9_10-4-48.png

    I do want the player to be able to attach a gamepad the phone and play with gamepad, that's why I turned on "Auto-Switch".

    upload_2022-1-9_10-9-8.png

    upload_2022-1-9_10-10-18.png
     
    Last edited: Jan 11, 2022
  2. Rene-Damm

    Rene-Damm

    Joined:
    Sep 15, 2012
    Posts:
    1,779
    The actual exception should be in the log right after the message that there was an exception. That one should come with a full callstack.
     
  3. Peter77

    Peter77

    QA Jesus

    Joined:
    Jun 12, 2013
    Posts:
    6,609
    Thank you for your answer.

    The following exception that is logged in Cloud Diagnostics along the "NotSupportedException while resolving binding" issue:

    Code (CSharp):
    1. NotSupportedException: Control count per binding cannot exceed byte.MaxValue=255
    2. UnityEngine.InputSystem.InputActionState+<>c.<SaveAndResetState>b__121_1 () (at <00000000000000000000000000000000>:0)
    3. UnityEngine.InputSystem.InputBindingCompositeContext+<get_controls>d__2.System.Collections.IEnumerable.GetEnumerator () (at <00000000000000000000000000000000>:0)
    4. UnityEngine.InputSystem.InputActionMap.ResolveBindings () (at <00000000000000000000000000000000>:0)
    5. UnityEngine.InputSystem.InputActionMap.LazyResolveBindings () (at <00000000000000000000000000000000>:0)
    6. UnityEngine.InputSystem.InputActionState.OnDeviceChange (UnityEngine.InputSystem.InputDevice device, UnityEngine.InputSystem.InputDeviceChange change) (at <00000000000000000000000000000000>:0)
    7. UnityEngine.InputSystem.InputManager.AddDevice (UnityEngine.InputSystem.InputDevice device) (at <00000000000000000000000000000000>:0)
    8. UnityEngine.InputSystem.InputManager.AddDevice (UnityEngine.InputSystem.Utilities.InternedString layout, System.Int32 deviceId, System.String deviceName, UnityEngine.InputSystem.Layouts.InputDeviceDescription deviceDescription, UnityEngine.InputSystem.InputDevice+DeviceFlags deviceFlags, UnityEngine.InputSystem.Utilities.InternedString variants) (at <00000000000000000000000000000000>:0)
    9. UnityEngine.InputSystem.InputManager.AddDevice (UnityEngine.InputSystem.Layouts.InputDeviceDescription description, System.Boolean throwIfNoLayoutFound, System.String deviceName, System.Int32 deviceId, UnityEngine.InputSystem.InputDevice+DeviceFlags deviceFlags) (at <00000000000000000000000000000000>:0)
    10. UnityEngine.InputSystem.InputManager.OnNativeDeviceDiscovered (System.Int32 deviceId, System.String deviceDescriptor) (at <00000000000000000000000000000000>:0)
    11. System.Action`2[T1,T2].Invoke (T1 arg1, T2 arg2) (at <00000000000000000000000000000000>:0)
    12. System.Action`2:Invoke(T1, T2)
    Please note that the issue occurs on different Android devices with different OS's. The exception and callstack don't help me further. Can you extract from it where the problem lies?
     
  4. Rene-Damm

    Rene-Damm

    Joined:
    Sep 15, 2012
    Posts:
    1,779
    Something must be adding more and more devices to the point where a single binding ends up resolving to more than 255 controls. Looking at the binding, it would seem that by that point 255 keyboards have been added.

    The most common cause for this is script code that manually does
    AddDevice
    over and over and never removes the devices. But the stack above looks like the device was actually reported by the Android backend. Which makes me suspect something must be misbehaving there.

    Android has a weird thing where the type of a device is a flag. And all kinds of devices end up reporting themselves as keyboards. But even then, for this to be the cause, it'd have to report a new keyboard device over and over and over.

    Another thing that puzzles me is that looking at your PlayerInput and action configuration, even having a thousand keyboards shouldn't matter. With control schemes and auto-switch being used, it should always track only the actively used devices and thus never try to resolve a
    <Keyboard>/rightArrow
    from all keyboards that have been reported.

    Is the above PlayerInput action setup the *only* way you are using those actions? Or by chance, do you happen to have "Generate C# Class" on and are using that one as well?
     
  5. Peter77

    Peter77

    QA Jesus

    Joined:
    Jun 12, 2013
    Posts:
    6,609
    Thank you for your reply and help.

    I checked it, we don't call
    AddDevice
    anywhere in the code.

    We're using "Generate C# Class". Here is how we use it...

    Code (CSharp):
    1. public class UIButtonShortcutId : ScriptableObject
    2. {
    3.     InputActions m_InputActions = null;
    4.  
    5.     void OnEnable()
    6.     {
    7.         m_InputActions = InputActionsUtility.Create();
    8.         m_InputActions.Enable();
    9.     }
    10.  
    11.     void OnDisable()
    12.     {
    13.         InputActionsUtility.Destroy(m_InputActions);
    14.     }

    Code (CSharp):
    1. public class HeroInput : MonoBehaviour
    2. {
    3.     InputActions m_InputActions;
    4.  
    5.     void Awake()
    6.     {
    7.         m_InputActions = InputActionsUtility.Create();
    8.         m_InputActions.Enable();
    9.     }
    10.  
    11.     void OnDestroy()
    12.     {
    13.         InputActionsUtility.Destroy(m_InputActions);
    14.     }

    Here is the
    InputActionsUtility
    code. It outputs the number of InputActions each time a level was loaded. It's 4 InputActions in a level and 2 InputActions in the mainmenu. Switching levels doesn't increase the number of InputActions, there doesn't seem to be a leak, I just tested it.
    Code (CSharp):
    1. public static class InputActionsUtility
    2. {
    3.    static int s_Count;
    4.  
    5.    [RuntimeInitializeOnLoadMethod]
    6.    static void RuntimeInitializeOnLoadMethod()
    7.    {
    8.        s_Count = 0;
    9.        Loading.scenesLoaded -= OnScenesLoaded;
    10.        Loading.scenesLoaded += OnScenesLoaded;
    11.    }
    12.  
    13.    static void OnScenesLoaded()
    14.    {
    15.        Dbg.Log(null, $"{s_Count} InputActions created");
    16.    }
    17.  
    18.    public static InputActions Create()
    19.    {
    20.        var obj = new InputActions();
    21.        s_Count++;
    22.        return obj;
    23.    }
    24.  
    25.    public static void Destroy(InputActions obj)
    26.    {
    27.        if (obj == null || obj.asset == null) return;
    28.        s_Count--;
    29.  
    30.        obj.Disable();
    31.  
    32.        // If we call Dispose() in OnDisable() while the editor exists playmode,
    33.        // Unity outputs an error that you must use DestroyImmediate instead.
    34.        // So this is our workaround here.
    35.        if (Application.isPlaying)
    36.            obj.Dispose();
    37.    }
    38. }
     
  6. Rene-Damm

    Rene-Damm

    Joined:
    Sep 15, 2012
    Posts:
    1,779
    Ah, so that would explain the "why are actions trying to grab *all* keyboards instead of one" part. The code generated by "Generate C# Class" will by default resolve against the full list of devices available through InputSystem.devices. This can be restricted manually through the devices property but unlike PlayerInput, the code here doesn't do any control scheme switching. So with 256 keyboards in InputSystem.devices, "<Keyboard>/rightArrow" would resolve to 256 controls.

    In general, when using PlayerInput, it's best not to also use "Generate C# Class".

    However, the *real* bug would still be the fact there are >255 keyboards in the first place. It very strongly looks like something in the Android backend causing that. A bug report for this one would be appreciated.
     
  7. Peter77

    Peter77

    QA Jesus

    Joined:
    Jun 12, 2013
    Posts:
    6,609
    Thank you for the reply.

    1. How can I workaround the issue? You mention I could restrict the available devices through a "devices property", but how? The game is heavily relying on the "Generate C# Class" thing, it's not an easy task for me to get rid of it.

    2. Is submitting a bug-report going to help, when I don't have a project where you can reliably reproduce the issue? I'm not able to reproduce this issue at all for example. So far any bug-report I submitted without a 100% reproduction case didn't lead to anything.
     
  8. Rene-Damm

    Rene-Damm

    Joined:
    Sep 15, 2012
    Posts:
    1,779
    Code (CSharp):
    1. var actions = new MyGeneratedActions();
    2. actions.devices = new InputDevice[] { Keyboard.current };
    This is the part that unfortunately, compared to PlayerInput, has to be managed manually.

    Ah, hmm, that indeed complicates things. I was under the impression that simply running the app for several hours inevitably leads to the problem. Is there by chance a pattern to the devices (brand?) on which the problem occurs?
     
  9. Peter77

    Peter77

    QA Jesus

    Joined:
    Jun 12, 2013
    Posts:
    6,609
    The "Control count per binding cannot exceed byte.MaxValue=255" problem seems to occur on iPad7,11 with iOS 15.3.1 only, according to Unity Cloud Diagnostics.

    I found the following warning in those reports that Cloud Diagnostics collected:
    Code (CSharp):
    1. Received stylus event from a device which shouldn't have supported it. Check IsStylusTouchSupported implementation
    This warning doesn't come from our code, probably from Unity or InputSystem. Is it any helpful?
     
  10. toonslab2

    toonslab2

    Joined:
    Mar 27, 2019
    Posts:
    3
    same bug on android with the InputSystem package 1.3.0, I use this code to enable android keyboards

    Code (CSharp):
    1. 06/02/2022 08:34:25] <Error>: NotSupportedException while resolving binding 'KeyboardPressAction:<keyboard>/<key>' in action map '<Unnamed Action Map>'
    2. UnityEngine.InputSystem.InputAction:Enable()
    3. Quattro.UnityInputs:Start()
    4. [06/02/2022 08:34:25] <Exception>: NotSupportedException: Control count per binding cannot exceed byte.MaxValue=255
    5. UnityEngine.InputSystem.InputActionState+BindingState.set_controlCount (System.Int32 value) (at <00000000000000000000000000000000>:0)
    6. UnityEngine.InputSystem.InputBindingResolver.AddActionMap (UnityEngine.InputSystem.InputActionMap map) (at <00000000000000000000000000000000>:0)
    7. UnityEngine.InputSystem.InputActionMap.ResolveBindings () (at <00000000000000000000000000000000>:0)
    8. UnityEngine.InputSystem.InputAction.Enable () (at <00000000000000000000000000000000>:0)
    9. Quattro.UnityInputs.Start () (at <00000000000000000000000000000000>:0)
    10. UnityEngine.InputSystem.InputAction:Enable()
    11. Quattro.UnityInputs:Start()
    where UnityInputs:Start is :
    Code (CSharp):
    1.  m_keyboardAction = new InputAction(name: "KeyboardPressAction", InputActionType.PassThrough,
    2.             binding: "<keyboard>/<key>");
    3.             m_keyboardAction.performed += callbackContext => KeyboardKeyPressPerformed(callbackContext.control as KeyControl);
    4.             m_keyboardAction.Enable();
     
    Last edited: Jun 2, 2022
  11. toonslab2

    toonslab2

    Joined:
    Mar 27, 2019
    Posts:
    3
    I get this error later too
    Code (CSharp):
    1. [06/02/2022 03:31:26] <Error>: NotSupportedException while resolving binding 'KeyboardPressAction:<keyboard>/<key>' in action map '<Unnamed Action Map>'
    2. UnityEngine.InputSystem.LowLevel.<>c__DisplayClass7_0:<set_onUpdate>b__0(NativeInputUpdateType, NativeInputEventBuffer*)
    3. [06/02/2022 03:31:26] <Exception>: NotSupportedException: Control count per binding cannot exceed byte.MaxValue=255
    4. UnityEngine.InputSystem.InputActionState+BindingState.set_controlCount (System.Int32 value) (at <00000000000000000000000000000000>:0)
    5. UnityEngine.InputSystem.InputBindingResolver.AddActionMap (UnityEngine.InputSystem.InputActionMap map) (at <00000000000000000000000000000000>:0)
    6. UnityEngine.InputSystem.InputActionMap.ResolveBindings () (at <00000000000000000000000000000000>:0)
    7. UnityEngine.InputSystem.InputActionMap.LazyResolveBindings () (at <00000000000000000000000000000000>:0)
    8. UnityEngine.InputSystem.InputActionState.OnDeviceChange (UnityEngine.InputSystem.InputDevice device, UnityEngine.InputSystem.InputDeviceChange change) (at <00000000000000000000000000000000>:0)
    9. UnityEngine.InputSystem.InputManager.OnUpdate (UnityEngine.InputSystem.LowLevel.InputUpdateType updateType, UnityEngine.InputSystem.LowLevel.InputEventBuffer& eventBuffer) (at <00000000000000000000000000000000>:0)
    10. UnityEngine.InputSystem.LowLevel.NativeInputRuntime+<>c__DisplayClass7_0.<set_onUpdate>b__0 (UnityEngineInternal.Input.NativeInputUpdateType updateType, UnityEngineInternal.Input.NativeInputEventBuffer* eventBufferPtr) (at <00000000000000000000000000000000>:0)
    11. UnityEngine.InputSystem.LowLevel.<>c__DisplayClass7_0:<set_onUpdate>b__0(NativeInputUpdateType, NativeInputEventBuffer*)
     
  12. toonslab2

    toonslab2

    Joined:
    Mar 27, 2019
    Posts:
    3
    I had to disable keyboards on android to stop the bug
     
    Last edited: Jun 20, 2022
  13. Peter77

    Peter77

    QA Jesus

    Joined:
    Jun 12, 2013
    Posts:
    6,609
    How would I do that?