๐Ÿ“ŠInput Prioritization

Summary

This is our approach for handling different game contexts/systems wanting to use the same input key at the same time.

Why not use Unreal's out-the-box input prioritization?

Unreal has two different approaches to input - "standard input", where we use named input actions e.g. InputAction Jump, defined in your project settings, and "enhanced input", where we add specific mapping contexts that have certain actions mapped to given keys.

Both of these have input prioritization, working out the box: standard inputs are processed in the order they are added to the stack, and mapping contexts add a "priority" field that can be used to order different mappings.

The downsides with the above approaches:

  • The two types of input aren't designed to work together - if you have an enhanced input, it won't consume a standard input, so both would play together.

  • There isn't much visibility on the ordering of different relevant contexts - there is no centralized place to see the ordering of different actions, so you need to manually find all the places we are adding inputs, and modify all of them if you want to reorder their priorities.

  • If an action is bound, it will either always consume, or never consume. There is no way to "conditionally consume", e.g. "on spacebar pressed, check for certain conditions, if they are met, perform the action and consume the input".

Our input prioritization system aims to tackle these problems.

How to use input prioritization

Initial Setup

  • Firstly, you will need to register your client to use the input prioritization system, by calling RegisterPrioritizedInputActions with your input priorities table.

    • This is done by default using DT_InputPrioritiesTable in BP_Origin_PlayerController. If your project's player controller extends this, you will have input prioritization working out the box.

    • The input priorities table is where we have the list of assorted "priority action names". For each action (Row Name), you have the ContextPriorities list: this outlines the priority order of different contests. Entries at the front of the list trump entries later in the list. You can add new actions, or add/reorganize the priorities of different contexts for a given action.

Adding Input Prioritization to an action

  • You can use your standard or enhanced inputs same as before, except for two differences:

    • The input mustn't be set to consume input by default. If it is, then it will consume regardless when it is reached in the native Unreal input flow, and so other inputs will be ignored regardless of where they sit in our priority list.

    • For the logic that you want to be gated behind input prioritization, first call JoinInputStack, providing the correct "priority action name" to the Action field, and an integer priority. Put the logic after the "Available" execution path.

      • Lower priority values will trump higher priority values (i.e. joining the input stack with priority 0 is treated as higher priority than joining the input stack with priority 4), and negative values are allowed. If multiple actions have the same priority value, they will all be run.

      • To determine the priority, use the GetInputContextPriority method, passing the same "priority action name", and a context enum, corresponding to an entry in the table. That way, the integer priority will be obtained from the context, and support reorganizing through the table.

      • Once you are done, if you want your action to consume the input for the provided "priority action name", call M2_InputPrioritizationSystem::ConsumeAction.

      • (There is also the "Consumed" execution path, which will be triggered if the input was consumed.)

(Input Prioritization in Standard UI)

For standard UI, the same input prioritization system is used under the hood, with the ShortcutPrioritizationName mapping to the "priority context name" field, and the ShortcutPrioritizationPriority being the priority, as if passed into the earlier JoinInputStack node.

One thing to note is that we are unable to use the GetInputContextPriority to use the enum context here. We have to manually input a number, e.g. Device corresponding to 1 for PrimaryAction.

For more details on this, see Keyboard Shortcuts in Standard Buttons

Last updated