Skip to content

Configure input bindings

This page covers two procedures. Setting bindings at construction through Configuration.Bindings, and replacing them at runtime through UI.SetBindings. Both work on the same InputBindings container and the same per-feature bindings classes.

For the model behind the bindings framework, refer to Input bindings.

To customise bindings at setup

  1. Build an InputBindings value with the fields you want to change. Leave the other fields null; defaults fill them at ingest:
    var bindings = new InputBindings
    {
        Navigation = new LegacyNavigationBindings
        {
            Up    = { KeyCode.W, KeyCode.UpArrow },
            Down  = { KeyCode.S, KeyCode.DownArrow },
            Left  = { KeyCode.A, KeyCode.LeftArrow },
            Right = { KeyCode.D, KeyCode.RightArrow },
            ConfirmKeys = { KeyCode.Return, KeyCode.Space, KeyCode.JoystickButton0 },
            CancelKeys  = { KeyCode.Escape, KeyCode.JoystickButton1 },
        },
    };
    
  2. Assign the value to Configuration.Bindings before constructing the UI.
    var config = new Configuration
    {
        AspectRatioLayouts = aspects,
        Bindings           = bindings,
    };
    m_ui = new UI(config, m_renderTexture, m_resourceProvider);
    

The constructor copies the bindings into UI.Bindings. Null fields become per-feature defaults (NavigationBindings.Default, TextboxBindings.Default, and so on). Widgets read the customised bindings from the first frame.

To replace bindings at runtime

Build a new InputBindings value the same way, then pass it to UI.SetBindings:

var textbox = LegacyTextboxBindings.Default as LegacyTextboxBindings;
textbox.SubmitBindings = new List<LegacyKeyBinding>
{
    new LegacyKeyBinding(KeyCode.KeypadEnter),
    new LegacyKeyBinding(KeyCode.Return),
};

ui.SetBindings(new InputBindings
{
    Textbox = textbox,
});

Null fields are filled with defaults again. SetBindings is safe to call between frames. Widgets pick up the new bindings on the next frame.

To bind a controller D-pad on the legacy backend

Legacy Input has no built-in D-pad button. LegacyNavigationBindings reads two Input Manager axes and computes the press events itself:

  1. Add two axes under Project Settings > Input Manager mapped to the controller D-pad. The default axis names are DPadHorizontal and DPadVertical. Set Type to Joystick Axis for each axis, and pick the correct joystick axis index for the target controller.
  2. Confirm UseDpad is true on the legacy navigation bindings. It is true by default. Set it to false to disable D-pad navigation entirely.
  3. Optionally rename the axes. Set DpadHorizontalAxis and DpadVerticalAxis on LegacyNavigationBindings to match the names used in the Input Manager.

On the Input System backend, the D-pad is read directly through Gamepad.current.dpad. No project configuration is required.

To add a shortcut with a modifier

LegacyKeyBinding and InputSystemKeyBinding both take a ModifierMask argument. The match is exact: a binding with Ctrl only fires when no other modifier is held.

var textbox = LegacyTextboxBindings.Default as LegacyTextboxBindings;
textbox.SelectAllBindings = new List<LegacyKeyBinding>
{
    new LegacyKeyBinding(KeyCode.A, ModifierMask.Ctrl),
};
textbox.CopyBindings = new List<LegacyKeyBinding>
{
    new LegacyKeyBinding(KeyCode.C, ModifierMask.Ctrl),
};

To accept multiple modifier combinations for the same action, list each binding separately:

textbox.CopyBindings = new List<LegacyKeyBinding>
{
    new LegacyKeyBinding(KeyCode.C, ModifierMask.Ctrl),
    new LegacyKeyBinding(KeyCode.C, ModifierMask.Ctrl | ModifierMask.Shift),
};

To add a gamepad button on the Input System backend

InputSystemKeyBinding accepts an InputSystemControl, which implicitly converts from Key and from GamepadButton. Pass a GamepadButton directly:

var nav = new InputSystemNavigationBindings
{
    Up    = { Key.UpArrow,    GamepadButton.DpadUp },
    Down  = { Key.DownArrow,  GamepadButton.DpadDown },
    Left  = { Key.LeftArrow,  GamepadButton.DpadLeft },
    Right = { Key.RightArrow, GamepadButton.DpadRight },
    ConfirmControls = { Key.Enter,  GamepadButton.South },
    CancelControls  = { Key.Escape, GamepadButton.East },
};

GamepadButton.LeftShoulder, GamepadButton.RightShoulder, GamepadButton.Start, and the other Input System gamepad buttons work the same way.

Pitfalls

A custom binding for one action erases all the others. : new LegacyTextboxBindings() creates an instance with empty Lists for every action. Setting only one field leaves the others empty, not defaulted. To replace a single action while keeping the rest of the defaults, start from LegacyTextboxBindings.Default, mutate the field you want to change, and assign the result:

var tb = LegacyTextboxBindings.Default as LegacyTextboxBindings;
tb.CopyBindings = new List<LegacyKeyBinding> { ... };
bindings.Textbox = tb;

A modifier shortcut fires for the wrong combination. : Modifier match is exact. Add a separate binding entry for each combination you want to accept.

A runtime SetBindings does not affect this frame. : Bindings are read by widgets when each widget runs. SetBindings mid-frame affects later widgets in the same DoUI body but not earlier ones. To swap bindings cleanly, call SetBindings between frames.

The legacy D-pad still does nothing after adding the axes. : The axis names on LegacyNavigationBindings and the names in the Input Manager must match exactly. Verify both, including capitalisation.

Additional resources