#if INPUTSYSTEM_SUPPORT && UX_NAVIGATION using System; using UnityEngine.InputSystem; using UnityEngine.InputSystem.Controls; namespace UnityEngine.UI { internal sealed class UXInputModeService : MonoBehaviour { private const float StickThresholdSqr = 0.04f; private const float AxisThreshold = 0.2f; private static UXInputModeService _instance; private InputAction _pointerAction; private InputAction _keyboardAction; private InputAction _gamepadAction; private InputAction _touchAction; 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; } GameObject 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; CreateActions(); } private void OnEnable() { SetActionsEnabled(true); } private void OnDisable() { SetActionsEnabled(false); } private void OnDestroy() { DisposeActions(); if (_instance == this) { _instance = null; } } private void CreateActions() { if (_pointerAction != null) { return; } _pointerAction = new InputAction("UXPointerInput", InputActionType.PassThrough); _pointerAction.AddBinding("/delta"); _pointerAction.AddBinding("/scroll"); _pointerAction.AddBinding("/leftButton"); _pointerAction.AddBinding("/rightButton"); _pointerAction.AddBinding("/middleButton"); _pointerAction.performed += OnPointerInput; _keyboardAction = new InputAction("UXKeyboardInput", InputActionType.PassThrough); _keyboardAction.AddBinding("/anyKey"); _keyboardAction.performed += OnKeyboardInput; _gamepadAction = new InputAction("UXGamepadInput", InputActionType.PassThrough); _gamepadAction.AddBinding("/buttonSouth"); _gamepadAction.AddBinding("/buttonNorth"); _gamepadAction.AddBinding("/buttonEast"); _gamepadAction.AddBinding("/buttonWest"); _gamepadAction.AddBinding("/startButton"); _gamepadAction.AddBinding("/selectButton"); _gamepadAction.AddBinding("/leftShoulder"); _gamepadAction.AddBinding("/rightShoulder"); _gamepadAction.AddBinding("/dpad"); _gamepadAction.AddBinding("/leftStick"); _gamepadAction.AddBinding("/rightStick"); _gamepadAction.performed += OnGamepadInput; _touchAction = new InputAction("UXTouchInput", InputActionType.PassThrough); _touchAction.AddBinding("/primaryTouch/press"); _touchAction.AddBinding("/primaryTouch/delta"); _touchAction.performed += OnTouchInput; } private void SetActionsEnabled(bool enabled) { if (_pointerAction == null) { return; } if (enabled) { _pointerAction.Enable(); _keyboardAction.Enable(); _gamepadAction.Enable(); _touchAction.Enable(); return; } _pointerAction.Disable(); _keyboardAction.Disable(); _gamepadAction.Disable(); _touchAction.Disable(); } private void DisposeActions() { if (_pointerAction != null) { _pointerAction.performed -= OnPointerInput; _pointerAction.Dispose(); _pointerAction = null; } if (_keyboardAction != null) { _keyboardAction.performed -= OnKeyboardInput; _keyboardAction.Dispose(); _keyboardAction = null; } if (_gamepadAction != null) { _gamepadAction.performed -= OnGamepadInput; _gamepadAction.Dispose(); _gamepadAction = null; } if (_touchAction != null) { _touchAction.performed -= OnTouchInput; _touchAction.Dispose(); _touchAction = null; } } private static void OnPointerInput(InputAction.CallbackContext context) { if (IsInputMeaningful(context.control)) { SetMode(UXInputMode.Pointer); } } private static void OnKeyboardInput(InputAction.CallbackContext context) { if (IsInputMeaningful(context.control)) { SetMode(UXInputMode.Keyboard); } } private static void OnGamepadInput(InputAction.CallbackContext context) { if (IsInputMeaningful(context.control)) { SetMode(UXInputMode.Gamepad); } } private static void OnTouchInput(InputAction.CallbackContext context) { if (IsInputMeaningful(context.control)) { SetMode(UXInputMode.Touch); } } 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 >= StickThresholdSqr; case Vector2Control vector2: return vector2.ReadValue().sqrMagnitude >= StickThresholdSqr; case AxisControl axis: return Mathf.Abs(axis.ReadValue()) >= AxisThreshold; default: return !control.noisy; } } internal static void SetMode(UXInputMode mode) { EnsureInstance(); if (CurrentMode == mode) { return; } CurrentMode = mode; OnModeChanged?.Invoke(mode); } } } #endif