Firstborn/Library/PackageCache/com.unity.inputsystem@1.4.4/Documentation~/HowDoI.md
Schaken-Mods b486678290 Library -Artifacts
Library -Artifacts
2023-03-28 12:24:16 -05:00

20 KiB

How do I…?

Devices:

Actions:

…check if the space key has been pressed this frame?

Use this code:

    Keyboard.current.space.wasPressedThisFrame

You can adapt this code to other Devices that have buttons or other types of input:

    Gamepad.current.aButton.wasPressedThisFrame

…find all connected gamepads?

Use the Gamepad class:

    var allGamepads = Gamepad.all;

    // Or more specific versions.
    var allPS4Gamepads = DualShockGamepadPS4.all;

Alternatively, you can use more generic Device queries using LINQ expressions or control paths:


    // Go through all devices and select gamepads.
    InputSystem.devices.Select(x => x is Gamepad);

    // Query everything that is using the gamepad layout or based on that layout.
    // NOTE: Don't forget to Dispose() the result.
    InputSystem.FindControls("<gamepad>");

…find the gamepad that the player is currently using?

Use this code:

    var gamepad = Gamepad.current;

    // This works for other types of devices, too.
    var keyboard = Keyboard.current;
    var mouse = Mouse.current;

…know when a new Device has been plugged in?

Use this code:

    InputSystem.onDeviceChange +=
        (device, change) =>
        {
            switch (change)
            {
                case InputDeviceChange.Added:
                    // New Device.
                    break;
                case InputDeviceChange.Disconnected:
                    // Device got unplugged.
                    break;
                case InputDeviceChange.Connected:
                    // Plugged back in.
                    break;
                case InputDeviceChange.Removed:
                    // Remove from Input System entirely; by default, Devices stay in the system once discovered.
                    break;
                default:
                    // See InputDeviceChange reference for other event types.
                    break;
            }
        }

For more details, see documentation on "Monitoring Devices".

…create a simple Fire-type Action?

Use this code:

    // Create an Action that binds to the primary action control on all devices.
    var action = new InputAction(binding: "*/{primaryAction}");

    // Have it run your code when the Action is triggered.
    action.performed += _ => Fire();

    // Start listening for control changes.
    action.Enable();

You can also have a serialized field of type InputAction in your MonoBehaviour, like this:


public class MyControllerComponent : MonoBehaviour
{
    public InputAction fireAction;
    public InputAction walkAction;
}

The Editor lets you add and edit Bindings for the Actions in the Inspector window.

Note: You still need to enable the Action in code and hook up your response. You can do so in the Awake method of your component:


    void Awake()
    {
        fireAction.performed += Fire;
        walkAction.performed += Walk;
    }

    void OnEnable()
    {
        fireAction.Enable();
        walkAction.Enable();
    }

    void OnDisable()
    {
        fireAction.Disable();
        walkAction.Disable();
    }

    void Fire(CallbackContext ctx)
    {
        //...
    }

    void Walk(CallbackContext ctx)
    {
        //...
    }

If you're worried about allocations from the delegates, you can use a polling approach rather than a callback-driven approach.


    void OnEnable()
    {
        fireAction.Enable();
        walkAction.Enable();
    }

    void OnDisable()
    {
        fireAction.Disable();
        walkAction.Disable();
    }

    void Update()
    {
        if (fireAction.triggered)
            Fire();
        if (walkAction.triggered)
            Walk();
    }

    void Fire()
    {
        //...
    }

    void Walk()
    {
        //...
    }

Typically, you need to deal with more than one Action. In this case, you might want to put these into an Input Actions Asset file. To create an Input Actions Asset, follow these steps:

  1. In the Project view, click Create.
  2. Select Input Actions.
  3. Double-click the Asset to create and edit one or multiple Input Action Maps containing Input Actions.

