// -------------------------------------------------------------------------------------------------------------------- // // Copyright (c) VRMADA, All rights reserved. // // -------------------------------------------------------------------------------------------------------------------- using System.Collections.Generic; using UltimateXR.Core; using UltimateXR.Core.Components; using UltimateXR.Core.Settings; using UltimateXR.UI.UnityInputModule.Controls; using UnityEngine; using UnityEngine.UI; #pragma warning disable 0414 namespace UltimateXR.UI.Helpers.Keyboard { /// /// UI component for a keyboard key. /// [ExecuteInEditMode] public class UxrKeyboardKeyUI : UxrComponent { #region Inspector Properties/Serialized Fields [SerializeField] private UxrKeyType _keyType; [SerializeField] private UxrKeyLayoutType _layout; [SerializeField] private string _printShift; [SerializeField] private string _printNoShift; [SerializeField] private string _printAltGr; [SerializeField] private string _forceLabel; [SerializeField] private Text _singleLayoutValue; [SerializeField] private Text _multipleLayoutValueTopLeft; [SerializeField] private Text _multipleLayoutValueBottomLeft; [SerializeField] private Text _multipleLayoutValueBottomRight; [SerializeField] private List _toggleSymbols; // Hidden in the custom inspector [SerializeField] private bool _nameDirty; #endregion #region Public Types & Data /// /// Gets the key type. /// public UxrKeyType KeyType => _keyType; /// /// Gets the layout use for the labels on the key. /// public UxrKeyLayoutType KeyLayoutType => _layout; /// /// Gets the character used when the key has a single label. /// public char SingleLayoutValue => _singleLayoutValue != null && _singleLayoutValue.text.Length > 0 ? _singleLayoutValue.text[0] : '?'; /// /// Gets the character used in the top left corner when the key has multiple labels, because it supports combination /// with shift and alt gr. /// public char MultipleLayoutValueTopLeft => _multipleLayoutValueTopLeft != null && _multipleLayoutValueTopLeft.text.Length > 0 ? _multipleLayoutValueTopLeft.text[0] : '?'; /// /// Gets the character used in the bottom left corner when the key has multiple labels, because it supports combination /// with shift and alt gr. /// public char MultipleLayoutValueBottomLeft => _multipleLayoutValueBottomLeft != null && _multipleLayoutValueBottomLeft.text.Length > 0 ? _multipleLayoutValueBottomLeft.text[0] : '?'; /// /// Gets the character used in the bottom right corner when the key has multiple labels, because it supports /// combination with shift and alt gr. /// public char MultipleLayoutValueBottomRight => _multipleLayoutValueBottomRight != null ? _multipleLayoutValueBottomRight.text[0] : '?'; /// /// Gets whether the key supports combination with shift and alt gr, and has a character specified for the bottom /// right. /// public bool HasMultipleLayoutValueBottomRight => _multipleLayoutValueBottomRight != null && _multipleLayoutValueBottomRight.text.Length > 0; /// /// Gets whether the key is a letter. /// public bool IsLetterKey => KeyType == UxrKeyType.Printable && char.IsLetter(SingleLayoutValue); /// /// Gets the current symbols group selected, for a key that has a role of /// . /// public UxrToggleSymbolsPage CurrentToggleSymbolsPage => KeyType == UxrKeyType.ToggleSymbols && _toggleSymbols != null && _currentSymbolsIndex < _toggleSymbols.Count ? _toggleSymbols[_currentSymbolsIndex] : null; /// /// Gets the next symbols group, for a key that has a role of /// , that would be selected if pressed. /// public UxrToggleSymbolsPage NextToggleSymbolsPage => KeyType == UxrKeyType.ToggleSymbols && _toggleSymbols != null && _toggleSymbols.Count > 0 ? _toggleSymbols[(_currentSymbolsIndex + 1) % _toggleSymbols.Count] : null; /// /// Gets the component the key belongs to. /// public UxrKeyboardUI Keyboard { get { if (_keyboard == null) { _keyboard = GetComponentInParent(); } return _keyboard; } } /// /// Gets the component for the key. /// public UxrControlInput ControlInput { get; private set; } /// /// Gets or sets whether the key can be interacted with. /// public bool Enabled { get => ControlInput.Enabled; set => ControlInput.Enabled = value; } /// /// Gets or sets the string that, if non-empty, will override the label content on the key. /// public string ForceLabel { get => _forceLabel; set { _forceLabel = value; SetupKeyLabels(); } } #endregion #region Public Methods /// /// Gets the character that would be printed if the key was pressed. /// /// Whether shift is pressed /// Whether alt gr is pressed /// Character that would be printed public char GetSingleLayoutValueNoForceLabel(bool shift, bool altGr) { if (shift && !string.IsNullOrEmpty(_printShift)) { return _printShift[0]; } if (altGr && !string.IsNullOrEmpty(_printAltGr)) { return _printAltGr[0]; } return !string.IsNullOrEmpty(_printNoShift) ? _printNoShift[0] : ' '; } /// /// Updates the label on the key. /// /// Whether shift is enabled public void UpdateLetterKeyLabel(bool shiftEnabled) { if (KeyType == UxrKeyType.Printable && _singleLayoutValue) { _singleLayoutValue.text = shiftEnabled ? _printShift : _printNoShift; } } /// /// Sets up the toggle symbol entries. /// /// Entries public void SetupToggleSymbolsPages(List entries) { if (_keyType == UxrKeyType.ToggleSymbols) { _toggleSymbols = entries; _currentSymbolsIndex = 0; if (entries != null) { for (int i = 0; i < entries.Count; ++i) { entries[i].KeysRoot.SetActive(i == 0); } } SetupKeyLabels(); } } /// /// Sets the default symbols as the ones currently active. /// public void SetDefaultSymbols() { if (_keyType == UxrKeyType.ToggleSymbols && _toggleSymbols != null && _toggleSymbols.Count > 0) { _currentSymbolsIndex = 0; for (int i = 0; i < _toggleSymbols.Count; ++i) { _toggleSymbols[i].KeysRoot.SetActive(i == _currentSymbolsIndex); } SetupKeyLabels(); } } /// /// Toggles to the next symbols. /// public void ToggleSymbols() { if (_keyType == UxrKeyType.ToggleSymbols && _toggleSymbols != null && _toggleSymbols.Count > 0) { _currentSymbolsIndex = (_currentSymbolsIndex + 1) % _toggleSymbols.Count; for (int i = 0; i < _toggleSymbols.Count; ++i) { _toggleSymbols[i].KeysRoot.SetActive(i == _currentSymbolsIndex); } SetupKeyLabels(); } } #endregion #region Unity /// /// Initializes the component. /// protected override void Awake() { base.Awake(); if (_keyboard == null) { _keyboard = GetComponentInParent(); } if (_keyboard == null && !Application.isEditor) { if (UxrGlobalSettings.Instance.LogLevelUI >= UxrLogLevel.Warnings) { Debug.LogWarning($"{UxrConstants.UiModule} {nameof(UxrKeyboardUI)} component not found in parent hierarchy of key " + name); } } ControlInput = GetComponent(); if (ControlInput == null) { if (UxrGlobalSettings.Instance.LogLevelUI >= UxrLogLevel.Errors) { Debug.LogError($"{UxrConstants.UiModule} Keyboard key {name} has no control input"); } } SetupKeyLabels(); if (_keyboard && Application.isPlaying) { _keyboard.RegisterKey(this); } } /// /// Called when the component is destroyed. /// protected override void OnDestroy() { base.OnDestroy(); if (_keyboard && Application.isPlaying) { _keyboard.UnregisterKey(this); } } #if UNITY_EDITOR /// /// Updates the labels and the GameObject's name in editor-mode depending on the labels that are set in the inspector. /// private void Update() { if (Application.isEditor) { if (!Application.isPlaying) { SetupKeyLabels(); } if (_nameDirty) { UpdateName(); } } } #endif #endregion #region Private Methods /// /// Sets up the labels on the key based on the current values in the inspector. /// private void SetupKeyLabels() { if (_singleLayoutValue) { _singleLayoutValue.text = ""; } if (_multipleLayoutValueTopLeft) { _multipleLayoutValueTopLeft.text = ""; } if (_multipleLayoutValueBottomLeft) { _multipleLayoutValueBottomLeft.text = ""; } if (_multipleLayoutValueBottomRight) { _multipleLayoutValueBottomRight.text = ""; } if (!string.IsNullOrEmpty(_forceLabel) && _singleLayoutValue) { _singleLayoutValue.text = _forceLabel; return; } if (_keyType == UxrKeyType.Printable) { if (_layout == UxrKeyLayoutType.SingleChar) { if (_singleLayoutValue) { _singleLayoutValue.text = _printShift.Length > 0 && (_keyboard.ShiftEnabled || _keyboard.CapsLockEnabled) ? _printShift : _printNoShift; } } else { if (_multipleLayoutValueTopLeft) { _multipleLayoutValueTopLeft.text = _printShift; } if (_multipleLayoutValueBottomLeft) { _multipleLayoutValueBottomLeft.text = _printNoShift; } if (_multipleLayoutValueBottomRight) { _multipleLayoutValueBottomRight.text = _printAltGr; } } } else if (_keyType == UxrKeyType.Tab) { if (_singleLayoutValue) { _singleLayoutValue.text = "Tab"; } } else if (_keyType == UxrKeyType.Shift) { if (_singleLayoutValue) { _singleLayoutValue.text = "Shift"; } } else if (_keyType == UxrKeyType.CapsLock) { if (_singleLayoutValue) { _singleLayoutValue.text = "Caps Lock"; } } else if (_keyType == UxrKeyType.Control) { if (_singleLayoutValue) { _singleLayoutValue.text = "Ctrl"; } } else if (_keyType == UxrKeyType.Alt) { if (_singleLayoutValue) { _singleLayoutValue.text = "Alt"; } } else if (_keyType == UxrKeyType.AltGr) { if (_singleLayoutValue) { _singleLayoutValue.text = "Alt Gr"; } } else if (_keyType == UxrKeyType.Enter) { if (_singleLayoutValue) { _singleLayoutValue.text = "Enter"; } } else if (_keyType == UxrKeyType.Backspace) { if (_singleLayoutValue) { _singleLayoutValue.text = "Backspace"; } } else if (_keyType == UxrKeyType.Del) { if (_singleLayoutValue) { _singleLayoutValue.text = "Del"; } } else if (_keyType == UxrKeyType.ToggleSymbols) { _singleLayoutValue.text = NextToggleSymbolsPage != null ? NextToggleSymbolsPage.Label : CurrentToggleSymbolsPage != null ? CurrentToggleSymbolsPage.Label : string.Empty; } else if (_keyType == UxrKeyType.Escape) { if (_singleLayoutValue) { _singleLayoutValue.text = "Esc"; } } } /// /// Updates the GameObject name based on the labels set up in the inspector. /// private void UpdateName() { if (_keyType == UxrKeyType.Printable) { if (_singleLayoutValue && _layout == UxrKeyLayoutType.SingleChar) { if (_singleLayoutValue.text == " ") { name = "Key Space"; } else { name = "Key " + _singleLayoutValue.text; } } else { name = "Key" + (!string.IsNullOrEmpty(_printShift) ? " " + _printShift : "") + (!string.IsNullOrEmpty(_printNoShift) ? " " + _printNoShift : "") + (!string.IsNullOrEmpty(_printAltGr) ? " " + _printAltGr : ""); } } else if (_keyType == UxrKeyType.ToggleSymbols) { name = "Key Toggle Symbols"; } else if (_keyType == UxrKeyType.ToggleViewPassword) { name = "Key Toggle View Password"; } else if (_singleLayoutValue) { name = $"Key {_singleLayoutValue.text}"; } _nameDirty = false; } #endregion #region Private Types & Data private UxrKeyboardUI _keyboard; private int _currentSymbolsIndex; #endregion } } #pragma warning restore 0414