using System; using System.Linq; using AlicizaX.InputGlyph; using UnityEngine; using UnityEngine.InputSystem; public static class GlyphService { /// /// 可选的全局数据库引用。你可以通过场景内的启动组件在 Awake 时赋值, /// 或者在调用每个方法时传入 InputGlyphDatabase 参数(见方法签名)。 /// 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; } /// /// 根据当前设备类别(或传入的 deviceOverride)尝试在 action.controls 中找到匹配的 control。 /// 匹配策略:检查 control.device.displayName 是否包含类别提示词(忽略大小写)。 /// 如果没有匹配项则返回第一个 control(作为最后的退路),或 null。 /// 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" }; } } /// /// 尝试根据 controlPath 和设备获取 TMP sprite 标签;如果失败会返回 displayFallback(可直接显示的文字)。 /// 逻辑: /// 1) 使用传入 db 或静态 Database; /// 2) 先在指定设备表中查找 entry,找不到则回退到 Keyboard 表; /// 3) 如果 table 或 tmpAsset 缺失 或 entry.Sprite 缺失,则用 displayFallback(从 controlPath 提取最后段或控制名)。 /// 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 = $""; 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; } }