using UnityEngine.UI; using UnityEngine.Assertions; using UnityEngine.InputSystem; #if XR_HANDS_1_1_OR_NEWER using UnityEngine.XR.Hands; #endif using UnityEngine.XR.Interaction.Toolkit.Inputs; using UnityEngine.XR.Interaction.Toolkit.Inputs.Readers; using UnityEngine.XR.Interaction.Toolkit.Inputs.Simulation; using UnityEngine.XR.Interaction.Toolkit.Utilities; namespace UnityEngine.XR.Interaction.Toolkit.Samples.DeviceSimulator { class XRInteractionSimulatorPlayModeMenu : MonoBehaviour { [Header("Menus")] [SerializeField] GameObject m_InputSelectionMenu; [SerializeField] GameObject m_ClosedInputSelectionMenu; [SerializeField] GameObject m_ControllerActionsMenu; [SerializeField] GameObject m_ClosedControllerActionsMenu; [SerializeField] GameObject m_HandActionsMenu; [SerializeField] GameObject m_ClosedHandActionsMenu; [Header("Input Readers")] [SerializeField] XRInputButtonReader m_ToggleActionMenu; [SerializeField] XRInputButtonReader m_ToggleInputSelectionMenu; [Header("Device Highlight Panels")] [SerializeField] GameObject m_HighlightFullBodyPanel; [SerializeField] GameObject m_HighlightLeftControllerPanel; [SerializeField] GameObject m_HighlightRightControllerPanel; [SerializeField] GameObject m_HighlightLeftHandPanel; [SerializeField] GameObject m_HighlightRightHandPanel; [SerializeField] GameObject m_HighlightHeadPanel; [Header("Controller Action Panels")] [SerializeField] GameObject m_ControllerActionHighlightPanel; [SerializeField] Text m_FirstControllerActionText; [SerializeField] Text m_SecondControllerActionText; [SerializeField] Text m_ThirdControllerActionText; [SerializeField] Text m_FourthControllerActionText; [SerializeField] Text m_FirstControllerBindingText; [SerializeField] Text m_SecondControllerBindingText; [SerializeField] Text m_ThirdControllerBindingText; [SerializeField] Text m_FourthControllerBindingText; [SerializeField] GameObject m_FirstControllerBindingGO; [SerializeField] GameObject m_SecondControllerBindingGO; [SerializeField] GameObject m_ThirdControllerBindingGO; [SerializeField] GameObject m_FourthControllerBindingGO; [Header("Hand Action Panels")] [SerializeField] GameObject m_HandActionHighlightPanel; [SerializeField] Text m_FirstHandActionText; [SerializeField] Text m_SecondHandActionText; [SerializeField] Text m_ThirdHandActionText; [SerializeField] Text m_FourthHandActionText; [SerializeField] Text m_FirstHandBindingText; [SerializeField] Text m_SecondHandBindingText; [SerializeField] Text m_ThirdHandBindingText; [SerializeField] Text m_FourthHandBindingText; [SerializeField] GameObject m_FirstHandBindingGO; [SerializeField] GameObject m_SecondHandBindingGO; [SerializeField] GameObject m_ThirdHandBindingGO; [SerializeField] GameObject m_FourthHandBindingGO; [Header("Hand UI")] [SerializeField] Image m_LeftHandIcon; [SerializeField] Image m_RightHandIcon; [SerializeField] GameObject m_HandPackageWarningPanel; [SerializeField] GameObject m_InputModalityManagerWarningPanel; [SerializeField] GameObject m_InputMenuHandVisualizerWarningPanel; [SerializeField] GameObject m_HandMenuHandVisualizerWarningPanel; XRInteractionSimulator m_Simulator; SimulatedDeviceLifecycleManager m_DeviceLifecycleManager; SimulatedHandExpressionManager m_HandExpressionManager; SimulatedDeviceLifecycleManager.DeviceMode m_PreviousDeviceMode = SimulatedDeviceLifecycleManager.DeviceMode.None; TargetedDevices m_PreviousTargetedDeviceInput = TargetedDevices.None; ControllerInputMode m_PreviousControllerInputMode = ControllerInputMode.None; SimulatedHandExpression m_PreviousHandExpression = new SimulatedHandExpression(); int m_ControllerActionIndex = -1; int m_HandActionIndex = -1; int m_QuickActionHandExpressionLength; int[] m_HandExpressionIndices = { -1, -1, -1, -1 }; bool m_PreviousControllerMenuState; bool m_PreviousHandMenuState; static readonly Color k_DisabledColor = new Color(0x70 / 255f, 0x70 / 255f, 0x70 / 255f); /// /// See . /// protected void Start() { #if HAS_FIND_FIRST_OBJECT_BY_TYPE var simulator = Object.FindFirstObjectByType(); #else var simulator = Object.FindObjectOfType(); #endif if (simulator != null) { m_Simulator = simulator; } else { Debug.LogError($"Could not find the XRInteractionSimulator component, disabling simulator UI.", this); gameObject.SetActive(false); return; } if (!m_Simulator.gameObject.TryGetComponent(out m_DeviceLifecycleManager)) { Debug.LogError($"Could not find SimulatedDeviceLifecycleManager component on {m_Simulator.name}, disabling simulator UI.", this); gameObject.SetActive(false); return; } if (!m_Simulator.gameObject.TryGetComponent(out m_HandExpressionManager)) { Debug.LogError($"Could not find SimulatedHandExpressionManager component on {m_Simulator.name}, disabling simulator UI.", this); gameObject.SetActive(false); return; } InitializeQuickActionPanels(); #if XR_HANDS_1_1_OR_NEWER CheckInputModalityManager(); #else m_HandPackageWarningPanel.SetActive(true); m_LeftHandIcon.color = k_DisabledColor; m_RightHandIcon.color = k_DisabledColor; #endif #if XR_HANDS_1_2_OR_NEWER if (!m_HandPackageWarningPanel.activeSelf && !m_InputModalityManagerWarningPanel.activeSelf) CheckHandVisualizer(); #endif } void CheckInputModalityManager() { if (ComponentLocatorUtility.TryFindComponent(out var inputModalityManager) && inputModalityManager.leftHand == null && inputModalityManager.rightHand == null) { m_InputModalityManagerWarningPanel.SetActive(true); m_LeftHandIcon.color = k_DisabledColor; m_RightHandIcon.color = k_DisabledColor; } } #if XR_HANDS_1_2_OR_NEWER void CheckHandVisualizer() { if (ComponentLocatorUtility.TryFindComponent(out var inputModalityManager)) { if (inputModalityManager.leftHand == null && inputModalityManager.rightHand == null) return; if ((inputModalityManager.leftHand != null && inputModalityManager.leftHand.GetComponentInChildren() != null) || (inputModalityManager.rightHand != null && inputModalityManager.rightHand.GetComponentInChildren() != null)) { return; } m_InputMenuHandVisualizerWarningPanel.SetActive(true); m_HandMenuHandVisualizerWarningPanel.SetActive(true); } } #endif void InitializeQuickActionPanels() { InitializeControllerQuickActionPanels(); InitializeHandQuickActionPanels(); } void InitializeControllerQuickActionPanels() { var inputModesLength = m_Simulator.quickActionControllerInputModes.Count; if (inputModesLength > 0) { GetControllerQuickActionNames(m_Simulator.quickActionControllerInputModes[0], m_FirstControllerActionText, m_FirstControllerBindingText); } else { m_FirstControllerActionText.gameObject.SetActive(false); m_FirstControllerBindingGO.SetActive(false); } if (inputModesLength > 1) { GetControllerQuickActionNames(m_Simulator.quickActionControllerInputModes[1], m_SecondControllerActionText, m_SecondControllerBindingText); } else { m_SecondControllerActionText.gameObject.SetActive(false); m_SecondControllerBindingGO.SetActive(false); } if (inputModesLength > 2) { GetControllerQuickActionNames(m_Simulator.quickActionControllerInputModes[2], m_ThirdControllerActionText, m_ThirdControllerBindingText); } else { m_ThirdControllerActionText.gameObject.SetActive(false); m_ThirdControllerBindingGO.SetActive(false); } if (inputModesLength > 3) { GetControllerQuickActionNames(m_Simulator.quickActionControllerInputModes[3], m_FourthControllerActionText, m_FourthControllerBindingText); } else { m_FourthControllerActionText.gameObject.SetActive(false); m_FourthControllerBindingGO.SetActive(false); } } void InitializeHandQuickActionPanels() { for (int i = 0; i < m_HandExpressionManager.simulatedHandExpressions.Count; i++) { if (m_HandExpressionManager.simulatedHandExpressions[i].isQuickAction) { if (m_QuickActionHandExpressionLength < 4) m_HandExpressionIndices[m_QuickActionHandExpressionLength] = i; m_QuickActionHandExpressionLength++; } } if (m_QuickActionHandExpressionLength > 0) { var handExpression = m_HandExpressionManager.simulatedHandExpressions[m_HandExpressionIndices[0]]; m_FirstHandActionText.text = handExpression.name; m_FirstHandBindingText.text = GetBindingString(handExpression.toggleInput); } else { m_FirstHandActionText.gameObject.SetActive(false); m_FirstHandBindingGO.SetActive(false); } if (m_QuickActionHandExpressionLength > 1) { var handExpression = m_HandExpressionManager.simulatedHandExpressions[m_HandExpressionIndices[1]]; m_SecondHandActionText.text = handExpression.name; m_SecondHandBindingText.text = GetBindingString(handExpression.toggleInput); } else { m_SecondHandActionText.gameObject.SetActive(false); m_SecondHandBindingGO.SetActive(false); } if (m_QuickActionHandExpressionLength > 2) { var handExpression = m_HandExpressionManager.simulatedHandExpressions[m_HandExpressionIndices[2]]; m_ThirdHandActionText.text = handExpression.name; m_ThirdHandBindingText.text = GetBindingString(handExpression.toggleInput); } else { m_ThirdHandActionText.gameObject.SetActive(false); m_ThirdHandBindingGO.SetActive(false); } if (m_QuickActionHandExpressionLength > 3) { var handExpression = m_HandExpressionManager.simulatedHandExpressions[m_HandExpressionIndices[3]]; m_FourthHandActionText.text = handExpression.name; m_FourthHandBindingText.text = GetBindingString(handExpression.toggleInput); } else { m_FourthHandActionText.gameObject.SetActive(false); m_FourthHandBindingGO.SetActive(false); } } void GetControllerQuickActionNames(ControllerInputMode inputMode, Text actionText, Text bindingText) { switch (inputMode) { case ControllerInputMode.None: actionText.text = "None"; bindingText.text = "?"; break; case ControllerInputMode.Trigger: actionText.text = "Trigger"; bindingText.text = GetBindingString(m_Simulator.triggerInput); break; case ControllerInputMode.Grip: actionText.text = "Grip"; bindingText.text = GetBindingString(m_Simulator.gripInput); break; case ControllerInputMode.PrimaryButton: actionText.text = "Primary"; bindingText.text = GetBindingString(m_Simulator.primaryButtonInput); break; case ControllerInputMode.SecondaryButton: actionText.text = "Secondary"; bindingText.text = GetBindingString(m_Simulator.secondaryButtonInput); break; case ControllerInputMode.Menu: actionText.text = "Menu"; bindingText.text = GetBindingString(m_Simulator.menuInput); break; case ControllerInputMode.Primary2DAxisClick: actionText.text = "Prim2DClick"; bindingText.text = GetBindingString(m_Simulator.primary2DAxisClickInput); break; case ControllerInputMode.Secondary2DAxisClick: actionText.text = "Sec2DClick"; bindingText.text = GetBindingString(m_Simulator.secondary2DAxisClickInput); break; case ControllerInputMode.Primary2DAxisTouch: actionText.text = "Prim2DTouch"; bindingText.text = GetBindingString(m_Simulator.primary2DAxisTouchInput); break; case ControllerInputMode.Secondary2DAxisTouch: actionText.text = "Sec2DTouch"; bindingText.text = GetBindingString(m_Simulator.secondary2DAxisTouchInput); break; case ControllerInputMode.PrimaryTouch: actionText.text = "PrimTouch"; bindingText.text = GetBindingString(m_Simulator.primaryTouchInput); break; case ControllerInputMode.SecondaryTouch: actionText.text = "SecTouch"; bindingText.text = GetBindingString(m_Simulator.secondaryTouchInput); break; default: Assert.IsTrue(false, $"Unhandled {nameof(inputMode)}={inputMode}."); break; } } static string GetBindingString(XRInputButtonReader reader) { if (reader == null) return string.Empty; InputAction action; switch (reader.inputSourceMode) { case XRInputButtonReader.InputSourceMode.InputActionReference: action = reader.inputActionReferencePerformed != null ? reader.inputActionReferencePerformed.action : null; break; case XRInputButtonReader.InputSourceMode.InputAction: action = reader.inputActionPerformed; break; default: action = null; break; } return action != null ? action.GetBindingDisplayString(0) : string.Empty; } /// /// See . /// protected void Update() { HandleHighlightedDevicePanels(); HandleHighlightedControllerActionPanels(); HandleHighlightedHandActionPanels(); HandleActiveMenus(); } /// /// Toggles the visibility of the input selection menu. /// public void OpenCloseInputSelectionMenu() { if (m_InputSelectionMenu.activeSelf) { m_ClosedInputSelectionMenu.SetActive(true); m_InputSelectionMenu.SetActive(false); } else { m_ClosedInputSelectionMenu.SetActive(false); m_InputSelectionMenu.SetActive(true); } } /// /// Toggles the visibility of for the controller actions menu. /// public void OpenCloseControllerActionsMenu() { if (m_ControllerActionsMenu.activeSelf) { m_ClosedControllerActionsMenu.SetActive(true); m_ControllerActionsMenu.SetActive(false); } else { m_ClosedControllerActionsMenu.SetActive(false); m_ControllerActionsMenu.SetActive(true); } } /// /// Toggles the visibility of for the hand actions menu. /// public void OpenCloseHandActionsMenu() { if (m_HandActionsMenu.activeSelf) { m_ClosedHandActionsMenu.SetActive(true); m_HandActionsMenu.SetActive(false); } else { m_ClosedHandActionsMenu.SetActive(false); m_HandActionsMenu.SetActive(true); } } void HandleActiveMenus() { if (m_PreviousDeviceMode != m_DeviceLifecycleManager.deviceMode && !m_Simulator.manipulatingFPS) { if (m_Simulator.manipulatingLeftController || m_Simulator.manipulatingRightController) { m_PreviousHandMenuState = m_HandActionsMenu.activeSelf; m_HandActionsMenu.SetActive(false); m_ClosedHandActionsMenu.SetActive(false); if (m_PreviousControllerMenuState) m_ControllerActionsMenu.SetActive(true); else m_ClosedControllerActionsMenu.SetActive(true); } else if (m_Simulator.manipulatingLeftHand || m_Simulator.manipulatingRightHand) { m_PreviousControllerMenuState = m_ControllerActionsMenu.activeSelf; m_ControllerActionsMenu.SetActive(false); m_ClosedControllerActionsMenu.SetActive(false); if (m_PreviousHandMenuState) m_HandActionsMenu.SetActive(true); else m_ClosedHandActionsMenu.SetActive(true); } m_PreviousDeviceMode = m_DeviceLifecycleManager.deviceMode; } if (m_Simulator.manipulatingFPS && m_PreviousDeviceMode != SimulatedDeviceLifecycleManager.DeviceMode.None) { if (m_PreviousDeviceMode == SimulatedDeviceLifecycleManager.DeviceMode.Controller) m_PreviousControllerMenuState = m_ControllerActionsMenu.activeSelf; else if (m_PreviousDeviceMode == SimulatedDeviceLifecycleManager.DeviceMode.Hand) m_PreviousHandMenuState = m_HandActionsMenu.activeSelf; m_HandActionsMenu.SetActive(false); m_ClosedHandActionsMenu.SetActive(false); m_ControllerActionsMenu.SetActive(false); m_ClosedControllerActionsMenu.SetActive(false); m_PreviousDeviceMode = SimulatedDeviceLifecycleManager.DeviceMode.None; } if (m_ToggleActionMenu.ReadWasPerformedThisFrame()) { if (m_Simulator.manipulatingLeftController || m_Simulator.manipulatingRightController) OpenCloseControllerActionsMenu(); else if (m_Simulator.manipulatingLeftHand || m_Simulator.manipulatingRightHand) OpenCloseHandActionsMenu(); } if (m_ToggleInputSelectionMenu.ReadWasPerformedThisFrame()) OpenCloseInputSelectionMenu(); } void HandleHighlightedDevicePanels() { if (m_Simulator.targetedDeviceInput != m_PreviousTargetedDeviceInput || m_PreviousDeviceMode != m_DeviceLifecycleManager.deviceMode) { ClearHighlightedDevicePanels(); if (m_Simulator.manipulatingFPS) { m_HighlightFullBodyPanel.SetActive(true); return; } if (m_Simulator.manipulatingLeftController) { m_HighlightLeftControllerPanel.SetActive(true); } if (m_Simulator.manipulatingRightController) { m_HighlightRightControllerPanel.SetActive(true); } if (m_Simulator.manipulatingLeftHand) { m_HighlightLeftHandPanel.SetActive(true); } if (m_Simulator.manipulatingRightHand) { m_HighlightRightHandPanel.SetActive(true); } if (m_Simulator.manipulatingHMD) { m_HighlightHeadPanel.SetActive(true); } m_PreviousTargetedDeviceInput = m_Simulator.targetedDeviceInput; } } void HandleHighlightedControllerActionPanels() { if (m_Simulator.controllerInputMode != m_PreviousControllerInputMode) { m_ControllerActionIndex = m_ControllerActionIndex < m_Simulator.quickActionControllerInputModes.Count - 1 ? m_ControllerActionIndex + 1 : 0; m_ControllerActionHighlightPanel.SetActive(true); if (m_ControllerActionIndex == 0) { m_ControllerActionHighlightPanel.transform.position = m_FirstControllerActionText.transform.position; } else if (m_ControllerActionIndex == 1) { m_ControllerActionHighlightPanel.transform.position = m_SecondControllerActionText.transform.position; } else if (m_ControllerActionIndex == 2) { m_ControllerActionHighlightPanel.transform.position = m_ThirdControllerActionText.transform.position; } else if (m_ControllerActionIndex == 3) { m_ControllerActionHighlightPanel.transform.position = m_FourthControllerActionText.transform.position; } else { m_ControllerActionHighlightPanel.SetActive(false); } m_PreviousControllerInputMode = m_Simulator.controllerInputMode; } } void HandleHighlightedHandActionPanels() { if (m_Simulator.currentHandExpression != m_PreviousHandExpression) { m_HandActionIndex = m_HandActionIndex < m_QuickActionHandExpressionLength - 1 ? m_HandActionIndex + 1 : 0; m_HandActionHighlightPanel.SetActive(true); if (m_HandActionIndex == 0) { m_HandActionHighlightPanel.transform.position = m_FirstHandActionText.transform.position; } else if (m_HandActionIndex == 1) { m_HandActionHighlightPanel.transform.position = m_SecondHandActionText.transform.position; } else if (m_HandActionIndex == 2) { m_HandActionHighlightPanel.transform.position = m_ThirdHandActionText.transform.position; } else if (m_HandActionIndex == 3) { m_HandActionHighlightPanel.transform.position = m_FourthHandActionText.transform.position; } else { m_HandActionHighlightPanel.SetActive(false); } m_PreviousHandExpression = m_Simulator.currentHandExpression; } } void ClearHighlightedDevicePanels() { m_HighlightFullBodyPanel.SetActive(false); m_HighlightLeftControllerPanel.SetActive(false); m_HighlightRightControllerPanel.SetActive(false); m_HighlightLeftHandPanel.SetActive(false); m_HighlightRightHandPanel.SetActive(false); m_HighlightHeadPanel.SetActive(false); } } }