// SteamVR Controller|SDK_SteamVR|004 namespace VRTK { #if VRTK_DEFINE_SDK_STEAMVR using UnityEngine; using System.Collections.Generic; using System.Text; using Valve.VR; using System; #if !VRTK_DEFINE_STEAMVR_PLUGIN_1_2_2_OR_NEWER using System; using System.Reflection; #endif #endif /// /// The SteamVR Controller SDK script provides a bridge to SDK methods that deal with the input devices. /// [SDK_Description(typeof(SDK_SteamVRSystem))] public class SDK_SteamVRController #if VRTK_DEFINE_SDK_STEAMVR : SDK_BaseController #else : SDK_FallbackController #endif { #if VRTK_DEFINE_SDK_STEAMVR protected SteamVR_TrackedObject cachedLeftTrackedObject; protected SteamVR_TrackedObject cachedRightTrackedObject; protected Dictionary cachedTrackedObjectsByGameObject = new Dictionary(); protected Dictionary cachedTrackedObjectsByIndex = new Dictionary(); protected Dictionary axisTouchStates = new Dictionary(); protected Dictionary axisTouchFidelity = new Dictionary() { { EVRButtonId.k_EButton_SteamVR_Touchpad, 0f }, { EVRButtonId.k_EButton_Axis2, 0.25f } }; protected ushort maxHapticVibration = 3999; #if !VRTK_DEFINE_STEAMVR_PLUGIN_1_2_2_OR_NEWER /// /// This method is called just after unloading the VRTK_SDKSetup that's using this SDK. /// /// The SDK Setup which is using this SDK. public override void OnAfterSetupUnload(VRTK_SDKSetup setup) { base.OnAfterSetupUnload(setup); SteamVR_ControllerManager controllerManager = setup.actualLeftController.transform.parent.GetComponent(); FieldInfo connectedField = typeof(SteamVR_ControllerManager).GetField( "connected", BindingFlags.NonPublic | BindingFlags.Instance ); if (connectedField == null) { return; } bool[] connected = (bool[])connectedField.GetValue(controllerManager); Array.Clear(connected, 0, connected.Length); connectedField.SetValue(controllerManager, connected); } #endif /// /// The ProcessUpdate method enables an SDK to run logic for every Unity Update /// /// The reference for the controller. /// A dictionary of generic options that can be used to within the update. public override void ProcessUpdate(VRTK_ControllerReference controllerReference, Dictionary options) { } /// /// The ProcessFixedUpdate method enables an SDK to run logic for every Unity FixedUpdate /// /// The reference for the controller. /// A dictionary of generic options that can be used to within the fixed update. public override void ProcessFixedUpdate(VRTK_ControllerReference controllerReference, Dictionary options) { } /// /// The GetCurrentControllerType method returns the current used ControllerType based on the SDK and headset being used. /// /// The reference to the controller to get type of. /// The ControllerType based on the SDK and headset being used. public override ControllerType GetCurrentControllerType(VRTK_ControllerReference controllerReference = null) { uint checkIndex = uint.MaxValue; if (VRTK_ControllerReference.IsValid(controllerReference)) { checkIndex = controllerReference.index; } else { VRTK_ControllerReference leftHand = VRTK_ControllerReference.GetControllerReference(GetControllerLeftHand()); VRTK_ControllerReference rightHand = VRTK_ControllerReference.GetControllerReference(GetControllerRightHand()); if (!VRTK_ControllerReference.IsValid(leftHand) && !VRTK_ControllerReference.IsValid(rightHand)) { return ControllerType.Undefined; } checkIndex = (VRTK_ControllerReference.IsValid(rightHand) ? rightHand.index : leftHand.index); } ControllerType returnType = ControllerType.Undefined; if (checkIndex < uint.MaxValue) { string controllerModelNumber = GetModelNumber(checkIndex); returnType = MatchControllerTypeByString(controllerModelNumber); } return returnType; } /// /// The GetControllerDefaultColliderPath returns the path to the prefab that contains the collider objects for the default controller of this SDK. /// /// The controller hand to check for /// A path to the resource that contains the collider GameObject. public override string GetControllerDefaultColliderPath(ControllerHand hand) { switch (GetCurrentControllerType()) { case ControllerType.SteamVR_ViveWand: return "ControllerColliders/HTCVive"; case ControllerType.SteamVR_OculusTouch: return (hand == ControllerHand.Left ? "ControllerColliders/SteamVROculusTouch_Left" : "ControllerColliders/SteamVROculusTouch_Right"); case ControllerType.SteamVR_ValveKnuckles: return (hand == ControllerHand.Left ? "ControllerColliders/ValveKnuckles_Left" : "ControllerColliders/ValveKnuckles_Right"); case ControllerType.SteamVR_WindowsMRController: return (hand == ControllerHand.Left ? "ControllerColliders/SteamVRWindowsMRController_Left" : "ControllerColliders/SteamVRWindowsMRController_Right"); default: return "ControllerColliders/Fallback"; } } /// /// The GetControllerElementPath returns the path to the game object that the given controller element for the given hand resides in. /// /// The controller element to look up. /// The controller hand to look up. /// Whether to get the initial path or the full path to the element. /// A string containing the path to the game object that the controller element resides in. public override string GetControllerElementPath(ControllerElements element, ControllerHand hand, bool fullPath = false) { string suffix = (fullPath ? "/attach" : ""); switch (element) { case ControllerElements.AttachPoint: return "tip/attach"; case ControllerElements.Trigger: return "trigger" + suffix; case ControllerElements.GripLeft: return GetControllerGripPath(hand, suffix, ControllerHand.Left); case ControllerElements.GripRight: return GetControllerGripPath(hand, suffix, ControllerHand.Right); case ControllerElements.Touchpad: return GetControllerTouchpadPath(hand, suffix); case ControllerElements.ButtonOne: return GetControllerButtonOnePath(hand, suffix); case ControllerElements.ButtonTwo: return GetControllerButtonTwoPath(hand, suffix); case ControllerElements.SystemMenu: return GetControllerSystemMenuPath(hand, suffix); case ControllerElements.StartMenu: return GetControllerStartMenuPath(hand, suffix); case ControllerElements.Body: return "body"; } return ""; } /// /// The GetControllerIndex method returns the index of the given controller. /// /// The GameObject containing the controller. /// The index of the given controller. public override uint GetControllerIndex(GameObject controller) { SteamVR_TrackedObject trackedObject = GetTrackedObject(controller); return (trackedObject != null ? (uint)trackedObject.index : uint.MaxValue); } /// /// The GetControllerByIndex method returns the GameObject of a controller with a specific index. /// /// The index of the controller to find. /// If true it will return the actual controller, if false it will return the script alias controller GameObject. /// The GameObject of the controller public override GameObject GetControllerByIndex(uint index, bool actual = false) { SetTrackedControllerCaches(); if (index < uint.MaxValue) { VRTK_SDKManager sdkManager = VRTK_SDKManager.instance; if (sdkManager != null) { if (cachedLeftTrackedObject != null && (uint)cachedLeftTrackedObject.index == index) { return (actual ? sdkManager.loadedSetup.actualLeftController : sdkManager.scriptAliasLeftController); } if (cachedRightTrackedObject != null && (uint)cachedRightTrackedObject.index == index) { return (actual ? sdkManager.loadedSetup.actualRightController : sdkManager.scriptAliasRightController); } } SteamVR_TrackedObject currentTrackedObjectByIndex = VRTK_SharedMethods.GetDictionaryValue(cachedTrackedObjectsByIndex, index); if (currentTrackedObjectByIndex != null) { return currentTrackedObjectByIndex.gameObject; } } return null; } /// /// The GetControllerOrigin method returns the origin of the given controller. /// /// The reference to the controller to retrieve the origin from. /// A Transform containing the origin of the controller. public override Transform GetControllerOrigin(VRTK_ControllerReference controllerReference) { SteamVR_TrackedObject trackedObject = GetTrackedObject(controllerReference.actual); if (trackedObject != null) { return (trackedObject.origin != null ? trackedObject.origin : trackedObject.transform.parent); } return null; } /// /// The GenerateControllerPointerOrigin method can create a custom pointer origin Transform to represent the pointer position and forward. /// /// The GameObject that the origin will become parent of. If it is a controller then it will also be used to determine the hand if required. /// A generated Transform that contains the custom pointer origin. [System.Obsolete("GenerateControllerPointerOrigin has been deprecated and will be removed in a future version of VRTK.")] public override Transform GenerateControllerPointerOrigin(GameObject parent) { switch (GetCurrentControllerType()) { case ControllerType.SteamVR_OculusTouch: if (IsControllerLeftHand(parent) || IsControllerRightHand(parent)) { GameObject generatedOrigin = new GameObject(parent.name + " _CustomPointerOrigin"); generatedOrigin.transform.SetParent(parent.transform); generatedOrigin.transform.localEulerAngles = new Vector3(40f, 0f, 0f); generatedOrigin.transform.localPosition = new Vector3((IsControllerLeftHand(parent) ? 0.0081f : -0.0081f), -0.0273f, -0.0311f); return generatedOrigin.transform; } break; } return null; } /// /// The GetControllerLeftHand method returns the GameObject containing the representation of the left hand controller. /// /// If true it will return the actual controller, if false it will return the script alias controller GameObject. /// The GameObject containing the left hand controller. public override GameObject GetControllerLeftHand(bool actual = false) { GameObject controller = GetSDKManagerControllerLeftHand(actual); if (controller == null && actual) { controller = VRTK_SharedMethods.FindEvenInactiveGameObject("Controller (left)", true); } return controller; } /// /// The GetControllerRightHand method returns the GameObject containing the representation of the right hand controller. /// /// If true it will return the actual controller, if false it will return the script alias controller GameObject. /// The GameObject containing the right hand controller. public override GameObject GetControllerRightHand(bool actual = false) { GameObject controller = GetSDKManagerControllerRightHand(actual); if (controller == null && actual) { controller = VRTK_SharedMethods.FindEvenInactiveGameObject("Controller (right)", true); } return controller; } /// /// The IsControllerLeftHand/1 method is used to check if the given controller is the the left hand controller. /// /// The GameObject to check. /// Returns true if the given controller is the left hand controller. public override bool IsControllerLeftHand(GameObject controller) { return CheckActualOrScriptAliasControllerIsLeftHand(controller); } /// /// The IsControllerRightHand/1 method is used to check if the given controller is the the right hand controller. /// /// The GameObject to check. /// Returns true if the given controller is the right hand controller. public override bool IsControllerRightHand(GameObject controller) { return CheckActualOrScriptAliasControllerIsRightHand(controller); } /// /// The IsControllerLeftHand/2 method is used to check if the given controller is the the left hand controller. /// /// The GameObject to check. /// If true it will check the actual controller, if false it will check the script alias controller. /// Returns true if the given controller is the left hand controller. public override bool IsControllerLeftHand(GameObject controller, bool actual) { return CheckControllerLeftHand(controller, actual); } /// /// The IsControllerRightHand/2 method is used to check if the given controller is the the right hand controller. /// /// The GameObject to check. /// If true it will check the actual controller, if false it will check the script alias controller. /// Returns true if the given controller is the right hand controller. public override bool IsControllerRightHand(GameObject controller, bool actual) { return CheckControllerRightHand(controller, actual); } /// /// The WaitForControllerModel method determines whether the controller model for the given hand requires waiting to load in on scene start. /// /// The hand to determine if the controller model will be ready for. /// Returns true if the controller model requires loading in at runtime and therefore needs waiting for. Returns false if the controller model will be available at start. public override bool WaitForControllerModel(ControllerHand hand) { return ShouldWaitForControllerModel(hand, false); } /// /// The GetControllerModel method returns the model alias for the given GameObject. /// /// The GameObject to get the model alias for. /// The GameObject that has the model alias within it. public override GameObject GetControllerModel(GameObject controller) { return GetControllerModelFromController(controller); } /// /// The GetControllerModel method returns the model alias for the given controller hand. /// /// The hand enum of which controller model to retrieve. /// The GameObject that has the model alias within it. public override GameObject GetControllerModel(ControllerHand hand) { GameObject model = GetSDKManagerControllerModelForHand(hand); if (model == null) { switch (hand) { case ControllerHand.Left: model = (defaultSDKLeftControllerModel != null ? defaultSDKLeftControllerModel.gameObject : null); break; case ControllerHand.Right: model = (defaultSDKRightControllerModel != null ? defaultSDKRightControllerModel.gameObject : null); break; } } return model; } /// /// The GetControllerRenderModel method gets the game object that contains the given controller's render model. /// /// The reference to the controller to check. /// A GameObject containing the object that has a render model for the controller. public override GameObject GetControllerRenderModel(VRTK_ControllerReference controllerReference) { SteamVR_RenderModel renderModel = controllerReference.actual.GetComponentInChildren(); return (renderModel != null ? renderModel.gameObject : null); } /// /// The SetControllerRenderModelWheel method sets the state of the scroll wheel on the controller render model. /// /// The GameObject containing the controller render model. /// If true and the render model has a scroll wheen then it will be displayed, if false then the scroll wheel will be hidden. public override void SetControllerRenderModelWheel(GameObject renderModel, bool state) { SteamVR_RenderModel model = renderModel.GetComponent(); if (model != null) { model.controllerModeState.bScrollWheelVisible = state; } } /// /// The HapticPulse/2 method is used to initiate a simple haptic pulse on the tracked object of the given controller reference. /// /// The reference to the tracked object to initiate the haptic pulse on. /// The intensity of the rumble of the controller motor. `0` to `1`. public override void HapticPulse(VRTK_ControllerReference controllerReference, float strength = 0.5f) { uint index = VRTK_ControllerReference.GetRealIndex(controllerReference); if (index < OpenVR.k_unTrackedDeviceIndexInvalid) { float convertedStrength = maxHapticVibration * strength; SteamVR_Controller.Device device = SteamVR_Controller.Input((int)index); device.TriggerHapticPulse((ushort)convertedStrength, EVRButtonId.k_EButton_Axis0); } } /// /// The HapticPulse/2 method is used to initiate a haptic pulse based on an audio clip on the tracked object of the given controller reference. /// /// The reference to the tracked object to initiate the haptic pulse on. /// The audio clip to use for the haptic pattern. public override bool HapticPulse(VRTK_ControllerReference controllerReference, AudioClip clip) { //SteamVR doesn't support audio haptics so return false to do a fallback. return false; } /// /// The GetHapticModifiers method is used to return modifiers for the duration and interval if the SDK handles it slightly differently. /// /// An SDK_ControllerHapticModifiers object with a given `durationModifier` and an `intervalModifier`. public override SDK_ControllerHapticModifiers GetHapticModifiers() { SDK_ControllerHapticModifiers modifiers = new SDK_ControllerHapticModifiers(); modifiers.maxHapticVibration = maxHapticVibration; return modifiers; } /// /// The GetVelocity method is used to determine the current velocity of the tracked object on the given controller reference. /// /// The reference to the tracked object to check for. /// A Vector3 containing the current velocity of the tracked object. public override Vector3 GetVelocity(VRTK_ControllerReference controllerReference) { uint index = VRTK_ControllerReference.GetRealIndex(controllerReference); if (index <= (uint)SteamVR_TrackedObject.EIndex.Hmd || index >= OpenVR.k_unTrackedDeviceIndexInvalid) { return Vector3.zero; } SteamVR_Controller.Device device = SteamVR_Controller.Input((int)index); return device.velocity; } /// /// The GetAngularVelocity method is used to determine the current angular velocity of the tracked object on the given controller reference. /// /// The reference to the tracked object to check for. /// A Vector3 containing the current angular velocity of the tracked object. public override Vector3 GetAngularVelocity(VRTK_ControllerReference controllerReference) { uint index = VRTK_ControllerReference.GetRealIndex(controllerReference); if (index <= (uint)SteamVR_TrackedObject.EIndex.Hmd || index >= OpenVR.k_unTrackedDeviceIndexInvalid) { return Vector3.zero; } SteamVR_Controller.Device device = SteamVR_Controller.Input((int)index); return device.angularVelocity; } /// /// The IsTouchpadStatic method is used to determine if the touchpad is currently not being moved. /// /// /// /// /// Returns true if the touchpad is not currently being touched or moved. public override bool IsTouchpadStatic(bool isTouched, Vector2 currentAxisValues, Vector2 previousAxisValues, int compareFidelity) { return (!isTouched || VRTK_SharedMethods.Vector2ShallowCompare(currentAxisValues, previousAxisValues, compareFidelity)); } /// /// The GetButtonAxis method retrieves the current X/Y axis values for the given button type on the given controller reference. /// /// The type of button to check for the axis on. /// The reference to the controller to check the button axis on. /// A Vector2 of the X/Y values of the button axis. If no axis values exist for the given button, then a Vector2.Zero is returned. public override Vector2 GetButtonAxis(ButtonTypes buttonType, VRTK_ControllerReference controllerReference) { uint index = VRTK_ControllerReference.GetRealIndex(controllerReference); if (index >= OpenVR.k_unTrackedDeviceIndexInvalid) { return Vector2.zero; } SteamVR_Controller.Device device = SteamVR_Controller.Input((int)index); switch (buttonType) { case ButtonTypes.Touchpad: return device.GetAxis(); case ButtonTypes.TouchpadTwo: return (VRTK_DeviceFinder.GetCurrentControllerType() == ControllerType.SteamVR_WindowsMRController ? device.GetAxis(EVRButtonId.k_EButton_Axis2) : Vector2.zero); case ButtonTypes.Trigger: return device.GetAxis(EVRButtonId.k_EButton_SteamVR_Trigger); case ButtonTypes.Grip: switch (GetCurrentControllerType()) { case ControllerType.SteamVR_OculusTouch: case ControllerType.SteamVR_ValveKnuckles: return device.GetAxis(EVRButtonId.k_EButton_Axis2); default: return new Vector2((GetControllerButtonState(buttonType, ButtonPressTypes.Press, controllerReference) ? 1f : 0f), 0f); } } return Vector2.zero; } /// /// The GetButtonSenseAxis method retrieves the current sense axis value for the given button type on the given controller reference. /// /// The type of button to check for the sense axis on. /// The reference to the controller to check the sense axis on. /// The current sense axis value. public override float GetButtonSenseAxis(ButtonTypes buttonType, VRTK_ControllerReference controllerReference) { uint index = VRTK_ControllerReference.GetRealIndex(controllerReference); if (index >= OpenVR.k_unTrackedDeviceIndexInvalid) { return 0f; } SteamVR_Controller.Device device = SteamVR_Controller.Input((int)index); switch (buttonType) { case ButtonTypes.Trigger: return device.GetAxis(EVRButtonId.k_EButton_Axis3).x; case ButtonTypes.Grip: return device.GetAxis(EVRButtonId.k_EButton_Axis2).x; case ButtonTypes.MiddleFinger: return device.GetAxis(EVRButtonId.k_EButton_Axis3).y; case ButtonTypes.RingFinger: return device.GetAxis(EVRButtonId.k_EButton_Axis4).x; case ButtonTypes.PinkyFinger: return device.GetAxis(EVRButtonId.k_EButton_Axis4).y; } return 0f; } /// /// The GetButtonHairlineDelta method is used to get the difference between the current button press and the previous frame button press. /// /// The type of button to get the hairline delta for. /// The reference to the controller to get the hairline delta for. /// The delta between the button presses. public override float GetButtonHairlineDelta(ButtonTypes buttonType, VRTK_ControllerReference controllerReference) { uint index = VRTK_ControllerReference.GetRealIndex(controllerReference); if (index >= OpenVR.k_unTrackedDeviceIndexInvalid) { return 0f; } SteamVR_Controller.Device device = SteamVR_Controller.Input((int)index); return (buttonType == ButtonTypes.Trigger || buttonType == ButtonTypes.TriggerHairline ? device.hairTriggerDelta : 0f); } /// /// The GetControllerButtonState method is used to determine if the given controller button for the given press type on the given controller reference is currently taking place. /// /// The type of button to check for the state of. /// The button state to check for. /// The reference to the controller to check the button state on. /// Returns true if the given button is in the state of the given press type on the given controller reference. public override bool GetControllerButtonState(ButtonTypes buttonType, ButtonPressTypes pressType, VRTK_ControllerReference controllerReference) { uint index = VRTK_ControllerReference.GetRealIndex(controllerReference); if (index >= OpenVR.k_unTrackedDeviceIndexInvalid) { return false; } switch (buttonType) { case ButtonTypes.Trigger: return IsButtonPressed(index, pressType, SteamVR_Controller.ButtonMask.Trigger); case ButtonTypes.TriggerHairline: if (pressType == ButtonPressTypes.PressDown) { return SteamVR_Controller.Input((int)index).GetHairTriggerDown(); } else if (pressType == ButtonPressTypes.PressUp) { return SteamVR_Controller.Input((int)index).GetHairTriggerUp(); } break; case ButtonTypes.Grip: return IsButtonPressed(index, pressType, SteamVR_Controller.ButtonMask.Grip); case ButtonTypes.Touchpad: return IsButtonPressed(index, pressType, SteamVR_Controller.ButtonMask.Touchpad); case ButtonTypes.ButtonOne: return IsButtonPressed(index, pressType, (1ul << (int)EVRButtonId.k_EButton_A)); case ButtonTypes.ButtonTwo: return IsButtonPressed(index, pressType, SteamVR_Controller.ButtonMask.ApplicationMenu); case ButtonTypes.StartMenu: return IsButtonPressed(index, pressType, SteamVR_Controller.ButtonMask.System); case ButtonTypes.TouchpadTwo: return (VRTK_DeviceFinder.GetCurrentControllerType() == ControllerType.SteamVR_WindowsMRController ? CheckAxisTouch(index, pressType, EVRButtonId.k_EButton_Axis2) : false); } return false; } protected virtual void Awake() { defaultSDKLeftControllerModel = (GetControllerLeftHand(true) != null ? GetControllerLeftHand(true).transform.Find("Model") : null); defaultSDKRightControllerModel = (GetControllerRightHand(true) != null ? GetControllerRightHand(true).transform.Find("Model") : null); #if VRTK_DEFINE_STEAMVR_PLUGIN_1_1_1_OR_OLDER SteamVR_Utils.Event.Listen("TrackedDeviceRoleChanged", OnTrackedDeviceRoleChanged); SteamVR_Utils.Event.Listen("render_model_loaded", OnRenderModelLoaded); #elif VRTK_DEFINE_STEAMVR_PLUGIN_1_2_0 SteamVR_Events.System("TrackedDeviceRoleChanged").Listen(OnTrackedDeviceRoleChanged); SteamVR_Events.RenderModelLoaded.Listen(OnRenderModelLoaded); #elif VRTK_DEFINE_STEAMVR_PLUGIN_1_2_1_OR_NEWER SteamVR_Events.System(EVREventType.VREvent_TrackedDeviceRoleChanged).Listen(OnTrackedDeviceRoleChanged); SteamVR_Events.RenderModelLoaded.Listen(OnRenderModelLoaded); #endif SetTrackedControllerCaches(true); } protected virtual void OnTrackedDeviceRoleChanged(T ignoredArgument) { SetTrackedControllerCaches(true); } protected virtual void OnRenderModelLoaded(SteamVR_RenderModel givenControllerRenderModel, bool successfullyLoaded) { if (successfullyLoaded) { SteamVR_RenderModel leftControllerRenderModel = (GetControllerLeftHand(true) != null ? GetControllerLeftHand(true).GetComponentInChildren() : null); SteamVR_RenderModel rightControllerRenderModel = (GetControllerRightHand(true) != null ? GetControllerRightHand(true).GetComponentInChildren() : null); ControllerHand selectedHand = ControllerHand.None; if (givenControllerRenderModel == leftControllerRenderModel) { selectedHand = ControllerHand.Left; } else if (givenControllerRenderModel == rightControllerRenderModel) { selectedHand = ControllerHand.Right; } OnControllerModelReady(selectedHand, VRTK_ControllerReference.GetControllerReference((uint)givenControllerRenderModel.index)); } } protected virtual void SetTrackedControllerCaches(bool forceRefresh = false) { if (forceRefresh) { cachedLeftTrackedObject = null; cachedRightTrackedObject = null; cachedTrackedObjectsByGameObject.Clear(); cachedTrackedObjectsByIndex.Clear(); } VRTK_SDKManager sdkManager = VRTK_SDKManager.instance; if (sdkManager != null) { if (cachedLeftTrackedObject == null && sdkManager.loadedSetup.actualLeftController) { cachedLeftTrackedObject = sdkManager.loadedSetup.actualLeftController.GetComponent(); } if (cachedRightTrackedObject == null && sdkManager.loadedSetup.actualRightController) { cachedRightTrackedObject = sdkManager.loadedSetup.actualRightController.GetComponent(); } } } protected virtual SteamVR_TrackedObject GetTrackedObject(GameObject controller) { SetTrackedControllerCaches(); if (IsControllerLeftHand(controller)) { return cachedLeftTrackedObject; } else if (IsControllerRightHand(controller)) { return cachedRightTrackedObject; } if (controller == null) { return null; } SteamVR_TrackedObject currentTrackedObjectByGameObject = VRTK_SharedMethods.GetDictionaryValue(cachedTrackedObjectsByGameObject, controller); if (currentTrackedObjectByGameObject != null) { return currentTrackedObjectByGameObject; } else { SteamVR_TrackedObject trackedObject = controller.GetComponent(); if (trackedObject != null) { VRTK_SharedMethods.AddDictionaryValue(cachedTrackedObjectsByGameObject, controller, trackedObject, true); VRTK_SharedMethods.AddDictionaryValue(cachedTrackedObjectsByIndex, (uint)trackedObject.index, trackedObject, true); } return trackedObject; } } protected virtual bool IsButtonPressed(uint index, ButtonPressTypes type, ulong button) { if (index >= OpenVR.k_unTrackedDeviceIndexInvalid) { return false; } SteamVR_Controller.Device device = SteamVR_Controller.Input((int)index); switch (type) { case ButtonPressTypes.Press: return device.GetPress(button); case ButtonPressTypes.PressDown: return device.GetPressDown(button); case ButtonPressTypes.PressUp: return device.GetPressUp(button); case ButtonPressTypes.Touch: return device.GetTouch(button); case ButtonPressTypes.TouchDown: return device.GetTouchDown(button); case ButtonPressTypes.TouchUp: return device.GetTouchUp(button); } return false; } protected virtual bool CheckAxisTouch(uint index, ButtonPressTypes type, EVRButtonId axisId) { if (index >= OpenVR.k_unTrackedDeviceIndexInvalid) { return false; } SteamVR_Controller.Device device = SteamVR_Controller.Input((int)index); Vector2 axisValue = device.GetAxis(axisId); bool currentAxisPressState = VRTK_SharedMethods.GetDictionaryValue(axisTouchStates, axisId, false, true); float axisFidelity = VRTK_SharedMethods.GetDictionaryValue(axisTouchFidelity, axisId); switch (type) { case ButtonPressTypes.Touch: return (!VRTK_SharedMethods.Vector3ShallowCompare(axisValue, Vector2.zero, axisFidelity)); case ButtonPressTypes.TouchDown: if (!currentAxisPressState && !VRTK_SharedMethods.Vector3ShallowCompare(axisValue, Vector2.zero, axisFidelity)) { VRTK_SharedMethods.AddDictionaryValue(axisTouchStates, axisId, true, true); return true; } return false; case ButtonPressTypes.TouchUp: if (currentAxisPressState && VRTK_SharedMethods.Vector3ShallowCompare(axisValue, Vector2.zero, axisFidelity)) { VRTK_SharedMethods.AddDictionaryValue(axisTouchStates, axisId, false, true); return true; } return false; } return false; } protected virtual string GetControllerGripPath(ControllerHand hand, string suffix, ControllerHand forceHand) { switch (GetCurrentControllerType()) { case ControllerType.SteamVR_ViveWand: return (forceHand == ControllerHand.Left ? "lgrip" : "rgrip") + suffix; case ControllerType.SteamVR_ValveKnuckles: return "button_b" + suffix; case ControllerType.SteamVR_OculusTouch: return "grip" + suffix; case ControllerType.SteamVR_WindowsMRController: return "handgrip" + suffix; } return null; } protected virtual string GetControllerTouchpadPath(ControllerHand hand, string suffix) { switch (GetCurrentControllerType()) { case ControllerType.SteamVR_ViveWand: case ControllerType.SteamVR_ValveKnuckles: case ControllerType.SteamVR_WindowsMRController: return "trackpad" + suffix; case ControllerType.SteamVR_OculusTouch: return "thumbstick" + suffix; } return null; } protected virtual string GetControllerButtonOnePath(ControllerHand hand, string suffix) { switch (GetCurrentControllerType()) { case ControllerType.SteamVR_OculusTouch: return (hand == ControllerHand.Left ? "x_button" : "a_button") + suffix; } return null; } protected virtual string GetControllerButtonTwoPath(ControllerHand hand, string suffix) { switch (GetCurrentControllerType()) { case ControllerType.SteamVR_ViveWand: case ControllerType.SteamVR_ValveKnuckles: case ControllerType.SteamVR_WindowsMRController: return "button" + suffix; case ControllerType.SteamVR_OculusTouch: return (hand == ControllerHand.Left ? "y_button" : "b_button") + suffix; } return null; } protected virtual string GetControllerSystemMenuPath(ControllerHand hand, string suffix) { switch (GetCurrentControllerType()) { case ControllerType.SteamVR_ViveWand: case ControllerType.SteamVR_ValveKnuckles: return "sys_button" + suffix; case ControllerType.SteamVR_OculusTouch: return (hand == ControllerHand.Left ? "enter_button" : "home_button") + suffix; } return null; } protected virtual string GetControllerStartMenuPath(ControllerHand hand, string suffix) { switch (GetCurrentControllerType()) { case ControllerType.SteamVR_OculusTouch: return (hand == ControllerHand.Left ? "enter_button" : "home_button") + suffix; } return null; } protected virtual ControllerType MatchControllerTypeByString(string controllerModelNumber) { //Direct string matches for speed switch (controllerModelNumber) { case "vive controller mv": case "vive controller dvt": return ControllerType.SteamVR_ViveWand; case "knuckles ev1.3": return ControllerType.SteamVR_ValveKnuckles; case "oculus rift cv1 (right controller)": case "oculus rift cv1 (left controller)": return ControllerType.SteamVR_OculusTouch; case "windowsmr: 0x045e/0x065b/0/2": return ControllerType.SteamVR_WindowsMRController; } return FuzzyMatchControllerTypeByString(controllerModelNumber); } protected virtual ControllerType FuzzyMatchControllerTypeByString(string controllerModelNumber) { //Fallback to fuzzy matching if (controllerModelNumber.Contains("knuckles")) { return ControllerType.SteamVR_ValveKnuckles; } else if (controllerModelNumber.Contains("vive")) { return ControllerType.SteamVR_ViveWand; } else if (controllerModelNumber.Contains("oculus rift")) { return ControllerType.SteamVR_OculusTouch; } else if (controllerModelNumber.Contains("windowsmr")) { return ControllerType.SteamVR_WindowsMRController; } return ControllerType.Undefined; } protected virtual string GetModelNumber(uint index) { return (SteamVR.instance != null ? SteamVR.instance.GetStringProperty(ETrackedDeviceProperty.Prop_ModelNumber_String, index) : "").ToLower(); } #endif } }