Set callbacks on actions
Setting callbacks on actions is one of the two main ways to respond to actions using the recommended workflow.
When you set up callbacks for your Action, the Action informs your code that a certain type of input has occurred, and your code can then respond accordingly.
The Input System offers the following ways to set up input callbacks:
- The PlayerInput component.
- Action callbacks.
- Action map callbacks
- The global On Action Change callback.
You can also use InputActionTrace to record all changes happening on actions, which is useful for debugging.
The Player Input component
With the Player Input component, you can set up callbacks using an interface in the inspector without requiring intermediate code. Refer to the PlayerInput component for further information.
Action callbacks
Every Action has a set of distinct phases it can go through in response to receiving input.
| Phase | Description |
|---|---|
Disabled |
The Action is disabled and can't receive input. |
Waiting |
The Action is enabled and is actively waiting for input. |
Started |
The Input System has received input that started an Interaction with the Action. |
Performed |
An Interaction with the Action has been completed. |
Canceled |
An Interaction with the Action has been canceled. |
You can read the current phase of an action using InputAction.phase.
The Started, Performed, and Canceled phases each have a callback associated with them:
jumpAction = InputSystem.actions.FindAction("Jump");
jumpAction.started += context => { /* Action was started */ };
jumpAction.performed += context => { /* Action was performed */ };
jumpAction.canceled += context => { /* Action was canceled */ };
Each callback receives an InputAction.CallbackContext structure, which holds context information that you can use to query the current state of the Action and to read out values from Controls that triggered the Action (InputAction.CallbackContext.ReadValue).
The contents of the callback context structure are only valid during the callback. In particular, it's not safe to store the received context and later access its properties from outside the callback.
When and how the callbacks are triggered depends on the interactions present on the respective bindings. If the bindings have no interactions that apply to them, the default interaction applies.
Subscribe to callbacks in a script
Subscribe to an action's callbacks in your script's OnEnable method, and unsubscribe in OnDisable, so that the action doesn't call your script while it's disabled. To unsubscribe, use a named method rather than a lambda expression. The following example responds each time the Jump action is performed:
using UnityEngine;
using UnityEngine.InputSystem;
/// <summary>
/// Example script that responds to the Jump action through callbacks.
/// </summary>
public class JumpCallbackExample : MonoBehaviour
{
InputAction m_JumpAction;
void Awake()
{
// Find the action once, and store the reference.
m_JumpAction = InputSystem.actions.FindAction("Jump");
}
void OnEnable()
{
// Subscribe when the script is enabled.
m_JumpAction.performed += OnJumpPerformed;
}
void OnDisable()
{
// Unsubscribe when the script is disabled, so the action doesn't call a disabled script.
m_JumpAction.performed -= OnJumpPerformed;
}
// The Input System calls this method each time the Jump action is performed.
void OnJumpPerformed(InputAction.CallbackContext context)
{
Debug.Log("Jump");
}
}
Respond to every change in a frame
The Input System calls an action's callbacks each time it processes an input event that changes the action. If several events arrive in the same frame, a callback such as performed can run more than once in that frame. For example, at a low frame rate, two quick button presses can perform an action twice before the next Update.
Polling doesn't show this. Methods such as WasPerformedThisFrame return true for the rest of the frame, however many times the action was performed in it. If you need to respond to each change separately, use callbacks.
Action map callbacks
Instead of listening to individual actions, you can listen to an entire action map for state changes on any action it contains.
playerActionMap = InputSystem.actions.FindActionMap("Player");
playerActionMap.actionTriggered +=
context => { /* An action in the map was started, performed, or canceled */ };
The argument received is the same InputAction.CallbackContext structure that you receive through the started, performed, and canceled callbacks.
Note
The Input System calls InputActionMap.actionTriggered for all three of the individual callbacks on Actions. That is, you get started, performed, and canceled all on a single callback.
Global input callback
Similar to InputSystem.onDeviceChange, your app can listen for any action-related change globally.
InputSystem.onActionChange +=
(obj, change) =>
{
// obj can be either an InputAction or an InputActionMap
// depending on the specific change.
switch (change)
{
case InputActionChange.ActionStarted:
case InputActionChange.ActionPerformed:
case InputActionChange.ActionCanceled:
Debug.Log($"{((InputAction)obj).name} {change}");
break;
}
};