#if INPUTSYSTEM_SUPPORT using System; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using UnityEngine; using UnityEngine.InputSystem; using Unity.Collections; using Unity.Collections.LowLevel.Unsafe; using UnityEngine.UI; namespace UnityEngine.UI { internal enum EHotkeyPressType : byte { Started = 0, Performed = 1 } // 优化1: 使用struct减少GC [StructLayout(LayoutKind.Sequential, Pack = 4)] internal struct HotkeyRegistration { public IHotkeyTrigger button; public EHotkeyPressType pressType; [MethodImpl(MethodImplOptions.AggressiveInlining)] public HotkeyRegistration(IHotkeyTrigger btn, EHotkeyPressType pressType) { this.button = btn; this.pressType = pressType; } } // 优化2: 使用struct存储handler信息 [StructLayout(LayoutKind.Sequential)] internal struct HandlerInfo { public Action handler; public InputActionReference action; public HandlerInfo(Action handler, InputActionReference action) { this.handler = handler; this.action = action; } } internal static class UXHotkeyRegisterManager { // 优化3: 使用数组池替代List,避免频繁扩容 private const int INITIAL_CAPACITY = 32; private const int MAX_REGISTRATIONS_PER_ACTION = 16; // 优化4: 使用固定大小的数组池 private static HotkeyRegistration[][] _registrationPool; private static int[] _registrationCounts; private static string[] _actionIds; private static int _actionCount; private static int _actionCapacity; // 优化5: 使用数组替代Dictionary(更快的查找) private static HandlerInfo[] _handlers; private static InputActionReference[] _actionRefs; // 优化6: Button到ActionId的映射(使用数组索引) private static IHotkeyTrigger[] _buttons; private static int[] _buttonToActionIndex; private static int _buttonCount; private static int _buttonCapacity; // 优化7: 缓存委托,避免每次创建 private static Action[] _cachedHandlers; private static int _cachedHandlerCount; static UXHotkeyRegisterManager() { _actionCapacity = INITIAL_CAPACITY; _registrationPool = new HotkeyRegistration[_actionCapacity][]; _registrationCounts = new int[_actionCapacity]; _actionIds = new string[_actionCapacity]; _handlers = new HandlerInfo[_actionCapacity]; _actionRefs = new InputActionReference[_actionCapacity]; _buttonCapacity = 64; _buttons = new IHotkeyTrigger[_buttonCapacity]; _buttonToActionIndex = new int[_buttonCapacity]; _cachedHandlers = new Action[INITIAL_CAPACITY]; for (int i = 0; i < _actionCapacity; i++) { _registrationPool[i] = new HotkeyRegistration[MAX_REGISTRATIONS_PER_ACTION]; _buttonToActionIndex[i] = -1; } } #if UNITY_EDITOR [UnityEditor.Callbacks.DidReloadScripts] internal static void ClearHotkeyRegistry() { for (int i = 0; i < _buttonCount; i++) { if (_buttons[i] != null) { UnregisterHotkey(_buttons[i]); } } Array.Clear(_registrationCounts, 0, _actionCount); Array.Clear(_actionIds, 0, _actionCount); Array.Clear(_handlers, 0, _actionCount); Array.Clear(_actionRefs, 0, _actionCount); Array.Clear(_buttons, 0, _buttonCount); Array.Clear(_buttonToActionIndex, 0, _buttonCount); _actionCount = 0; _buttonCount = 0; _cachedHandlerCount = 0; } #endif [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static void RegisterHotkey(IHotkeyTrigger button, InputActionReference action, EHotkeyPressType pressType) { if (action == null || action.action == null || button == null) return; string actionId = action.action.id.ToString(); int actionIndex = FindOrCreateActionIndex(actionId); // 添加注册信息 ref int count = ref _registrationCounts[actionIndex]; if (count >= MAX_REGISTRATIONS_PER_ACTION) { Debug.LogWarning($"Max registrations reached for action: {actionId}"); return; } _registrationPool[actionIndex][count] = new HotkeyRegistration(button, pressType); count++; // 记录button映射 int buttonIndex = FindOrCreateButtonIndex(button); _buttonToActionIndex[buttonIndex] = actionIndex; // 优化8: 只在第一次注册时创建handler if (count == 1) { Action handler = GetOrCreateHandler(actionIndex); _handlers[actionIndex] = new HandlerInfo(handler, action); _actionRefs[actionIndex] = action; switch (pressType) { case EHotkeyPressType.Started: action.action.started += handler; break; case EHotkeyPressType.Performed: action.action.performed += handler; break; } action.action.Enable(); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void UnregisterHotkey(IHotkeyTrigger button) { if (button == null) return; int buttonIndex = FindButtonIndex(button); if (buttonIndex < 0) return; int actionIndex = _buttonToActionIndex[buttonIndex]; if (actionIndex < 0) return; // 从注册列表中移除 ref int count = ref _registrationCounts[actionIndex]; HotkeyRegistration[] registrations = _registrationPool[actionIndex]; for (int i = count - 1; i >= 0; i--) { if (ReferenceEquals(registrations[i].button, button)) { EHotkeyPressType pressType = registrations[i].pressType; // 优化9: Swap-remove,避免数组移动 registrations[i] = registrations[count - 1]; registrations[count - 1] = default; count--; // 如果是最后一个注册,清理handler if (count == 0) { ref HandlerInfo handlerInfo = ref _handlers[actionIndex]; InputActionReference actionRef = _actionRefs[actionIndex]; if (actionRef != null && actionRef.action != null) { switch (pressType) { case EHotkeyPressType.Started: actionRef.action.started -= handlerInfo.handler; break; case EHotkeyPressType.Performed: actionRef.action.performed -= handlerInfo.handler; break; } actionRef.action.Disable(); } handlerInfo = default; _actionRefs[actionIndex] = null; _actionIds[actionIndex] = null; } break; } } // 清理button映射 _buttons[buttonIndex] = null; _buttonToActionIndex[buttonIndex] = -1; } // 优化10: 使用缓存的委托,避免闭包分配 [MethodImpl(MethodImplOptions.AggressiveInlining)] private static Action GetOrCreateHandler(int actionIndex) { if (actionIndex < _cachedHandlers.Length && _cachedHandlers[actionIndex] != null) { return _cachedHandlers[actionIndex]; } if (actionIndex >= _cachedHandlers.Length) { Array.Resize(ref _cachedHandlers, actionIndex + 1); } // 优化11: 使用静态方法 + 参数传递,避免闭包 int capturedIndex = actionIndex; _cachedHandlers[actionIndex] = ctx => OnHotkeyTriggered(capturedIndex); return _cachedHandlers[actionIndex]; } [MethodImpl(MethodImplOptions.AggressiveInlining)] private static void OnHotkeyTriggered(int actionIndex) { int count = _registrationCounts[actionIndex]; if (count > 0) { // 触发最后一个注册的button(栈顶) ref HotkeyRegistration registration = ref _registrationPool[actionIndex][count - 1]; registration.button?.HotkeyActionTrigger(); } } // 优化12: 线性查找(小数据集比Dictionary更快) [MethodImpl(MethodImplOptions.AggressiveInlining)] private static int FindOrCreateActionIndex(string actionId) { // 查找现有 for (int i = 0; i < _actionCount; i++) { if (_actionIds[i] == actionId) return i; } // 创建新的 if (_actionCount >= _actionCapacity) { ExpandActionCapacity(); } int index = _actionCount++; _actionIds[index] = actionId; return index; } [MethodImpl(MethodImplOptions.AggressiveInlining)] private static int FindOrCreateButtonIndex(IHotkeyTrigger button) { // 查找现有 for (int i = 0; i < _buttonCount; i++) { if (ReferenceEquals(_buttons[i], button)) return i; } // 查找空槽 for (int i = 0; i < _buttonCapacity; i++) { if (_buttons[i] == null) { _buttons[i] = button; if (i >= _buttonCount) _buttonCount = i + 1; return i; } } // 扩容 if (_buttonCount >= _buttonCapacity) { ExpandButtonCapacity(); } int index = _buttonCount++; _buttons[index] = button; return index; } [MethodImpl(MethodImplOptions.AggressiveInlining)] private static int FindButtonIndex(IHotkeyTrigger button) { for (int i = 0; i < _buttonCount; i++) { if (ReferenceEquals(_buttons[i], button)) return i; } return -1; } private static void ExpandActionCapacity() { int newCapacity = _actionCapacity * 2; Array.Resize(ref _registrationPool, newCapacity); Array.Resize(ref _registrationCounts, newCapacity); Array.Resize(ref _actionIds, newCapacity); Array.Resize(ref _handlers, newCapacity); Array.Resize(ref _actionRefs, newCapacity); for (int i = _actionCapacity; i < newCapacity; i++) { _registrationPool[i] = new HotkeyRegistration[MAX_REGISTRATIONS_PER_ACTION]; } _actionCapacity = newCapacity; } private static void ExpandButtonCapacity() { int newCapacity = _buttonCapacity * 2; Array.Resize(ref _buttons, newCapacity); Array.Resize(ref _buttonToActionIndex, newCapacity); for (int i = _buttonCapacity; i < newCapacity; i++) { _buttonToActionIndex[i] = -1; } _buttonCapacity = newCapacity; } // 优化13: 批量操作API [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void RegisterHotkeyBatch(Span buttons, InputActionReference action, EHotkeyPressType pressType) { for (int i = 0; i < buttons.Length; i++) { RegisterHotkey(buttons[i], action, pressType); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void UnregisterHotkeyBatch(Span buttons) { for (int i = 0; i < buttons.Length; i++) { UnregisterHotkey(buttons[i]); } } // 调试信息 #if UNITY_EDITOR public static string GetDebugInfo() { return $"Actions: {_actionCount}/{_actionCapacity}, Buttons: {_buttonCount}/{_buttonCapacity}"; } #endif } } public static class UXHotkeyHotkeyExtension { [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void BindHotKey(this IHotkeyTrigger button) { if (button?.HotkeyAction != null) { UXHotkeyRegisterManager.RegisterHotkey( button, button.HotkeyAction, button.HotkeyPressType ); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void UnBindHotKey(this IHotkeyTrigger button) { if (button?.HotkeyAction != null) { UXHotkeyRegisterManager.UnregisterHotkey(button); } } // 优化14: 批量绑定 [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void BindHotKeyBatch(this IHotkeyTrigger[] buttons) { if (buttons == null) return; for (int i = 0; i < buttons.Length; i++) { buttons[i]?.BindHotKey(); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void UnBindHotKeyBatch(this IHotkeyTrigger[] buttons) { if (buttons == null) return; for (int i = 0; i < buttons.Length; i++) { buttons[i]?.UnBindHotKey(); } } } #endif