If you then click Generate C# Class in the Inspector for that Asset, Unity generates a wrapper class for your Actions which you can use like this:

    MyInputActionAssetClass actions;

    public void OnEnable()
    {
        actions = new MyInputActionAssetClass();
        controls.myActionsMap.fire.performed += Fire;
        controls.myActionsMap.walk.performed += Walk;
    }

For more details, see documentation on Actions.

…require a button to be held for 0.4 seconds before triggering an Action?

Put a hold Interaction on the Action, like this:


    var action = new InputAction(binding: "*/{PrimaryAction}",
        modifiers: "hold(duration=0.4)");

To display UI feedback when the button starts being held, use the started callback.


    action.started += _ => ShowGunChargeUI();
    action.performed += _ => FinishGunChargingAndHideChargeUI();
    action.cancelled += _ => HideChargeUI();

…use a "positive" and a "negative" button to drive an axis?

Use an axis composite binding in the UI or in code, and bind its parts to the respective buttons.

var accelerateAction = new InputAction("Accelerate");
accelerateAction.AddCompositeBinding("Axis")
    .With("Positive", "<Gamepad>/rightTrigger")
    .With("Negative", "<Gamepad>/leftTrigger");

…create a UI to rebind input in my game?

Create a UI with a button to trigger rebinding. If the user clicks the button to bind a control to an action, use InputAction.PerformInteractiveRebinding to handle the rebinding:

    void RemapButtonClicked(InputAction actionToRebind)
    {
        var rebindOperation = actionToRebind.PerformInteractiveRebinding()
                    // To avoid accidental input from mouse motion
                    .WithControlsExcluding("Mouse")
                    .OnMatchWaitForAnother(0.1f)
                    .Start();
    }

You can install the Tanks Demo sample for the Input System package using the Package Manager, which has an example of an interactive rebinding UI.

…set up an Action to specifically target the left-hand XR controller?

Use this code:

    var action = new InputAction(binding: "/<XRController>{leftHand}/position");

You can also set this up for any Input Bindings in the Inspector or the Input Action Asset editor window without having to deal with paths directly.

…wait for any button to be pressed on any device?

Use this code:

    var myAction = new InputAction(binding: "/*/<button>");
    myAction.onPerformed += (action, control) => Debug.Log($"Button {control.name} pressed!");
    myAction.Enable();

Note: This is inefficient and resource-intensive. The amount of processing an Action has to do is directly correlated with the amount of Controls it targets. Targeting every single button of every single Device yields a large number of Controls and results in a high processing overhead. For example, the keyboard alone contributes many buttons, each of which has to be processed individually.

…make my left-hand XR controller my right-hand one?

Use this code:

    var controller = XRController.leftHand;
    InputSystem.SetUsage(controller, CommonUsages.RightHand);

…get all current touches from the touchscreen?

The recommended way is to use EnhancedTouch.Touch.activeTouches:

    using Touch = UnityEngine.InputSystem.EnhancedTouch.Touch;

    public void Update()
    {
        foreach (var touch in Touch.activeTouches)
            Debug.Log($"{touch.touchId}: {touch.screenPosition},{touch.phase}");
    }

Note: You must first enable enhanced touch support by calling InputSystem.EnhancedTouch.Enable().

You can also use the lower-level Touchscreen.current.touches API.

…create a Device?

Use this code:

    InputSystem.AddDevice<Gamepad>();

An alternative way is to inform the Input System that a Device is available, and let the system create the Device from a matching layout. If no layout exists, the Input System doesn't create the Device until you add one.

    InputSystem.ReportAvailableDevice(
        new InputDeviceDescription
        {
            product = "AwesomeGadget",
            manufacturer = "Awesome Products Inc."
        }
    );

…create my own custom Devices?

There are two possible ways to do this.

