Search Unity

  1. Good news ✨ We have more Unite Now videos available for you to watch on-demand! Come check them out and ask our experts any questions!
    Dismiss Notice

Rebinding Keys Isn't reflected in existing controlSchemes

Discussion in 'Input System' started by ZachariBarnes, Feb 15, 2020.

  1. ZachariBarnes

    ZachariBarnes

    Joined:
    Nov 6, 2017
    Posts:
    9
    I've been working to migrate my game to the new Input system in order to have the ability to allow the players to Rebind all all the controls in my game, including existing axis(Vertical, Horizontal, ect...)
    I've created my Input actions and configured them they way I believe they need to be configured.
    upload_2020-2-15_16-58-49.png upload_2020-2-15_16-59-22.png

    And I've written code that allows me to read the inputs and react to them.

    Code (CSharp):
    1. public class GameController : MonoBehaviour
    2. {
    3.   public InputMaster controls;
    4.     bool pausePressed, deselectPressed, resetCameraPressed, restartPressed;
    5.  
    6.     public void Awake()
    7.     {
    8.         controls = new InputMaster();
    9.         if (PlayerPrefs.HasKey("Controls"))
    10.         {
    11.             string controlsJSON = PlayerPrefs.GetString("Controls");
    12.             controls.asset.LoadFromJson(controlsJSON);
    13.         }
    14.         controls.GameplayControls.Pause.performed += ctx => pausePressed = !pausePressed;
    15.         controls.GameplayControls.Deselect.performed += ctx => deselectPressed = !deselectPressed;
    16.         controls.GameplayControls.ResetCamera.performed += ctx => resetCameraPressed = !resetCameraPressed;
    17.         controls.GameplayControls.Restart.performed += ctx => restartPressed = !restartPressed;
    18.  
    19.     }
    20.  
    21.     private void OnEnable()
    22.     {
    23.         controls.Enable();
    24.     }
    25.  
    26.     private void OnDisable()
    27.     {
    28.         controls.Disable();
    29.     }
    30. }
    31.  
    32.    public class RTS_Camera : MonoBehaviour
    33.     {
    34.         public InputMaster controls;
    35.         Vector2 movement;
    36.         Mouse mouse;
    37.         float mouseZoom;
    38.         float screenWidth;
    39.         float screenHeight;
    40.         Vector2 center;
    41.         float rotationInput;
    42.         int zoomInput;
    43.         private void Awake()
    44.         {
    45.  
    46.             controls = new InputMaster();
    47.             controls.CameraMovementControls.Movement.performed += ctx => movement = ctx.ReadValue<Vector2>();
    48.             controls.CameraMovementControls.Rotate.performed += ctx => rotationInput = ctx.ReadValue<float>();
    49.             controls.CameraMovementControls.Zoom.performed += ctx => zoomInput = Mathf.RoundToInt(ctx.ReadValue<float>());
    50.             mouse = Mouse.current;
    51.             mouseZoom = mouse.scroll.y.ReadValue();
    52.             screenWidth = Screen.width;
    53.             screenHeight = Screen.height;
    54.             center = new Vector2(screenWidth / 2, screenHeight / 2);
    55.         }
    56.         private void OnEnable()
    57.         {
    58.             controls.Enable();
    59.         }
    60.  
    61.         private void OnDisable()
    62.         {
    63.             controls.Disable();
    64.         }
    65. }
    66.  
    That all works as I would expect, However when I Rebind the controls Using the "Rebind Action UI" script (Transplanted into my project from the "Rebinding UI" Sample) the "ActionBindingText" Updates with the new controls but my Existing 'InputMaster' Objects still only respond to the original controls. This is my primary issue right now.

    My end goal is to allow users to rebind controls and have those controls persist across plays (and between closing and reopening the game.)
    The secondary issue I am having is that I have no idea how to "Save" the binds once they are set but I am assuming I'll need to save off the .asset JSON and load based on the saved JSON. Is that the correct line of thinking?

    I've been banging my head against this for quite awhile and I would appreciate any help you can provide.
    Thanks
    -Zachari Barnes
     
  2. ZachariBarnes

    ZachariBarnes

    Joined:
    Nov 6, 2017
    Posts:
    9
    I've also Used the Input Debugger and It doesn't appear that anything was remapped, but I don't think overrides show on the Input Debugger by default.
     
  3. bilbaeno

    bilbaeno

    Joined:
    Dec 13, 2012
    Posts:
    4
    I am having the same issue at the moment. I am using the RebindActionUI script from the sample, and it is updating the labels for the bindings, but the Actions and Bindings never seem to be modified. It is the same for the sample scene in the sample.
     
    GhostStreetGuru likes this.
  4. GhostStreetGuru

    GhostStreetGuru

    Joined:
    Dec 4, 2016
    Posts:
    16
    @bilbaeno I'm seeing the same thing as you.
    I'm on Unity 2019.2.11.f1

    Could that be when it isn't carrying the keybinding all the way into gameplay?
     
  5. GhostStreetGuru

    GhostStreetGuru

    Joined:
    Dec 4, 2016
    Posts:
    16
    @Rene-Damm any thoughts? are we just missing a step here?
     
  6. GhostStreetGuru

    GhostStreetGuru

    Joined:
    Dec 4, 2016
    Posts:
    16
    upload_2020-3-2_23-26-18.png

    I have not set up any specific control schemes. Would that break the rebinding process in a way that doesnt throw an error code?
     
  7. bilbaeno

    bilbaeno

    Joined:
    Dec 13, 2012
    Posts:
    4
    From what I've learned it isn't supposed to change the actual binding in the asset, just set an override path for the binding.

    But even so, I am not receiving input from the override binding.
     
    tigerleapgorge likes this.
  8. GhostStreetGuru

    GhostStreetGuru

    Joined:
    Dec 4, 2016
    Posts:
    16
    Yeah same.

    I've been throwing in debug strings and when I throw them in OnActionChange in RebindActionUI.cs to try and expose the name for the action, I get null reference errors.
    upload_2020-3-3_20-19-58.png

    (pic of the error coming after my session loads)
     
  9. GhostStreetGuru

    GhostStreetGuru

    Joined:
    Dec 4, 2016
    Posts:
    16
  10. GhostStreetGuru

    GhostStreetGuru

    Joined:
    Dec 4, 2016
    Posts:
    16
    I made a control scheme but that broke more things in my game and didnt fix the rebind not applying the override. Poking around the RebindActionUI.cs file i tried to find a place to plug in ApplyBindingOverride() but i can't get all the info i need to pass along. Any one been able to figure this out?

    upload_2020-3-4_23-55-32.png
     
    tigerleapgorge likes this.
  11. GhostStreetGuru

    GhostStreetGuru

    Joined:
    Dec 4, 2016
    Posts:
    16
    tigerleapgorge and ZachariBarnes like this.
  12. Rene-Damm

    Rene-Damm

    Unity Technologies

    Joined:
    Sep 15, 2012
    Posts:
    1,463
    Sorry for my lateness here.

    So, one general thing, with the C# generated wrappers, control schemes won't do anything except with additional scripting. This is a gotcha that has caught many users unawares and something I would urgently like to have fixed after 1.0. Basically, whereas PlayerInput automatically takes care of device pairing and control scheme selection, you get none of this ATM with generated C# wrappers. Means that all bindings are active no matter what. You need to manually hook up that part.

    Code (CSharp):
    1. var controls = new InputMaster();
    2.  
    3. // Restrict the controls to certain devices.
    4. controls.devices = new InputDevice[] { Keyboard.current, Mouse.current };
    5.  
    6. // Restrict the controls to one control scheme.
    7. controls.bindingGroup = InputBinding.MaskByGroup(controls.controlSchemes.First(x => x.name == "Keyboard&Mouse").bindingGroup);
    Not pretty and not convenient. On the list for improvement.

    Finally, we have an open bug where ApplyBindingOverride does not correctly flush out state on actions and old controls end up sticking around. I've started looking into it and a fix is expected to land in the next package after 1.0.0-preview.6. My suspicion is that this may be what you're running into here.

    As for saving rebinds, we have adding some more convenient wrappers on this on the list for after 1.0. I've posted about how to manually do this here.
     
    tigerleapgorge and ZachariBarnes like this.
  13. GhostStreetGuru

    GhostStreetGuru

    Joined:
    Dec 4, 2016
    Posts:
    16
    Thank you for the info drop, @Rene-Damm

    So does the RebindActionUI prefab actually call ApplyBindingOverride in its current iteration and it is just failing to flush old controls out?

    or is there an insertion point where that function needs to be added?
     
    ZachariBarnes likes this.
  14. GhostStreetGuru

    GhostStreetGuru

    Joined:
    Dec 4, 2016
    Posts:
    16
    @Rene-Damm

    For reference:
    Issue occurs as detailed above on 1.0.0-preview.6
     
    ZachariBarnes likes this.
  15. GhostStreetGuru

    GhostStreetGuru

    Joined:
    Dec 4, 2016
    Posts:
    16
    @Rene-Damm bumping this to see if the potential fix for rebinding UI successfully impacting the player at runtime is slated to be included in the next update? Between the rebinding action UI prefab, the control binding Ui prefab in the tank demo scene, and a UI of my own I have not been able to apply a binding override so far. This would be a huge plus to get this on the next update (which hopefully is not delayed)
     
    ZachariBarnes likes this.
  16. Rene-Damm

    Rene-Damm

    Unity Technologies

    Joined:
    Sep 15, 2012
    Posts:
    1,463
    Having a look. Will get back to you.
     
  17. GhostStreetGuru

    GhostStreetGuru

    Joined:
    Dec 4, 2016
    Posts:
    16
    @Rene-Damm any luck so far?
     
  18. GhostStreetGuru

    GhostStreetGuru

    Joined:
    Dec 4, 2016
    Posts:
    16
    Sorry to poke so much, @Rene-Damm
    Any timeline on a fix for this? I just can't figure out why none of my solutions work for this problem. I'd already used the Rebinding UI prefab provided in the Package Manager to set up my rebinding screen, so overcoming the hump of "I bind something, it updates the UI, but my controls dont effectively change for the player" would just make this who feature fall into place. Please save me <3 I've been blocked on this feature for a month now
     
    ZachariBarnes likes this.
  19. ItsTwelveOclock

    ItsTwelveOclock

    Joined:
    May 28, 2017
    Posts:
    9
    I have the same issue. The RebindUI sample scene doesn't seem to actually rebind anything. @Rene-Damm should we just go back to using the old input system for the time being? Any estimate on when updates to the input system will be coming? I have other issues such as InputAction.performed or InputAction.cancelled not being fired OnButtonRelease after rebinding which could be related.
     
    ZachariBarnes likes this.
  20. abdo400

    abdo400

    Joined:
    Feb 12, 2016
    Posts:
    42
    Adding the code in UpdateBindingDisplay() logged me the new override path, but it still didn't trigger any action with the new key binding. The old key binding still works...

    upload_2020-4-15_17-44-3.png
     
  21. GhostStreetGuru

    GhostStreetGuru

    Joined:
    Dec 4, 2016
    Posts:
    16
    @Rene-Damm to follow up, newest update to the input system and it’s prefabs (.7 preview) does not resolve the issue
     
    ZachariBarnes likes this.
  22. ZachariBarnes

    ZachariBarnes

    Joined:
    Nov 6, 2017
    Posts:
    9
    Yeah still having the same issue. I also tried the code suggested to set the binding group but the new control still doesn't work and the old one does. Is there an ETA on this fix? This feature request has been blocked in my game since January because of this...
     
  23. GhostStreetGuru

    GhostStreetGuru

    Joined:
    Dec 4, 2016
    Posts:
    16
    GENTLEMEN, WHERE I WAS TOO DUMB TO UNDERSTAND BEFORE, NO MOOORE!

    @Rene-Damm actually gave me the solution and i didn't realize it. upload_2020-5-8_1-24-51.png

    Here is a sample of what I had been using. My input action was named NewControls so I had built this into each script that needed to hear player input. This was utilizing the C# Generated Wrapper that Rene was talking about. I also had a PlayerInput component on my game object that was set to call C# events.

    This was wrong.

    Solution:
    In order to make the RebindActionUI prefab function, I had to set the PlayerInput component to call Unity Events, and then manually link the events. I had to remove everything in the red box above as well as the "NewControls.IShooterActions" from the top line in the picture above. Then I left all of my OnMove/OnShoot/OnSubmit/etc. methods in my script and instead of the wrapper (variable "controls" in the picture above) calling them, i manually linked them to the unity events in the PlayerInput component in the inspector.

    After that, my keybindings started to fall into place. The other gotcha I ran into was that my "Input System UI Input Module" component with the EventSystem had been using actions from the same action map that I had setup rebinding elements for. This rendered them as "enabled" even when the PlayerInput module was disabled. If you have an action map for "In Game Events" then you'll want another action map for "UI Interactions" and have those actions in the "Input System UI Input Module". So you can disable your PlayerInput component as you enter the rebinding menu, use the "UI Interactions" action map to continue to navigate around and interact with the rebinding ui, and then re-enable your PlayerInput component as you exit the rebinding menu.
     
    ZachariBarnes likes this.
  24. GhostStreetGuru

    GhostStreetGuru

    Joined:
    Dec 4, 2016
    Posts:
    16
  25. ZachariBarnes

    ZachariBarnes

    Joined:
    Nov 6, 2017
    Posts:
    9
    Thanks I'll try this out sometime this week I hope!
     
  26. skeptika

    skeptika

    Joined:
    Dec 31, 2011
    Posts:
    107
    Was this ever resolved? I tried using the Rebinding UI example and prefab, and while it does update the new binding in the UI, it does not actually rebind (at runtime). I couldn't follow Ghosts proposed solution at all. Has anyone gotten the Rebinding UI example/prefab to actually rebind at runtime?

    Video is Renee showing the example and prefab that I'm referring to:
     
  27. GhostStreetGuru

    GhostStreetGuru

    Joined:
    Dec 4, 2016
    Posts:
    16
    How are you attaching a PlayerInput component or C# class to your object?
     
  28. skeptika

    skeptika

    Joined:
    Dec 31, 2011
    Posts:
    107
    I did precisely what the video suggests, which is take the prefab he built and the scripts he included, and simply reconnect it to my Player Controls (and yes I override the prefab to my values).



    The button itself uses his script to actually perform the binding.



    It does work, in the same sense that his example works, I see it update the UI with the new key for rebinding, however it does not change the underlying controls. Note: his provided scene ALSO doesn't seem to update his controls, it literally only changes the UI. It seems very bizarre to me to release an official sample called Rebinding Sample that doesn't actually rebind (even at runtime)?

    It's using entirely his code, nothing custom. The only thing "custom" is the references themselves to my player controls via the inspector.
     
    Last edited: Jul 13, 2020
    maxmitchelll and ZachariBarnes like this.
  29. Shaelle

    Shaelle

    Joined:
    Nov 19, 2018
    Posts:
    3
    I had the same issue, and this video
    given me the hint to solution. Manuals I have seen before used the following approach: after you created PlayerControls asset, you used it to generate C# class, and created scripts like

    public PlayerControls controls;

    ...

    controls = new PlayerControls();

    controls.Input.Interact.performed += ctx => Interact();

    The thing is: you do not need it now. What you do need, is to add to the game object (where you controls should be) component called "Player Input". In it, you must setup Actions and Default Map (which should be the same as on the buttons you using to change keybindings).

    When you can select behaviour. If you using "Send messages", it will show you list of messages this component generates based on you input, and all you have to do, is to create in a script attached to the same gameoject method with the same name as in the list. For example, I have action called "Interact" and I see that among the messages list there is "OnInteract". So I just create in the script following method:

    public void OnInteract()
    {
    Debug.Log("Interacting");
    }

    Last, but not least: you have to disable action map before you can rebind it. In my experimental project, I am using following code (attached to a three buttons on UI) for manually turn it on or off:

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.InputSystem;

    public class ToogleInput : MonoBehaviour
    {

    public PlayerInput playerController;

    private InputActionMap actionMap;


    // Start is called before the first frame update
    void Start()
    {
    actionMap = playerController.actions.FindActionMap("Input");
    }


    public void On()
    {
    actionMap.Enable();

    Check();
    }

    public void Off()
    {
    actionMap.Disable();

    Check();
    }


    public void Check()
    {
    if (actionMap.enabled) { Debug.Log(" action map enabled"); }
    else { Debug.Log(" action map disabled"); }
    }
    }

    Of course in real project you have to do it automatically (and do checks for assignments etc.).
     
  30. ZachariBarnes

    ZachariBarnes

    Joined:
    Nov 6, 2017
    Posts:
    9
    To update On this I have attempted all the things explained in the above posts, I have added the player Input component and attempted a rebind. It failed due to the action map being enabled so I added an enable and disable to the Interactive rebind. Code to follow

    public void StartInteractiveRebind()
    {
    if (!ResolveActionAndBinding(out var action, out var bindingIndex))
    return;

    action.actionMap.Disable();
    // If the binding is a composite, we need to rebind each part in turn.
    if (action.bindings[bindingIndex].isComposite)
    {
    var firstPartIndex = bindingIndex + 1;
    if (firstPartIndex < action.bindings.Count && action.bindings[firstPartIndex].isPartOfComposite)
    PerformInteractiveRebind(action, firstPartIndex, allCompositeParts: true);
    }
    else
    {
    PerformInteractiveRebind(action, bindingIndex);
    }
    action.actionMap.Enable();
    }

    However once again this only updates the UI to display the new key but the game does not respond to the input at all. I really don't think it can be said better than this:

    @Rene-Damm is there any update on this at all? This Issue has been open since Feb 15. It'll be 6 months in 10 days...
    @GhostStreetGuru did you ever get this resolved in your experiments?
     
  31. RaoulWB

    RaoulWB

    Joined:
    Feb 9, 2014
    Posts:
    7
    As I'm trying to get an Input rebinder to work for my game, I ended up doing everything mentioned in the previous posts with no luck.

    Only useful thing I could add is that both with or without enabling/disabling the actions and action map on rebind, this is what the Input Debug window shows me:

    Before doing any rebinding
    upload_2020-8-7_17-46-12.png

    After having rebound an action called "Jump".
    A new action with the same name seems to have been created?
    upload_2020-8-7_17-48-14.png

    This third "Jump" action is correctly rebound to the button I pressed ("enter" in this case). As all of you reported so far, the UI also correctly shows the new input binding (which, again, is the "enter" key).

    I'm not particularly expert of the Input Debugger, but the apparent creation of a new action instead of modifying the existing ones could be a good lead to understand what's wrong?


    Btw, in case anyone wonders, the actions being doubled by default should be unrelated to this input rebinding matter: a second copy of each action appears the moment the Input Action Asset of choice gets enabled. I can also add that no additional copies of the actions get created if you were to Enable() it multiple times, nor if you happen to both call Enable() and Disable() back and forth at any point.

    Addendum:
    If I keep rebinding this jump action, no more copies of the action get created, but instead this "third instance" of the action just keeps changing according to what I'm pressing.
    upload_2020-8-7_18-10-58.png

    Effectively, the "third instance" always shows exactly what is shown in the UI.


    The more I keep inspecting this, the more likely it seems that this a good element to check.
     

    Attached Files:

    ZachariBarnes likes this.
  32. itsnottme

    itsnottme

    Joined:
    Mar 8, 2017
    Posts:
    82
    Was anyone able to get this working?
    I did some testing and changing the binding directly from the InputActions works as expected, but doesn't work when using InputActionReference as used in the Input System rebinding example.
     
    ZachariBarnes likes this.
  33. ZachariBarnes

    ZachariBarnes

    Joined:
    Nov 6, 2017
    Posts:
    9
    No I still have a non-functioning input binder in my game. At this rate it looks I'm shipping without the ability to rebind keys.
    I wish I was more active on this forum so I would know who to ping for help. @Rene-Damm hasn't responded to this thread in many months.
     
  34. itsnottme

    itsnottme

    Joined:
    Mar 8, 2017
    Posts:
    82
    I found a solution, but it's not pretty.

    controls is the class I create the InputActions in. You have to make sure, you use the same InputActions you use for the input controls in the game.

    Code (CSharp):
    1. foreach (var map in controls.inputs.asset.actionMaps)
    2.             {
    3.                 foreach (var tempAction in map.actions)
    4.                 {
    5.                     if (tempAction.name == m_Action.action.name)
    6.                     {
    7.                         inputAction = tempAction;
    8.                         break;
    9.                     }
    10.                 }
    11.                 if (inputAction != null)
    12.                 {
    13.                     break;
    14.                 }
    15.             }
     
unityunity