#if INPUTSYSTEM_SUPPORT && UX_NAVIGATION using System; using UnityEngine.InputSystem; using UnityEngine.InputSystem.Controls; namespace UnityEngine.UI { internal sealed class UXInputModeService : MonoBehaviour { private static UXInputModeService _instance; private InputAction _pointerAction; private InputAction _gamepadAction; public static UXInputMode CurrentMode { get; private set; } = UXInputMode.Pointer; public static event Action OnModeChanged; [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterSceneLoad)] private static void Bootstrap() { EnsureInstance(); } internal static UXInputModeService EnsureInstance() { if (_instance != null) { return _instance; } var go = new GameObject("[UXInputModeService]"); go.hideFlags = HideFlags.HideAndDontSave; DontDestroyOnLoad(go); _instance = go.AddComponent(); return _instance; } private void Awake() { if (_instance != null && _instance != this) { Destroy(gameObject); return; } _instance = this; DontDestroyOnLoad(gameObject); hideFlags = HideFlags.HideAndDontSave; } private void OnEnable() { CreateActions(); } private void OnDisable() { DisposeActions(); } private void OnDestroy() { DisposeActions(); if (_instance == this) { _instance = null; } } private void CreateActions() { if (_pointerAction != null || _gamepadAction != null) { return; } _pointerAction = new InputAction("UXPointerInput", InputActionType.PassThrough); _pointerAction.AddBinding("/anyKey"); _pointerAction.AddBinding("/delta"); _pointerAction.AddBinding("/scroll"); _pointerAction.AddBinding("/leftButton"); _pointerAction.AddBinding("/rightButton"); _pointerAction.AddBinding("/middleButton"); _pointerAction.performed += OnPointerInput; _pointerAction.Enable(); _gamepadAction = new InputAction("UXGamepadInput", InputActionType.PassThrough); _gamepadAction.AddBinding("/*"); _gamepadAction.AddBinding("/*"); _gamepadAction.performed += OnGamepadInput; _gamepadAction.Enable(); } private void DisposeActions() { if (_pointerAction != null) { _pointerAction.performed -= OnPointerInput; _pointerAction.Disable(); _pointerAction.Dispose(); _pointerAction = null; } if (_gamepadAction != null) { _gamepadAction.performed -= OnGamepadInput; _gamepadAction.Disable(); _gamepadAction.Dispose(); _gamepadAction = null; } } private static void OnPointerInput(InputAction.CallbackContext context) { if (!IsInputMeaningful(context.control)) { return; } SetMode(UXInputMode.Pointer); } private static void OnGamepadInput(InputAction.CallbackContext context) { if (!IsInputMeaningful(context.control)) { return; } SetMode(UXInputMode.Gamepad); } private static bool IsInputMeaningful(InputControl control) { if (control == null || control.device == null || control.synthetic) { return false; } switch (control) { case ButtonControl button: return button.IsPressed(); case StickControl stick: return stick.ReadValue().sqrMagnitude >= 0.04f; case Vector2Control vector2: return vector2.ReadValue().sqrMagnitude >= 0.04f; case AxisControl axis: return Mathf.Abs(axis.ReadValue()) >= 0.2f; default: return !control.noisy; } } internal static void SetMode(UXInputMode mode) { EnsureInstance(); if (CurrentMode == mode) { return; } CurrentMode = mode; OnModeChanged?.Invoke(mode); } } } #endif