com.alicizax.unity.ui.exten.../Runtime/UXComponent/Navigation/UXInputModeService.cs

237 lines
7.2 KiB
C#
Raw Normal View History

#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<UXInputMode> 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<UXInputModeService>();
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);
2026-03-23 13:41:41 +08:00
_pointerAction.AddBinding("<Mouse>/delta");
_pointerAction.AddBinding("<Mouse>/scroll");
_pointerAction.AddBinding("<Mouse>/leftButton");
_pointerAction.AddBinding("<Mouse>/rightButton");
_pointerAction.AddBinding("<Mouse>/middleButton");
_pointerAction.performed += OnPointerInput;
_keyboardAction = new InputAction("UXKeyboardInput", InputActionType.PassThrough);
_keyboardAction.AddBinding("<Keyboard>/anyKey");
_keyboardAction.performed += OnKeyboardInput;
_gamepadAction = new InputAction("UXGamepadInput", InputActionType.PassThrough);
_gamepadAction.AddBinding("<Gamepad>/buttonSouth");
_gamepadAction.AddBinding("<Gamepad>/buttonNorth");
_gamepadAction.AddBinding("<Gamepad>/buttonEast");
_gamepadAction.AddBinding("<Gamepad>/buttonWest");
_gamepadAction.AddBinding("<Gamepad>/startButton");
_gamepadAction.AddBinding("<Gamepad>/selectButton");
_gamepadAction.AddBinding("<Gamepad>/leftShoulder");
_gamepadAction.AddBinding("<Gamepad>/rightShoulder");
_gamepadAction.AddBinding("<Gamepad>/dpad");
_gamepadAction.AddBinding("<Gamepad>/leftStick");
_gamepadAction.AddBinding("<Gamepad>/rightStick");
_gamepadAction.performed += OnGamepadInput;
_touchAction = new InputAction("UXTouchInput", InputActionType.PassThrough);
_touchAction.AddBinding("<Touchscreen>/primaryTouch/press");
_touchAction.AddBinding("<Touchscreen>/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