AlicizaX/Client/Assets/InputGlyph/GlyphService.cs
陈思海 5862fb2af1 add
1.新增手柄相关适配
2.新增设备重映射绑定
3.新增设备映射图标更新
2025-12-09 20:31:44 +08:00

156 lines
6.2 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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