If you want to use one of the existing C# InputDevice classes in code to interface with your Device, you can build on an existing layout using JSON:

    {
        "name" : "MyDevice",
        "extend" : "Gamepad", // Or some other thing
        "controls" : [
            {
                "name" : "firstButton",
                "layout" : "Button",
                "offset" : 0,
                "bit": 0,
                "format" : "BIT",
            },
            {
                "name" : "secondButton",
                "layout" : "Button",
                "offset" : 0,
                "bit": 1,
                "format" : "BIT",
            },
            {
                "name" : "axis",
                "layout" : "Axis",
                "offset" : 4,
                "format" : "FLT",
                "parameters" : "clamp=true,clampMin=0,clampMax=1"
            }
        ]
    }

You then register your layout with the system and then instantiate it:

    InputSystem.RegisterControlLayout(myDeviceJson);
    var device = InputSystem.AddDevice("MyDevice");

Alternatively, you can create your own InputDevice class and state layouts in C#.

    public struct MyDeviceState : IInputStateTypeInfo
    {
        // FourCC type codes are used to identify the memory layouts of state blocks.
        public FourCC format => new FourCC('M', 'D', 'E', 'V');

        [InputControl(name = "firstButton", layout = "Button", bit = 0)]
        [InputControl(name = "secondButton", layout = "Button", bit = 1)]
        public int buttons;
        [InputControl(layout = "Analog", parameters="clamp=true,clampMin=0,clampMax=1")]
        public float axis;
    }

    [InputState(typeof(MyDeviceState)]
    public class MyDevice : InputDevice
    {
        public ButtonControl firstButton { get; private set; }
        public ButtonControl secondButton { get; private set; }
        public AxisControl axis { get; private set; }

        protected override void FinishSetup(InputControlSetup setup)
        {
             firstButton = setup.GetControl<ButtonControl>(this, "firstButton");
             secondButton = setup.GetControl<ButtonControl>(this, "secondButton");
             axis = setup.GetControl<AxisControl>(this, "axis");
             base.FinishSetup(setup);
        }
    }

To create an instance of your Device, register it as a layout and then instantiate it:

    InputSystem.RegisterControlLayout("MyDevice", typeof(MyDevice));
    InputSystem.AddDevice("MyDevice");

For more information, see documentation on HID.

…deal with my gamepad data arriving in a format different from GamepadState?

Extend the "Gamepad" layout and customize its Controls.

A real-world example of this is the Xbox Controller on macOS, which is supported through HID. Its layout looks like this:

{
    "name" : "XboxGamepadOSX",
    "extend" : "Gamepad",
    "format" : "HID",
    "device" : { "interface" : "HID", "product" : "Xbox.*Controller" },
    "controls" : [
        { "name" : "leftShoulder", "offset" : 2, "bit" : 8 },
        { "name" : "rightShoulder", "offset" : 2, "bit" : 9 },
        { "name" : "leftStickPress", "offset" : 2, "bit" : 14 },
        { "name" : "rightStickPress", "offset" : 2, "bit" : 15 },
        { "name" : "buttonSouth", "offset" : 2, "bit" : 12 },
        { "name" : "buttonEast", "offset" : 2, "bit" : 13 },
        { "name" : "buttonWest", "offset" : 2, "bit" : 14 },
        { "name" : "buttonNorth", "offset" : 2, "bit" : 15 },
        { "name" : "dpad", "offset" : 2 },
        { "name" : "dpad/up", "offset" : 0, "bit" : 8 },
        { "name" : "dpad/down", "offset" : 0, "bit" : 9 },
        { "name" : "dpad/left", "offset" : 0, "bit" : 10 },
        { "name" : "dpad/right", "offset" : 0, "bit" : 11 },
        { "name" : "start", "offset" : 2, "bit" : 4 },
        { "name" : "select", "offset" : 2, "bit" : 5 },
        { "name" : "xbox", "offset" : 2, "bit" : 2, "layout" : "Button" },
        { "name" : "leftTrigger", "offset" : 4, "format" : "BYTE" },
        { "name" : "rightTrigger", "offset" : 5, "format" : "BYTE" },
        { "name" : "leftStick", "offset" : 6, "format" : "VC2S" },
        { "name" : "leftStick/x", "offset" : 0, "format" : "SHRT", "parameters" : "normalize,normalizeMin=-0.5,normalizeMax=0.5" },
        { "name" : "leftStick/y", "offset" : 2, "format" : "SHRT", "parameters" : "invert,normalize,normalizeMin=-0.5,normalizeMax=0.5" },
        { "name" : "rightStick", "offset" : 10, "format" : "VC2S" },
        { "name" : "rightStick/x", "offset" : 0, "format" : "SHRT", "parameters" : "normalize,normalizeMin=-0.5,normalizeMax=0.5" },
        { "name" : "rightStick/y", "offset" : 2, "format" : "SHRT", "parameters" : "invert,normalize,normalizeMin=-0.5,normalizeMax=0.5" }
    ]
}

The same principle applies if some buttons on your Device are swapped, for example. In this case, you can remap their offsets.

…force the Input System to use my own layout when the native backend discovers a specific Device?

Describe the Device in the layout, like this:

     {
        "name" : "MyGamepad",
        "extend" : "Gamepad",
        "device" : {
            // All strings in here are regexs and case-insensitive.
            "product" : "MyController",
            "manufacturer" : "MyCompany"
        }
     }

Note that you don't have to restart Unity in order for changes in your layout to take effect on native Devices. The Input System applies changes automatically on every domain reload, so you can just keep refining a layout and your Device is recreated with the most up-to-date version every time scripts are recompiled.

…add deadzoning to my gamepad sticks?

Put a stick deadzone Processor on the sticks, like this:

     {
        "name" : "MyGamepad",
        "extend" : "Gamepad",
        "controls" : [
            {
                "name" : "leftStick",
                "processors" : "stickDeadzone(min=0.125,max=0.925)"
            },
            {
                "name" : "rightStick",
                "processors" : "stickDeadzone(min=0.125,max=0.925)"
            }
        ]
    }

You can do the same in your C# state structs.

    public struct MyDeviceState
    {
        [InputControl(processors = "stickDeadzone(min=0.125,max=0.925)"]
        public StickControl leftStick;
        [InputControl(processors = "stickDeadzone(min=0.125,max=0.925)"]
        public StickControl rightStick;
    }

The gamepad layout already adds stick deadzone processors which take their min and max values from InputSettings.defaultDeadzoneMin and InputSettings.defaultDeadzoneMax.

…give my head tracking an extra update before rendering?

First, enable before render updates on your Device.

    {
        "name" : "MyHMD",
        "extend" : "HMD",
        "beforeRender" : "Update"
    }

Then, make sure you put extra StateEvents for your HMD on the queue right in time before rendering. Also, if your HMD is a combination of non-tracking and tracking controls, you can update just the tracking by sending a delta event instead of a full state event.

…record events flowing through the system?

Use this code:


    var trace = new InputEventTrace(); // Can also give device ID to only
                                       // trace events for a specific device.

    trace.Enable();

    //…run stuff

    var current = new InputEventPtr();
    while (trace.GetNextEvent(ref current))
    {
        Debug.Log("Got some event: " + current);
    }

    // Also supports IEnumerable.
    foreach (var eventPtr in trace)
        Debug.Log("Got some event: " + eventPtr);

    // Trace consumes unmanaged resources. Make sure to dispose.
    trace.Dispose();

…see events as they're processed?

Use this code:


    InputSystem.onEvent +=
        (eventPtr, device) =>
        {
            // Can handle events yourself, for example, and then stop them
            // from further processing by marking them as handled.
            eventPtr.handled = true;
        };

…see what Devices I have and what state they're in?

Go to Windows > Analysis > Input Debugger(Debugging.md), then double click on a Device to see its Controls. You can also click the Remote Devices button to remotely see Devices from Unity Players deployed to any connected computers or devices.

//: # (TODO: working on having device setups from players mirrored 1:1 into the running input system in the editor (including having their input available in the editor))