AlicizaX/Client/Assets/InputGlyph/GlyphService.cs

138 lines
5.4 KiB
C#
Raw Normal View History

using System;
2025-12-05 19:04:53 +08:00
using UnityEngine;
using UnityEngine.InputSystem;
2025-12-05 19:04:53 +08:00
public static class GlyphService
2025-12-05 19:04:53 +08:00
{
2026-03-09 20:38:15 +08:00
// 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 = { '{', '}', '<', '>', '\'', '"' };
2025-12-17 20:03:29 +08:00
public static InputGlyphDatabase Database
{
get
{
if (_database == null)
{
_database = Resources.Load<InputGlyphDatabase>("InputGlyphDatabase");
}
return _database;
}
}
private static InputGlyphDatabase _database;
2026-03-09 20:38:15 +08:00
public static string GetBindingControlPath(InputAction action, string compositePartName = null, InputDeviceWatcher.InputDeviceCategory? deviceOverride = null)
{
if (action == null) return string.Empty;
2026-03-09 20:38:15 +08:00
var binding = GetBindingControl(action, compositePartName, deviceOverride);
2025-12-10 17:38:31 +08:00
return binding.hasOverrides ? binding.effectivePath : binding.path;
}
2025-12-05 19:04:53 +08:00
2026-03-09 20:38:15 +08:00
public static bool TryGetTMPTagForActionPath(InputAction reference, string compositePartName, InputDeviceWatcher.InputDeviceCategory device, out string tag, out string displayFallback, InputGlyphDatabase db = null)
2025-12-05 19:04:53 +08:00
{
2026-03-09 20:38:15 +08:00
string path = GetBindingControlPath(reference, compositePartName, device);
2025-12-10 17:38:31 +08:00
return TryGetTMPTagForActionPath(path, device, out tag, out displayFallback, db);
2025-12-05 19:04:53 +08:00
}
2026-03-09 20:38:15 +08:00
public static bool TryGetUISpriteForActionPath(InputAction reference, string compositePartName, InputDeviceWatcher.InputDeviceCategory device, out Sprite sprite, InputGlyphDatabase db = null)
{
2026-03-09 20:38:15 +08:00
string path = GetBindingControlPath(reference, compositePartName, device);
2025-12-10 17:38:31 +08:00
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;
}
2026-03-09 20:38:15 +08:00
static InputBinding GetBindingControl(InputAction action, string compositePartName = null, InputDeviceWatcher.InputDeviceCategory? deviceOverride = null)
2025-12-10 17:38:31 +08:00
{
if (action == null) return default;
var curCategory = deviceOverride ?? InputDeviceWatcher.CurrentCategory;
var hints = GetDeviceHintsForCategory(curCategory);
2026-03-09 20:38:15 +08:00
foreach (var b in action.bindings)
{
2026-03-09 20:38:15 +08:00
if (!string.IsNullOrEmpty(compositePartName))
{
2026-03-09 20:38:15 +08:00
if (!b.isPartOfComposite) continue;
if (!string.Equals(b.name, compositePartName, StringComparison.OrdinalIgnoreCase)) continue;
}
2026-03-09 20:38:15 +08:00
// 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;
}
2025-12-10 17:38:31 +08:00
return default;
}
2026-03-09 20:38:15 +08:00
// 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:
2026-03-09 20:38:15 +08:00
return KeyboardHints;
case InputDeviceWatcher.InputDeviceCategory.Xbox:
2026-03-09 20:38:15 +08:00
return XboxHints;
case InputDeviceWatcher.InputDeviceCategory.PlayStation:
2026-03-09 20:38:15 +08:00
return PlayStationHints;
default:
2026-03-09 20:38:15 +08:00
return XboxHints;
}
}
2025-12-05 19:04:53 +08:00
2026-03-09 20:38:15 +08:00
public static string GetDisplayNameFromInputAction(InputAction action, string compositePartName = null, InputDeviceWatcher.InputDeviceCategory deviceOverride = InputDeviceWatcher.InputDeviceCategory.Keyboard)
2025-12-05 19:04:53 +08:00
{
2026-03-09 20:38:15 +08:00
if (action == null) return string.Empty;
var binding = GetBindingControl(action, compositePartName, deviceOverride);
return binding.ToDisplayString();
2025-12-05 19:04:53 +08:00
}
2025-12-17 20:03:29 +08:00
2025-12-10 17:38:31 +08:00
public static string GetDisplayNameFromControlPath(string controlPath)
2025-12-05 19:04:53 +08:00
{
if (string.IsNullOrEmpty(controlPath)) return string.Empty;
var parts = controlPath.Split('/');
2026-03-09 20:38:15 +08:00
var last = parts[parts.Length - 1].Trim(TrimChars);
2025-12-05 19:04:53 +08:00
return last;
}
}