I’ve been using the new input system for a couple days or so, and I am just figuring out how should everything work. This time, I am facing a problem on my rebinding system. I support gamepad and keyboard, and when I use the PerformInteractiveRebinding function from the InputAction, I see that only the last WithCancelingThrough is the one that matters, as repeated calls to this will override the info (from the docs: Note that every rebind operation has only one such path. Calling this method repeatedly will overwrite the path set from prior calls). Any workaround in my case, where I want to have more than one possible cancel button (one for keyboard and the other for gamepad)?
@Szappy I ended up using a dirty little hack. Instead of using WithCancelingThrough, I intercepted certain cancel keys in the OnComplete call like this:
if (action.bindings[bindingIdx].overridePath == "<Gamepad>/select" || action.bindings[bindingIdx].overridePath == "<Keyboard>/escape")
InputActionRebindingExtensions.ApplyBindingOverride(action, bindingIdx, new InputBinding{overridePath = ""});
That way both the gamepad select as well as keyboard escape keys would immediately save the binding as empty.
I wanted to add to this that if you use .WithControlsHavingToMatchPath(“”) and have different key binding fields for keyboard and gamepad you can still use @Memoriesin8bit hack but you will have keyboard excluded for gamepad for instance. So in this case you can add .WithCancelingThrough(“/escape”) to the rebindingOperation for your gamepad.
Found a less dirty hack. Instead we can save the devicepaths and ask each device that we have for the last input time. In my case I have just a Gamepad and a Mouse + Keyboard. This will only cause issues if the player opens the rebinding for one button with a mouse and tries to cancel with controller. Because we predict, if we started the rebind operation with a controller, that we will try to cancel with the keyboard. Fine enough for me!
var excludingGamepadDevice = "<Gamepad>/select";
var excludingKeyboardDevice = "<Keyboard>/escape";
var excludingDevice = InputUtils.WasLastInputController() ? excludingGamepadDevice : excludingKeyboardDevice;
var rebind = actionToRebind.PerformInteractiveRebinding(bindingIndex)
.WithCancelingThrough(excludingDevice)
This is what the Method would look like for Checking, if the last Input device was a controller:
public static class InputUtils {
public static bool WasLastInputController() {
var lastInputTime = Keyboard.current.lastUpdateTime;
if (Mouse.current.lastUpdateTime > lastInputTime) {
lastInputTime = Mouse.current.lastUpdateTime;
}
return Gamepad.all.Count > 0 && Gamepad.all.Any(gamepad => gamepad.lastUpdateTime > lastInputTime);
}
}