//======= Copyright (c) Valve Corporation, All rights reserved. ===============
using UnityEngine;
using Valve.VR;
using System.IO;
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Linq;
using Valve.Newtonsoft.Json;
using System.Text;
namespace Valve.VR
{
public partial class SteamVR_Input
{
public const string defaultInputGameObjectName = "[SteamVR Input]";
private const string localizationKeyName = "localization";
public static string actionsFilePath;
/// True if the actions file has been initialized
public static bool fileInitialized = false;
/// True if the steamvr input system initialization process has completed successfully
public static bool initialized = false;
/// True if the preinitialization process (setting up dictionaries, etc) has completed successfully
public static bool preInitialized = false;
/// The serialized version of the actions file we're currently using (only used in editor)
public static SteamVR_Input_ActionFile actionFile;
/// The hash of the current action file on disk
public static string actionFileHash;
/// An event that fires when the non visual actions (everything except poses / skeletons) have been updated
public static event Action onNonVisualActionsUpdated;
/// An event that fires when the pose actions have been updated
public static event PosesUpdatedHandler onPosesUpdated;
public delegate void PosesUpdatedHandler(bool skipSendingEvents);
/// An event that fires when the skeleton actions have been updated
public static event SkeletonsUpdatedHandler onSkeletonsUpdated;
public delegate void SkeletonsUpdatedHandler(bool skipSendingEvents);
protected static bool initializing = false;
protected static int startupFrame = 0;
public static bool isStartupFrame
{
get
{
return Time.frameCount >= (startupFrame-1) && Time.frameCount <= (startupFrame+1);
}
}
#region array accessors
/// An array of all action sets
public static SteamVR_ActionSet[] actionSets;
/// An array of all actions (in all action sets)
public static SteamVR_Action[] actions;
/// An array of all input actions
public static ISteamVR_Action_In[] actionsIn;
/// An array of all output actions (haptic)
public static ISteamVR_Action_Out[] actionsOut;
/// An array of all the boolean actions
public static SteamVR_Action_Boolean[] actionsBoolean;
/// An array of all the single actions
public static SteamVR_Action_Single[] actionsSingle;
/// An array of all the vector2 actions
public static SteamVR_Action_Vector2[] actionsVector2;
/// An array of all the vector3 actions
public static SteamVR_Action_Vector3[] actionsVector3;
/// An array of all the pose actions
public static SteamVR_Action_Pose[] actionsPose;
/// An array of all the skeleton actions
public static SteamVR_Action_Skeleton[] actionsSkeleton;
/// An array of all the vibration (haptic) actions
public static SteamVR_Action_Vibration[] actionsVibration;
/// An array of all the input actions that are not pose or skeleton actions (boolean, single, vector2, vector3)
public static ISteamVR_Action_In[] actionsNonPoseNonSkeletonIn;
protected static Dictionary actionSetsByPath = new Dictionary();
protected static Dictionary actionSetsByPathLowered = new Dictionary();
protected static Dictionary actionsByPath = new Dictionary();
protected static Dictionary actionsByPathLowered = new Dictionary();
protected static Dictionary actionSetsByPathCache = new Dictionary();
protected static Dictionary actionsByPathCache = new Dictionary();
protected static Dictionary actionsByNameCache = new Dictionary();
protected static Dictionary actionSetsByNameCache = new Dictionary();
#endregion
static SteamVR_Input()
{
#if !UNITY_EDITOR
//If you want a single frame of performance increase on application start and have already generated your actions uncomment the following two lines
//SteamVR_Actions.Preinitialize();
//return;
#endif
FindPreinitializeMethod();
}
public static void ForcePreinitialize()
{
FindPreinitializeMethod();
}
private static void FindPreinitializeMethod()
{
Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
for (int assemblyIndex = 0; assemblyIndex < assemblies.Length; assemblyIndex++)
{
Assembly assembly = assemblies[assemblyIndex];
Type type = assembly.GetType(SteamVR_Input_Generator_Names.fullActionsClassName);
if (type != null)
{
MethodInfo preinitMethodInfo = type.GetMethod(SteamVR_Input_Generator_Names.preinitializeMethodName);
if (preinitMethodInfo != null)
{
preinitMethodInfo.Invoke(null, null);
return;
}
}
}
}
///
/// Get all the handles for actions and action sets.
/// Initialize our dictionaries of action / action set names.
/// Setup the tracking space universe origin
///
public static void Initialize(bool force = false)
{
if (initialized == true && force == false)
return;
#if UNITY_EDITOR
CheckSetup();
if (IsOpeningSetup())
return;
#endif
//Debug.Log("[SteamVR] Initializing SteamVR input...");
initializing = true;
startupFrame = Time.frameCount;
SteamVR_ActionSet_Manager.Initialize();
SteamVR_Input_Source.Initialize();
for (int actionIndex = 0; actionIndex < actions.Length; actionIndex++)
{
SteamVR_Action action = actions[actionIndex];
action.Initialize(true);
}
for (int actionSetIndex = 0; actionSetIndex < actionSets.Length; actionSetIndex++)
{
SteamVR_ActionSet set = actionSets[actionSetIndex];
set.Initialize(true);
}
if (SteamVR_Settings.instance.activateFirstActionSetOnStart)
{
if (actionSets.Length > 0)
actionSets[0].Activate();
else
{
Debug.LogError("[SteamVR] No action sets to activate.");
}
}
SteamVR_Action_Pose.SetTrackingUniverseOrigin(SteamVR_Settings.instance.trackingSpace);
initialized = true;
initializing = false;
//Debug.Log("[SteamVR] Input initialization complete.");
}
public static void PreinitializeFinishActionSets()
{
for (int actionSetIndex = 0; actionSetIndex < actionSets.Length; actionSetIndex++)
{
SteamVR_ActionSet actionSet = actionSets[actionSetIndex];
actionSet.FinishPreInitialize();
}
}
public static void PreinitializeActionSetDictionaries()
{
actionSetsByPath.Clear();
actionSetsByPathLowered.Clear();
actionSetsByPathCache.Clear();
for (int actionSetIndex = 0; actionSetIndex < actionSets.Length; actionSetIndex++)
{
SteamVR_ActionSet actionSet = actionSets[actionSetIndex];
actionSetsByPath.Add(actionSet.fullPath, actionSet);
actionSetsByPathLowered.Add(actionSet.fullPath.ToLower(), actionSet);
}
}
public static void PreinitializeActionDictionaries()
{
actionsByPath.Clear();
actionsByPathLowered.Clear();
actionsByPathCache.Clear();
for (int actionIndex = 0; actionIndex < actions.Length; actionIndex++)
{
SteamVR_Action action = actions[actionIndex];
actionsByPath.Add(action.fullPath, action);
actionsByPathLowered.Add(action.fullPath.ToLower(), action);
}
}
/// Gets called by SteamVR_Behaviour every Update and updates actions if the steamvr settings are configured to update then.
public static void Update()
{
if (initialized == false || isStartupFrame)
return;
if (SteamVR.settings.IsInputUpdateMode(SteamVR_UpdateModes.OnUpdate))
{
UpdateNonVisualActions();
}
if (SteamVR.settings.IsPoseUpdateMode(SteamVR_UpdateModes.OnUpdate))
{
UpdateVisualActions();
}
}
///
/// Gets called by SteamVR_Behaviour every LateUpdate and updates actions if the steamvr settings are configured to update then.
/// Also updates skeletons regardless of settings are configured to so we can account for animations on the skeletons.
///
public static void LateUpdate()
{
if (initialized == false || isStartupFrame)
return;
if (SteamVR.settings.IsInputUpdateMode(SteamVR_UpdateModes.OnLateUpdate))
{
UpdateNonVisualActions();
}
if (SteamVR.settings.IsPoseUpdateMode(SteamVR_UpdateModes.OnLateUpdate))
{
//update poses and skeleton
UpdateVisualActions();
}
else
{
//force skeleton update so animation blending sticks
UpdateSkeletonActions(true);
}
}
/// Gets called by SteamVR_Behaviour every FixedUpdate and updates actions if the steamvr settings are configured to update then.
public static void FixedUpdate()
{
if (initialized == false || isStartupFrame)
return;
if (SteamVR.settings.IsInputUpdateMode(SteamVR_UpdateModes.OnFixedUpdate))
{
UpdateNonVisualActions();
}
if (SteamVR.settings.IsPoseUpdateMode(SteamVR_UpdateModes.OnFixedUpdate))
{
UpdateVisualActions();
}
}
/// Gets called by SteamVR_Behaviour every OnPreCull and updates actions if the steamvr settings are configured to update then.
public static void OnPreCull()
{
if (initialized == false || isStartupFrame)
return;
if (SteamVR.settings.IsInputUpdateMode(SteamVR_UpdateModes.OnPreCull))
{
UpdateNonVisualActions();
}
if (SteamVR.settings.IsPoseUpdateMode(SteamVR_UpdateModes.OnPreCull))
{
UpdateVisualActions();
}
}
///
/// Updates the states of all the visual actions (pose / skeleton)
///
/// Controls whether or not events are fired from this update call
public static void UpdateVisualActions(bool skipStateAndEventUpdates = false)
{
if (initialized == false)
return;
SteamVR_ActionSet_Manager.UpdateActionStates();
UpdatePoseActions(skipStateAndEventUpdates);
UpdateSkeletonActions(skipStateAndEventUpdates);
}
///
/// Updates the states of all the pose actions
///
/// Controls whether or not events are fired from this update call
public static void UpdatePoseActions(bool skipSendingEvents = false)
{
if (initialized == false)
return;
for (int actionIndex = 0; actionIndex < actionsPose.Length; actionIndex++)
{
SteamVR_Action_Pose action = actionsPose[actionIndex];
action.UpdateValues(skipSendingEvents);
}
if (onPosesUpdated != null)
onPosesUpdated(false);
}
///
/// Updates the states of all the skeleton actions
///
/// Controls whether or not events are fired from this update call
public static void UpdateSkeletonActions(bool skipSendingEvents = false)
{
if (initialized == false)
return;
for (int actionIndex = 0; actionIndex < actionsSkeleton.Length; actionIndex++)
{
SteamVR_Action_Skeleton action = actionsSkeleton[actionIndex];
action.UpdateValue(skipSendingEvents);
}
if (onSkeletonsUpdated != null)
onSkeletonsUpdated(skipSendingEvents);
}
///
/// Updates the states of all the non visual actions (boolean, single, vector2, vector3)
///
public static void UpdateNonVisualActions()
{
if (initialized == false)
return;
SteamVR_ActionSet_Manager.UpdateActionStates();
for (int actionIndex = 0; actionIndex < actionsNonPoseNonSkeletonIn.Length; actionIndex++)
{
ISteamVR_Action_In action = actionsNonPoseNonSkeletonIn[actionIndex];
action.UpdateValues();
}
if (onNonVisualActionsUpdated != null)
onNonVisualActionsUpdated();
}
#region String accessor helpers
#region action accessors
///
/// Get an action's action data by the full path to that action. Action paths are in the format /actions/[actionSet]/[direction]/[actionName]
///
/// The type of action you're expecting to get back
/// The full path to the action you want (Action paths are in the format /actions/[actionSet]/[direction]/[actionName])
/// case sensitive searches are faster
public static T GetActionDataFromPath(string path, bool caseSensitive = false) where T : SteamVR_Action_Source_Map
{
SteamVR_Action action = GetBaseActionFromPath(path, caseSensitive);
if (action != null)
{
T actionData = (T)action.GetSourceMap();
return actionData;
}
return null;
}
///
/// Get an action set's data by the full path to that action. Action set paths are in the format /actions/[actionSet]
///
/// The full path to the action you want (Action set paths are in the format /actions/[actionSet])
/// case sensitive searches are faster
public static SteamVR_ActionSet_Data GetActionSetDataFromPath(string path, bool caseSensitive = false)
{
SteamVR_ActionSet actionSet = GetActionSetFromPath(path, caseSensitive);
if (actionSet != null)
{
return actionSet.GetActionSetData();
}
return null;
}
///
/// Get an action by the full path to that action. Action paths are in the format /actions/[actionSet]/[direction]/[actionName]
///
/// The type of action you're expecting to get back
/// The full path to the action you want (Action paths are in the format /actions/[actionSet]/[direction]/[actionName])
/// case sensitive searches are faster
public static T GetActionFromPath(string path, bool caseSensitive = false, bool returnNulls = false) where T : SteamVR_Action, new()
{
SteamVR_Action foundAction = GetBaseActionFromPath(path, caseSensitive);
if (foundAction != null)
return foundAction.GetCopy();
if (returnNulls)
return null;
return CreateFakeAction(path, caseSensitive);
}
// non-copy version
public static SteamVR_Action GetBaseActionFromPath(string path, bool caseSensitive = false)
{
if (string.IsNullOrEmpty(path))
return null;
if (caseSensitive)
{
if (actionsByPath.ContainsKey(path))
{
return actionsByPath[path];
}
}
else
{
if (actionsByPathCache.ContainsKey(path))
{
return actionsByPathCache[path];
}
else if (actionsByPath.ContainsKey(path))
{
actionsByPathCache.Add(path, actionsByPath[path]);
return actionsByPath[path];
}
else
{
string loweredPath = path.ToLower();
if (actionsByPathLowered.ContainsKey(loweredPath))
{
actionsByPathCache.Add(path, actionsByPathLowered[loweredPath]);
return actionsByPath[loweredPath];
}
else
{
actionsByPathCache.Add(path, null);
}
}
}
return null;
}
public static bool HasActionPath(string path, bool caseSensitive = false)
{
SteamVR_Action action = GetBaseActionFromPath(path, caseSensitive);
return action != null;
}
public static bool HasAction(string actionName, bool caseSensitive = false)
{
SteamVR_Action action = GetBaseAction(null, actionName, caseSensitive);
return action != null;
}
public static bool HasAction(string actionSetName, string actionName, bool caseSensitive = false)
{
SteamVR_Action action = GetBaseAction(actionSetName, actionName, caseSensitive);
return action != null;
}
///
/// Get an action by the full path to that action. Action paths are in the format /actions/[actionSet]/[direction]/[actionName]
///
/// The full path to the action you want (Action paths are in the format /actions/[actionSet]/[direction]/[actionName])
/// case sensitive searches are faster
public static SteamVR_Action_Boolean GetBooleanActionFromPath(string path, bool caseSensitive = false)
{
return GetActionFromPath(path, caseSensitive);
}
///
/// Get an action by the full path to that action. Action paths are in the format /actions/[actionSet]/[direction]/[actionName]
///
/// The full path to the action you want (Action paths are in the format /actions/[actionSet]/[direction]/[actionName])
/// case sensitive searches are faster
public static SteamVR_Action_Single GetSingleActionFromPath(string path, bool caseSensitive = false)
{
return GetActionFromPath(path, caseSensitive);
}
///
/// Get an action by the full path to that action. Action paths are in the format /actions/[actionSet]/[direction]/[actionName]
///
/// The full path to the action you want (Action paths are in the format /actions/[actionSet]/[direction]/[actionName])
/// case sensitive searches are faster
public static SteamVR_Action_Vector2 GetVector2ActionFromPath(string path, bool caseSensitive = false)
{
return GetActionFromPath(path, caseSensitive);
}
///
/// Get an action by the full path to that action. Action paths are in the format /actions/[actionSet]/[direction]/[actionName]
///
/// The full path to the action you want (Action paths are in the format /actions/[actionSet]/[direction]/[actionName])
/// case sensitive searches are faster
public static SteamVR_Action_Vector3 GetVector3ActionFromPath(string path, bool caseSensitive = false)
{
return GetActionFromPath(path, caseSensitive);
}
///
/// Get an action by the full path to that action. Action paths are in the format /actions/[actionSet]/[direction]/[actionName]
///
/// The full path to the action you want (Action paths are in the format /actions/[actionSet]/[direction]/[actionName])
/// case sensitive searches are faster
public static SteamVR_Action_Vibration GetVibrationActionFromPath(string path, bool caseSensitive = false)
{
return GetActionFromPath(path, caseSensitive);
}
///
/// Get an action by the full path to that action. Action paths are in the format /actions/[actionSet]/[direction]/[actionName]
///
/// The full path to the action you want (Action paths are in the format /actions/[actionSet]/[direction]/[actionName])
/// case sensitive searches are faster
public static SteamVR_Action_Pose GetPoseActionFromPath(string path, bool caseSensitive = false)
{
return GetActionFromPath(path, caseSensitive);
}
///
/// Get an action by the full path to that action. Action paths are in the format /actions/[actionSet]/[direction]/[actionName]
///
/// The full path to the action you want (Action paths are in the format /actions/[actionSet]/[direction]/[actionName])
/// case sensitive searches are faster
public static SteamVR_Action_Skeleton GetSkeletonActionFromPath(string path, bool caseSensitive = false)
{
return GetActionFromPath(path, caseSensitive);
}
///
/// Get an action by the full path to that action. Action paths are in the format /actions/[actionSet]/[direction]/[actionName]
///
/// The type of action you're expecting to get back
/// The full path to the action you want (Action paths are in the format /actions/[actionSet]/[direction]/[actionName])
/// case sensitive searches are faster
/// returns null if the action does not exist
public static T GetAction(string actionSetName, string actionName, bool caseSensitive = false, bool returnNulls = false) where T : SteamVR_Action, new()
{
SteamVR_Action action = GetBaseAction(actionSetName, actionName, caseSensitive);
if (action != null)
return (T)action.GetCopy();
if (returnNulls)
return null;
return CreateFakeAction(actionSetName, actionName, caseSensitive);
}
public static SteamVR_Action GetBaseAction(string actionSetName, string actionName, bool caseSensitive = false)
{
if (actions == null)
{
return null;
}
if (string.IsNullOrEmpty(actionSetName))
{
for (int actionIndex = 0; actionIndex < actions.Length; actionIndex++)
{
if (caseSensitive)
{
if (actions[actionIndex].GetShortName() == actionName)
return actions[actionIndex];
}
else
{
if (string.Equals(actions[actionIndex].GetShortName(), actionName, StringComparison.CurrentCultureIgnoreCase))
return actions[actionIndex];
}
}
}
else
{
SteamVR_ActionSet actionSet = GetActionSet(actionSetName, caseSensitive, true);
if (actionSet != null)
{
for (int actionIndex = 0; actionIndex < actionSet.allActions.Length; actionIndex++)
{
if (caseSensitive)
{
if (actionSet.allActions[actionIndex].GetShortName() == actionName)
return actionSet.allActions[actionIndex];
}
else
{
if (string.Equals(actionSet.allActions[actionIndex].GetShortName(), actionName, StringComparison.CurrentCultureIgnoreCase))
return actionSet.allActions[actionIndex];
}
}
}
}
return null;
}
private static T CreateFakeAction(string actionSetName, string actionName, bool caseSensitive) where T : SteamVR_Action, new()
{
if (typeof(T) == typeof(SteamVR_Action_Vibration))
{
return SteamVR_Action.CreateUninitialized(actionSetName, SteamVR_ActionDirections.Out, actionName, caseSensitive);
}
else
{
return SteamVR_Action.CreateUninitialized(actionSetName, SteamVR_ActionDirections.In, actionName, caseSensitive);
}
}
private static T CreateFakeAction(string actionPath, bool caseSensitive) where T : SteamVR_Action, new()
{
return SteamVR_Action.CreateUninitialized(actionPath, caseSensitive);
}
///
/// Get an action by the full path to that action. Action paths are in the format /actions/[actionSet]/[direction]/[actionName]
///
/// The type of action you're expecting to get back
/// The full path to the action you want (Action paths are in the format /actions/[actionSet]/[direction]/[actionName])
/// case sensitive searches are faster
public static T GetAction(string actionName, bool caseSensitive = false) where T : SteamVR_Action, new()
{
return GetAction(null, actionName, caseSensitive);
}
///
/// Get an action by the full path to that action. Action paths are in the format /actions/[actionSet]/[direction]/[actionName]
///
/// The type of action you're expecting to get back
/// The full path to the action you want (Action paths are in the format /actions/[actionSet]/[direction]/[actionName])
/// case sensitive searches are faster
public static SteamVR_Action_Boolean GetBooleanAction(string actionSetName, string actionName, bool caseSensitive = false)
{
return GetAction(actionSetName, actionName, caseSensitive);
}
///
/// Get an action by the full path to that action. Action paths are in the format /actions/[actionSet]/[direction]/[actionName]
///
/// The type of action you're expecting to get back
/// The full path to the action you want (Action paths are in the format /actions/[actionSet]/[direction]/[actionName])
/// case sensitive searches are faster
public static SteamVR_Action_Boolean GetBooleanAction(string actionName, bool caseSensitive = false)
{
return GetAction(null, actionName, caseSensitive);
}
///
/// Get an action by the full path to that action. Action paths are in the format /actions/[actionSet]/[direction]/[actionName]
///
/// The type of action you're expecting to get back
/// The full path to the action you want (Action paths are in the format /actions/[actionSet]/[direction]/[actionName])
/// case sensitive searches are faster
public static SteamVR_Action_Single GetSingleAction(string actionSetName, string actionName, bool caseSensitive = false)
{
return GetAction(actionSetName, actionName, caseSensitive);
}
///
/// Get an action by the full path to that action. Action paths are in the format /actions/[actionSet]/[direction]/[actionName]
///
/// The type of action you're expecting to get back
/// The full path to the action you want (Action paths are in the format /actions/[actionSet]/[direction]/[actionName])
/// case sensitive searches are faster
public static SteamVR_Action_Single GetSingleAction(string actionName, bool caseSensitive = false)
{
return GetAction(null, actionName, caseSensitive);
}
///
/// Get an action by the full path to that action. Action paths are in the format /actions/[actionSet]/[direction]/[actionName]
///
/// The type of action you're expecting to get back
/// The full path to the action you want (Action paths are in the format /actions/[actionSet]/[direction]/[actionName])
/// case sensitive searches are faster
public static SteamVR_Action_Vector2 GetVector2Action(string actionSetName, string actionName, bool caseSensitive = false)
{
return GetAction(actionSetName, actionName, caseSensitive);
}
///
/// Get an action by the full path to that action. Action paths are in the format /actions/[actionSet]/[direction]/[actionName]
///
/// The type of action you're expecting to get back
/// The full path to the action you want (Action paths are in the format /actions/[actionSet]/[direction]/[actionName])
/// case sensitive searches are faster
public static SteamVR_Action_Vector2 GetVector2Action(string actionName, bool caseSensitive = false)
{
return GetAction(null, actionName, caseSensitive);
}
///
/// Get an action by the full path to that action. Action paths are in the format /actions/[actionSet]/[direction]/[actionName]
///
/// The type of action you're expecting to get back
/// The full path to the action you want (Action paths are in the format /actions/[actionSet]/[direction]/[actionName])
/// case sensitive searches are faster
public static SteamVR_Action_Vector3 GetVector3Action(string actionSetName, string actionName, bool caseSensitive = false)
{
return GetAction(actionSetName, actionName, caseSensitive);
}
///
/// Get an action by the full path to that action. Action paths are in the format /actions/[actionSet]/[direction]/[actionName]
///
/// The type of action you're expecting to get back
/// The full path to the action you want (Action paths are in the format /actions/[actionSet]/[direction]/[actionName])
/// case sensitive searches are faster
public static SteamVR_Action_Vector3 GetVector3Action(string actionName, bool caseSensitive = false)
{
return GetAction(null, actionName, caseSensitive);
}
///
/// Get an action by the full path to that action. Action paths are in the format /actions/[actionSet]/[direction]/[actionName]
///
/// The type of action you're expecting to get back
/// The full path to the action you want (Action paths are in the format /actions/[actionSet]/[direction]/[actionName])
/// case sensitive searches are faster
public static SteamVR_Action_Pose GetPoseAction(string actionSetName, string actionName, bool caseSensitive = false)
{
return GetAction(actionSetName, actionName, caseSensitive);
}
///
/// Get an action by the full path to that action. Action paths are in the format /actions/[actionSet]/[direction]/[actionName]
///
/// The type of action you're expecting to get back
/// The full path to the action you want (Action paths are in the format /actions/[actionSet]/[direction]/[actionName])
/// case sensitive searches are faster
public static SteamVR_Action_Pose GetPoseAction(string actionName, bool caseSensitive = false)
{
return GetAction(null, actionName, caseSensitive);
}
///
/// Get an action by the full path to that action. Action paths are in the format /actions/[actionSet]/[direction]/[actionName]
///
/// The type of action you're expecting to get back
/// The full path to the action you want (Action paths are in the format /actions/[actionSet]/[direction]/[actionName])
/// case sensitive searches are faster
public static SteamVR_Action_Skeleton GetSkeletonAction(string actionSetName, string actionName, bool caseSensitive = false)
{
return GetAction(actionSetName, actionName, caseSensitive);
}
///
/// Get an action by the full path to that action. Action paths are in the format /actions/[actionSet]/[direction]/[actionName]
///
/// The type of action you're expecting to get back
/// The full path to the action you want (Action paths are in the format /actions/[actionSet]/[direction]/[actionName])
/// case sensitive searches are faster
public static SteamVR_Action_Skeleton GetSkeletonAction(string actionName, bool caseSensitive = false)
{
return GetAction(null, actionName, caseSensitive);
}
///
/// Get an action by the full path to that action. Action paths are in the format /actions/[actionSet]/[direction]/[actionName]
///
/// The type of action you're expecting to get back
/// The full path to the action you want (Action paths are in the format /actions/[actionSet]/[direction]/[actionName])
/// case sensitive searches are faster
public static SteamVR_Action_Vibration GetVibrationAction(string actionSetName, string actionName, bool caseSensitive = false)
{
return GetAction(actionSetName, actionName, caseSensitive);
}
///
/// Get an action by the full path to that action. Action paths are in the format /actions/[actionSet]/[direction]/[actionName]
///
/// The type of action you're expecting to get back
/// The full path to the action you want (Action paths are in the format /actions/[actionSet]/[direction]/[actionName])
/// case sensitive searches are faster
public static SteamVR_Action_Vibration GetVibrationAction(string actionName, bool caseSensitive = false)
{
return GetAction(null, actionName, caseSensitive);
}
///
/// Get an action set by the full path to that action set. Action set paths are in the format /actions/[actionSet]
///
/// The type of action set you're expecting to get back
/// The name to the action set you want
/// case sensitive searches are faster
/// returns a null if the set does not exist
public static T GetActionSet(string actionSetName, bool caseSensitive = false, bool returnNulls = false) where T : SteamVR_ActionSet, new()
{
if (actionSets == null)
{
if (returnNulls)
return null;
return SteamVR_ActionSet.CreateFromName(actionSetName);
}
for (int actionSetIndex = 0; actionSetIndex < actionSets.Length; actionSetIndex++)
{
if (caseSensitive)
{
if (actionSets[actionSetIndex].GetShortName() == actionSetName)
return actionSets[actionSetIndex].GetCopy();
}
else
{
if (string.Equals(actionSets[actionSetIndex].GetShortName(), actionSetName, StringComparison.CurrentCultureIgnoreCase))
return actionSets[actionSetIndex].GetCopy();
}
}
if (returnNulls)
return null;
return SteamVR_ActionSet.CreateFromName(actionSetName);
}
///
/// Get an action set by the full path to that action set. Action set paths are in the format /actions/[actionSet]
///
/// The type of action set you're expecting to get back
/// The name to the action set you want
/// case sensitive searches are faster
public static SteamVR_ActionSet GetActionSet(string actionSetName, bool caseSensitive = false, bool returnsNulls = false)
{
return GetActionSet(actionSetName, caseSensitive, returnsNulls);
}
protected static bool HasActionSet(string name, bool caseSensitive = false)
{
SteamVR_ActionSet actionSet = GetActionSet(name, caseSensitive, true);
return actionSet != null;
}
///
/// Get an action set by the full path to that action set. Action set paths are in the format /actions/[actionSet]
///
/// The type of action set you're expecting to get back
/// The full path to the action set you want (Action paths are in the format /actions/[actionSet])
/// case sensitive searches are faster
public static T GetActionSetFromPath(string path, bool caseSensitive = false, bool returnsNulls = false) where T : SteamVR_ActionSet, new()
{
if (actionSets == null || actionSets[0] == null || string.IsNullOrEmpty(path))
{
if (returnsNulls)
return null;
return SteamVR_ActionSet.Create(path);
}
if (caseSensitive)
{
if (actionSetsByPath.ContainsKey(path))
{
return actionSetsByPath[path].GetCopy();
}
}
else
{
if (actionSetsByPathCache.ContainsKey(path))
{
SteamVR_ActionSet set = actionSetsByPathCache[path];
if (set == null)
return null;
else
return set.GetCopy();
}
else if (actionSetsByPath.ContainsKey(path))
{
actionSetsByPathCache.Add(path, actionSetsByPath[path]);
return actionSetsByPath[path].GetCopy();
}
else
{
string loweredPath = path.ToLower();
if (actionSetsByPathLowered.ContainsKey(loweredPath))
{
actionSetsByPathCache.Add(path, actionSetsByPathLowered[loweredPath]);
return actionSetsByPath[loweredPath].GetCopy();
}
else
{
actionSetsByPathCache.Add(path, null);
}
}
}
if (returnsNulls)
return null;
return SteamVR_ActionSet.Create(path);
}
///
/// Get an action set by the full path to that action set. Action set paths are in the format /actions/[actionSet]
///
/// The full path to the action set you want (Action paths are in the format /actions/[actionSet])
/// case sensitive searches are faster
public static SteamVR_ActionSet GetActionSetFromPath(string path, bool caseSensitive = false)
{
return GetActionSetFromPath(path, caseSensitive);
}
#endregion
#region digital string accessors
///
/// Get the state of an action by the action set name, action name, and input source. Optionally case sensitive (for faster results)
///
/// The name of the action set the action is contained in
/// The name of the action to get the state of
/// The input source to get the action state from
/// Whether or not the action set and action name searches should be case sensitive (case sensitive searches are faster)
public static bool GetState(string actionSet, string action, SteamVR_Input_Sources inputSource, bool caseSensitive = false)
{
SteamVR_Action_Boolean booleanAction = GetAction(actionSet, action, caseSensitive);
if (booleanAction != null)
{
return booleanAction.GetState(inputSource);
}
return false;
}
///
/// Get the state of an action by the action name and input source. Optionally case sensitive (for faster results)
///
/// The name of the action to get the state of
/// The input source to get the action state from
/// Whether or not the action set and action name searches should be case sensitive (case sensitive searches are faster)
public static bool GetState(string action, SteamVR_Input_Sources inputSource, bool caseSensitive = false)
{
return GetState(null, action, inputSource, caseSensitive);
}
///
/// Get the state down of an action by the action set name, action name, and input source. Optionally case sensitive (for faster results)
///
/// The name of the action set the action is contained in
/// The name of the action to get the state of
/// The input source to get the action state from
/// Whether or not the action set and action name searches should be case sensitive (case sensitive searches are faster)
/// True when the action was false last update and is now true. Returns false again afterwards.
public static bool GetStateDown(string actionSet, string action, SteamVR_Input_Sources inputSource, bool caseSensitive = false)
{
SteamVR_Action_Boolean booleanAction = GetAction(actionSet, action, caseSensitive);
if (booleanAction != null)
{
return booleanAction.GetStateDown(inputSource);
}
return false;
}
///
/// Get the state down of an action by the action name and input source. Optionally case sensitive (for faster results)
///
/// The name of the action to get the state of
/// The input source to get the action state from
/// Whether or not the action set and action name searches should be case sensitive (case sensitive searches are faster)
/// True when the action was false last update and is now true. Returns false again afterwards.
public static bool GetStateDown(string action, SteamVR_Input_Sources inputSource, bool caseSensitive = false)
{
return GetStateDown(null, action, inputSource, caseSensitive);
}
///
/// Get the state up of an action by the action set name, action name, and input source. Optionally case sensitive (for faster results)
///
/// The name of the action set the action is contained in
/// The name of the action to get the state of
/// The input source to get the action state from
/// Whether or not the action set and action name searches should be case sensitive (case sensitive searches are faster)
/// True when the action was true last update and is now false. Returns false again afterwards.
public static bool GetStateUp(string actionSet, string action, SteamVR_Input_Sources inputSource, bool caseSensitive = false)
{
SteamVR_Action_Boolean booleanAction = GetAction(actionSet, action, caseSensitive);
if (booleanAction != null)
{
return booleanAction.GetStateUp(inputSource);
}
return false;
}
///
/// Get the state up of an action by the action name and input source. Optionally case sensitive (for faster results)
///
/// The name of the action to get the state of
/// The input source to get the action state from
/// Whether or not the action set and action name searches should be case sensitive (case sensitive searches are faster)
/// True when the action was true last update and is now false. Returns false again afterwards.
public static bool GetStateUp(string action, SteamVR_Input_Sources inputSource, bool caseSensitive = false)
{
return GetStateDown(null, action, inputSource, caseSensitive);
}
#endregion
#region analog string accessors
///
/// Get the float value of an action by the action set name, action name, and input source. Optionally case sensitive (for faster results). (same as GetSingle)
///
/// The name of the action set the action is contained in
/// The name of the action to get the state of
/// The input source to get the action state from
/// Whether or not the action set and action name searches should be case sensitive (case sensitive searches are faster)
public static float GetFloat(string actionSet, string action, SteamVR_Input_Sources inputSource, bool caseSensitive = false)
{
SteamVR_Action_Single singleAction = GetAction(actionSet, action, caseSensitive);
if (singleAction != null)
{
return singleAction.GetAxis(inputSource);
}
return 0;
}
///
/// Get the float value of an action by the action name and input source. Optionally case sensitive (for faster results). (same as GetSingle)
///
/// The name of the action to get the state of
/// The input source to get the action state from
/// Whether or not the action set and action name searches should be case sensitive (case sensitive searches are faster)
public static float GetFloat(string action, SteamVR_Input_Sources inputSource, bool caseSensitive = false)
{
return GetFloat(null, action, inputSource, caseSensitive);
}
///
/// Get the float value of an action by the action set name, action name, and input source. Optionally case sensitive (for faster results). (same as GetFloat)
///
/// The name of the action set the action is contained in
/// The name of the action to get the state of
/// The input source to get the action state from
/// Whether or not the action set and action name searches should be case sensitive (case sensitive searches are faster)
public static float GetSingle(string actionSet, string action, SteamVR_Input_Sources inputSource, bool caseSensitive = false)
{
SteamVR_Action_Single singleAction = GetAction(actionSet, action, caseSensitive);
if (singleAction != null)
{
return singleAction.GetAxis(inputSource);
}
return 0;
}
///
/// Get the float value of an action by the action name and input source. Optionally case sensitive (for faster results). (same as GetFloat)
///
/// The name of the action to get the state of
/// The input source to get the action state from
/// Whether or not the action set and action name searches should be case sensitive (case sensitive searches are faster)
public static float GetSingle(string action, SteamVR_Input_Sources inputSource, bool caseSensitive = false)
{
return GetFloat(null, action, inputSource, caseSensitive);
}
///
/// Get the Vector2 value of an action by the action set name, action name, and input source. Optionally case sensitive (for faster results)
///
/// The name of the action set the action is contained in
/// The name of the action to get the state of
/// The input source to get the action state from
/// Whether or not the action set and action name searches should be case sensitive (case sensitive searches are faster)
public static Vector2 GetVector2(string actionSet, string action, SteamVR_Input_Sources inputSource, bool caseSensitive = false)
{
SteamVR_Action_Vector2 vectorAction = GetAction(actionSet, action, caseSensitive);
if (vectorAction != null)
{
return vectorAction.GetAxis(inputSource);
}
return Vector2.zero;
}
///
/// Get the Vector2 value of an action by the action name and input source. Optionally case sensitive (for faster results)
///
/// The name of the action to get the state of
/// The input source to get the action state from
/// Whether or not the action set and action name searches should be case sensitive (case sensitive searches are faster)
public static Vector2 GetVector2(string action, SteamVR_Input_Sources inputSource, bool caseSensitive = false)
{
return GetVector2(null, action, inputSource, caseSensitive);
}
///
/// Get the Vector3 value of an action by the action set name, action name, and input source. Optionally case sensitive (for faster results)
///
/// The name of the action set the action is contained in
/// The name of the action to get the state of
/// The input source to get the action state from
/// Whether or not the action set and action name searches should be case sensitive (case sensitive searches are faster)
public static Vector3 GetVector3(string actionSet, string action, SteamVR_Input_Sources inputSource, bool caseSensitive = false)
{
SteamVR_Action_Vector3 vectorAction = GetAction(actionSet, action, caseSensitive);
if (vectorAction != null)
{
return vectorAction.GetAxis(inputSource);
}
return Vector3.zero;
}
///
/// Get the Vector3 value of an action by the action name and input source. Optionally case sensitive (for faster results)
///
/// The name of the action to get the state of
/// The input source to get the action state from
/// Whether or not the action set and action name searches should be case sensitive (case sensitive searches are faster)
public static Vector3 GetVector3(string action, SteamVR_Input_Sources inputSource, bool caseSensitive = false)
{
return GetVector3(null, action, inputSource, caseSensitive);
}
#endregion
#endregion
///
/// Returns all of the action sets. If we're in the editor, doesn't rely on the actionSets field being filled.
///
public static SteamVR_ActionSet[] GetActionSets()
{
return actionSets;
}
///
/// Returns all of the actions of the specified type. If we're in the editor, doesn't rely on the arrays being filled.
///
/// The type of actions you want to get
public static T[] GetActions() where T : SteamVR_Action
{
Type type = typeof(T);
if (type == typeof(SteamVR_Action))
{
return actions as T[];
}
else if (type == typeof(ISteamVR_Action_In))
{
return actionsIn as T[];
}
else if (type == typeof(ISteamVR_Action_Out))
{
return actionsOut as T[];
}
else if (type == typeof(SteamVR_Action_Boolean))
{
return actionsBoolean as T[];
}
else if (type == typeof(SteamVR_Action_Single))
{
return actionsSingle as T[];
}
else if (type == typeof(SteamVR_Action_Vector2))
{
return actionsVector2 as T[];
}
else if (type == typeof(SteamVR_Action_Vector3))
{
return actionsVector3 as T[];
}
else if (type == typeof(SteamVR_Action_Pose))
{
return actionsPose as T[];
}
else if (type == typeof(SteamVR_Action_Skeleton))
{
return actionsSkeleton as T[];
}
else if (type == typeof(SteamVR_Action_Vibration))
{
return actionsVibration as T[];
}
else
{
Debug.Log("[SteamVR] Wrong type.");
}
return null;
}
///
/// Gets the localized name of the device that the action corresponds to.
///
///
///
///
/// - VRInputString_Hand - Which hand the origin is in. E.g. "Left Hand"
/// - VRInputString_ControllerType - What kind of controller the user has in that hand.E.g. "Vive Controller"
/// - VRInputString_InputSource - What part of that controller is the origin. E.g. "Trackpad"
/// - VRInputString_All - All of the above. E.g. "Left Hand Vive Controller Trackpad"
///
///
public static string GetLocalizedName(ulong originHandle, params EVRInputStringBits[] localizedParts)
{
int localizedPartsMask = 0;
for (int partIndex = 0; partIndex < localizedParts.Length; partIndex++)
localizedPartsMask |= (int)localizedParts[partIndex];
StringBuilder stringBuilder = new StringBuilder(500);
OpenVR.Input.GetOriginLocalizedName(originHandle, stringBuilder, 500, localizedPartsMask);
return stringBuilder.ToString();
}
/// Tell SteamVR that we're using the actions file at the path defined in SteamVR_Settings.
public static void IdentifyActionsFile(bool showLogs = true)
{
string currentPath = Application.dataPath;
int lastIndex = currentPath.LastIndexOf('/');
currentPath = currentPath.Remove(lastIndex, currentPath.Length - lastIndex);
string fullPath = System.IO.Path.Combine(currentPath, SteamVR_Settings.instance.actionsFilePath);
fullPath = fullPath.Replace("\\", "/");
if (File.Exists(fullPath))
{
EVRInputError err = OpenVR.Input.SetActionManifestPath(fullPath);
if (err != EVRInputError.None)
Debug.LogError("[SteamVR] Error loading action manifest into SteamVR: " + err.ToString());
else
{
int numActions = 0;
if (SteamVR_Input.actions != null)
{
numActions = SteamVR_Input.actions.Length;
if (showLogs)
Debug.Log(string.Format("[SteamVR] Successfully loaded {0} actions from action manifest into SteamVR ({1})", numActions, fullPath));
}
else
{
if (showLogs)
Debug.LogWarning("[SteamVR] No actions found, but the action manifest was loaded. This usually means you haven't generated actions. Window -> SteamVR Input -> Save and Generate.");
}
}
}
else
{
if (showLogs)
Debug.LogError("[SteamVR] Could not find actions file at: " + fullPath);
}
}
///
/// Does the actions file in memory differ from the one on disk as determined by a md5 hash
///
public static bool HasFileInMemoryBeenModified()
{
string projectPath = Application.dataPath;
int lastIndex = projectPath.LastIndexOf("/");
projectPath = projectPath.Remove(lastIndex, projectPath.Length - lastIndex);
actionsFilePath = Path.Combine(projectPath, SteamVR_Settings.instance.actionsFilePath);
string jsonText = null;
if (File.Exists(actionsFilePath))
{
jsonText = System.IO.File.ReadAllText(actionsFilePath);
}
else
{
return true;
}
string newHashFromFile = SteamVR_Utils.GetBadMD5Hash(jsonText);
string newJSON = JsonConvert.SerializeObject(SteamVR_Input.actionFile, Formatting.Indented, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore });
string newHashFromMemory = SteamVR_Utils.GetBadMD5Hash(newJSON);
return newHashFromFile != newHashFromMemory;
}
public static bool CreateEmptyActionsFile(bool completelyEmpty = false)
{
string projectPath = Application.dataPath;
int lastIndex = projectPath.LastIndexOf("/");
projectPath = projectPath.Remove(lastIndex, projectPath.Length - lastIndex);
actionsFilePath = Path.Combine(projectPath, SteamVR_Settings.instance.actionsFilePath);
if (File.Exists(actionsFilePath))
{
Debug.LogErrorFormat("[SteamVR] Actions file already exists in project root: {0}", actionsFilePath);
return false;
}
actionFile = new SteamVR_Input_ActionFile();
if (completelyEmpty == false)
{
actionFile.action_sets.Add(SteamVR_Input_ActionFile_ActionSet.CreateNew());
actionFile.actions.Add(SteamVR_Input_ActionFile_Action.CreateNew(actionFile.action_sets[0].shortName,
SteamVR_ActionDirections.In, SteamVR_Input_ActionFile_ActionTypes.boolean));
}
string newJSON = JsonConvert.SerializeObject(actionFile, Formatting.Indented, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore });
File.WriteAllText(actionsFilePath, newJSON);
actionFile.InitializeHelperLists();
fileInitialized = true;
return true;
}
public static bool DoesActionsFileExist()
{
string projectPath = Application.dataPath;
int lastIndex = projectPath.LastIndexOf("/");
projectPath = projectPath.Remove(lastIndex, projectPath.Length - lastIndex);
actionsFilePath = Path.Combine(projectPath, SteamVR_Settings.instance.actionsFilePath);
return File.Exists(actionsFilePath);
}
///
/// Load from disk and deserialize the actions file
///
/// Force a refresh of this file from disk
public static bool InitializeFile(bool force = false, bool showErrors = true)
{
bool actionsFileExists = DoesActionsFileExist();
string jsonText = null;
if (actionsFileExists)
{
jsonText = System.IO.File.ReadAllText(actionsFilePath);
}
else
{
if (showErrors)
Debug.LogErrorFormat("[SteamVR] Actions file does not exist in project root: {0}", actionsFilePath);
return false;
}
if (fileInitialized == true || (fileInitialized == true && force == false))
{
string newHash = SteamVR_Utils.GetBadMD5Hash(jsonText);
if (newHash == actionFileHash)
{
return true;
}
actionFileHash = newHash;
}
actionFile = Valve.Newtonsoft.Json.JsonConvert.DeserializeObject(jsonText);
actionFile.InitializeHelperLists();
fileInitialized = true;
return true;
}
///
/// Deletes the action manifest file and all the default bindings it had listed in the default bindings section
///
/// True if we deleted an action file, false if not.
public static bool DeleteManifestAndBindings()
{
if (DoesActionsFileExist() == false)
return false;
InitializeFile();
string[] filesToDelete = actionFile.GetFilesToCopy();
foreach (string bindingFilePath in filesToDelete)
{
FileInfo bindingFileInfo = new FileInfo(bindingFilePath);
bindingFileInfo.IsReadOnly = false;
File.Delete(bindingFilePath);
}
if (File.Exists(actionsFilePath))
{
FileInfo actionFileInfo = new FileInfo(actionsFilePath);
actionFileInfo.IsReadOnly = false;
File.Delete(actionsFilePath);
actionFile = null;
fileInitialized = false;
return true;
}
return false;
}
#if UNITY_EDITOR
public static string GetResourcesFolderPath(bool fromAssetsDirectory = false)
{
string inputFolder = string.Format("Assets/{0}", SteamVR_Settings.instance.steamVRInputPath);
string path = Path.Combine(inputFolder, "Resources");
bool createdDirectory = false;
if (Directory.Exists(inputFolder) == false)
{
Directory.CreateDirectory(inputFolder);
createdDirectory = true;
}
if (Directory.Exists(path) == false)
{
Directory.CreateDirectory(path);
createdDirectory = true;
}
if (createdDirectory)
UnityEditor.AssetDatabase.Refresh();
if (fromAssetsDirectory == false)
return path.Replace("Assets/", "");
else
return path;
}
private static bool checkingSetup = false;
private static bool openingSetup = false;
public static bool IsOpeningSetup() { return openingSetup; }
private static void CheckSetup()
{
if (checkingSetup == false && openingSetup == false && (SteamVR_Input.actions == null || SteamVR_Input.actions.Length == 0))
{
checkingSetup = true;
Debug.Break();
bool open = UnityEditor.EditorUtility.DisplayDialog("[SteamVR]", "It looks like you haven't generated actions for SteamVR Input yet. Would you like to open the SteamVR Input window?", "Yes", "No");
if (open)
{
openingSetup = true;
UnityEditor.EditorApplication.isPlaying = false;
Type editorWindowType = FindType("Valve.VR.SteamVR_Input_EditorWindow");
if (editorWindowType != null)
{
var window = UnityEditor.EditorWindow.GetWindow(editorWindowType, false, "SteamVR Input", true);
if (window != null)
window.Show();
}
}
else
{
Debug.LogError("[SteamVR] This version of SteamVR will not work if you do not create and generate actions. Please open the SteamVR Input window or downgrade to version 1.2.3 (on github)");
}
checkingSetup = false;
}
}
private static Type FindType(string typeName)
{
var type = Type.GetType(typeName);
if (type != null) return type;
foreach (var a in AppDomain.CurrentDomain.GetAssemblies())
{
type = a.GetType(typeName);
if (type != null)
return type;
}
return null;
}
#endif
}
}