Search Unity

PerformInteractiveRebindings for composite

Discussion in 'Input System' started by Jichaels, Nov 19, 2019.

  1. Jichaels

    Jichaels

    Joined:
    Dec 27, 2018
    Posts:
    237
    Hello guys,

    I want users to be able to rebind their controls through an UI, but I can't find a way to do this with composite bindings :/

    This is what my input asset looks like : Sans titre.png

    And this is basically what I'm trying to achieve :

    Code (CSharp):
    1. public class InputsRebinding : MonoBehaviour
    2. {
    3.  
    4.     [SerializeField] private TextMeshProUGUI forwardText;
    5.     [SerializeField] private TextMeshProUGUI leftText;
    6.     [SerializeField] private TextMeshProUGUI backwardText;
    7.     [SerializeField] private TextMeshProUGUI rightText;
    8.  
    9.     [SerializeField] private Button forwardButton;
    10.     [SerializeField] private Button leftButton;
    11.     [SerializeField] private Button backwardButton;
    12.     [SerializeField] private Button rightButton;
    13.  
    14.     [SerializeField] private InputActionReference movementReference;
    15.  
    16.  
    17.     private void Awake()
    18.     {
    19.         UpdateText();
    20.         forwardButton.onClick.AddListener(() => RemapAction(movementReference.action, 0));
    21.         backwardButton.onClick.AddListener(() => RemapAction(movementReference.action, 1));
    22.         leftButton.onClick.AddListener(() => RemapAction(movementReference.action, 2));
    23.         rightButton.onClick.AddListener(() => RemapAction(movementReference.action, 3));
    24.     }
    25.  
    26.  
    27.     public void RemapAction(InputAction action, int? targetBinding = null)
    28.     {
    29.         var remapOperation = action.PerformInteractiveRebinding();
    30.         remapOperation.WithCancelingThrough("<Keyboard>/escape");
    31.         remapOperation.WithControlsExcluding("Mouse");
    32.         remapOperation.OnMatchWaitForAnother(0.1f);
    33.         remapOperation.WithBindingGroup("MouseKeyboard");
    34.  
    35.         if (targetBinding.HasValue)
    36.         {
    37.             remapOperation.WithTargetBinding(targetBinding.Value);
    38.         }
    39.      
    40.         remapOperation.Start();
    41.     }
    42.  
    43.     private void UpdateText()
    44.     {
    45.         forwardText.text = InputControlPath.ToHumanReadableString(movementReference.action.bindings[0].effectivePath);
    46.         leftText.text = InputControlPath.ToHumanReadableString(movementReference.action.bindings[1].effectivePath);
    47.         backwardText.text = InputControlPath.ToHumanReadableString(movementReference.action.bindings[2].effectivePath);
    48.         rightText.text = InputControlPath.ToHumanReadableString(movementReference.action.bindings[3].effectivePath);
    49.     }
    50.  
    51. }

    What's the correct way to do this ? I searched through the doc and github to no avail :/

    Thanks !


    EDIT : Also, I'm on AZERTY layout but my Z key is displayed as W (because of the location mapping). Is there a way to get the "real" name of the control ?
     
    Last edited: Nov 19, 2019
  2. Jichaels

    Jichaels

    Joined:
    Dec 27, 2018
    Posts:
    237
    I found a way to display the "real" value :

    Instead of using :
    InputControlPath.ToHumanReadableString(movementReference.action.bindings[2].effectivePath, InputControlPath.HumanReadableStringOptions.OmitDevice)

    I'm using :
    movementReference.action.controls[0].displayName


    Still don't know how I'm supposed to get the indexes (hardcode it ?) or how to rebind at runtime though :/
     
    valentin56610 likes this.
  3. Jichaels

    Jichaels

    Joined:
    Dec 27, 2018
    Posts:
    237
  4. Rene-Damm

    Rene-Damm

    Joined:
    Sep 15, 2012
    Posts:
    1,779
    Sorry for the long lag here.

    We're in the process of putting the finishing touches on an extensive pass over binding display strings and rebinding UI support including a sample for how to put together a rebind UI using the APIs (and also including a ready-made prefab and scripting component that you can use in your own projects). This includes support for dealing with composites both in case you want to rebind them as a whole as well as when splitting them up into individual rebinds. The changes should be in the next package.
     
  5. Rene-Damm

    Rene-Damm

    Joined:
    Sep 15, 2012
    Posts:
    1,779
    Addendum, this should also work out of the box with the incoming changes.
     
  6. Jichaels

    Jichaels

    Joined:
    Dec 27, 2018
    Posts:
    237
    Oh wow, that's cool ! Looking forward to it as I still couldn't make it work (and yes, what I wanted to do is split a composite so I could remap each)
     
  7. ElementalCode

    ElementalCode

    Joined:
    Aug 6, 2014
    Posts:
    4
    Any updates on rebinding composite axis?

    I am doing

    Code (CSharp):
    1.  
    2. ActionToRebind.action.PerformInteractiveRebinding()
    3.             .WithControlsExcluding("Mouse")
    4.             .WithCancelingThrough("<Keyboard>/escape")
    5.             .WithTargetBinding(0)
    6.             .WithBindingGroup("Keyboard")
    7.             .OnMatchWaitForAnother(0.1f)
    8.             .Start()
    9.  
    And the "onComplete" never triggers and I can't remap. Tried without the BindingGroup, without the BindingTarget, without the ExcludeMouse, Without the Cancel, tried all combinations and I keep failing. What am I missing?
     
  8. Pandanym

    Pandanym

    Joined:
    Dec 2, 2017
    Posts:
    17
    Bump, still finding a way to rebind a composite.
     
    valentin56610 likes this.
  9. Pandanym

    Pandanym

    Joined:
    Dec 2, 2017
    Posts:
    17
    And I mean individually rebind each key, not the weird rebinding that is present in the (uncommented) code in the tanks demo.
     
  10. Jichaels

    Jichaels

    Joined:
    Dec 27, 2018
    Posts:
    237
    Yeah, I still need it too, and no sign of this new package either :/
     
  11. Pandanym

    Pandanym

    Joined:
    Dec 2, 2017
    Posts:
    17
    Finally managed to get something working.

    So the trick is that a composite is a binding, but it's also made of bindings. So for this action :


    action.bindings[0] is WASD, and is a 2D vector. PerformInteractiveRebinding will only accept a 2D vector like a left stick.

    However action.bindings[1] is the W key ! If you do PerformInteractiveRebinding with WithTargetBinding(1) you can rebind it. The only problem is that it will still only accept a 2D vector, so you need to use useWithExpectedControlType("Button").

    Here's my script (use it on a button) you'll need to set the bindingIndex int manually in editor depending on your setup.

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using UnityEngine.InputSystem;
    5. using UnityEngine.UI;
    6. using TMPro;
    7. using UnityEngine.EventSystems;
    8.  
    9. public class RebindButton : MonoBehaviour
    10. {
    11.     public InputActionReference actionReference;
    12.     public int inputBindingIndex;    
    13.     public TextMeshProUGUI buttonText;
    14.  
    15.     private InputActionRebindingExtensions.RebindingOperation rebindingOperation;
    16.     private Button button;
    17.  
    18.     private void OnValidate()
    19.     {
    20.         inputBindingIndex = Mathf.Clamp(inputBindingIndex, 0, actionReference.action.bindings.Count-1);
    21.     }
    22.  
    23.     void Start()
    24.     {
    25.         button = GetComponentInChildren<Button>();
    26.  
    27.         button.onClick.AddListener(StartRebind);
    28.  
    29.         buttonText.text = InputControlPath.ToHumanReadableString(actionReference.action.bindings[inputBindingIndex].effectivePath);
    30.     }
    31.  
    32.     private void OnDestroy()
    33.     {
    34.         button.onClick.RemoveAllListeners();
    35.     }
    36.  
    37.     public void StartRebind()
    38.     {
    39.         actionReference.action.Disable();
    40.  
    41.         print("launching rebind");
    42.  
    43.         var rebindingOperation = actionReference.action.PerformInteractiveRebinding()
    44.                     .WithControlsExcluding("Mouse/delta")
    45.                     .WithControlsExcluding("Mouse/position")
    46.                     .WithCancelingThrough("<Keyboard>/escape")
    47.                     .WithTargetBinding(inputBindingIndex)
    48.                     .Start()
    49.                     .OnComplete((x) =>
    50.                     {
    51.                         // update button string
    52.                         buttonText.text = InputControlPath.ToHumanReadableString(x.action.bindings[inputBindingIndex].effectivePath);
    53.  
    54.                         actionReference.action.Enable();
    55.                         x.Dispose();
    56.                     })
    57.                     .OnCancel((x)=>
    58.                     {
    59.                         // deselect button
    60.                         FindObjectOfType<EventSystem>().SetSelectedGameObject(null);
    61.                         x.Dispose();
    62.                         actionReference.action.Enable();
    63.                     });
    64.  
    65.         if (actionReference.action.bindings[inputBindingIndex].isPartOfComposite)
    66.         {
    67.             rebindingOperation.WithExpectedControlType("Button");
    68.         }
    69.     }
    70. }
    71.  
     

    Attached Files:

  12. Rene-Damm

    Rene-Damm

    Joined:
    Sep 15, 2012
    Posts:
    1,779
    Sorry, wanted to have all this out before Christmas but things came together slower than expected and I really needed a break...

    The PR with the rebinding changes and a new rebinding UI sample has landed and is on the develop branch. 1.0.0-preview.4 is slated for early next week.
     
  13. Pandanym

    Pandanym

    Joined:
    Dec 2, 2017
    Posts:
    17
    Will it break my workaround ?
     
  14. Jichaels

    Jichaels

    Joined:
    Dec 27, 2018
    Posts:
    237
    No problem, everyone needs a break sometime.

    Hope it will fix some problems I have and make things like rebinds easier, then the new input system will be in a pretty good state !
     
  15. Rene-Damm

    Rene-Damm

    Joined:
    Sep 15, 2012
    Posts:
    1,779
    I've recorded a video with a quick fly-through of the changes.

    If you get a chance to give the new stuff a try, let me know it goes :)

    Think it should be fine. Most of the changes have been mere extensions and shouldn't be break. PerformInteractiveRebinding() did change a bit under the hood to perform more configuration out of the box but if that should get in the way, you can just reset things to get back to how it was before.
     
    AyoubGharbi likes this.
  16. Pandanym

    Pandanym

    Joined:
    Dec 2, 2017
    Posts:
    17
    You rock ! Changes you've made to the composite rebindings are excellent, thank you.

    EDIT : just saw the display options and I love it, this will come really handy for tutorials and contextual actions.
     
    Last edited: Jan 26, 2020
  17. Jichaels

    Jichaels

    Joined:
    Dec 27, 2018
    Posts:
    237
    Can't test it right now, but your video shows that it's really good !

    Will try as soon as I can :)
     
  18. Pandanym

    Pandanym

    Joined:
    Dec 2, 2017
    Posts:
    17
    Some feedback : I like that the display strings are localized using system language, but I haven't found a way to manually set it. I'm a french dev making games in english and seeing "press ESPACE to jump" is a bit jarring.
     
  19. Jichaels

    Jichaels

    Joined:
    Dec 27, 2018
    Posts:
    237
    Then localize the whole text ! If you want I've a really simple localization system that you can use :D
     
  20. Pandanym

    Pandanym

    Joined:
    Dec 2, 2017
    Posts:
    17
    We already do that, but I prefer to play games in english and so do many of my peers.
     
  21. MasterZ0

    MasterZ0

    Joined:
    Jul 24, 2020
    Posts:
    18
    Try to put the bindingIndex value inside of PerformInteractiveRebinding() :)

    Code (CSharp):
    1. public void RemapAction(InputAction action, string actionName, string group, int bindingIndex= -1)
    2. {
    3.         controls.Disable();
    4.  
    5.         var rebindOperation = action.PerformInteractiveRebinding(bindingIndex)
    6.             .WithControlsExcluding(actionName)
    7.             .WithBindingGroup(group)
    8.             .OnMatchWaitForAnother(0.1f)
    9.             .OnComplete(operation => RebindEnd(operation, group))
    10.             .OnCancel(operation => RebindError(operation));
    11.  
    12.         rebindOperation.Start();
    13. }
     
    FlightOfOne, XuKedddd and Aksoq like this.