How do I…?
Get Started:
- … set up input in a blank project?
- … set up uGUI to work with the input system?
- … move my code from the old input system to the new one?
- … keep using the old input system alongside the new one?
Players:
- … have multiple players in my game?
- … detect when a player is switching from keyboard&mouse to gamepad?
- … manually determine which control scheme and devices a player is using?
Actions:
- … create a button input?
- … create a value input?
- … create a SHIFT+B input?
- … create a WASD input?
- … create a camera rotation input?
- … require a button to be pressed quickly or slowly?
- … act on an input continuously every frame?
- … change parameters on a processor or interaction at runtime?
Rebinding:
- … let the user rebind an action to a different control?
- … show in the UI what an action is currently bound to?
- … save and load rebinds?
UI:
Devices:
- … detect when a device is connected or disconnected?
- … find out which devices are available?
- … wait for the player to press a button on any device?
- … read input directly from a device?
- … create my own input device?
Gamepads:
- … let a gamepad control the mouse cursor?
- … determine whether the player is using an Xbox or PlayStation controller?
Touch:
Keyboards:
- … bind to the ‘a’ text input?
- … have two players use the same keyboard?
- … receive text input?
- … find out which text character corresponds to a key?
Sensors:
Debugging:
Testing:
- … create mock input in an automated test?
- … set an action’s value programmatically?
- … record and replay input?
Scripting:
- … set up input without using MonoBehaviours?
- … add or remove bindings programmatically?
- … create a self-contained component using input?
- … listen to all input coming in?
Get Started
… set up input in a blank project?
- Install the input system package through the Unity Package Manager as per the documentation.
This adds the
UnityEngine.InputSystem
API to your project and enables support for it in the native Unity runtime. - Add a
PlayerInput
to aGameObject
. This adds an.inputactions
asset to your project and sets up one player in the game to use those actions.
If you prefer to not rely onMonoBehaviour
s andGameObject
s here, see “How do I set up input without using MonoBehaviours”. - Read input from the actions in script.
public class CharacterController : MonoBehaviour { public InputActionReference fire; public InputActionReference move; public void Update() { if (fire.action.WasPressedThisFrame()) Fire(); var moveVector = move.action.ReadValue<Vector2>(); Move(moveVector); } //... }
… set up uGUI to work with the input system?
Go to the EventSystem
object and click the “Replace with InputSystemUIInputModule” button. Optionally, to use your own bindings instead of the default ones, drag your custom .inputactions
asset into the Actions Asset
field.
This will set up uGUI to receive events generated from input defined in an .inputactions
asset. If needed, you can customize the bindings.
… keep using the old input system alongside the new one?
After installation, set Active Input Handling
in Player Preferences
to Both
.
Players
… have multiple players in my game?
Each PlayerInput
represents one player. Having more than one GameObject
with the PlayerInput
component on it in the game creates multiple independent players. Each player gets assigned devices for exclusive use by that player.
Create a player prefab
Each player needs to be self-contained in so far as it should only respond to input from its own respective PlayerInput
.
Alternatively, you can respond to input using callbacks/events:
Join players from a lobby
A simple lobby setup can be created using PlayerInputManager
.
Alternatively, you can create a simple “press button to join” setup using InputSystem.onAnyButtonPress
.
public class PlayerLobby : MonoBehaviour
{
public GameObject playerPrefab;
private IDisposable m_ButtonPressListener;
private void OnEnable()
{
m_ButtonPressListener = InputSystem.onAnyButtonPress
.Call(button =>
{
// Grab the device from the button control.
var device = button.device;
// Check if the device is already used by another player.
if (PlayerInput.FindFirstPairedToDevice(device) != null)
{
// It is. Ignore this button press.
return;
}
// It is not, so create a new player.
var player = PlayerInput.Instantiate(playerPrefab, pairWithDevice: device);
Debug.Log($"Player {player.playerIndex+1} joined");
});
}
private void OnDisable()
{
m_ButtonPressListener?.Dispose();
}
}
Spawn players
You can manually spawn new players using PlayerInput.Instantiate
.
// Four players, each one on a gamepad.
PlayerInstantiate(playerPrefab, controlScheme: "Gamepad", Gamepad.all[0]);
PlayerInstantiate(playerPrefab, controlScheme: "Gamepad", Gamepad.all[1]);
PlayerInstantiate(playerPrefab, controlScheme: "Gamepad", Gamepad.all[2]);
PlayerInstantiate(playerPrefab, controlScheme: "Gamepad", Gamepad.all[3]);
Customize each player individually
Actions
… let the user rebind an action to a different control?
… save and load rebinds?
Call SaveBindingOverridesAsJson
to create a string containing all rebinds for the given set of actions and LoadBindingOverridesFromJson
to restore rebinds from such a string.
void SaveUserRebinds(PlayerInput player)
{
var rebinds = player.actions.SaveBindingOverridesAsJson();
PlayerPrefs.SetString("rebinds", rebinds);
}
void LoadUserRebinds(PlayerInput player)
{
var rebinds = PlayerPrefs.GetString("rebinds");
player.actions.LoadBindingOverridesFromJson(rebinds);
}
Devices
… find out which devices are available?
foreach (var device in InputSystem.devices)
{
if (device is Keyboard)
Debug.Log("Keyboard detected");
else if (device is Mouse)
Debug.Log("Mouse detected");
else if (device is Gamepad)
Debug.Log("Gamepad detected");
else if (device is Touchscreen)
Debug.Log("Touchscreen detected");
else
Debug.Log("Other kind of device: " + device);
}
… wait for the player to press a button on any device?
// Call delegate once on button press.
InputSystem.onAnyButtonPress
.CallOnce(button => Debug.Log($"Button {button} was pressed!"));
// Call delegate whenever a button is pressed.
// NOTE: This will add overhead to event processing until the listener is disposed.
var listener = InputSystem.onAnyButtonPress
.Call(button => Debug.Log($"Button {button} was pressed!"));
// To dispose of the listener.
listener.Dispose();
… read input directly from a device?
// Keyboard.
if (Keyboard.current.spaceKey.isPressed)
Debug.Log("Space key is pressed");
// Mouse.
if (Mouse.current.leftButton.isPressed)
Debug.Log("LMB is pressed");
var mousePosition = Mouse.current.position.ReadValue();
// Gamepad.
if (Gamepad.all[0].buttonSouth.isPressed)
Debug.Log("A button on first gamepad is pressed");
var leftStick = Gamepad.all[0].leftStick.ReadValue();
// Generic.
var device = InputSystem.devices[0];
var buttonSouthValue = device["buttonSouth"].ReadValueAsObject(); // Allocates.
var leftStickX = ((AxisControl)device["leftStick/x"]).ReadValue();
foreach (var control in device.allControls)
Debug.Log($"Control {control.path} = {control.ReadValueAsObject()}");
Gamepads
… let a gamepad control the mouse cursor?
… determine whether the player is using an Xbox or PlayStation controller?
// Xbox/XInput.
if (gamepad is XInputController)
Debug.Log("Using Xbox controller");
// PlayStation.
if (gamepad is DualShockGamepad)
Debug.Log("Using DualShock controller");
For PlayerInput
such as when receiving OnControlsChanged
.
void OnControlsChanged(PlayerInput player)
{
if (player.GetDevice<XInputController>() != null)
Debug.Log("Player is using an Xbox controller");
else if (player.GetDevice<DualShockGamepad>() != null)
Debug.Log("Player is using a PlayStation controller");
}
You can also utilize these classes in control schemes. For example, you can have a base “Gamepad” scheme with bindings shared between the controllers and then have additional control schemes specific to Xbox and PlayStation controllers. PlayerInput
will pick the control scheme that best matches a given controller.
Note:
Xbox and PlayStation and Switch controller support is available across platforms. However, when working on these consoles, you will, in addition to the input system package, need the console-specific input package available through the respective licensee channels.
Keyboards
… bind to the ‘a’ text input?
Use the “By Character Mapped to Key” group in the control picker instead of the “By Location of Key (Using US Layout)” group.
When manually creating actions/bindings in script:
// Bind to the key to the right of the CAPS LOCK key.
// This binding will refer to the key regardless of the language
// layout currently selected.
var action1 = new InputAction(binding: "<Keyboard>/a");
// Bind to the key that inputs the 'a' character. If no such key
// exists in the currently active language layout, the action will
// remain unbound.
var action2 = new InputAction(binding: "<Keyboard>/#(a)");
… have two players use the same keyboard?
PlayerInput
will, by default, not assign two players to the same device. However, you can manually switch players to use the same keyboard or spawn them that way from the beginning.
- Create two separate control schemes for the keyboard.
- Spawn players using the control schemes or switch existing players to them.
// Spawn two players. One using WASD and one using arrows. PlayerInput.Instantiate(playerPrefab, controlScheme: "KeyboardWASD", pairWithDevice: Keyboard.current); PlayerInput.Instantiate(playerPrefab, controlScheme: "KeyboardArrows", pairWithDevice: Keyboard.current); // Alternatively, switch existing players. PlayerInput.all[0].SwitchCurrentControlScheme("KeyboardWASD", Keyboard.current); PlayerInput.all[1].SwitchCurrentControlScheme("KeyboardArrows", Keyboard.current);
… receive text input?
Use Keyboard.onTextInput
.
Keyboard.current.onTextInput +=
character => Debug.Log($"Char {character} input received");
For IME input, use Keyboard.onIMECompositionChange
.
Sensors
… read gyroscope input?
You can read out rotation rates via Gyroscope.angularVelocity
.
// Turn on sensor.
InputSystem.EnableDevice(Gyroscope.current);
// Read out value.
var value = Gyroscope.current.angularVelocity.ReadValue();
You can read out gravity via GravitySensor.gravity
.
// Turn on sensor.
InputSystem.EnableDevice(GravitySensor.current);
// Read out value.
var value = GravitySensor.current.gravity.ReadValue();
You can read out acceleration via LinearAccelerationSensor.acceleration
.
// Turn on sensor.
InputSystem.EnableDevice(LinearAccelerationSensor.current);
// Read out value.
var value = LinearAccelerationSensor.current.acceleration.ReadValue();
You can read out attitude via AttitudeSensor.attitude
.
// Turn on sensor.
InputSystem.EnableDevice(AttitudeSensor.current);
// Read out value.
var value = AttitudeSensor.current.attitude.ReadValue();
These controls can also be bound in actions.
Debugging
… test my game on Android or iOS?
There are several ways to test your mobile game with respect to input.
Unity Remote
Device Simulator
Build and run player
Testing
… create mock input in an automated test?
- Create a test assembly and add references for
UnityEngine.InputSystem
andUnityEngine.InputSystem.TestFramework
. - Add
com.unity.inputsystem
totestables
in your project’smanifest.json
file.
// InputTestFixture isolates input for testing. No devices and no input from the host machine.
// Automatically cleans up any input-related setup put in place by a test.
class Tests : InputTestFixture
{
[Test] // Works with [Test] and [UnityTest].
public void Test()
{
// Can add devices here or in setup. Whatever we add to or register with the
// input system will be removed after the test has finished.
var mouse = InputSystem.AddDevice<Mouse>();
// Move the mouse.
Set(mouse.position, new Vector2(123, 234));
// Can also step input manually in tests. In a [UnityTest], this
// happens automatically whenever Unity advances by a frame.
InputSystem.Update();
}
}
More info in the docs.
… set an action’s value programmatically?
Actions need to be bound to controls. They do not have values by themselves.
You can create an InputDevice
automatically from an InputActionAsset
using the following function. This creates controls on the device that mirror the actions found in the asset.
// Take a set of actions and create an InputDevice for it that has a control
// for each of the actions. Also binds the actions to that those controls.
public static InputDevice SetUpMockInputForActions(InputActionAsset actions)
{
var layoutName = actions.name;
// Build a device layout that simply has one control for each action in the asset.
InputSystem.RegisterLayoutBuilder(() =>
{
var builder = new InputControlLayout.Builder()
.WithName(layoutName);
foreach (var action in actions)
{
builder.AddControl(action.name) // Must not have actions in separate maps with the same name.
.WithLayout(action.expectedControlType);
}
return builder.Build();
}, name: layoutName);
// Create the device.
var device = InputSystem.AddDevice(layoutName);
// Add a control scheme for it to the actions.
actions.AddControlScheme("MockInput")
.WithRequiredDevice($"<{layoutName}>");
// Bind the actions in the newly added control scheme.
foreach (var action in actions)
action.AddBinding($"<{layoutName}>/{action.name}", groups: "MockInput");
// Restrict the actions to bind only to our newly created
// device using the bindings we just added.
actions.bindingMask = InputBinding.MaskByGroup("MockInput");
actions.devices = new[] { device };
return device;
}
Using this function, you can, for example, do:
var mockInput = SetUpMockInputForActions(actions);
Press((ButtonControl)mockInput["fire"]);
… record and replay input?
Scripting
… set up input without using MonoBehaviours?
While it is possible to create input actions from scratch through the API, an easier way is usually to create an .inputactions
asset and turn it into code automatically by turning on Generate C# Class
in its properties.
public class InputController : MonoBehaviour
{
private MyActions m_Actions;
private void Start()
{
m_Actions = new MyActions();
}
private void OnEnable()
{
m_Actions.Player.Enable();
}
private void OnDisable()
{
m_Actions.Disable();
}
private void Update()
{
if (m_Actions.Player.Fire.WasPressedThisFrame())
Fire();
var moveValue = m_Actions.Player.Move.ReadValue<Vector2>();
Move(moveValue);
}
//...
}
To instead create input actions entirely in code:
// "Standalone" action.
var action = new InputAction(binding: "<Gamepad>/buttonSouth");
action.Enable();
// "Standalone" action map.
var map = new InputActionMap();
var action1InMap = map.AddAction("action1", binding: "<Gamepad>/buttonSouth");
var action2InMap = map.AddAction("action2", binding: "<Gamepad>/rightTrigger);
map.Enable();
// Entire action asset.
var asset = ScriptableObject.CreateInstance<InputActionAsset>();
var gameplay = asset.AddActionMap("Gameplay");
var moveAction = gameplay.AddAction("Move");
moveAction.AddCompositeBinding("2DVector")
.With("Up", "<Keyboard>/w")
.With("Left", "<Keyboard>/a")
.With("Down", "<Keyboard>/s")
.With("Right", "<Keyboard>/d");
var fireAction = gameplay.AddAction("Fire", binding: "<Mouse>/leftButton");
asset.Enable();