using System; using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.Events; #if ZED_STEAM_VR using Valve.VR; #endif /// /// Extended version of ZEDControllerTracker that also checks for several inputs in a generic way. /// You can check a state with /// Used because input methods vary a lot between controllers and between SteamVR (new and old) and Oculus. /// See base class ZEDControllerTracker for any code that don't directly relate to inputs. /// public class ZEDControllerTracker_DemoInputs : ZEDControllerTracker { //#if ZED_STEAM_VR #if ZED_SVR_2_0_INPUT /// /// SteamVR action to cause a Fire event when checked or subscribed to. /// [Header("SteamVR Plugin 2.0 Bindings")] [Tooltip("SteamVR action to cause a Fire event when checked or subscribed to.")] public SteamVR_Action_Boolean fireBinding = SteamVR_Input.GetAction("Fire"); /// /// SteamVR action to cause a Click event when checked or subscribed to. /// [Tooltip("SteamVR action to cause a Click event when checked or subscribed to.")] public SteamVR_Action_Boolean clickBinding = SteamVR_Input.GetAction("Click"); /// /// SteamVR action to cause a Back event when checked or subscribed to. /// [Tooltip("SteamVR action to cause a Back event when checked or subscribed to.")] public SteamVR_Action_Boolean backBinding = SteamVR_Input.GetAction("Back"); /// /// SteamVR action to cause a Grab event when checked or subscribed to. /// [Tooltip("SteamVR action to cause a Grab event when checked or subscribed to.")] public SteamVR_Action_Boolean grabBinding = SteamVR_Input.GetAction("Grab"); /// /// SteamVR action to cause a Vector2 UI navigation event when checked or subscribed to. /// [Tooltip("SteamVR action to cause a UI navigation event when checked or subscribed to.")] public SteamVR_Action_Vector2 navigateUIBinding = SteamVR_Input.GetAction("NavigateUI"); #elif ZED_STEAM_VR /// /// Legacy SteamVR button to cause a Fire event when checked or subscribed to. /// [Header("SteamVR Legacy Input Bindings")] [Tooltip("Legacy SteamVR button to cause a Fire event when checked or subscribed to.")] public EVRButtonId fireBinding_Legacy = EVRButtonId.k_EButton_SteamVR_Trigger; /// /// Legacy SteamVR button to cause a Click event when checked or subscribed to. /// [Tooltip("Legacy SteamVR button to cause a Click event when checked or subscribed to.")] public EVRButtonId clickBinding_Legacy = EVRButtonId.k_EButton_SteamVR_Trigger; /// /// Legacy SteamVR button to cause a Back event when checked or subscribed to. /// [Tooltip("Legacy SteamVR button to cause a Back event when checked or subscribed to.")] public EVRButtonId backBinding_Legacy = EVRButtonId.k_EButton_Grip; /// /// Legacy SteamVR button to cause a Grip event when checked or subscribed to. /// [Tooltip("Legacy SteamVR button to cause a Grip event when checked or subscribed to.")] public EVRButtonId grabBinding_Legacy = EVRButtonId.k_EButton_SteamVR_Trigger; /// /// Legacy SteamVR axis to cause a Vector2 Navigate UI event when checked or subscribed to. /// [Tooltip("Legacy SteamVR button to cause a Vector2 Navigate UI event when checked or subscribed to.")] public EVRButtonId navigateUIBinding_Legacy = EVRButtonId.k_EButton_Axis0; #endif #if ZED_OCULUS /// /// Oculus Button checked to signal a Fire event when checked or subscribed to. /// [Header("Oculus Input Bindings")] [Tooltip("Oculus Button checked to signal a Fire event when checked or subscribed to")] public OVRInput.Button fireButton = OVRInput.Button.PrimaryIndexTrigger; /// /// Oculus Button checked to signal a Click event when checked or subscribed to. /// [Tooltip("Oculus Button checked to signal a Click event when checked or subscribed to")] public OVRInput.Button clickButton = OVRInput.Button.PrimaryIndexTrigger; /// /// Oculus Button checked to signal a Back event when checked or subscribed to. /// [Tooltip("Oculus Button checked to signal a Back event when checked or subscribed to")] public OVRInput.Button backButton = OVRInput.Button.Two; //Y, or B if just right controller is connected. /// /// Oculus Button checked to signal a Grab event when checked or subscribed to. /// [Tooltip("Oculus Button checked to signal a Grab event when checked or subscribed to")] public OVRInput.Button grabButton = OVRInput.Button.PrimaryHandTrigger; /// /// Oculus Button checked to signal a Vector2 UI navigation event when checked or subscribed to. /// [Tooltip("Oculus Button checked to signal a Vector2 UI navigation event when checked or subscribed to")] public OVRInput.Axis2D navigateUIAxis = OVRInput.Axis2D.PrimaryThumbstick; public static bool ovrUpdateCalledThisFrame = false; #endif /// /// Events called when the Fire button/action was just pressed. /// [Header("Events")] [Space(5)] [Tooltip("Events called when the Fire button/action was just pressed.")] public UnityEvent onFireDown; /// /// Events called when the Fire button/action was just released. /// [Tooltip("Events called when the Fire button/action was just released.")] public UnityEvent onFireUp; /// /// Events called when the Click button/action was just pressed. /// [Tooltip("Events called when the Click button/action was just pressed.")] public UnityEvent onClickDown; /// /// Events called when the Click button/action was just released. /// [Tooltip("Events called when the Click button/action was just released.")] public UnityEvent onClickUp; /// /// Events called when the Back button/action was just pressed. /// [Tooltip("Events called when the Back button/action was just pressed.")] public UnityEvent onBackDown; /// /// Events called when the Back button/action was just released. /// [Tooltip("Events called when the Back button/action was just released.")] public UnityEvent onBackUp; /// /// Events called when the Grab button/action was just pressed. /// [Tooltip("Events called when the Grab button/action was just pressed.")] public UnityEvent onGrabDown; /// /// Events called when the Grab button/action was just released. /// [Tooltip("Events called when the Grab button/action was just released.")] public UnityEvent onGrabUp; /// /// Returns if the Fire button/action matched the provided state. /// /// Whether to check if the button/action is just pressed, just released, or is being held down. public bool CheckFireButton(ControllerButtonState state) { #if ZED_SVR_2_0_INPUT return CheckSteamVRBoolActionState(fireBinding, state); #elif ZED_STEAM_VR return CheckSteamVRButtonState_Legacy(fireBinding_Legacy, state); #endif #if ZED_OCULUS return CheckOculusButtonState(fireButton, state); #endif return false; } /// /// Returns if the Click button/action matched the provided state. /// /// Whether to check if the button/action is just pressed, just released, or is being held down. public bool CheckClickButton(ControllerButtonState state) { #if ZED_SVR_2_0_INPUT return CheckSteamVRBoolActionState(clickBinding, state); #elif ZED_STEAM_VR return CheckSteamVRButtonState_Legacy(clickBinding_Legacy, state); #endif #if ZED_OCULUS return CheckOculusButtonState(clickButton, state); #endif return false; } /// /// Returns if the Back button/action matched the provided state. /// /// Whether to check if the button/action is just pressed, just released, or is being held down. public bool CheckBackButton(ControllerButtonState state) { #if ZED_SVR_2_0_INPUT return CheckSteamVRBoolActionState(backBinding, state); #elif ZED_STEAM_VR return CheckSteamVRButtonState_Legacy(backBinding_Legacy, state); #endif #if ZED_OCULUS return CheckOculusButtonState(backButton, state); #endif return false; } /// /// Returns if the Grab button/action matched the provided state. /// /// Whether to check if the button/action is just pressed, just released, or is being held down. public bool CheckGrabButton(ControllerButtonState state) { #if ZED_SVR_2_0_INPUT return CheckSteamVRBoolActionState(grabBinding, state); #elif ZED_STEAM_VR return CheckSteamVRButtonState_Legacy(grabBinding_Legacy, state); #endif #if ZED_OCULUS return CheckOculusButtonState(grabButton, state); #endif return false; } /// /// Returns the current 2D axis value of the NavigateUIAxis button/action. /// public Vector2 CheckNavigateUIAxis() { #if ZED_SVR_2_0_INPUT return CheckSteamVR2DAxis(navigateUIBinding); #elif ZED_STEAM_VR return CheckSteamVRAxis_Legacy(navigateUIBinding_Legacy); #endif #if ZED_OCULUS return CheckOculus2DAxisState(navigateUIAxis); #endif return Vector3.zero; } protected override void Awake() { base.Awake(); #if ZED_SVR_2_0_INPUT if (!useLegacySteamVRInput) { if(!SteamVR.active) SteamVR.Initialize(true); //Force SteamVR to activate, so we can use the input system. } #endif } protected override void Update() { base.Update(); if (CheckClickButton(ControllerButtonState.Down)) onClickDown.Invoke(); if (CheckClickButton(ControllerButtonState.Up)) onClickUp.Invoke(); if (CheckFireButton(ControllerButtonState.Down)) onFireDown.Invoke(); if (CheckFireButton(ControllerButtonState.Up)) onFireUp.Invoke(); if (CheckBackButton(ControllerButtonState.Down)) onBackDown.Invoke(); if (CheckBackButton(ControllerButtonState.Up)) onBackUp.Invoke(); if (CheckGrabButton(ControllerButtonState.Down)) onGrabDown.Invoke(); if (CheckGrabButton(ControllerButtonState.Up)) onGrabUp.Invoke(); } protected void LateUpdate() { #if ZED_OCULUS ovrUpdateCalledThisFrame = false; #endif } #if ZED_STEAM_VR protected override void UpdateControllerState() { base.UpdateControllerState(); //If using legacy SteamVR input, we check buttons directly from the OpenVR API. #if ZED_SVR_2_0_INPUT //If using SteamVR plugin 2.0 or higher, give the option to use legacy input. if (useLegacySteamVRInput) { openvrsystem.GetControllerState((uint)index, ref controllerstate, controllerstatesize); } #else //We're using an older SteamVR plugin, so we need to use the legacy input. openvrsystem.GetControllerState((uint)index, ref controllerstate, controllerstatesize); #endif } #endif #if ZED_OCULUS /// /// Checks the button state of a given Oculus button. /// /// Whether to check if the button/action is just pressed, just released, or is being held down. public bool CheckOculusButtonState(OVRInput.Button button, ControllerButtonState state) { if (!ovrUpdateCalledThisFrame) { OVRInput.Update(); ovrUpdateCalledThisFrame = true; } bool result = false; switch (state) { case ControllerButtonState.Down: result = OVRInput.GetDown(button, GetOculusController()); break; case ControllerButtonState.Held: result = OVRInput.Get(button, GetOculusController()); break; case ControllerButtonState.Up: result = OVRInput.GetUp(button, GetOculusController()); break; } return result; } /// /// Returns the axis of a given Oculus axis button/joystick. /// public Vector3 CheckOculus2DAxisState(OVRInput.Axis2D axis) { if (!ovrUpdateCalledThisFrame) { OVRInput.Update(); ovrUpdateCalledThisFrame = true; } return OVRInput.Get(axis, GetOculusController()); } /// /// Returns the Oculus controller script of the controller currently attached to this object. /// public OVRInput.Controller GetOculusController() { if (deviceToTrack == Devices.LeftController) return OVRInput.Controller.LTouch; else if (deviceToTrack == Devices.RightController) return OVRInput.Controller.RTouch; else return OVRInput.Controller.None; } /// /// Returns if this script is bound to an Oculus Touch controller that is currently not connected. /// For example, if it's a Right Controller but only the left is connected, it returns false. /// If not bound to a controller, returns true. /// /// private bool IsConnectedController() { if (!objecttracker) return true; //Not attached to a tracker. Return true since it doesn't depend on a controller to be alive. if (objecttracker.deviceToTrack != ZEDControllerTracker.Devices.LeftController && objecttracker.deviceToTrack != ZEDControllerTracker.Devices.RightController) return true; //Not bound to a left or right controller, so let it live. string connectedcontrollers = OVRInput.GetConnectedControllers().ToString().ToLower(); if (connectedcontrollers == "touch") return true; //Both controllers are connected, so if (objecttracker.deviceToTrack == ZEDControllerTracker.Devices.LeftController && connectedcontrollers == "ltouch") return true; //Left controller only. if (objecttracker.deviceToTrack == ZEDControllerTracker.Devices.RightController && connectedcontrollers == "rtouch") return true; //Right controller only. return false; } #endif //#if ZED_STEAM_VR #if ZED_SVR_2_0_INPUT /// /// Checks the button state of a given SteamVR boolean action. /// /// Whether to check if the button/action is just pressed, just released, or is being held down. protected bool CheckSteamVRBoolActionState(SteamVR_Action_Boolean action, ControllerButtonState buttonstate) { switch(buttonstate) { case ControllerButtonState.Down: return action.GetLastStateDown(GetSteamVRInputSource()); case ControllerButtonState.Held: return action.GetLastState(GetSteamVRInputSource()); case ControllerButtonState.Up: return action.GetLastStateUp(GetSteamVRInputSource()); default: return false; } } /// /// Returns the axis of a given SteamVR 2D action. /// protected Vector2 CheckSteamVR2DAxis(SteamVR_Action_Vector2 action) { return action.GetAxis(GetSteamVRInputSource()); } public SteamVR_Input_Sources GetSteamVRInputSource() { if (deviceToTrack == Devices.LeftController) return SteamVR_Input_Sources.LeftHand; else if (deviceToTrack == Devices.RightController) return SteamVR_Input_Sources.RightHand; else return SteamVR_Input_Sources.Camera; } #elif ZED_STEAM_VR public bool CheckSteamVRButtonState_Legacy(EVRButtonId button, ControllerButtonState state) { switch(state) { case ControllerButtonState.Down: return GetVRButtonDown_Legacy(button); case ControllerButtonState.Held: default: return GetVRButtonHeld_Legacy(button); case ControllerButtonState.Up: return GetVRButtonReleased_Legacy(button); } } /// /// Returns if the VR controller button with the given ID was pressed for the first time this frame. /// /// EVR ID of the button as listed in OpenVR. public bool GetVRButtonDown_Legacy(EVRButtonId buttonid) { if (openvrsystem == null) return false; //If VR isn't running, we can't check. bool washeldlastupdate = (lastcontrollerstate.ulButtonPressed & (1UL << (int)buttonid)) > 0L; if (washeldlastupdate == true) return false; //If the key was held last check, it can't be pressed for the first time now. bool isheld = (controllerstate.ulButtonPressed & (1UL << (int)buttonid)) > 0L; return isheld; //If we got here, we know it was not down last frame. } /// /// Returns if the VR controller button with the given ID is currently held. /// /// EVR ID of the button as listed in OpenVR. public bool GetVRButtonHeld_Legacy(EVRButtonId buttonid) { if (openvrsystem == null) return false; //If VR isn't running, we can't check. bool isheld = (controllerstate.ulButtonPressed & (1UL << (int)buttonid)) > 0L; return isheld; } /// /// Returns if the VR controller button with the given ID was held last frame, but released this frame. /// /// EVR ID of the button as listed in OpenVR. public bool GetVRButtonReleased_Legacy(EVRButtonId buttonid) { if (openvrsystem == null) return false; //If VR isn't running, we can't check. bool washeldlastupdate = (lastcontrollerstate.ulButtonPressed & (1UL << (int)buttonid)) > 0L; if (washeldlastupdate == false) return false; //If the key was held last check, it can't be released now. bool isheld = (controllerstate.ulButtonPressed & (1UL << (int)buttonid)) > 0L; return !isheld; //If we got here, we know it was not up last frame. } /// /// Returns the value of an axis with the provided ID. /// Note that for single-value axes, the relevant value will be the X in the returned Vector2 (the Y is unused). /// /// public Vector2 CheckSteamVRAxis_Legacy(EVRButtonId buttonid) { //Convert the EVRButtonID enum to the axis number and check if it's not an axis. uint axis = (uint)buttonid - (uint)EVRButtonId.k_EButton_Axis0; if (axis < 0 || axis > 4) { Debug.LogError("Called GetAxis with " + buttonid + ", which is not an axis."); return Vector2.zero; } switch (axis) { case 0: return new Vector2(controllerstate.rAxis0.x, controllerstate.rAxis0.y); case 1: return new Vector2(controllerstate.rAxis1.x, controllerstate.rAxis1.y); case 2: return new Vector2(controllerstate.rAxis2.x, controllerstate.rAxis2.y); case 3: return new Vector2(controllerstate.rAxis3.x, controllerstate.rAxis3.y); case 4: return new Vector2(controllerstate.rAxis4.x, controllerstate.rAxis4.y); default: return Vector2.zero; } } #endif } /// /// List of possible button states, used to check inputs. /// public enum ControllerButtonState { /// /// The button was pressed this frame. /// Down, /// /// The button is being held down - it doesn't matter which frame it started being held. /// Held, /// /// The button was released this frame. /// Up }