Rebinding with optional Modifier keys

I have been implementing the new Input System in my current game and am a bit flummoxed by rebinding.

It appears that if a binding is setup as one type (Button, ButtonWithOneModifier, ButtonWithTwoModifiers) there’s no way to rebind to a different type. (It looks like I could override the existing functionality and delete the old binding and create a new binding from code, but that’s not a rebinding, and ignores the function calls clearly intended for rebinding.) Is there an intended way to do this that I am missing, or does this functionality not exist?

As an example if it’s not clear: I have an Action called Interact and bind it by default to the keyboard value ‘E’. Then I have an options menu in my game where actions can be rebound. However I can not find any way (at least using PerformInteractiveRebinding()) to allow the user to rebind the Interact action to ‘Shift-E’ if they wanted to for some reason. I thought perhaps I could make all bindings ButtonWithTwoModifiers and leave the modifiers empty if needed, but that doesn’t seem to work either.

Can you create 2 or 3 bindings in the aciton and set it up such that only one of them is bound with a value? I haven’t actually tried this, it’s just an idea. You could have one Button binding and one ButtonWIthOneModifier and one ButtonWithTwoModifiers within the same action. It might be pretty complicated to figure out how the user wants to bind … maybe if the binding process listens for all keys pressed and then finishes when no keys are pressed? and then keeps only the last 3 pressed at most.

The current rebinding support does indeed not yet have a whole lot of flexibility (well, you could argue it has none :)) in terms of altering the binding setup. In other words, except for being able to add new bindings (WithRebindingAddingNewBinding), there’s no built-in support for having it automatically deal with bindings involving more than a single control. It’s on the list.

ATM the options are to either deal with this at the UI level or to manually script the respective logic by using the callbacks of RebindingOperation and synthetizing a composite binding from the list of candidate controls.

Thanks for clearing that up. I was starting to pull my hair out thinking I was making things entirely too complicated. :stuck_out_tongue:

I might try multiple bindings and see if that’s an easier approach but it’s good to know I’m not spending time redoing functionality that already exists.

Here we are, May of 2022.

I’m trying to get over this hurdle at the moment. Any guidance?

Specifically, the 1.3 changelog notes say this should work with buttons via this line:

  • If an binding of higher complexity “consumes” a given input, all bindings waiting to consume the same input will automatically get skipped. So, if a “Shift+B” binding composite consumes a “B” key press, a binding to “B” that is waiting in line will get skipped and not see the key press.

Here’s my binding:
8127827--1054151--upload_2022-5-14_10-59-41.png

I’m getting actions firing for both Interact and Secondary Interact, unfortunately.

Is it relating to how I wrote my binding code?

input = GetComponent<PlayerInput>();
input.actions["Interact"].started += PrimaryStart;
input.actions["Interact"].canceled += PrimaryEnd;
input.actions["Secondary Interact"].started += SecondaryStart;
input.actions["Secondary Interact"].canceled += SecondaryEnd;

https://docs.unity3d.com/Packages/com.unity.inputsystem@1.3/manual/KnownLimitations.html#actions

They say in the next release this limitation will go away? If I remember correctly.

What’s the status on this? Not sure where to look. Can binding types be changed easily now in 1.4.4?

I’ve been looking into this again and found a couple bits that can help:

  • Project Settings / Input System Package / Enable Input Consumption allows you to have two non-competing inputs (for instance, tab and shift-tab).

  • .PerformInteractiveRebinding(index).OnMatchWaitForAnother(1f) allows you to wait for the player to press multiple keys when rebinding.

However, if you have a Binding (that does not have a modifier) and want to override it with a Binding that has a modifier, I do not see a direct way to do that with the current system. I also could get not a Binding with a modifier, where the modifier is set to none, to work. (So for instance you could bind to None-Tab and allow the player to rebind as Shift-Tab.)

This leaves adding your own binding using the RebindingOperation callback as mentioned above, but that means that you have to externally keep track of what you have added as being an override and manage any changes. This seems like a giant pita to me, and looks like a pretty substantial shortcoming in the existing system.

This should be doable by customizing OneModifierComposite that comes out of the box. Like, even copypasting it from GitHub, making sure modifier initializes to something like -1, and then modifying the read functions to just ignore the modifier when the field value is -1, should do the trick. I think :slight_smile:

But yeah, rebinding composites is… messy business.