using System;
using UnityEngine;
using UnityEngine.InputSystem;
public static class GlyphService
{
// 缓存的设备提示数组,避免内存分配
private static readonly string[] KeyboardHints = { "Keyboard", "Mouse" };
private static readonly string[] XboxHints = { "XInput", "Xbox", "Gamepad" };
private static readonly string[] PlayStationHints = { "DualShock", "DualSense", "PlayStation", "Gamepad" };
private static readonly char[] TrimChars = { '{', '}', '<', '>', '\'', '"' };
///
/// 获取输入图标数据库实例
///
public static InputGlyphDatabase Database
{
get
{
if (_database == null)
{
_database = Resources.Load("InputGlyphDatabase");
}
return _database;
}
}
private static InputGlyphDatabase _database;
///
/// 获取输入操作的绑定控制路径
///
/// 输入操作
/// 复合部分名称(可选)
/// 设备类型覆盖(可选)
/// 绑定控制路径
public static string GetBindingControlPath(InputAction action, string compositePartName = null, InputDeviceWatcher.InputDeviceCategory? deviceOverride = null)
{
if (action == null) return string.Empty;
var binding = GetBindingControl(action, compositePartName, deviceOverride);
return binding.hasOverrides ? binding.effectivePath : binding.path;
}
///
/// 尝试获取输入操作的 TextMeshPro 标签
///
/// 输入操作引用
/// 复合部分名称
/// 设备类型
/// 输出的 TMP 标签
/// 显示回退文本
/// 数据库实例(可选)
/// 是否成功获取
public static bool TryGetTMPTagForActionPath(InputAction reference, string compositePartName, InputDeviceWatcher.InputDeviceCategory device, out string tag, out string displayFallback, InputGlyphDatabase db = null)
{
string path = GetBindingControlPath(reference, compositePartName, device);
return TryGetTMPTagForActionPath(path, device, out tag, out displayFallback, db);
}
///
/// 尝试获取输入操作的 UI Sprite
///
/// 输入操作引用
/// 复合部分名称
/// 设备类型
/// 输出的 Sprite
/// 数据库实例(可选)
/// 是否成功获取
public static bool TryGetUISpriteForActionPath(InputAction reference, string compositePartName, InputDeviceWatcher.InputDeviceCategory device, out Sprite sprite, InputGlyphDatabase db = null)
{
string path = GetBindingControlPath(reference, compositePartName, device);
return TryGetUISpriteForActionPath(path, device, out sprite, db);
}
///
/// 根据控制路径尝试获取 TextMeshPro 标签
///
/// 控制路径
/// 设备类型
/// 输出的 TMP 标签
/// 显示回退文本
/// 数据库实例(可选)
/// 是否成功获取
public static bool TryGetTMPTagForActionPath(string controlPath, InputDeviceWatcher.InputDeviceCategory device, out string tag, out string displayFallback, InputGlyphDatabase db = null)
{
tag = null;
displayFallback = null;
db = db ?? Database;
displayFallback = GetDisplayNameFromControlPath(controlPath);
var sprite = db.FindSprite(controlPath, device) ?? db.FindSprite(controlPath, InputDeviceWatcher.InputDeviceCategory.Keyboard);
var spriteName = sprite == null ? string.Empty : sprite.name;
tag = $"";
return true;
}
///
/// 根据控制路径尝试获取 UI Sprite
///
/// 控制路径
/// 设备类型
/// 输出的 Sprite
/// 数据库实例(可选)
/// 是否成功获取
public static bool TryGetUISpriteForActionPath(string controlPath, InputDeviceWatcher.InputDeviceCategory device, out Sprite sprite, InputGlyphDatabase db = null)
{
sprite = null;
db = db ?? Database;
if (string.IsNullOrEmpty(controlPath) || db == null) return false;
sprite = db.FindSprite(controlPath, device) ?? db.FindSprite(controlPath, InputDeviceWatcher.InputDeviceCategory.Keyboard);
return sprite != null;
}
///
/// 获取输入操作的绑定控制
///
static InputBinding GetBindingControl(InputAction action, string compositePartName = null, InputDeviceWatcher.InputDeviceCategory? deviceOverride = null)
{
if (action == null) return default;
var curCategory = deviceOverride ?? InputDeviceWatcher.CurrentCategory;
var hints = GetDeviceHintsForCategory(curCategory);
foreach (var b in action.bindings)
{
if (!string.IsNullOrEmpty(compositePartName))
{
if (!b.isPartOfComposite) continue;
if (!string.Equals(b.name, compositePartName, StringComparison.OrdinalIgnoreCase)) continue;
}
// 替换 LINQ Any() 以避免委托分配
if (!string.IsNullOrEmpty(b.path) && ContainsAnyHint(b.path, hints)) return b;
if (!string.IsNullOrEmpty(b.effectivePath) && ContainsAnyHint(b.effectivePath, hints)) return b;
}
return default;
}
// 辅助方法,避免 LINQ Any() 的内存分配
///
/// 检查路径是否包含任何提示字符串
///
static bool ContainsAnyHint(string path, string[] hints)
{
for (int i = 0; i < hints.Length; i++)
{
if (path.IndexOf(hints[i], StringComparison.OrdinalIgnoreCase) >= 0)
return true;
}
return false;
}
///
/// 根据设备类型获取设备提示字符串数组
///
static string[] GetDeviceHintsForCategory(InputDeviceWatcher.InputDeviceCategory cat)
{
switch (cat)
{
case InputDeviceWatcher.InputDeviceCategory.Keyboard:
return KeyboardHints;
case InputDeviceWatcher.InputDeviceCategory.Xbox:
return XboxHints;
case InputDeviceWatcher.InputDeviceCategory.PlayStation:
return PlayStationHints;
default:
return XboxHints;
}
}
///
/// 从输入操作获取显示名称
///
/// 输入操作
/// 复合部分名称(可选)
/// 设备类型覆盖
/// 显示名称
public static string GetDisplayNameFromInputAction(InputAction action, string compositePartName = null, InputDeviceWatcher.InputDeviceCategory deviceOverride = InputDeviceWatcher.InputDeviceCategory.Keyboard)
{
if (action == null) return string.Empty;
var binding = GetBindingControl(action, compositePartName, deviceOverride);
return binding.ToDisplayString();
}
///
/// 从控制路径获取显示名称
///
/// 控制路径
/// 显示名称
public static string GetDisplayNameFromControlPath(string controlPath)
{
if (string.IsNullOrEmpty(controlPath)) return string.Empty;
var parts = controlPath.Split('/');
var last = parts[parts.Length - 1].Trim(TrimChars);
return last;
}
}