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;
}
}