How to rebind composite actions?

I have a composite action for movement

And I want to have a button in game for each of those. So that when it's clicked it would start listening for a button to rebind it.
Standard stuff, press button for 'Forward' and change it from 'W' to 'E'

As far as I got is I have a button that has an OnClick function that passes the name of the action to rebind, finds it, and preforms the interactive rebind. Which works for regular actions, but how can I rebind a single key in a composite action?

public void RebindButton(string actionName)
{
    InputAction action = control.currentActionMap.asset.FindAction(actionName);

    control.currentActionMap.Disable();

    //start binding
    var rebind = action.PerformInteractiveRebinding();
    rebind.WithControlsExcluding("Mouse");
    rebind.Start()
          .OnComplete(finishedRebind)
          .OnCancel(finishedRebind);

}

Looking for the same solution.

ATM the API makes this awkward. I'll go and have a look how to make that easier.

Using WithTargetBinding you can instruct RebindingOperation to rebind a specific binding on an action. This can be used to direct it at specific part bindings.

var bindingIndex = action.bindings.IndexOf(x => x.isPartOfComposite && x.name == "Up");
rebind.WithTargetBinding(bindingIndex);
6 Likes

Just to add this, while not perfect, there is an alternate way doable as of 1.1-preview.3 (though I think it's been in there for a bit).

// Let's say you have a composite that you named
// "WASD" in the editor. The following call returns
// a sort of "iterator" which can also be used to
// query binding indices.
var wasd = action.ChangeBinding("WASD");

// We can use NextPartBinding() to iterate forward
// to parts of the composite.
var up = wasd.NextPartBinding("Up");
var down = wasd.NextPartBinding("Down");
var left = wasd.NextPartBinding("Left");
var right = wasd.NextPartBinding("Right");

// And then we can use the bindingIndex property
// to pass it on to the rebind.
rebind.WithTargetBinding(up.bindingIndex);

I'm on the latest version of the input system and I'm trying to implement the WASD rebinding. The action.ChangeBinding() doesn't accept an argument of type string and the wasd.NextPartBinding("") doesn't exist. How Can I Fix this ?
6910043--809786--upload_2021-3-7_15-44-43.png

6911867--810239--upload_2021-3-8_8-59-4.png

6911867--810242--upload_2021-3-8_8-59-24.png


Have you tried the documentation?
https://docs.unity3d.com/Packages/com.unity.inputsystem@1.1/api/UnityEngine.InputSystem.InputActionSetupExtensions.BindingSyntax.html#UnityEngine_InputSystem_InputActionSetupExtensions_BindingSyntax_NextPartBinding_System_String_

Yes I tried but I'm a bit loss. After 5 hours it still didn't work at all. certain methods doesn't exist how can I declare them ? Can you guide me ?


Post your (entire) script here, in CODE tags (see the post editor toolbar). Will take a look.

My script work fine for normal rebinding but i failed to get a single thing that works for composite bindings like axis. So I deleted all the composite bindings code 2 days ago. I also tried to do what was said on this post. but as shown on the screen I sent above, the methods don't seem to be declared. How would you have done it? I think it might be of interest to a lot of people other than me (+ me).

Hello Transarc,

You are using the wrong method you should use ChangeCompositeBinding("Wasd"); instead then it does have that method.

What I only have now is, when I try it out it doesn't register my input. I have a button and when I press it it does the code below and wait for a input respond, and for normal action buttons works fine, but for the composite does seems like it does nothing

My code looks like this

  _startRebindObject.SetActive(false);
            _waitingForInputObject.SetActive(true);
            _playerInput.SwitchCurrentActionMap("UI");

            var arrowKeys = _attackAction.action.ChangeCompositeBinding("ArrowKeys");

            var part = arrowKeys.NextPartBinding(partBinding);

            rebindingOperation = _attackAction.action.PerformInteractiveRebinding()
                                                    .WithTargetBinding(part.bindingIndex)
                                                    .WithControlsExcluding("Mouse")
                                                    .OnMatchWaitForAnother(_WAITFORANOTHERINPUT_SECONDS)
                                                    .OnComplete(operation => RebindComplete())
                                                    .Start();

Hello all. Im struggling with the same issues.

I have a UI action map which has an action named "navigate". In there I have 2 binding groups (is that the correct term? not sure) one for the gamepad control scheme which listens to stick or d-pad inputs and one group for keyboard controlscheme. Inside that group I have four composites, Up,Left,Down and Right.

I've tried nearly everything suggested in this thread and nothing seems to work.

bindingIndex = navigateAction.action.bindings.IndexOf(x => x.name == composite);

returns -1.

I ended up with the following code but I know its junk (even though Im a beginner in Unity and scripting) even though it works. Currently I can this function by hooking it to buttons and pass the string parameter to "select" which rebind to perform.

   public void StartRebindingWASD(string composite)
    {
        uicontrols.Disable();
        switch (composite)
        {

//  I ended up hardcoding the bindingIndex here, as nothing else seems to work
            case "Up": selector = 0; bindingIndex = 11; break;
            case "Left": selector = 1; bindingIndex = 12; break;
            case "Down": selector = 2; bindingIndex = 13; break;
            case "Right": selector = 3; bindingIndex = 14; break;
            default: selector = -1; bindingIndex = -1; break;
        }


        wasdDisplayTexts[selector].text = "";
        wasdStartRebindObject[selector].SetActive(false);
        wasdWaitingForInputObject[selector].SetActive(true);

      // bindingIndex = navigateAction.action.bindings.IndexOf(x => x.name == composite);
        Debug.Log(bindingIndex);
        rebindingOperation = navigateAction.action.PerformInteractiveRebinding(bindingIndex)
                                      .WithControlsExcluding("Mouse")
                 // how the hell do I exclude the "enter" key for this rebinding?                     
                                      .WithControlsExcluding("<Keyboard>/enter")
                                      .WithCancelingThrough("<Keyboard>/escape")
                                      .OnMatchWaitForAnother(0.1f)
                                      .OnCancel(operation => RebindComplete(bindingIndex))
                                      .OnComplete(operation => RebindComplete(bindingIndex))
                                      .Start();
    }

    void RebindComplete(int bindingIndex)
    {
        wasdDisplayTexts[selector].text = InputControlPath.ToHumanReadableString(navigateAction.action.bindings[bindingIndex].effectivePath, InputControlPath.HumanReadableStringOptions.OmitDevice);
        rebindingOperation.Dispose();

        wasdStartRebindObject[selector].SetActive(true);
        wasdWaitingForInputObject[selector].SetActive(false);
        uicontrols.Enable();
    }

On a sidenote, how do I exclude the "enter" key? the above gives me "any key" when I hit the enter key when waiting for input.

When I try to ise ChangeCompositeBinding it seems there is a namespace Im missing. Do I need a directive In unaware of?

Ok for anyone else reading this.......

Im using the 1.0.2 version so that explains why I cant use some of the above suggestions.

As for excluding the "enter" key, or any other key for that matter, the Input debugger screen helped me realize what keys to exclude in my rebinding script to make it work as desired. So for example I noticed that "enter" key also registers a "anyKey" press so I also had to exclude that. Another example are the "shift" keys where you need to exclude "rightShift", "leftShift" and "shift" in order to exclude them from rebinding.

I managed to make the system work a week ago. I can send the code if needed but I pretty much used the first solution of the thread.

1 Like

I managed to implement this solution but the names were all in lowercase, even when the composite binding was named "Up" in the asset.

So any search with the strings .ToLower or ToUpper just in case should do the work.

1 Like


I've been starting using this method, and it seemed I was on the right track, as the up, down, left, right bindingIndex gave me the right numbers, but it doesn't actually allow me to press any buttons when performing the interactive rebind. It only allows something like, mouse scroll, or gamepad sticks/dpad. And then once it accepts even those, I start getting errors. Does anyone know why I can't use any keys when rebinding a composite?
code looks like this (for keyboard rebinding):

rebindOperation = currentButtonRebinding.PerformInteractiveRebinding();
                    rebindOperation.WithTargetBinding(currentBindingIndex);
                    rebindOperation.WithControlsExcluding("<Gamepad>");
                    rebindOperation.OnMatchWaitForAnother(0.1f);
                    rebindOperation.OnComplete(operation => RebindCompleted());

                rebindOperation.Start();

and, as a side, i do have other action type buttons that rebinding keys DO work. it's just when trying to rebind new composite for some reason. nothing happens, it never goes onto that RebindCompleted unless I use the scrollwheel which causes errors.

Hey, I solved the problem its really simple
Ex:
int index=1//it should start from 1 cuz 0 is for the actual composite wasd binding and then 1 for W subbinding,2 for S subbinding and so on as we move down the group.
wasd.action.PerformInteractiveRebinding(index).WithCancelingThrough("/escape").WithControlsExcluding("Mouse").OnCancel(Cancel).OnMatchWaitForAnother(.1f).OnComplete(Completed).Start();

So if u r making a rebinding script,
it should be like this,
1:it should retreive the action reference and show for which binding index it should do rebinding.
2:after getting the binding index it should check whether the binding is composite or not.
3.if it is not composite then simple do the rebinding other wise it should show for which subbinding index it should perform the rebinding which is always greater than 0 and then do rebinding with that subbinding index.

I hope it helps

You should always feed an binding index to the function action.PerformInteractiveRebinding(index) otherwise it will not work correctly if the bindings for that action is greater than 1.

Could we get an update from Unity here as of how we are supposed to acheive composite rebindind? Also how to display their text would be nice.

1 Like