using System; using System.Collections.Generic; using UnityEngine.InputSystem; using UnityEngine.InputSystem.Controls; using UnityEngine.XR.Interaction.Toolkit.Utilities.Pooling; namespace UnityEngine.XR.Interaction.Toolkit.UI { /// /// Matches the UI Model to the state of the Interactor. /// public interface IUIInteractor { /// /// Updates the current UI Model to match the state of the Interactor. /// /// The returned model that will match this Interactor. void UpdateUIModel(ref TrackedDeviceModel model); /// /// Attempts to retrieve the current UI Model. /// /// The returned model that reflects the UI state of this Interactor. /// Returns if the model was retrieved. Otherwise, returns . bool TryGetUIModel(out TrackedDeviceModel model); } /// /// Matches the UI Model to the state of the Interactor with support for hover events. /// public interface IUIHoverInteractor : IUIInteractor { /// /// The event that is called when the Interactor begins hovering over a UI element. /// /// /// The passed to each listener is only valid while the event is invoked, /// do not hold a reference to it. /// UIHoverEnterEvent uiHoverEntered { get; } /// /// The event that is called when this Interactor ends hovering over a UI element. /// /// /// The passed to each listener is only valid while the event is invoked, /// do not hold a reference to it. /// UIHoverExitEvent uiHoverExited { get; } /// /// The calls this method when the Interactor begins hovering over a UI element. /// /// Event data containing the UI element that is being hovered over. /// /// is only valid during this method call, do not hold a reference to it. /// /// void OnUIHoverEntered(UIHoverEventArgs args); /// /// The calls this method when the Interactor ends hovering over a UI element. /// /// Event data containing the UI element that is no longer hovered over. /// /// is only valid during this method call, do not hold a reference to it. /// /// void OnUIHoverExited(UIHoverEventArgs args); } /// /// Custom class for input modules that send UI input in XR. /// [AddComponentMenu("Event/XR UI Input Module", 11)] [HelpURL(XRHelpURLConstants.k_XRUIInputModule)] public partial class XRUIInputModule : UIInputModule { struct RegisteredInteractor { public IUIInteractor interactor; public TrackedDeviceModel model; internal bool deactivating; internal bool active; public RegisteredInteractor(IUIInteractor interactor, int deviceIndex) { this.interactor = interactor; model = new TrackedDeviceModel(deviceIndex) { interactor = interactor, }; active = true; deactivating = false; } } struct RegisteredTouch { public bool isValid; public int touchId; public TouchModel model; public RegisteredTouch(Touch touch, int deviceIndex) { touchId = touch.fingerId; model = new TouchModel(deviceIndex); isValid = true; } } /// /// Represents which Active Input Mode will be used in the situation where the Active Input Handling project setting is set to Both. /// /// public enum ActiveInputMode { /// /// Only use input polled through the built-in Unity Input Manager (Old). /// InputManagerBindings, /// /// Only use input polled from through the newer Input System package. /// InputSystemActions, /// /// Scan through input from both Unity Input Manager and Input System action references. /// Note: This may cause undesired effects or may impact performance if input configuration is duplicated. /// Both, } [HideInInspector] [SerializeField] ActiveInputMode m_ActiveInputMode; /// /// Configures which Active Input Mode will be used in the situation where the Active Input Handling project setting is set to Both. /// /// [Obsolete("activeInputMode has been deprecated in version 3.1.0. Input System Package (New) will be the default input handling mode used when active input handling is set to Both.")] public ActiveInputMode activeInputMode { get => m_ActiveInputMode; set => m_ActiveInputMode = value; } [Header("Input Devices")] [SerializeField] [Tooltip("If true, will forward 3D tracked device data to UI elements.")] bool m_EnableXRInput = true; /// /// If , will forward 3D tracked device data to UI elements. /// public bool enableXRInput { get => m_EnableXRInput; set => m_EnableXRInput = value; } [SerializeField] [Tooltip("If true, will forward 2D mouse data to UI elements. Ignored when any Input System UI Actions are used.")] bool m_EnableMouseInput = true; /// /// If , will forward 2D mouse data to UI elements. Ignored when any Input System UI Actions are used. /// public bool enableMouseInput { get => m_EnableMouseInput; set => m_EnableMouseInput = value; } [SerializeField] [Tooltip("If true, will forward 2D touch data to UI elements. Ignored when any Input System UI Actions are used.")] bool m_EnableTouchInput = true; /// /// If , will forward 2D touch data to UI elements. Ignored when any Input System UI Actions are used. /// public bool enableTouchInput { get => m_EnableTouchInput; set => m_EnableTouchInput = value; } [SerializeField] [Tooltip("If true, will forward gamepad data to UI elements. Ignored when any Input System UI Actions are used.")] bool m_EnableGamepadInput = true; /// /// If , will forward gamepad data to UI elements. Ignored when any Input System UI Actions are used. /// public bool enableGamepadInput { get => m_EnableGamepadInput; set => m_EnableGamepadInput = value; } [SerializeField] [Tooltip("If true, will forward joystick data to UI elements. Ignored when any Input System UI Actions are used.")] bool m_EnableJoystickInput = true; /// /// If , will forward joystick data to UI elements. Ignored when any Input System UI Actions are used. /// public bool enableJoystickInput { get => m_EnableJoystickInput; set => m_EnableJoystickInput = value; } #if ENABLE_INPUT_SYSTEM [Header("Input System UI Actions")] #else [HideInInspector] #endif [SerializeField] [Tooltip("Pointer input action reference, such as a mouse or single-finger touch device.")] InputActionReference m_PointAction; /// /// The Input System action to use to move the pointer on the currently active UI. Must be a Control. /// public InputActionReference pointAction { get => m_PointAction; set => SetInputAction(ref m_PointAction, value); } #if !ENABLE_INPUT_SYSTEM [HideInInspector] #endif [SerializeField] [Tooltip("Left-click input action reference, typically the left button on a mouse.")] InputActionReference m_LeftClickAction; /// /// The Input System action to use to determine whether the left button of a pointer is pressed. Must be a Control. /// public InputActionReference leftClickAction { get => m_LeftClickAction; set => SetInputAction(ref m_LeftClickAction, value); } #if !ENABLE_INPUT_SYSTEM [HideInInspector] #endif [SerializeField] [Tooltip("Middle-click input action reference, typically the middle button on a mouse.")] InputActionReference m_MiddleClickAction; /// /// The Input System action to use to determine whether the middle button of a pointer is pressed. Must be a Control. /// public InputActionReference middleClickAction { get => m_MiddleClickAction; set => SetInputAction(ref m_MiddleClickAction, value); } #if !ENABLE_INPUT_SYSTEM [HideInInspector] #endif [SerializeField] [Tooltip("Right-click input action reference, typically the right button on a mouse.")] InputActionReference m_RightClickAction; /// /// The Input System action to use to determine whether the right button of a pointer is pressed. Must be a Control. /// public InputActionReference rightClickAction { get => m_RightClickAction; set => SetInputAction(ref m_RightClickAction, value); } #if !ENABLE_INPUT_SYSTEM [HideInInspector] #endif [SerializeField] [Tooltip("Scroll wheel input action reference, typically the scroll wheel on a mouse.")] InputActionReference m_ScrollWheelAction; /// /// The Input System action to use to move the pointer on the currently active UI. Must be a Control. /// public InputActionReference scrollWheelAction { get => m_ScrollWheelAction; set => SetInputAction(ref m_ScrollWheelAction, value); } #if !ENABLE_INPUT_SYSTEM [HideInInspector] #endif [SerializeField] [Tooltip("Navigation input action reference will change which UI element is currently selected to the one up, down, left of or right of the currently selected one.")] InputActionReference m_NavigateAction; /// /// The Input System action to use to navigate the currently active UI. Must be a Control. /// public InputActionReference navigateAction { get => m_NavigateAction; set => SetInputAction(ref m_NavigateAction, value); } #if !ENABLE_INPUT_SYSTEM [HideInInspector] #endif [SerializeField] [Tooltip("Submit input action reference will trigger a submission of the currently selected UI in the Event System.")] InputActionReference m_SubmitAction; /// /// The Input System action to use for submitting or activating a UI element. Must be a Control. /// public InputActionReference submitAction { get => m_SubmitAction; set => SetInputAction(ref m_SubmitAction, value); } #if !ENABLE_INPUT_SYSTEM [HideInInspector] #endif [SerializeField] [Tooltip("Cancel input action reference will trigger canceling out of the currently selected UI in the Event System.")] InputActionReference m_CancelAction; /// /// The Input System action to use for cancelling or backing out of a UI element. Must be a Control. /// public InputActionReference cancelAction { get => m_CancelAction; set => SetInputAction(ref m_CancelAction, value); } #if !ENABLE_INPUT_SYSTEM [HideInInspector] #endif [SerializeField] [Tooltip("When enabled, built-in Input System actions will be used if no Input System UI Actions are assigned.")] bool m_EnableBuiltinActionsAsFallback = true; /// /// When enabled, built-in Input System actions will be used if no Input System UI Actions are assigned. This uses the /// currently enabled Input System devices: , , , and . /// public bool enableBuiltinActionsAsFallback { get => m_EnableBuiltinActionsAsFallback; set { m_EnableBuiltinActionsAsFallback = value; m_UseBuiltInInputSystemActions = m_EnableBuiltinActionsAsFallback && !InputActionReferencesAreSet(); } } #if !ENABLE_LEGACY_INPUT_MANAGER || ENABLE_INPUT_SYSTEM [HideInInspector] #else [Header("Input Manager (Old) Gamepad/Joystick Bindings")] #endif [SerializeField] [Tooltip("Name of the horizontal axis for gamepad/joystick UI navigation when using the old Input Manager.")] string m_HorizontalAxis = "Horizontal"; /// /// Name of the horizontal axis for UI navigation when using the old Input Manager. /// public string horizontalAxis { get => m_HorizontalAxis; set => m_HorizontalAxis = value; } #if !ENABLE_LEGACY_INPUT_MANAGER || ENABLE_INPUT_SYSTEM [HideInInspector] #endif [SerializeField] [Tooltip("Name of the vertical axis for gamepad/joystick UI navigation when using the old Input Manager.")] string m_VerticalAxis = "Vertical"; /// /// Name of the vertical axis for UI navigation when using the old Input Manager. /// public string verticalAxis { get => m_VerticalAxis; set => m_VerticalAxis = value; } #if !ENABLE_LEGACY_INPUT_MANAGER || ENABLE_INPUT_SYSTEM [HideInInspector] #endif [SerializeField] [Tooltip("Name of the gamepad/joystick button to use for UI selection or submission when using the old Input Manager.")] string m_SubmitButton = "Submit"; /// /// Name of the gamepad/joystick button to use for UI selection or submission when using the old Input Manager. /// public string submitButton { get => m_SubmitButton; set => m_SubmitButton = value; } #if !ENABLE_LEGACY_INPUT_MANAGER || ENABLE_INPUT_SYSTEM [HideInInspector] #endif [SerializeField] [Tooltip("Name of the gamepad/joystick button to use for UI cancel or back commands when using the old Input Manager.")] string m_CancelButton = "Cancel"; /// /// Name of the gamepad/joystick button to use for UI cancel or back commands when using the old Input Manager. /// public string cancelButton { get => m_CancelButton; set => m_CancelButton = value; } // Initialize to 1 so mouse always uses pointer ID of 0 int m_RollingPointerId = 1; Stack m_DeletedPointerIds = new Stack(); bool m_UseBuiltInInputSystemActions; PointerModel m_PointerState; NavigationModel m_NavigationState; internal const float kPixelPerLine = 20f; readonly List m_RegisteredTouches = new List(); readonly List m_RegisteredInteractors = new List(); // Reusable event args readonly LinkedPool m_UIHoverEventArgs = new LinkedPool(() => new UIHoverEventArgs(), collectionCheck: false); /// /// See MonoBehavior.OnEnable. /// protected override void OnEnable() { base.OnEnable(); // Check active input mode is correct #if ENABLE_LEGACY_INPUT_MANAGER && !ENABLE_INPUT_SYSTEM m_ActiveInputMode = ActiveInputMode.InputManagerBindings; #else m_ActiveInputMode = ActiveInputMode.InputSystemActions; #endif m_PointerState = new PointerModel(0); m_NavigationState = new NavigationModel(); m_UseBuiltInInputSystemActions = m_EnableBuiltinActionsAsFallback && !InputActionReferencesAreSet(); if (m_ActiveInputMode != ActiveInputMode.InputManagerBindings) EnableAllActions(); } /// /// See MonoBehavior.OnDisable. /// protected override void OnDisable() { RemovePointerEventData(m_PointerState.pointerId); if (m_ActiveInputMode != ActiveInputMode.InputManagerBindings) DisableAllActions(); base.OnDisable(); } /// /// Register an with the UI system. /// Calling this will enable it to start interacting with UI. /// /// The to use. public void RegisterInteractor(IUIInteractor interactor) { if (interactor == null) return; for (var i = 0; i < m_RegisteredInteractors.Count; i++) { var registeredInteractor = m_RegisteredInteractors[i]; if (registeredInteractor.interactor == interactor) { // If it was previously disabled by deactivation, reactivate if (!registeredInteractor.active) { registeredInteractor.active = true; registeredInteractor.deactivating = false; registeredInteractor.model.Reset(true); m_RegisteredInteractors[i] = registeredInteractor; } return; } } if (!m_DeletedPointerIds.TryPop(out var newId)) newId = m_RollingPointerId++; m_RegisteredInteractors.Add(new RegisteredInteractor(interactor, newId)); } /// /// Unregisters an with the UI system. /// This cancels all UI Interaction and makes the no longer able to affect UI. /// /// The to stop using. public void UnregisterInteractor(IUIInteractor interactor) { if (interactor == null) return; for (var i = 0; i < m_RegisteredInteractors.Count; i++) { var registeredInteractor = m_RegisteredInteractors[i]; if (registeredInteractor.interactor == interactor) { if (registeredInteractor.active) { registeredInteractor.deactivating = true; registeredInteractor.active = false; m_RegisteredInteractors[i] = registeredInteractor; } return; } } } /// /// Gets an from its corresponding Unity UI Pointer Id. /// This can be used to identify individual Interactors from the underlying UI Events. /// /// A unique integer representing an object that can point at UI. /// Returns the interactor associated with . /// Returns if no Interactor is associated (e.g. if it's a mouse event). public IUIInteractor GetInteractor(int pointerId) { for (var i = 0; i < m_RegisteredInteractors.Count; i++) { if (m_RegisteredInteractors[i].model.pointerId == pointerId && m_RegisteredInteractors[i].active) { return m_RegisteredInteractors[i].interactor; } } return null; } /// Retrieves the UI Model for a selected . /// The you want the model for. /// The returned model that reflects the UI state of the . /// Returns if the model was retrieved. Otherwise, returns . public bool GetTrackedDeviceModel(IUIInteractor interactor, out TrackedDeviceModel model) { for (var i = 0; i < m_RegisteredInteractors.Count; i++) { if (m_RegisteredInteractors[i].interactor == interactor) { model = m_RegisteredInteractors[i].model; return true; } } model = new TrackedDeviceModel(-1); return false; } /// protected override void DoProcess() { if (m_EnableXRInput) { for (var i = 0; i < m_RegisteredInteractors.Count; i++) { var registeredInteractor = m_RegisteredInteractors[i]; var oldTarget = registeredInteractor.model.implementationData.pointerTarget; // If device is removed, we send a default state to unclick any UI var isDestroyedUnityObject = registeredInteractor.interactor is Object unityObject && unityObject == null; if (isDestroyedUnityObject || registeredInteractor.deactivating) { registeredInteractor.model.Reset(false); ProcessTrackedDevice(ref registeredInteractor.model, true); RemovePointerEventData(registeredInteractor.model.pointerId); if (isDestroyedUnityObject) { m_DeletedPointerIds.Push(registeredInteractor.model.pointerId); m_RegisteredInteractors.RemoveAt(i--); continue; } else { registeredInteractor.deactivating = false; registeredInteractor.model.Reset(true); m_RegisteredInteractors[i] = registeredInteractor; } } else if (!registeredInteractor.active) { continue; } else { registeredInteractor.interactor.UpdateUIModel(ref registeredInteractor.model); ProcessTrackedDevice(ref registeredInteractor.model); // Some poke logic happens during the Raycast call in ProcessTrackedDevice // and requires an additional update to the select field of the UI Model registeredInteractor.model.UpdatePokeSelectState(); m_RegisteredInteractors[i] = registeredInteractor; } // If hover target changed, send event var newTarget = registeredInteractor.model.implementationData.pointerTarget; if (oldTarget != newTarget) { using (m_UIHoverEventArgs.Get(out var args)) { args.interactorObject = registeredInteractor.interactor; args.deviceModel = registeredInteractor.model; if (args.interactorObject != null && args.interactorObject is IUIHoverInteractor hoverInteractor) { if (oldTarget != null) { args.uiObject = oldTarget; hoverInteractor.OnUIHoverExited(args); } if (newTarget != null && newTarget.activeInHierarchy) { args.uiObject = newTarget; hoverInteractor.OnUIHoverEntered(args); } } } } // In the case where the target is disabled while being hovered, this // will fire the appropriate event to any listeners as well as reset the // current model to prevent stale data from causing unwanted behavior if ((oldTarget != null && !oldTarget.activeInHierarchy) || (oldTarget is not null && oldTarget == null)) { using (m_UIHoverEventArgs.Get(out var args)) { if (oldTarget == newTarget) { registeredInteractor.model.Reset(true); m_RegisteredInteractors[i] = registeredInteractor; } var interactor = registeredInteractor.interactor; if (interactor != null && interactor is IUIHoverInteractor hoverInteractor) { args.interactorObject = interactor; args.uiObject = oldTarget; args.deviceModel = registeredInteractor.model; hoverInteractor.OnUIHoverExited(args); } } } } } #if ENABLE_LEGACY_INPUT_MANAGER && !ENABLE_INPUT_SYSTEM // Touch needs to take precedence because of the mouse emulation layer if (m_ActiveInputMode != ActiveInputMode.InputSystemActions) { var hasTouches = false; if (m_EnableTouchInput) hasTouches = ProcessLegacyTouches(); if (m_EnableMouseInput && !hasTouches) GetLegacyMouseState(); GetLegacyNavigationState(); } #endif if (m_ActiveInputMode != ActiveInputMode.InputManagerBindings) GetPointerStates(); ProcessPointerState(ref m_PointerState); ProcessNavigationState(ref m_NavigationState); } void GetPointerStates() { if (m_UseBuiltInInputSystemActions) { if (m_EnableTouchInput && Touchscreen.current != null) { m_PointerState.position = Touchscreen.current.position.ReadValue(); #if UNITY_2022_3_OR_NEWER m_PointerState.displayIndex = Touchscreen.current.displayIndex.ReadValue(); #endif } if (m_EnableMouseInput && Mouse.current != null) { m_PointerState.position = Mouse.current.position.ReadValue(); #if UNITY_2022_3_OR_NEWER m_PointerState.displayIndex = Mouse.current.displayIndex.ReadValue(); #endif m_PointerState.scrollDelta = Mouse.current.scroll.ReadValue() * (1 / kPixelPerLine); m_PointerState.leftButtonPressed = Mouse.current.leftButton.isPressed; m_PointerState.rightButtonPressed = Mouse.current.rightButton.isPressed; m_PointerState.middleButtonPressed = Mouse.current.middleButton.isPressed; } if (m_EnableGamepadInput && Gamepad.current != null) { // Combine left stick and dpad for navigation movement m_NavigationState.move = Gamepad.current.leftStick.ReadValue() + Gamepad.current.dpad.ReadValue(); m_NavigationState.submitButtonDown = Gamepad.current.buttonSouth.isPressed; m_NavigationState.cancelButtonDown = Gamepad.current.buttonEast.isPressed; } if (m_EnableJoystickInput && Joystick.current != null) { // Combine main joystick and hatswitch for navigation movement m_NavigationState.move = Joystick.current.stick.ReadValue() + (Joystick.current.hatswitch != null ? Joystick.current.hatswitch.ReadValue() : Vector2.zero); m_NavigationState.submitButtonDown = Joystick.current.trigger.isPressed; // This will always be false until we can rely on a secondary button from the joystick m_NavigationState.cancelButtonDown = false; } } else { if (IsActionEnabled(m_PointAction)) { m_PointerState.position = m_PointAction.action.ReadValue(); #if UNITY_2022_3_OR_NEWER m_PointerState.displayIndex = GetDisplayIndexFor(m_PointAction.action.activeControl); #endif } if (IsActionEnabled(m_ScrollWheelAction)) m_PointerState.scrollDelta = m_ScrollWheelAction.action.ReadValue() * (1 / kPixelPerLine); if (IsActionEnabled(m_LeftClickAction)) m_PointerState.leftButtonPressed = m_LeftClickAction.action.IsPressed(); if (IsActionEnabled(m_RightClickAction)) m_PointerState.rightButtonPressed = m_RightClickAction.action.IsPressed(); if (IsActionEnabled(m_MiddleClickAction)) m_PointerState.middleButtonPressed = m_MiddleClickAction.action.IsPressed(); if (IsActionEnabled(m_NavigateAction)) m_NavigationState.move = m_NavigateAction.action.ReadValue(); if (IsActionEnabled(m_SubmitAction)) m_NavigationState.submitButtonDown = m_SubmitAction.action.WasPerformedThisFrame(); if (IsActionEnabled(m_CancelAction)) m_NavigationState.cancelButtonDown = m_CancelAction.action.WasPerformedThisFrame(); } } #if ENABLE_LEGACY_INPUT_MANAGER && !ENABLE_INPUT_SYSTEM void GetLegacyMouseState() { if (Input.mousePresent) { m_PointerState.position = Input.mousePosition; m_PointerState.scrollDelta = Input.mouseScrollDelta; m_PointerState.leftButtonPressed = Input.GetMouseButton(0); m_PointerState.rightButtonPressed = Input.GetMouseButton(1); m_PointerState.middleButtonPressed = Input.GetMouseButton(2); } } bool ProcessLegacyTouches() { var hasTouches = Input.touchCount > 0; if (!hasTouches) return false; var touchCount = Input.touchCount; for (var touchIndex = 0; touchIndex < touchCount; ++touchIndex) { var touch = Input.GetTouch(touchIndex); var registeredTouchIndex = -1; // Find if touch already exists for (var j = 0; j < m_RegisteredTouches.Count; j++) { if (touch.fingerId == m_RegisteredTouches[j].touchId) { registeredTouchIndex = j; break; } } if (registeredTouchIndex < 0) { // Not found, search empty pool for (var j = 0; j < m_RegisteredTouches.Count; j++) { if (!m_RegisteredTouches[j].isValid) { // Re-use the Id var pointerId = m_RegisteredTouches[j].model.pointerId; m_RegisteredTouches[j] = new RegisteredTouch(touch, pointerId); registeredTouchIndex = j; break; } } if (registeredTouchIndex < 0) { // No Empty slots, add one registeredTouchIndex = m_RegisteredTouches.Count; if (!m_DeletedPointerIds.TryPop(out var newId)) newId = m_RollingPointerId++; m_RegisteredTouches.Add(new RegisteredTouch(touch, newId)); } } var registeredTouch = m_RegisteredTouches[registeredTouchIndex]; registeredTouch.model.selectPhase = touch.phase; registeredTouch.model.position = touch.position; m_RegisteredTouches[registeredTouchIndex] = registeredTouch; } for (var i = 0; i < m_RegisteredTouches.Count; i++) { var registeredTouch = m_RegisteredTouches[i]; ProcessTouch(ref registeredTouch.model); if (registeredTouch.model.selectPhase == TouchPhase.Ended || registeredTouch.model.selectPhase == TouchPhase.Canceled) registeredTouch.isValid = false; m_RegisteredTouches[i] = registeredTouch; } return true; } void GetLegacyNavigationState() { if ((m_EnableGamepadInput || m_EnableJoystickInput) && Input.GetJoystickNames().Length > 0) { m_NavigationState.move = new Vector2(Input.GetAxis(m_HorizontalAxis), Input.GetAxis(m_VerticalAxis)); m_NavigationState.submitButtonDown = Input.GetButton(m_SubmitButton); m_NavigationState.cancelButtonDown = Input.GetButton(m_CancelButton); } } #endif bool InputActionReferencesAreSet() { return (m_PointAction != null || m_LeftClickAction != null || m_RightClickAction != null || m_MiddleClickAction != null || m_NavigateAction != null || m_SubmitAction != null || m_CancelAction != null || m_ScrollWheelAction != null); } void EnableAllActions() { EnableInputAction(m_PointAction); EnableInputAction(m_LeftClickAction); EnableInputAction(m_RightClickAction); EnableInputAction(m_MiddleClickAction); EnableInputAction(m_NavigateAction); EnableInputAction(m_SubmitAction); EnableInputAction(m_CancelAction); EnableInputAction(m_ScrollWheelAction); } void DisableAllActions() { DisableInputAction(m_PointAction); DisableInputAction(m_LeftClickAction); DisableInputAction(m_RightClickAction); DisableInputAction(m_MiddleClickAction); DisableInputAction(m_NavigateAction); DisableInputAction(m_SubmitAction); DisableInputAction(m_CancelAction); DisableInputAction(m_ScrollWheelAction); } static bool IsActionEnabled(InputActionReference inputAction) { return inputAction != null && inputAction.action != null && inputAction.action.enabled; } static void EnableInputAction(InputActionReference inputAction) { if (inputAction == null || inputAction.action == null) return; inputAction.action.Enable(); } static void DisableInputAction(InputActionReference inputAction) { if (inputAction == null || inputAction.action == null) return; inputAction.action.Disable(); } void SetInputAction(ref InputActionReference inputAction, InputActionReference value) { if (Application.isPlaying && inputAction != null) inputAction.action?.Disable(); inputAction = value; if (Application.isPlaying && isActiveAndEnabled && inputAction != null) inputAction.action?.Enable(); } #if UNITY_2022_3_OR_NEWER int GetDisplayIndexFor(InputControl control) { var displayIndex = 0; if (control != null && control.device is Pointer pointerCast && pointerCast != null) { displayIndex = pointerCast.displayIndex.ReadValue(); Debug.Assert(displayIndex <= byte.MaxValue, "Display index was larger than expected", this); } return displayIndex; } #endif } }