com.alicizax.unity.ui.exten.../Runtime/UXComponent/Navigation/UXInputModeService.cs
陈思海 dc8923564b 优化
非适配手柄 增加可选UX_NAVIGATION 宏
优化部分结构
2026-03-26 16:12:50 +08:00

170 lines
4.8 KiB
C#

#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<UXInputMode> 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<UXInputModeService>();
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("<Keyboard>/anyKey");
_pointerAction.AddBinding("<Mouse>/delta");
_pointerAction.AddBinding("<Mouse>/scroll");
_pointerAction.AddBinding("<Mouse>/leftButton");
_pointerAction.AddBinding("<Mouse>/rightButton");
_pointerAction.AddBinding("<Mouse>/middleButton");
_pointerAction.performed += OnPointerInput;
_pointerAction.Enable();
_gamepadAction = new InputAction("UXGamepadInput", InputActionType.PassThrough);
_gamepadAction.AddBinding("<Gamepad>/*");
_gamepadAction.AddBinding("<Joystick>/*");
_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