AlicizaX/Client/Assets/Scripts/CustomeModule/InputGlyph/GlyphService.cs

310 lines
10 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
{
private static readonly string[] KeyboardGroupHints = { "keyboard", "mouse", "keyboard&mouse", "keyboardmouse", "kbm" };
private static readonly string[] XboxGroupHints = { "xbox", "xinput", "gamepad", "controller" };
private static readonly string[] PlayStationGroupHints = { "playstation", "dualshock", "dualsense", "gamepad", "controller" };
private static readonly string[] OtherGamepadGroupHints = { "gamepad", "controller", "joystick" };
2026-03-09 20:38:15 +08:00
private static readonly char[] TrimChars = { '{', '}', '<', '>', '\'', '"' };
private static InputGlyphDatabase _database;
2025-12-17 20:03:29 +08:00
public static InputGlyphDatabase Database
{
get
{
if (_database == null)
{
_database = Resources.Load<InputGlyphDatabase>("InputGlyphDatabase");
}
return _database;
}
}
public static string GetBindingControlPath(
InputAction action,
string compositePartName = null,
InputDeviceWatcher.InputDeviceCategory? deviceOverride = null)
{
return TryGetBindingControl(action, compositePartName, deviceOverride, out InputBinding binding)
? GetEffectivePath(binding)
: string.Empty;
}
public static string GetBindingControlPath(
InputActionReference actionReference,
string compositePartName = null,
InputDeviceWatcher.InputDeviceCategory? deviceOverride = null)
{
return GetBindingControlPath(actionReference != null ? actionReference.action : null, compositePartName, deviceOverride);
}
2025-12-17 20:03:29 +08:00
public static bool TryGetTMPTagForActionPath(
InputAction action,
string compositePartName,
InputDeviceWatcher.InputDeviceCategory device,
out string tag,
out string displayFallback,
InputGlyphDatabase db = null)
{
string controlPath = GetBindingControlPath(action, compositePartName, device);
return TryGetTMPTagForActionPath(controlPath, device, out tag, out displayFallback, db);
}
public static bool TryGetTMPTagForActionPath(
InputActionReference actionReference,
string compositePartName,
InputDeviceWatcher.InputDeviceCategory device,
out string tag,
out string displayFallback,
InputGlyphDatabase db = null)
2025-12-10 17:38:31 +08:00
{
return TryGetTMPTagForActionPath(actionReference != null ? actionReference.action : null, compositePartName, device, out tag, out displayFallback, db);
}
2025-12-10 17:38:31 +08:00
public static bool TryGetUISpriteForActionPath(
InputAction action,
string compositePartName,
InputDeviceWatcher.InputDeviceCategory device,
out Sprite sprite,
InputGlyphDatabase db = null)
{
string controlPath = GetBindingControlPath(action, compositePartName, device);
return TryGetUISpriteForActionPath(controlPath, device, out sprite, db);
}
public static bool TryGetUISpriteForActionPath(
InputActionReference actionReference,
string compositePartName,
InputDeviceWatcher.InputDeviceCategory device,
out Sprite sprite,
InputGlyphDatabase db = null)
{
return TryGetUISpriteForActionPath(actionReference != null ? actionReference.action : null, compositePartName, device, out sprite, db);
}
public static bool TryGetTMPTagForActionPath(
string controlPath,
InputDeviceWatcher.InputDeviceCategory device,
out string tag,
out string displayFallback,
InputGlyphDatabase db = null)
{
2025-12-10 17:38:31 +08:00
displayFallback = GetDisplayNameFromControlPath(controlPath);
tag = null;
2025-12-10 17:38:31 +08:00
if (!TryGetUISpriteForActionPath(controlPath, device, out Sprite sprite, db))
{
return false;
}
2025-12-10 17:38:31 +08:00
tag = $"<sprite name=\"{sprite.name}\">";
2025-12-10 17:38:31 +08:00
return true;
}
public static bool TryGetUISpriteForActionPath(
string controlPath,
InputDeviceWatcher.InputDeviceCategory device,
out Sprite sprite,
InputGlyphDatabase db = null)
2025-12-10 17:38:31 +08:00
{
sprite = null;
db ??= Database;
return db != null && db.TryGetSprite(controlPath, device, out sprite);
}
public static string GetDisplayNameFromInputAction(
InputAction action,
string compositePartName = null,
InputDeviceWatcher.InputDeviceCategory? deviceOverride = null)
{
if (!TryGetBindingControl(action, compositePartName, deviceOverride, out InputBinding binding))
{
return string.Empty;
}
string display = binding.ToDisplayString();
return string.IsNullOrEmpty(display) ? GetDisplayNameFromControlPath(GetEffectivePath(binding)) : display;
2025-12-10 17:38:31 +08:00
}
public static string GetDisplayNameFromControlPath(string controlPath)
{
if (string.IsNullOrWhiteSpace(controlPath))
{
return string.Empty;
}
string[] parts = controlPath.Split('/');
string last = parts[parts.Length - 1].Trim(TrimChars);
return last;
}
2025-12-10 17:38:31 +08:00
public static bool TryGetBindingControl(
InputAction action,
string compositePartName,
InputDeviceWatcher.InputDeviceCategory? deviceOverride,
out InputBinding binding)
2025-12-10 17:38:31 +08:00
{
binding = default;
if (action == null)
{
return false;
}
InputDeviceWatcher.InputDeviceCategory category = deviceOverride ?? InputDeviceWatcher.CurrentCategory;
int bestScore = int.MinValue;
bool requireCompositePart = !string.IsNullOrEmpty(compositePartName);
for (int i = 0; i < action.bindings.Count; i++)
{
InputBinding candidate = action.bindings[i];
if (candidate.isComposite)
{
continue;
}
if (requireCompositePart)
{
if (!candidate.isPartOfComposite || !string.Equals(candidate.name, compositePartName, StringComparison.OrdinalIgnoreCase))
{
continue;
}
}
else if (candidate.isPartOfComposite)
{
continue;
}
2026-03-09 20:38:15 +08:00
string path = GetEffectivePath(candidate);
if (string.IsNullOrWhiteSpace(path))
{
continue;
}
int score = ScoreBinding(candidate, category);
if (score > bestScore)
{
bestScore = score;
binding = candidate;
}
}
return bestScore > int.MinValue;
}
private static int ScoreBinding(InputBinding binding, InputDeviceWatcher.InputDeviceCategory category)
2026-03-09 20:38:15 +08:00
{
int score = 0;
string path = GetEffectivePath(binding);
if (MatchesBindingGroups(binding.groups, category))
{
score += 100;
}
else if (!string.IsNullOrWhiteSpace(binding.groups))
{
score -= 20;
}
if (MatchesControlPath(path, category))
{
score += 60;
}
if (!binding.isPartOfComposite)
{
score += 5;
}
return score;
}
private static bool MatchesBindingGroups(string groups, InputDeviceWatcher.InputDeviceCategory category)
{
if (string.IsNullOrWhiteSpace(groups))
{
return false;
}
string[] hints = GetGroupHints(category);
string[] tokens = groups.Split(InputBinding.Separator);
for (int i = 0; i < tokens.Length; i++)
2026-03-09 20:38:15 +08:00
{
string token = tokens[i].Trim();
if (ContainsAny(token, hints))
{
2026-03-09 20:38:15 +08:00
return true;
}
2026-03-09 20:38:15 +08:00
}
2026-03-09 20:38:15 +08:00
return false;
}
private static bool MatchesControlPath(string path, InputDeviceWatcher.InputDeviceCategory category)
{
if (string.IsNullOrWhiteSpace(path))
{
return false;
}
switch (category)
{
case InputDeviceWatcher.InputDeviceCategory.Keyboard:
return StartsWithDevice(path, "<Keyboard>") || StartsWithDevice(path, "<Mouse>");
case InputDeviceWatcher.InputDeviceCategory.Xbox:
return StartsWithDevice(path, "<Gamepad>") || StartsWithDevice(path, "<Joystick>") || ContainsAny(path, XboxGroupHints);
case InputDeviceWatcher.InputDeviceCategory.PlayStation:
return StartsWithDevice(path, "<Gamepad>") || StartsWithDevice(path, "<Joystick>") || ContainsAny(path, PlayStationGroupHints);
default:
return StartsWithDevice(path, "<Gamepad>") || StartsWithDevice(path, "<Joystick>") || ContainsAny(path, OtherGamepadGroupHints);
}
}
private static bool StartsWithDevice(string path, string deviceTag)
{
return path.StartsWith(deviceTag, StringComparison.OrdinalIgnoreCase);
}
2025-12-05 19:04:53 +08:00
private static string[] GetGroupHints(InputDeviceWatcher.InputDeviceCategory category)
2025-12-05 19:04:53 +08:00
{
switch (category)
{
case InputDeviceWatcher.InputDeviceCategory.Keyboard:
return KeyboardGroupHints;
case InputDeviceWatcher.InputDeviceCategory.Xbox:
return XboxGroupHints;
case InputDeviceWatcher.InputDeviceCategory.PlayStation:
return PlayStationGroupHints;
default:
return OtherGamepadGroupHints;
}
2025-12-05 19:04:53 +08:00
}
2025-12-17 20:03:29 +08:00
private static bool ContainsAny(string source, string[] hints)
2025-12-05 19:04:53 +08:00
{
if (string.IsNullOrWhiteSpace(source) || hints == null)
{
return false;
}
for (int i = 0; i < hints.Length; i++)
{
if (source.IndexOf(hints[i], StringComparison.OrdinalIgnoreCase) >= 0)
{
return true;
}
}
return false;
}
private static string GetEffectivePath(InputBinding binding)
{
return string.IsNullOrWhiteSpace(binding.effectivePath) ? binding.path : binding.effectivePath;
2025-12-05 19:04:53 +08:00
}
}