156 lines
6.2 KiB
C#
156 lines
6.2 KiB
C#
using System;
|
||
using System.Linq;
|
||
using AlicizaX.InputGlyph;
|
||
using UnityEngine;
|
||
using UnityEngine.InputSystem;
|
||
|
||
public static class GlyphService
|
||
{
|
||
/// <summary>
|
||
/// 可选的全局数据库引用。你可以通过场景内的启动组件在 Awake 时赋值,
|
||
/// 或者在调用每个方法时传入 InputGlyphDatabase 参数(见方法签名)。
|
||
/// </summary>
|
||
public static InputGlyphDatabase Database { get; set; }
|
||
|
||
public static string GetBindingDisplay(InputAction action, InputGlyphDatabase db = null)
|
||
{
|
||
if (action == null) return string.Empty;
|
||
var control = GetBindingControl(action);
|
||
return control != null ? control.displayName : string.Empty;
|
||
}
|
||
|
||
public static string GetBindingControlPath(InputAction action, InputDeviceWatcher.InputDeviceCategory? deviceOverride = null, InputGlyphDatabase db = null)
|
||
{
|
||
if (action == null) return string.Empty;
|
||
var control = GetBindingControl(action, deviceOverride);
|
||
return control != null ? $"{(control.device?.displayName ?? "Unknown")}/{control.displayName}" : string.Empty;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 根据当前设备类别(或传入的 deviceOverride)尝试在 action.controls 中找到匹配的 control。
|
||
/// 匹配策略:检查 control.device.displayName 是否包含类别提示词(忽略大小写)。
|
||
/// 如果没有匹配项则返回第一个 control(作为最后的退路),或 null。
|
||
/// </summary>
|
||
public static InputControl GetBindingControl(InputAction action, InputDeviceWatcher.InputDeviceCategory? deviceOverride = null)
|
||
{
|
||
if (action == null) return null;
|
||
|
||
var curCategory = deviceOverride ?? InputDeviceWatcher.CurrentCategory;
|
||
var hints = GetDeviceHintsForCategory(curCategory);
|
||
|
||
// 首先找匹配 hints 的 control
|
||
foreach (var control in action.controls)
|
||
{
|
||
var deviceName = control.device?.displayName ?? string.Empty;
|
||
if (hints.Any(h => deviceName.IndexOf(h, StringComparison.OrdinalIgnoreCase) >= 0))
|
||
{
|
||
return control;
|
||
}
|
||
}
|
||
|
||
// 如果没有匹配,尝试返回第一个 gamepad/keyboard 优先的 control(更健壮)
|
||
if (action.controls.Count > 0)
|
||
{
|
||
// 优先返回 keyboard/mouse 类型(如果当前类别是 keyboard)
|
||
if (curCategory == InputDeviceWatcher.InputDeviceCategory.Keyboard)
|
||
{
|
||
var k = action.controls.FirstOrDefault(c => (c.device?.displayName ?? "").IndexOf("Keyboard", StringComparison.OrdinalIgnoreCase) >= 0)
|
||
?? action.controls.First();
|
||
return k;
|
||
}
|
||
|
||
return action.controls.First();
|
||
}
|
||
|
||
return null;
|
||
}
|
||
|
||
static string[] GetDeviceHintsForCategory(InputDeviceWatcher.InputDeviceCategory cat)
|
||
{
|
||
switch (cat)
|
||
{
|
||
case InputDeviceWatcher.InputDeviceCategory.Keyboard:
|
||
return new[] { "Keyboard", "Mouse" };
|
||
case InputDeviceWatcher.InputDeviceCategory.Xbox:
|
||
return new[] { "XInput", "Xbox", "Gamepad" };
|
||
case InputDeviceWatcher.InputDeviceCategory.PlayStation:
|
||
return new[] { "DualShock", "DualSense", "PlayStation", "Gamepad" };
|
||
default:
|
||
return new[] { "Gamepad", "Joystick", "Keyboard", "Mouse" };
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 尝试根据 controlPath 和设备获取 TMP sprite 标签;如果失败会返回 displayFallback(可直接显示的文字)。
|
||
/// 逻辑:
|
||
/// 1) 使用传入 db 或静态 Database;
|
||
/// 2) 先在指定设备表中查找 entry,找不到则回退到 Keyboard 表;
|
||
/// 3) 如果 table 或 tmpAsset 缺失 或 entry.Sprite 缺失,则用 displayFallback(从 controlPath 提取最后段或控制名)。
|
||
/// </summary>
|
||
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;
|
||
if (string.IsNullOrEmpty(controlPath) || db == null)
|
||
{
|
||
displayFallback = GetDisplayNameFromControlPath(controlPath);
|
||
return false;
|
||
}
|
||
|
||
var entry = db.FindEntryByControlPath(controlPath, device);
|
||
if (entry == null)
|
||
{
|
||
// 设备缺失或没有 entry -> 回退 keyboard
|
||
entry = db.FindEntryByControlPath(controlPath, InputDeviceWatcher.InputDeviceCategory.Keyboard);
|
||
}
|
||
|
||
if (entry == null)
|
||
{
|
||
displayFallback = GetDisplayNameFromControlPath(controlPath);
|
||
return false;
|
||
}
|
||
|
||
// 查找对应表(优先目标设备,再 keyboard)
|
||
var table = db.GetTable(device) ?? db.GetTable(InputDeviceWatcher.InputDeviceCategory.Keyboard);
|
||
if (table == null || table.tmpAsset == null)
|
||
{
|
||
displayFallback = GetDisplayNameFromControlPath(controlPath);
|
||
return false;
|
||
}
|
||
|
||
var sprite = entry.Sprite;
|
||
if (sprite == null)
|
||
{
|
||
displayFallback = GetDisplayNameFromControlPath(controlPath);
|
||
return false;
|
||
}
|
||
|
||
var spriteName = sprite.name;
|
||
tag = $"<sprite name=\"{spriteName}\">";
|
||
return true;
|
||
}
|
||
|
||
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;
|
||
|
||
var entry = db.FindEntryByControlPath(controlPath, device) ?? db.FindEntryByControlPath(controlPath, InputDeviceWatcher.InputDeviceCategory.Keyboard);
|
||
if (entry == null) return false;
|
||
if (entry.Sprite == null) return false;
|
||
|
||
sprite = entry.Sprite;
|
||
return true;
|
||
}
|
||
|
||
static string GetDisplayNameFromControlPath(string controlPath)
|
||
{
|
||
if (string.IsNullOrEmpty(controlPath)) return string.Empty;
|
||
var parts = controlPath.Split('/');
|
||
var last = parts[parts.Length - 1].Trim(new char[] { '{', '}', '<', '>', '\'', '"' });
|
||
return last;
|
||
}
|
||
}
|