Add InputDeviceIconSetSO configuration guide and related documentation
- 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.
This commit is contained in:
109
Assets/_Game/Scripts/UI/InputDeviceDetector.cs
Normal file
109
Assets/_Game/Scripts/UI/InputDeviceDetector.cs
Normal file
@@ -0,0 +1,109 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user