AlicizaX/Client/Assets/InputGlyph/GlyphService.cs
2026-03-09 20:38:15 +08:00

138 lines
5.4 KiB
C#

using System;
using UnityEngine;
using UnityEngine.InputSystem;
public static class GlyphService
{
// Cached device hint arrays to avoid allocations
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>("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;
}
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);
}
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);
}
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 = $"<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;
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;
}
// Replace LINQ Any() to avoid delegate allocation
if (!string.IsNullOrEmpty(b.path) && ContainsAnyHint(b.path, hints)) return b;
if (!string.IsNullOrEmpty(b.effectivePath) && ContainsAnyHint(b.effectivePath, hints)) return b;
}
return default;
}
// Helper method to avoid LINQ Any() allocation
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;
}
}