user-customizable controls

Many games allow players to customize the input controls, mapping in-game actions to new keys and buttons to suit personal preference or new devices. When we launched Homeworld: Deserts of Kharak we got quite a bit of criticism for not allowing players to rebind hot keys (a pretty standard feature for RTS games). We did add the feature post-launch, but it was non-trivial to implement.

Does the new input system provide a way for end users to customize the controls? I’ve briefly reviewed the architecture documentation and I don’t see customization called out explicitly but I may have overlooked something.

If customization isn’t built into the system, how would a developer go about enabling control customization for their game?

(By the way, thanks for the in-depth preview of the new input system and opportunity to provide feedback, this is great.)

Yup, customization is the very first requirement that made it on the list of the new system given that it was the most glaring shortcoming of the current one.

The demo includes a rudimentary UI that allows you to rebind controls. You’ll also see help texts in the demo change based on the bindings you’ve customized. Persistence of the bindings is kinda implemented but not fully hooked up (and there’s a problem in there in how we deal with modified state; but that’s something specific to the prototype).

1 Like

You can already… I worked for about 3 hours to make it works, but it does…
Here is how to do it:
Make a script…
First you need the PlayerInput of course
and you need its control schemes in the action map:

PlayerInput playerInput;
List<ControlScheme> controlScheme;

after that you need the initialization put it in the Start or whatever you need:

controlScheme = playerInput.GetAction<XXX>.actionMap.controlSchemes;

Take care that you need the actionMap’s controlSchemes List because the playerInput.GetAction.controlScheme does not retrieve multiply input source like Gamepad and Keyboard…
in the actionMap.controlSchemes list you can access all of them…

Now, you need two method in your input manager that waits for a key and the other that retrieves the very first pressed key / moved axis, etc… here is mine:

static void WaitForAny (InputControlDescriptor descriptor)
    {
        if (!waitingForKey) {
            inputControlDescriptor = descriptor;
            waitingForKey = true;
            InputSystem.ListenForBinding (BindInputControl);
        }
    }

    static bool BindInputControl(InputControl control)
    {
        actionMapInput.BindControl(inputControlDescriptor, control, false);
        inputControlDescriptor = null;
        if (onGotInput != null) onGotInput(0);
        Debug.Log(control.name);
        waitingForKey = false;
        return true;
    }

However this is just my raw waiting code… I made 2 wrapper both for Button Input and Axis Input:

public static void WaitForAxis (BlackenedInputBindings axisBind, BlackenedInputSources inputSource, bool positive)
    {
        if (controlScheme != null)
            WaitForAny(positive ? controlScheme[(int)inputSource].bindings[(int)axisBind].buttonAxisSources[0].positive : controlScheme[(int)inputSource].bindings[(int)axisBind].buttonAxisSources[0].negative);
    }

    public static void WaitForKey (BlackenedInputBindings buttonBind, BlackenedInputSources inputSource)
    {
        Debug.Log(controlScheme[(int)inputSource].bindings[2].sources[0]);
        if (controlScheme != null)
            WaitForAny(controlScheme[(int)inputSource].bindings[(int)buttonBind].sources[0]);
    }

And thats all… With a simple C# event handler in your InputManager, you can easily bind a specific button to retrieve the input code you got in the BindInputControl method… Mine is for example the if (onGotInput != null) onGotInput(0);

and in my Button’s code:

public void OnClick()
    {
        if (!CustomInputManager.waitingForKey)
        {
            displayText.text = LanguageManager.GetText("Lang_WaitForKey");
            CustomInputManager.onGotInput += X;
            if (isAxis)
                CustomInputManager.WaitForAxis(bindIndex, inputSource, positive);
            else
                CustomInputManager.WaitForKey(bindIndex, inputSource);
        }
    }

And the method binded to the event, which get called when the User makes an input:

void OnAnyKeyPress(int keyCode)
    {
        CustomInputManager.onGotInput -= X;
        displayText.text = LanguageManager.GetText("Got it!!!");
    }

Note: This binds a new key to the actionMap ONLY while your game is running… However you can easily save this code, and when your game starts, re-bind the codes again…
I hope this helped :slight_smile:

2 Likes

Thanks for the all the details. I’m glad to hear customization was considered from the beginning. I will review and digest the approach and think about how we would apply it to RTS games.

Can we do this by visual scripting