- Created a new markdown file detailing the configuration of InputDeviceIconSetSO. - Included sections on system architecture, field explanations, image specifications, and complete workflow from setup to runtime. - Documented the automatic device recognition logic and provided troubleshooting for common issues. - Added references to relevant files and scripts for easier navigation.
110 lines
5.0 KiB
C#
110 lines
5.0 KiB
C#
using UnityEngine;
|
||
using UnityEngine.InputSystem;
|
||
using UnityEngine.InputSystem.LowLevel;
|
||
|
||
namespace BaseGames.UI
|
||
{
|
||
/// <summary>
|
||
/// 设备检测器 —— 监听 InputSystem 的事件流,识别玩家最后使用的输入设备类型,
|
||
/// 并通过 InputDeviceTypeEventChannelSO 广播给全局。
|
||
///
|
||
/// 布置方式:挂在 UIRoot 或常驻 GameObject 上;只需存在一个实例。
|
||
/// </summary>
|
||
public sealed class InputDeviceDetector : MonoBehaviour
|
||
{
|
||
[Header("Event Channel")]
|
||
[Tooltip("广播当前设备类型变化")]
|
||
[SerializeField] private InputDeviceTypeEventChannelSO _onDeviceChanged;
|
||
|
||
/// <summary>当前活跃输入设备类型,供轮询使用。</summary>
|
||
public InputDeviceType CurrentDevice { get; private set; } = InputDeviceType.KeyboardMouse;
|
||
|
||
private void OnEnable()
|
||
{
|
||
// 监听所有输入事件:每次有任何 StateEvent/DeltaStateEvent 时触发
|
||
InputSystem.onEvent += OnInputSystemEvent;
|
||
// 监听设备连接/断开(热插拔)
|
||
InputSystem.onDeviceChange += OnDeviceChange;
|
||
}
|
||
|
||
private void OnDisable()
|
||
{
|
||
InputSystem.onEvent -= OnInputSystemEvent;
|
||
InputSystem.onDeviceChange -= OnDeviceChange;
|
||
}
|
||
|
||
// ── Event Handlers ────────────────────────────────────────────────────
|
||
|
||
private void OnInputSystemEvent(InputEventPtr eventPtr, InputDevice device)
|
||
{
|
||
// 只关心真实输入事件,滤掉内部状态事件
|
||
if (!eventPtr.IsA<StateEvent>() && !eventPtr.IsA<DeltaStateEvent>()) return;
|
||
|
||
var detected = ClassifyDevice(device);
|
||
if (detected == CurrentDevice) return;
|
||
|
||
CurrentDevice = detected;
|
||
_onDeviceChanged?.Raise(CurrentDevice);
|
||
}
|
||
|
||
private void OnDeviceChange(InputDevice device, InputDeviceChange change)
|
||
{
|
||
// 当设备重新连接时重新检测(防止手柄拔插后图标仍显示手柄图标)
|
||
if (change == InputDeviceChange.Reconnected || change == InputDeviceChange.Added)
|
||
{
|
||
// 保持当前 CurrentDevice 不变,等到实际输入事件再切换
|
||
}
|
||
}
|
||
|
||
// ── Device Classification ─────────────────────────────────────────────
|
||
|
||
/// <summary>
|
||
/// 根据 InputDevice 的布局层次识别设备类型。
|
||
/// Unity InputSystem 的设备层次:
|
||
/// DualShockGamepad → Gamepad → HID
|
||
/// XInputController → Gamepad → HID
|
||
/// SwitchProControllerHID → Gamepad → HID
|
||
/// Keyboard / Mouse
|
||
/// </summary>
|
||
private static InputDeviceType ClassifyDevice(InputDevice device)
|
||
{
|
||
if (device is Keyboard or Mouse)
|
||
return InputDeviceType.KeyboardMouse;
|
||
|
||
if (device is Gamepad gamepad)
|
||
{
|
||
var desc = gamepad.description;
|
||
string manufacturer = desc.manufacturer ?? string.Empty;
|
||
string product = desc.product ?? string.Empty;
|
||
string interfaceName = desc.interfaceName ?? string.Empty;
|
||
|
||
// PlayStation: DualShock 3/4 or DualSense (PS5)
|
||
if (InputSystem.IsFirstLayoutBasedOnSecond(gamepad.layout, "DualShockGamepad")
|
||
|| product.Contains("DualShock", System.StringComparison.OrdinalIgnoreCase)
|
||
|| product.Contains("DualSense", System.StringComparison.OrdinalIgnoreCase)
|
||
|| manufacturer.Contains("Sony", System.StringComparison.OrdinalIgnoreCase))
|
||
return InputDeviceType.PlayStationController;
|
||
|
||
// Nintendo Switch Pro Controller / Joy-Con
|
||
if (InputSystem.IsFirstLayoutBasedOnSecond(gamepad.layout, "SwitchProControllerHID")
|
||
|| product.Contains("Switch", System.StringComparison.OrdinalIgnoreCase)
|
||
|| product.Contains("Joy-Con", System.StringComparison.OrdinalIgnoreCase)
|
||
|| manufacturer.Contains("Nintendo", System.StringComparison.OrdinalIgnoreCase))
|
||
return InputDeviceType.SwitchController;
|
||
|
||
// Xbox / XInput (DirectInput 会走 HID 路径,XInput 走 XInputController)
|
||
if (InputSystem.IsFirstLayoutBasedOnSecond(gamepad.layout, "XInputController")
|
||
|| product.Contains("Xbox", System.StringComparison.OrdinalIgnoreCase)
|
||
|| interfaceName.Equals("XInput", System.StringComparison.OrdinalIgnoreCase))
|
||
return InputDeviceType.XboxController;
|
||
|
||
// 未知手柄 → 默认 Xbox 图标集
|
||
return InputDeviceType.XboxController;
|
||
}
|
||
|
||
// 无法识别 → 键鼠
|
||
return InputDeviceType.KeyboardMouse;
|
||
}
|
||
}
|
||
}
|