using System; using System.Collections.Generic; using UnityEngine; using UnityEngine.InputSystem; public static class InputActionReader { private readonly struct InputReadKey : IEquatable { public readonly string ActionName; public readonly int OwnerId; public readonly string OwnerKey; public InputReadKey(string actionName, int ownerId) { ActionName = actionName ?? string.Empty; OwnerId = ownerId; OwnerKey = string.Empty; } public InputReadKey(string actionName, string ownerKey) { ActionName = actionName ?? string.Empty; OwnerId = 0; OwnerKey = ownerKey ?? string.Empty; } public bool Equals(InputReadKey other) { return OwnerId == other.OwnerId && string.Equals(ActionName, other.ActionName, StringComparison.Ordinal) && string.Equals(OwnerKey, other.OwnerKey, StringComparison.Ordinal); } public override bool Equals(object obj) { return obj is InputReadKey other && Equals(other); } public override int GetHashCode() { unchecked { int hashCode = 17; hashCode = (hashCode * 31) + OwnerId; hashCode = (hashCode * 31) + StringComparer.Ordinal.GetHashCode(ActionName); hashCode = (hashCode * 31) + StringComparer.Ordinal.GetHashCode(OwnerKey); return hashCode; } } } private static readonly HashSet PressedKeys = new(); private static readonly HashSet ToggledKeys = new(); public static T ReadValue(string actionName) where T : struct { return ResolveAction(actionName).ReadValue(); } public static object ReadValue(string actionName) { return ResolveAction(actionName).ReadValueAsObject(); } public static bool TryReadValue(string actionName, out T value) where T : struct { InputAction inputAction = ResolveAction(actionName); if (inputAction.IsPressed()) { value = inputAction.ReadValue(); return true; } value = default; return false; } public static bool TryReadValue(string actionName, out object value) { InputAction inputAction = ResolveAction(actionName); if (inputAction.IsPressed()) { value = inputAction.ReadValueAsObject(); return true; } value = default; return false; } public static bool TryReadValueOnce(UnityEngine.Object owner, string actionName, out T value) where T : struct { if (owner == null) { value = default; return false; } return TryReadValueOnceInternal(new InputReadKey(actionName, owner.GetInstanceID()), actionName, out value); } public static bool ReadButton(string actionName) { InputAction inputAction = ResolveAction(actionName); if (inputAction.type == InputActionType.Button) { return Convert.ToBoolean(inputAction.ReadValueAsObject()); } throw new NotSupportedException("[InputActionReader] The Input Action must be a button type."); } public static bool ReadButtonOnce(UnityEngine.Object owner, string actionName) { return owner != null && ReadButtonOnce(owner.GetInstanceID(), actionName); } public static bool ReadButtonOnce(int instanceID, string actionName) { return ReadButtonOnceInternal(new InputReadKey(actionName, instanceID), actionName); } public static bool ReadButtonOnce(string key, string actionName) { return ReadButtonOnceInternal(new InputReadKey(actionName, key), actionName); } public static bool ReadButtonToggle(UnityEngine.Object owner, string actionName) { return owner != null && ReadButtonToggle(owner.GetInstanceID(), actionName); } public static bool ReadButtonToggle(int instanceID, string actionName) { return ReadButtonToggleInternal(new InputReadKey(actionName, instanceID), actionName); } public static bool ReadButtonToggle(string key, string actionName) { return ReadButtonToggleInternal(new InputReadKey(actionName, key), actionName); } public static void ResetToggledButton(string key, string actionName) { ToggledKeys.Remove(new InputReadKey(actionName, key)); } public static void ResetToggledButton(string actionName) { if (string.IsNullOrEmpty(actionName) || ToggledKeys.Count == 0) { return; } InputReadKey[] snapshot = new InputReadKey[ToggledKeys.Count]; ToggledKeys.CopyTo(snapshot); for (int i = 0; i < snapshot.Length; i++) { if (string.Equals(snapshot[i].ActionName, actionName, StringComparison.Ordinal)) { ToggledKeys.Remove(snapshot[i]); } } } public static void ResetToggledButtons() { ToggledKeys.Clear(); } private static InputAction ResolveAction(string actionName) { return InputBindingManager.Action(actionName) ?? throw new InvalidOperationException($"[InputActionReader] Action '{actionName}' is not available."); } private static bool TryReadValueOnceInternal(InputReadKey readKey, string actionName, out T value) where T : struct { InputAction inputAction = ResolveAction(actionName); if (inputAction.IsPressed()) { if (PressedKeys.Add(readKey)) { value = inputAction.ReadValue(); return true; } } else { PressedKeys.Remove(readKey); } value = default; return false; } private static bool ReadButtonOnceInternal(InputReadKey readKey, string actionName) { if (ReadButton(actionName)) { return PressedKeys.Add(readKey); } PressedKeys.Remove(readKey); return false; } private static bool ReadButtonToggleInternal(InputReadKey readKey, string actionName) { if (ReadButtonOnceInternal(readKey, actionName)) { if (!ToggledKeys.Add(readKey)) { ToggledKeys.Remove(readKey); } } return ToggledKeys.Contains(readKey); } }