using System; using System.Collections.Generic; using UnityEngine.Events; using UnityEngine.UI; namespace UnityEngine.InputSystem.Samples.RebindUI { public class ActionLabel : MonoBehaviour { [Tooltip("Reference to action that is to be rebound from the UI.")] [SerializeField] private InputActionReference m_Action; [SerializeField] private string m_BindingId; [SerializeField] private InputBinding.DisplayStringOptions m_DisplayStringOptions; [Tooltip("Text label that will receive the current, formatted binding string.")] [SerializeField] private Text m_BindingText; [Tooltip("Event that is triggered when the way the binding is display should be updated. This allows displaying " + "bindings in custom ways, e.g. using images instead of text.")] [SerializeField] private UpdateBindingUIEvent m_UpdateBindingUIEvent; private static List s_InputActionUIs; /// /// Reference to the action that is to be rebound. /// public InputActionReference actionReference { get => m_Action; set { m_Action = value; UpdateBindingDisplay(); } } /// /// ID (in string form) of the binding that is to be rebound on the action. /// /// public string bindingId { get => m_BindingId; set { m_BindingId = value; UpdateBindingDisplay(); } } /// /// Text component that receives the display string of the binding. Can be null in which /// case the component entirely relies on . /// public Text bindingText { get => m_BindingText; set { m_BindingText = value; UpdateBindingDisplay(); } } /// /// Display options for the binding. /// public InputBinding.DisplayStringOptions displayStringOptions { get => m_DisplayStringOptions; set { m_DisplayStringOptions = value; UpdateBindingDisplay(); } } /// /// Trigger a refresh of the currently displayed binding. /// public void UpdateBindingDisplay() { var displayString = string.Empty; var deviceLayoutName = default(string); var controlPath = default(string); // Get display string from action. var action = m_Action?.action; if (action != null) { var bindingIndex = action.bindings.IndexOf(x => x.id.ToString() == m_BindingId); if (bindingIndex != -1) displayString = action.GetBindingDisplayString(bindingIndex, out deviceLayoutName, out controlPath, displayStringOptions); } // Set on label (if any). if (m_BindingText != null) m_BindingText.text = displayString; // Give listeners a chance to configure UI in response. m_UpdateBindingUIEvent?.Invoke(this, displayString, deviceLayoutName, controlPath); } protected void OnEnable() { if (s_InputActionUIs == null) s_InputActionUIs = new List(); s_InputActionUIs.Add(this); if (s_InputActionUIs.Count == 1) InputSystem.onActionChange += OnActionChange; UpdateBindingDisplay(); } protected void OnDisable() { s_InputActionUIs.Remove(this); if (s_InputActionUIs.Count == 0) { s_InputActionUIs = null; InputSystem.onActionChange -= OnActionChange; } } // When the action system re-resolves bindings, we want to update our UI in response // to show the currently relevant binding. private static void OnActionChange(object obj, InputActionChange change) { if (change != InputActionChange.BoundControlsChanged) return; var action = obj as InputAction; var actionMap = action?.actionMap ?? obj as InputActionMap; var actionAsset = actionMap?.asset ?? obj as InputActionAsset; for (var i = 0; i < s_InputActionUIs.Count; ++i) { var component = s_InputActionUIs[i]; var referencedAction = component.actionReference?.action; if (referencedAction == null) continue; if (referencedAction == action || referencedAction.actionMap == actionMap || referencedAction.actionMap?.asset == actionAsset) component.UpdateBindingDisplay(); } } } [Serializable] public class UpdateBindingUIEvent : UnityEvent { } }