diff --git a/Editor/AlicizaX.UI.Extension.Editor.asmdef b/Editor/AlicizaX.UI.Extension.Editor.asmdef index fce090a..744e6a5 100644 --- a/Editor/AlicizaX.UI.Extension.Editor.asmdef +++ b/Editor/AlicizaX.UI.Extension.Editor.asmdef @@ -26,6 +26,11 @@ "name": "com.unity.textmeshpro", "expression": "", "define": "TEXTMESHPRO_SUPPORT" + }, + { + "name": "com.unity.inputsystem", + "expression": "1.0.0", + "define": "INPUTSYSTEM_SUPPORT" } ], "noEngineReferences": false diff --git a/Editor/UX/UXButtonEditor.cs b/Editor/UX/UXButtonEditor.cs index 801cd38..91ade7b 100644 --- a/Editor/UX/UXButtonEditor.cs +++ b/Editor/UX/UXButtonEditor.cs @@ -18,6 +18,7 @@ internal class UXButtonEditor : Editor Sound, Event } + private SerializedProperty m_Interactable; private SerializedProperty m_Mode; private SerializedProperty m_OnValueChanged; @@ -42,6 +43,12 @@ internal class UXButtonEditor : Editor private SerializedProperty hoverAudioClip; private SerializedProperty clickAudioClip; +#if INPUTSYSTEM_SUPPORT + private SerializedProperty _hotKeyRefrence; + private SerializedProperty _hotkeyPressType; +#endif + + private void OnEnable() { customSkin = AssetDatabase.LoadAssetAtPath("Packages/com.alicizax.unity.ui.extension/Editor/Res/GUISkin/UIExtensionGUISkin.guiskin"); @@ -60,6 +67,10 @@ internal class UXButtonEditor : Editor hoverAudioClip = serializedObject.FindProperty("hoverAudioClip"); clickAudioClip = serializedObject.FindProperty("clickAudioClip"); +#if INPUTSYSTEM_SUPPORT + _hotKeyRefrence = serializedObject.FindProperty("_hotKeyRefrence"); + _hotkeyPressType = serializedObject.FindProperty("_hotkeyPressType"); +#endif CreateChildTransitionList(); } @@ -212,6 +223,12 @@ internal class UXButtonEditor : Editor EditorGUILayout.Space(); EditorGUILayout.PropertyField(m_OnClick); } + + EditorGUILayout.Separator(); +#if INPUTSYSTEM_SUPPORT + EditorGUILayout.PropertyField(_hotkeyPressType); + EditorGUILayout.PropertyField(_hotKeyRefrence); +#endif } private void DrawAudioTab() diff --git a/Runtime/AlicizaX.UI.Extension.asmdef b/Runtime/AlicizaX.UI.Extension.asmdef index 303ebcc..7a2aba6 100644 --- a/Runtime/AlicizaX.UI.Extension.asmdef +++ b/Runtime/AlicizaX.UI.Extension.asmdef @@ -3,7 +3,8 @@ "rootNamespace": "AlicizaX.UI.Extension", "references": [ "GUID:6055be8ebefd69e48b49212b09b47b2f", - "GUID:80ecb87cae9c44d19824e70ea7229748" + "GUID:80ecb87cae9c44d19824e70ea7229748", + "GUID:75469ad4d38634e559750d17036d5f7c" ], "includePlatforms": [], "excludePlatforms": [], @@ -27,6 +28,11 @@ "name": "com.kyrylokuzyk.primetween", "expression": "1.2.1", "define": "PRIMETWEEN_SUPPORT" + }, + { + "name": "com.unity.inputsystem", + "expression": "1.0.0", + "define": "INPUTSYSTEM_SUPPORT" } ], "noEngineReferences": false diff --git a/Runtime/UXComponent/UX/UXButton.cs b/Runtime/UXComponent/UX/UXButton.cs index 636f8c1..dd36bfd 100644 --- a/Runtime/UXComponent/UX/UXButton.cs +++ b/Runtime/UXComponent/UX/UXButton.cs @@ -6,6 +6,7 @@ using AlicizaX.UI.Extension; using UnityEngine; using UnityEngine.Events; using UnityEngine.EventSystems; +using UnityEngine.Serialization; using UnityEngine.UI; [Serializable] @@ -50,6 +51,19 @@ public class UXButton : UIBehaviour, IButton, [SerializeField] private UXGroup m_UXGroup; [SerializeField] private AudioClip hoverAudioClip; [SerializeField] private AudioClip clickAudioClip; +#if INPUTSYSTEM_SUPPORT + [SerializeField] internal UnityEngine.InputSystem.InputActionReference _hotKeyRefrence; + [SerializeField] internal EHotkeyPressType _hotkeyPressType; + + internal void OnHotkeyTriggered() + { + if (m_Interactable) + { + OnSubmit(null); + } + } + +#endif #endregion @@ -222,7 +236,8 @@ public class UXButton : UIBehaviour, IButton, ProcessClick(); } - void ISubmitHandler.OnSubmit(BaseEventData eventData) + + public void OnSubmit(BaseEventData eventData) { UpdateVisualState(SelectionState.Pressed, false); ProcessClick(); diff --git a/Runtime/UXComponent/UX/UXHotkey.cs b/Runtime/UXComponent/UX/UXHotkey.cs new file mode 100644 index 0000000..f7d52f0 --- /dev/null +++ b/Runtime/UXComponent/UX/UXHotkey.cs @@ -0,0 +1,190 @@ +#if INPUTSYSTEM_SUPPORT +using UnityEngine; +using UnityEngine.InputSystem; +using System.Collections.Generic; +using System.Collections; + +internal enum EHotkeyPressType +{ + Started, + Performed +} + +internal static class UXHotkeyComponent +{ + private readonly struct HotkeyRegistration + { + public readonly InputActionReference reference; + public readonly EHotkeyPressType pressType; + public readonly UXButton button; + + public HotkeyRegistration(UXButton btn, InputActionReference reference, EHotkeyPressType pressType) + { + button = btn; + this.reference = reference; + this.pressType = pressType; + } + } + + private static readonly Dictionary> _hotkeyRegistry = + new Dictionary>(32); + + + private static readonly Dictionary handler, EHotkeyPressType pressType)> _sharedHandlers = + new Dictionary, EHotkeyPressType)>(32); + + + private static readonly Dictionary> _buttonRegistrations = + new Dictionary>(64); + + +#if UNITY_EDITOR + [UnityEditor.Callbacks.DidReloadScripts] + internal static void ClearHotkeyRegistry() + { + foreach (var key in _buttonRegistrations.Keys) + { + UnregisterHotkey(key); + } + + _sharedHandlers.Clear(); + _hotkeyRegistry.Clear(); + _buttonRegistrations.Clear(); + } +#endif + + internal static void RegisterHotkey(UXButton button, InputActionReference action, EHotkeyPressType pressType) + { + if (action == null || action.action == null || button == null) + return; + + string actionId = action.action.id.ToString(); + + + HotkeyRegistration registration = new HotkeyRegistration(button, action, pressType); + + + if (!_hotkeyRegistry.TryGetValue(actionId, out var registrations)) + { + registrations = new List(4); + _hotkeyRegistry[actionId] = registrations; + } + + registrations.Add(registration); + + + if (!_buttonRegistrations.TryGetValue(button, out var actionIds)) + { + actionIds = new HashSet(); + _buttonRegistrations[button] = actionIds; + } + + actionIds.Add(actionId); + + if (!_sharedHandlers.ContainsKey(actionId)) + { + System.Action handler = ctx => OnHotkeyTriggered(actionId); + _sharedHandlers[actionId] = (handler, pressType); + + switch (pressType) + { + case EHotkeyPressType.Started: + action.action.started += handler; + break; + case EHotkeyPressType.Performed: + action.action.performed += handler; + break; + } + + action.action.Enable(); + } + } + + public static void UnregisterHotkey(UXButton button) + { + if (button == null || !_buttonRegistrations.TryGetValue(button, out var actionIds)) + return; + + foreach (var actionId in actionIds) + { + if (_hotkeyRegistry.TryGetValue(actionId, out var registrations)) + { + for (int i = registrations.Count - 1; i >= 0; i--) + { + if (registrations[i].button == button) + { + registrations.RemoveAt(i); + break; + } + } + + if (registrations.Count == 0) + { + _hotkeyRegistry.Remove(actionId); + + if (_sharedHandlers.TryGetValue(actionId, out var handlerInfo)) + { + var (handler, pressType) = handlerInfo; + var actionRef = registrations.Count > 0 ? registrations[0].reference : null; + + if (actionRef != null && actionRef.action != null) + { + actionRef.action.Disable(); + + + switch (pressType) + { + case EHotkeyPressType.Started: + actionRef.action.started -= handler; + break; + case EHotkeyPressType.Performed: + actionRef.action.performed -= handler; + break; + } + } + + _sharedHandlers.Remove(actionId); + } + } + } + } + + + _buttonRegistrations.Remove(button); + } + + private static void OnHotkeyTriggered(string actionId) + { + if (_hotkeyRegistry.TryGetValue(actionId, out var registrations) && registrations.Count > 0) + { + var registration = registrations[registrations.Count - 1]; + registration.button.OnHotkeyTriggered(); + } + } +} + +public static class UXButtonHotkeyExtension +{ + public static void BindHotKey(this UXButton button) + { + if (button == null) return; + +#if INPUTSYSTEM_SUPPORT + if (button._hotKeyRefrence != null) + { + UXHotkeyComponent.RegisterHotkey( + button, + button._hotKeyRefrence, + button._hotkeyPressType + ); + } +#endif + } + + public static void UnBindHotKey(this UXButton button) + { + if (button == null) return; + UXHotkeyComponent.UnregisterHotkey(button); + } +} +#endif diff --git a/Runtime/UXComponent/UX/UXHotkey.cs.meta b/Runtime/UXComponent/UX/UXHotkey.cs.meta new file mode 100644 index 0000000..9064b0e --- /dev/null +++ b/Runtime/UXComponent/UX/UXHotkey.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 0aa77908962c48199d63710fa15b8c37 +timeCreated: 1754555268 \ No newline at end of file