//========= Copyright 2016-2018, HTC Corporation. All rights reserved. =========== using HTC.UnityPlugin.Utility; using System; using System.Collections.Generic; using UnityEngine; using UnityEngine.Events; namespace HTC.UnityPlugin.Vive { // Use this helper component to combine multiple Vive inputs into one virtual button public class ViveInputVirtualButton : MonoBehaviour { public enum InputsOperatorEnum { Or, And, } [Serializable] public class InputEntry { public ViveRoleProperty viveRole = ViveRoleProperty.New(HandRole.RightHand); [CustomOrderedEnum] public ControllerButton button = ControllerButton.Trigger; } [Serializable] public struct OutputEventArgs { public ViveInputVirtualButton senderObj; public ButtonEventType eventType; } [Serializable] public class OutputEvent : UnityEvent { } [SerializeField] private InputsOperatorEnum m_combineInputsOperator = InputsOperatorEnum.Or; [SerializeField] private List m_inputs = new List(); [SerializeField] private OutputEvent m_onVirtualPress = new OutputEvent(); [SerializeField] private OutputEvent m_onVirtualClick = new OutputEvent(); [SerializeField] private OutputEvent m_onVirtualPressDown = new OutputEvent(); [SerializeField] private OutputEvent m_onVirtualPressUp = new OutputEvent(); [SerializeField] private List m_toggleGameObjectOnVirtualClick = new List(); [SerializeField] private List m_toggleComponentOnVirtualClick = new List(); private bool m_isUpdating; private int m_updatedFrameCount; private bool m_prevPressState = false; private bool m_currPressState = false; private float m_lastPressDownTime = 0f; private int m_clickCount = 0; [Obsolete("Use Behaviour.enable instead.")] public bool active { get { return enabled; } set { enabled = value; } } public InputsOperatorEnum combineInputsOperator { get { return m_combineInputsOperator; } } public List inputs { get { return m_inputs; } } public List toggleGameObjectOnVirtualClick { get { return m_toggleGameObjectOnVirtualClick; } } public List toggleComponentOnVirtualClick { get { return m_toggleComponentOnVirtualClick; } } public OutputEvent onPress { get { return m_onVirtualPress; } } public OutputEvent onClick { get { return m_onVirtualClick; } } public OutputEvent onPressDown { get { return m_onVirtualPressDown; } } public OutputEvent onPressUp { get { return m_onVirtualPressUp; } } private bool isPress { get { return m_currPressState; } } private bool isDown { get { return !m_prevPressState && m_currPressState; } } private bool isUp { get { return m_prevPressState && !m_currPressState; } } #if UNITY_EDITOR private void Reset() { m_inputs.Add(new InputEntry() { viveRole = ViveRoleProperty.New(HandRole.RightHand), button = ControllerButton.Trigger, }); } #endif private void UpdateState() { if (!ChangeProp.Set(ref m_updatedFrameCount, Time.frameCount)) { return; } m_prevPressState = m_currPressState; m_currPressState = false; if (m_inputs.Count == 0) { return; } switch (m_combineInputsOperator) { case InputsOperatorEnum.Or: m_currPressState = false; for (int i = 0, imax = m_inputs.Count; i < imax; ++i) { if (ViveInput.GetPress(m_inputs[i].viveRole, m_inputs[i].button)) { m_currPressState = true; break; } } break; case InputsOperatorEnum.And: m_currPressState = true; for (int i = 0, imax = m_inputs.Count; i < imax; ++i) { if (!ViveInput.GetPress(m_inputs[i].viveRole, m_inputs[i].button)) { m_currPressState = false; break; } } break; } } private void Update() { m_isUpdating = true; UpdateState(); var timeNow = Time.unscaledTime; // handle events if (isPress) { if (isDown) { // record click count if (timeNow - m_lastPressDownTime < ViveInput.clickInterval) { ++m_clickCount; } else { m_clickCount = 1; } // record press down time m_lastPressDownTime = timeNow; // PressDown event if (m_onVirtualPressDown != null) { m_onVirtualPressDown.Invoke(new OutputEventArgs() { senderObj = this, eventType = ButtonEventType.Down, }); } } // Press event if (m_onVirtualPress != null) { m_onVirtualPress.Invoke(new OutputEventArgs() { senderObj = this, eventType = ButtonEventType.Press, }); } } else if (isUp) { // PressUp event if (m_onVirtualPressUp != null) { m_onVirtualPressUp.Invoke(new OutputEventArgs() { senderObj = this, eventType = ButtonEventType.Up, }); } if (timeNow - m_lastPressDownTime < ViveInput.clickInterval) { for (int i = m_toggleGameObjectOnVirtualClick.Count - 1; i >= 0; --i) { if (m_toggleGameObjectOnVirtualClick[i] != null) { m_toggleGameObjectOnVirtualClick[i].SetActive(!m_toggleGameObjectOnVirtualClick[i].activeSelf); } } for (int i = m_toggleComponentOnVirtualClick.Count - 1; i >= 0; --i) { if (m_toggleComponentOnVirtualClick[i] != null) { m_toggleComponentOnVirtualClick[i].enabled = !m_toggleComponentOnVirtualClick[i].enabled; } } // Click event if (m_onVirtualClick != null) { m_onVirtualClick.Invoke(new OutputEventArgs() { senderObj = this, eventType = ButtonEventType.Click, }); } } } if (!isActiveAndEnabled) { InternalDisable(); } m_isUpdating = false; } private void OnDisable() { if (!m_isUpdating) { InternalDisable(); } } private void InternalDisable() { var timeNow = Time.unscaledTime; // clean up m_prevPressState = m_currPressState; m_currPressState = false; if (isUp) { // PressUp event if (m_onVirtualPressUp != null) { m_onVirtualPressUp.Invoke(new OutputEventArgs() { senderObj = this, eventType = ButtonEventType.Up, }); } if (timeNow - m_lastPressDownTime < ViveInput.clickInterval) { for (int i = m_toggleGameObjectOnVirtualClick.Count - 1; i >= 0; --i) { if (m_toggleGameObjectOnVirtualClick[i] != null) { m_toggleGameObjectOnVirtualClick[i].SetActive(!m_toggleGameObjectOnVirtualClick[i].activeSelf); } } for (int i = m_toggleComponentOnVirtualClick.Count - 1; i >= 0; --i) { if (m_toggleComponentOnVirtualClick[i] != null) { m_toggleComponentOnVirtualClick[i].enabled = !m_toggleComponentOnVirtualClick[i].enabled; } } // Click event if (m_onVirtualClick != null) { m_onVirtualClick.Invoke(new OutputEventArgs() { senderObj = this, eventType = ButtonEventType.Click, }); } } } m_prevPressState = false; } public bool GetVirtualPress() { UpdateState(); return isPress; } public bool GetVirtualPressDown() { UpdateState(); return isDown; } public bool GetVirtualPressUp() { UpdateState(); return isUp; } public int GetVirtualClickCount() { UpdateState(); return m_clickCount; } public float GetLastVirtualPressDownTime() { UpdateState(); return m_lastPressDownTime; } } }