using UnityEngine.InputSystem.Controls; using UnityEngine.InputSystem.Layouts; using UnityEngine.InputSystem.LowLevel; using UnityEngine.InputSystem.Utilities; namespace UnityEngine.InputSystem.LowLevel { internal struct JoystickState : IInputStateTypeInfo { public static FourCC kFormat => new FourCC('J', 'O', 'Y'); [InputControl(name = "trigger", displayName = "Trigger", layout = "Button", usages = new[] { "PrimaryTrigger", "PrimaryAction", "Submit" }, bit = (int)Button.Trigger)] public int buttons; [InputControl(displayName = "Stick", layout = "Stick", usage = "Primary2DMotion", processors = "stickDeadzone")] public Vector2 stick; public enum Button { // IMPORTANT: Order has to match what is expected by DpadControl. HatSwitchUp, HatSwitchDown, HatSwitchLeft, HatSwitchRight, Trigger } public FourCC format => kFormat; } } namespace UnityEngine.InputSystem { /// /// A joystick with an arbitrary number of buttons and axes. /// /// /// Joysticks are somewhat hard to classify as there is little commonality other /// than that there is one main stick 2D control and at least one button. From the /// input system perspective, everything that is not a and /// that has at least one and one control /// is considered a candidate for being a joystick. /// /// Optionally, a joystick may also have the ability to , i.e. /// for the stick to rotate around its own axis, and at least one . /// /// Note that devices based on Joystick may have many more controls. Joystick /// itself only defines a minimum required to separate joysticks as a concept /// from other types of devices. /// [InputControlLayout(stateType = typeof(JoystickState), isGenericTypeOfDevice = true)] public class Joystick : InputDevice { /// /// The primary trigger button of the joystick. /// /// Control representing the primary trigger button. /// /// This is the type control on the joystick /// that has the usage. /// public ButtonControl trigger { get; protected set; } /// /// The 2D axis of the stick itself. /// /// Control representing the main joystick axis. /// /// This is the type control on the joystick /// that has the usage. /// public StickControl stick { get; protected set; } /// /// An optional control representing the rotation of the stick around its /// own axis (i.e. side-to-side circular motion). If not supported, will be /// null. /// /// Control representing the twist motion of the joystick. /// /// This is the type control on the joystick /// that has the usage. /// public AxisControl twist { get; protected set; } /// /// An optional control representing a four-way "hat switch" on the /// joystick. If not supported, will be null. /// /// Control representing a hatswitch on the joystick. /// /// Hat switches are usually thumb-operated four-way switches that operate /// much like the "d-pad" on a gamepad (see ). /// If present, this is the type control on the /// joystick that has the usage. /// public Vector2Control hatswitch { get; protected set; } /// /// The joystick that was added or used last. Null if there is none. /// /// Joystick that was added or used last. /// /// See for details about when a device /// is made current. /// /// public static Joystick current { get; private set; } /// /// A list of joysticks currently connected to the system. /// /// All currently connected joystick. /// /// Does not cause GC allocation. /// /// Do not hold on to the value returned by this getter but rather query it whenever /// you need it. Whenever the joystick setup changes, the value returned by this getter /// is invalidated. /// /// public new static ReadOnlyArray all => new ReadOnlyArray(s_Joysticks, 0, s_JoystickCount); /// /// Called when the joystick has been created but before it is added /// to the system. /// protected override void FinishSetup() { // Mandatory controls. trigger = GetChildControl("{PrimaryTrigger}"); stick = GetChildControl("{Primary2DMotion}"); // Optional controls. twist = TryGetChildControl("{Twist}"); hatswitch = TryGetChildControl("{Hatswitch}"); base.FinishSetup(); } /// /// Make the joystick the one. /// /// /// This is called automatically by the input system when a device /// receives input or is added to the system. See /// for details. /// public override void MakeCurrent() { base.MakeCurrent(); current = this; } /// /// Called when the joystick is added to the system. /// protected override void OnAdded() { ArrayHelpers.AppendWithCapacity(ref s_Joysticks, ref s_JoystickCount, this); } /// /// Called when the joystick is removed from the system. /// protected override void OnRemoved() { base.OnRemoved(); if (current == this) current = null; // Remove from `all`. var index = ArrayHelpers.IndexOfReference(s_Joysticks, this, s_JoystickCount); if (index != -1) ArrayHelpers.EraseAtWithCapacity(s_Joysticks, ref s_JoystickCount, index); else { Debug.Assert(false, $"Joystick {this} seems to not have been added but is being removed (joystick list: {string.Join(", ", all)})"); // Put in else to not allocate on normal path. } } private static int s_JoystickCount; private static Joystick[] s_Joysticks; } }