You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
413 lines
15 KiB
413 lines
15 KiB
//========= Copyright 2016-2018, HTC Corporation. All rights reserved. =========== |
|
|
|
using HTC.UnityPlugin.VRModuleManagement; |
|
using HTC.UnityPlugin.Utility; |
|
using System; |
|
using System.IO; |
|
using UnityEngine; |
|
using UnityEngine.Serialization; |
|
using System.Collections.Generic; |
|
|
|
namespace HTC.UnityPlugin.Vive |
|
{ |
|
public class ViveRoleBindingsHelper : SingletonBehaviour<ViveRoleBindingsHelper> |
|
{ |
|
[Serializable] |
|
public struct Binding |
|
{ |
|
[FormerlySerializedAs("sn")] |
|
public string device_sn; |
|
public VRModuleDeviceModel device_model; |
|
public string role_name; |
|
[FormerlySerializedAs("sv")] |
|
public int role_value; |
|
} |
|
|
|
[Serializable] |
|
public struct RoleData |
|
{ |
|
public string type; |
|
public Binding[] bindings; |
|
} |
|
|
|
[Serializable] |
|
public class BindingConfig |
|
{ |
|
[NonSerialized] |
|
[Obsolete("This field is always true now. Use VIUSettings.autoLoadBindingConfigOnStart to control if the project will auto load config.")] |
|
public bool apply_bindings_on_load = true; |
|
[NonSerialized] |
|
[Obsolete("Use VIUSettings.bindingInterfaceSwitchKey instead.")] |
|
public string toggle_interface_key_code = string.Empty; |
|
[NonSerialized] |
|
[Obsolete("Use VIUSettings.bindingInterfaceSwitchKeyModifier instead.")] |
|
public string toggle_interface_modifier = string.Empty; |
|
[NonSerialized] |
|
[Obsolete("Use VIUSettings.bindingInterfaceObject instead.")] |
|
public string interface_prefab = DEFAULT_INTERFACE_PREFAB; |
|
|
|
public RoleData[] roles = new RoleData[0]; |
|
} |
|
|
|
[Obsolete("Use VIUSettings.BINDING_INTERFACE_CONFIG_FILE_PATH_DEFAULT_VALUE instead.")] |
|
public const string AUTO_LOAD_CONFIG_PATH = "vive_role_bindings.cfg"; |
|
[Obsolete("Use VIUSettings.BINDING_INTERFACE_PREFAB_DEFAULT_RESOURCE_PATH instead.")] |
|
public const string DEFAULT_INTERFACE_PREFAB = "VIUBindingInterface"; |
|
|
|
private static BindingConfig s_bindingConfig = new BindingConfig(); |
|
|
|
private static GameObject s_interfaceObj; |
|
private static Dictionary<string, VRModuleDeviceModel> s_modelHintTable = new Dictionary<string, VRModuleDeviceModel>(); |
|
|
|
public static BindingConfig bindingConfig { get { return s_bindingConfig; } } |
|
|
|
public static bool isBindingInterfaceEnabled { get { return s_interfaceObj != null && s_interfaceObj.activeSelf; } } |
|
|
|
static ViveRoleBindingsHelper() |
|
{ |
|
SetDefaultInitGameObjectGetter(VRModule.GetInstanceGameObject); |
|
} |
|
|
|
[RuntimeInitializeOnLoadMethod] |
|
private static void OnLoad() |
|
{ |
|
if (VRModule.Active && VRModule.activeModule != VRModuleActiveEnum.Uninitialized) |
|
{ |
|
TryInitializeOnLoad(); |
|
} |
|
else |
|
{ |
|
VRModule.onActiveModuleChanged += OnActiveModuleChanged; |
|
} |
|
} |
|
|
|
private static void OnActiveModuleChanged(VRModuleActiveEnum activatedModule) |
|
{ |
|
if (activatedModule != VRModuleActiveEnum.Uninitialized) |
|
{ |
|
VRModule.onActiveModuleChanged -= OnActiveModuleChanged; |
|
|
|
TryInitializeOnLoad(); |
|
} |
|
} |
|
|
|
private static void TryInitializeOnLoad() |
|
{ |
|
if (VIUSettings.autoLoadBindingConfigOnStart) |
|
{ |
|
if (LoadBindingConfigFromFile(VIUSettings.bindingConfigFilePath)) |
|
{ |
|
var appliedCount = ApplyBindingConfigToRoleMap(); |
|
|
|
Debug.Log("ViveRoleBindingsHelper: " + appliedCount + " bindings applied from " + VIUSettings.bindingConfigFilePath); |
|
} |
|
} |
|
|
|
if (!Active && VIUSettings.enableBindingInterfaceSwitch) |
|
{ |
|
Initialize(); |
|
} |
|
} |
|
|
|
private void Update() |
|
{ |
|
if (!IsInstance) { return; } |
|
|
|
if (VIUSettings.enableBindingInterfaceSwitch) |
|
{ |
|
if (Input.GetKeyDown(VIUSettings.bindingInterfaceSwitchKey) && (VIUSettings.bindingInterfaceSwitchKeyModifier == KeyCode.None || Input.GetKey(VIUSettings.bindingInterfaceSwitchKeyModifier))) |
|
{ |
|
ToggleBindingInterface(); |
|
} |
|
} |
|
} |
|
|
|
public static VRModuleDeviceModel GetDeviceModelHint(string deviceSN) |
|
{ |
|
var deviceIndex = VRModule.GetConnectedDeviceIndex(deviceSN); |
|
if (VRModule.IsValidDeviceIndex(deviceIndex)) |
|
{ |
|
return VRModule.GetCurrentDeviceState(deviceIndex).deviceModel; |
|
} |
|
|
|
VRModuleDeviceModel deviceModel; |
|
if (s_modelHintTable.TryGetValue(deviceSN, out deviceModel)) |
|
{ |
|
return deviceModel; |
|
} |
|
|
|
return VRModuleDeviceModel.Unknown; |
|
} |
|
|
|
public static void EnableBindingInterface() |
|
{ |
|
if (s_interfaceObj == null) |
|
{ |
|
if (VIUSettings.bindingInterfaceObjectSource == null) |
|
{ |
|
Debug.LogWarning("VIUSettings.bindingInterfaceObjectSource is null."); |
|
return; |
|
} |
|
|
|
s_interfaceObj = Instantiate(VIUSettings.bindingInterfaceObjectSource); |
|
} |
|
else |
|
{ |
|
s_interfaceObj.SetActive(true); |
|
} |
|
} |
|
|
|
public static void DisableBindingInterface() |
|
{ |
|
if (s_interfaceObj != null) |
|
{ |
|
s_interfaceObj.SetActive(false); |
|
} |
|
} |
|
|
|
public static void ToggleBindingInterface() |
|
{ |
|
if (!isBindingInterfaceEnabled) |
|
{ |
|
EnableBindingInterface(); |
|
} |
|
else |
|
{ |
|
DisableBindingInterface(); |
|
} |
|
} |
|
|
|
public static void LoadBindingConfigFromRoleMap(params Type[] roleTypeFilter) |
|
{ |
|
var roleDataList = ListPool<RoleData>.Get(); |
|
var filterUsed = roleTypeFilter != null && roleTypeFilter.Length > 0; |
|
|
|
if (filterUsed) |
|
{ |
|
roleDataList.AddRange(s_bindingConfig.roles); |
|
} |
|
|
|
for (int i = 0, imax = ViveRoleEnum.ValidViveRoleTable.Count; i < imax; ++i) |
|
{ |
|
var roleType = ViveRoleEnum.ValidViveRoleTable.GetValueByIndex(i); |
|
var roleName = ViveRoleEnum.ValidViveRoleTable.GetKeyByIndex(i); |
|
var roleMap = ViveRole.GetMap(roleType); |
|
|
|
if (filterUsed) |
|
{ |
|
// apply filter |
|
var filtered = false; |
|
foreach (var t in roleTypeFilter) { if (roleType == t) { filtered = true; break; } } |
|
if (!filtered) { continue; } |
|
} |
|
|
|
if (roleMap.BindingCount > 0) |
|
{ |
|
var bindingTable = roleMap.BindingTable; |
|
|
|
var roleData = new RoleData() |
|
{ |
|
type = roleName, |
|
bindings = new Binding[bindingTable.Count], |
|
}; |
|
|
|
for (int j = 0, jmax = bindingTable.Count; j < jmax; ++j) |
|
{ |
|
var binding = new Binding(); |
|
binding.device_sn = bindingTable.GetKeyByIndex(j); |
|
binding.role_value = bindingTable.GetValueByIndex(j); |
|
binding.role_name = roleMap.RoleValueInfo.GetNameByRoleValue(binding.role_value); |
|
|
|
// save the device_model for better recognition of the device |
|
if (VRModule.IsDeviceConnected(binding.device_sn)) |
|
{ |
|
binding.device_model = VRModule.GetCurrentDeviceState(VRModule.GetConnectedDeviceIndex(binding.device_sn)).deviceModel; |
|
s_modelHintTable[binding.device_sn] = binding.device_model; |
|
} |
|
else if (!s_modelHintTable.TryGetValue(binding.device_sn, out binding.device_model)) |
|
{ |
|
binding.device_model = VRModuleDeviceModel.Unknown; |
|
} |
|
|
|
roleData.bindings[j] = binding; |
|
} |
|
|
|
if (filterUsed) |
|
{ |
|
// merge with existing role data |
|
var roleDataIndex = roleDataList.FindIndex((item) => item.type == roleName); |
|
if (roleDataIndex >= 0) |
|
{ |
|
roleDataList[roleDataIndex] = roleData; |
|
} |
|
else |
|
{ |
|
roleDataList.Add(roleData); |
|
} |
|
} |
|
else |
|
{ |
|
roleDataList.Add(roleData); |
|
} |
|
} |
|
else |
|
{ |
|
if (roleDataList.Count > 0) |
|
{ |
|
// don't write to config if no bindings |
|
roleDataList.RemoveAll((item) => item.type == roleName); |
|
} |
|
} |
|
} |
|
|
|
s_bindingConfig.roles = roleDataList.ToArray(); |
|
|
|
ListPool<RoleData>.Release(roleDataList); |
|
} |
|
|
|
public static int ApplyBindingConfigToRoleMap(params Type[] roleTypeFilter) |
|
{ |
|
var appliedCount = 0; |
|
var filterUsed = roleTypeFilter != null && roleTypeFilter.Length > 0; |
|
|
|
foreach (var roleData in s_bindingConfig.roles) |
|
{ |
|
Type roleType; |
|
if (string.IsNullOrEmpty(roleData.type) || !ViveRoleEnum.ValidViveRoleTable.TryGetValue(roleData.type, out roleType)) { continue; } |
|
|
|
if (filterUsed) |
|
{ |
|
// apply filter |
|
var filtered = false; |
|
foreach (var t in roleTypeFilter) { if (roleType == t) { filtered = true; break; } } |
|
if (!filtered) { continue; } |
|
} |
|
|
|
var roleMap = ViveRole.GetMap(roleType); |
|
roleMap.UnbindAll(); |
|
|
|
foreach (var binding in roleData.bindings) |
|
{ |
|
// bind device according to role_name first |
|
// if role_name is invalid then role_value is used |
|
int roleValue; |
|
if (string.IsNullOrEmpty(binding.role_name) || !roleMap.RoleValueInfo.TryGetRoleValueByName(binding.role_name, out roleValue)) |
|
{ |
|
roleValue = binding.role_value; |
|
} |
|
|
|
roleMap.BindDeviceToRoleValue(binding.device_sn, roleValue); |
|
++appliedCount; |
|
} |
|
} |
|
|
|
return appliedCount; |
|
} |
|
|
|
public static void SaveBindingConfigToFile(string configPath, bool prettyPrint = true) |
|
{ |
|
var dir = Path.GetDirectoryName(configPath); |
|
if (!string.IsNullOrEmpty(dir) && !Directory.Exists(configPath)) |
|
{ |
|
Directory.CreateDirectory(dir); |
|
} |
|
|
|
using (var outputFile = new StreamWriter(configPath)) |
|
{ |
|
outputFile.Write(JsonUtility.ToJson(s_bindingConfig, prettyPrint)); |
|
} |
|
} |
|
|
|
public static bool LoadBindingConfigFromFile(string configPath) |
|
{ |
|
if (string.IsNullOrEmpty(configPath) || !File.Exists(configPath)) |
|
{ |
|
return false; |
|
} |
|
|
|
using (var inputFile = new StreamReader(configPath)) |
|
{ |
|
s_bindingConfig = JsonUtility.FromJson<BindingConfig>(inputFile.ReadToEnd()); |
|
|
|
foreach (var roleData in s_bindingConfig.roles) |
|
{ |
|
foreach (var binding in roleData.bindings) |
|
{ |
|
if (VRModule.IsDeviceConnected(binding.device_sn)) |
|
{ |
|
s_modelHintTable[binding.device_sn] = VRModule.GetCurrentDeviceState(VRModule.GetConnectedDeviceIndex(binding.device_sn)).deviceModel; |
|
} |
|
else |
|
{ |
|
s_modelHintTable[binding.device_sn] = binding.device_model; |
|
} |
|
} |
|
} |
|
|
|
return true; |
|
} |
|
} |
|
|
|
public static void BindAllCurrentDeviceClassMappings(VRModuleDeviceClass deviceClass) |
|
{ |
|
for (int i = 0, imax = ViveRoleEnum.ValidViveRoleTable.Count; i < imax; ++i) |
|
{ |
|
var roleMap = ViveRole.GetMap(ViveRoleEnum.ValidViveRoleTable.GetValueByIndex(i)); |
|
var roleInfo = roleMap.RoleValueInfo; |
|
for (int rv = roleInfo.MinValidRoleValue, rvmax = roleInfo.MaxValidRoleValue; rv <= rvmax; ++rv) |
|
{ |
|
if (!roleInfo.IsValidRoleValue(rv)) { continue; } |
|
if (roleMap.IsRoleValueBound(rv)) { continue; } |
|
|
|
var mappedDevice = roleMap.GetMappedDeviceByRoleValue(rv); |
|
var mappedDeviceState = VRModule.GetCurrentDeviceState(mappedDevice); |
|
if (mappedDeviceState.deviceClass != deviceClass) { continue; } |
|
|
|
roleMap.BindDeviceToRoleValue(mappedDeviceState.serialNumber, rv); |
|
} |
|
} |
|
} |
|
|
|
public static void BindAllCurrentMappings() |
|
{ |
|
for (int i = 0, imax = ViveRoleEnum.ValidViveRoleTable.Count; i < imax; ++i) |
|
{ |
|
var roleMap = ViveRole.GetMap(ViveRoleEnum.ValidViveRoleTable.GetValueByIndex(i)); |
|
roleMap.BindAll(); |
|
} |
|
} |
|
|
|
public static void UnbindAllCurrentBindings() |
|
{ |
|
for (int i = 0, imax = ViveRoleEnum.ValidViveRoleTable.Count; i < imax; ++i) |
|
{ |
|
var roleMap = ViveRole.GetMap(ViveRoleEnum.ValidViveRoleTable.GetValueByIndex(i)); |
|
roleMap.UnbindAll(); |
|
} |
|
} |
|
|
|
public static void SaveBindings(string configPath, bool prettyPrint = true) |
|
{ |
|
LoadBindingConfigFromRoleMap(); |
|
SaveBindingConfigToFile(configPath, prettyPrint); |
|
} |
|
|
|
public static void LoadBindings(string configPath) |
|
{ |
|
LoadBindingConfigFromFile(configPath); |
|
ApplyBindingConfigToRoleMap(); |
|
} |
|
|
|
[Obsolete("Use SaveBindings instead")] |
|
public static void SaveRoleBindings(string filePath, bool prettyPrint = false) |
|
{ |
|
SaveBindings(filePath, prettyPrint); |
|
} |
|
|
|
[Obsolete("Use LoadBindings instead")] |
|
public static void LoadRoleBindings(string filePath) |
|
{ |
|
LoadBindings(filePath); |
|
} |
|
} |
|
} |