using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
#if UNITY_2019_3_OR_NEWER
using UnityEngine.XR;
#endif
#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
/// !! On v2.0, Steam VR action bindings must be done in the inspector ro once steam.initialize(true) has been called !!
///
/// 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
public static bool ovrUpdateCalledThisFrame = false;
#if UNITY_2019_3_OR_NEWER
///
/// Input Button checked to signal a Fire event when checked or subscribed to.
///
[Header("Input Bindings")]
[Tooltip("Input Button checked to signal a Fire event when checked or subscribed to")]
public InputFeatureUsage fireButton = CommonUsages.triggerButton;
///
/// Input Button checked to signal a Click event when checked or subscribed to.
///
[Tooltip("Input Button checked to signal a Click event when checked or subscribed to")]
public InputFeatureUsage clickButton = CommonUsages.triggerButton;
///
/// Input Button checked to signal a Back event when checked or subscribed to.
///
[Tooltip("Input Button checked to signal a Back event when checked or subscribed to")]
public InputFeatureUsage backButton = CommonUsages.secondaryButton; //Y, or B if just right controller is connected.
///
/// Input Button checked to signal a Grab event when checked or subscribed to.
///
[Tooltip("Input Button checked to signal a Grab event when checked or subscribed to")]
public InputFeatureUsage grabButton = CommonUsages.gripButton;
///
/// Input Button checked to signal a Vector2 UI navigation event when checked or subscribed to.
///
[Tooltip("Input Button checked to signal a Vector2 UI navigation event when checked or subscribed to")]
public InputFeatureUsage navigateUIAxis = CommonUsages.primary2DAxis;
private bool fireActive = false;
private bool clickActive = false;
private bool backActive = false;
private bool grabActive = false;
#else
///
/// 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;
#endif
#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
#if UNITY_2019_3_OR_NEWER
return CheckButtonState(fireButton, state, fireActive);
#else
return CheckOculusButtonState(fireButton, state);
#endif
#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
#if UNITY_2019_3_OR_NEWER
return CheckButtonState(clickButton, state, clickActive);
#else
return CheckOculusButtonState(clickButton, state);
#endif
#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
#if UNITY_2019_3_OR_NEWER
return CheckButtonState(backButton, state, backActive);
#else
return CheckOculusButtonState(backButton, state);
#endif
#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
#if UNITY_2019_3_OR_NEWER
return CheckButtonState(grabButton, state, grabActive);
#else
return CheckOculusButtonState(grabButton, state);
#endif
#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
#if UNITY_2019_3_OR_NEWER
return Check2DAxisState(navigateUIAxis);
#else
return CheckOculus2DAxisState(navigateUIAxis);
#endif
#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.
//script binding example
//fireBinding = SteamVR_Input._default.inActions.GrabGrip; //...
}
#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;
}
#if UNITY_2019_3_OR_NEWER
public bool CheckButtonState(InputFeatureUsage button, ControllerButtonState state, bool isActive){
bool down = false;
bool up = false;
InputDevice device = new InputDevice();
if (deviceToTrack == Devices.LeftController)
device = InputDevices.GetDeviceAtXRNode(XRNode.LeftHand);
else device = InputDevices.GetDeviceAtXRNode(XRNode.RightHand);
ProcessInputDeviceButton(device, button, ref isActive,
() => // On Button Down
{
down = true;
},
() => // On Button Up
{
up = true;
});
if (state == ControllerButtonState.Down) return down;
if (state == ControllerButtonState.Up) return up;
else return false;
}
public Vector2 Check2DAxisState(InputFeatureUsage navigateUIAxis){
InputDevice device = new InputDevice();
if (deviceToTrack == Devices.LeftController)
device = InputDevices.GetDeviceAtXRNode(XRNode.LeftHand);
else device = InputDevices.GetDeviceAtXRNode(XRNode.RightHand);
Vector2 result = Vector2.zero;
if (device.TryGetFeatureValue(navigateUIAxis, out Vector2 value))
result = value;
return result;
}
private void ProcessInputDeviceButton(InputDevice inputDevice, InputFeatureUsage button, ref bool _wasPressedDownPreviousFrame, Action onButtonDown = null, Action onButtonUp = null, Action onButtonHeld = null)
{
if (inputDevice.TryGetFeatureValue(button, out bool isPressed) && isPressed)
{
if (!_wasPressedDownPreviousFrame) // // this is button down
{
onButtonDown?.Invoke();
}
_wasPressedDownPreviousFrame = true;
onButtonHeld?.Invoke();
}
else
{
if (_wasPressedDownPreviousFrame) // this is button up
{
onButtonUp?.Invoke();
}
_wasPressedDownPreviousFrame = false;
}
}
#endif
///
/// 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;
}
#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.Any;
}
#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
}