/// <summary> /// Returns the <see cref="Toolkit.Input.InputSourceType"/> of the currently detected controller, based on the <see cref="Toolkit.Input.SupportedControllerType"/>. /// </summary> /// <param name="supportedControllerType">The current controller type.</param> /// <returns>The enum value of the currently detected controller's InputSource type.</returns> protected virtual InputSourceType GetInputSourceType(SupportedControllerType supportedControllerType) { return(InputSourceType.Controller); }
/// <summary> /// Gets or adds a controller using the InputDevice name provided. /// </summary> /// <param name="inputDevice">The InputDevice from XR SDK.</param> /// <returns>The controller reference.</returns> protected virtual GenericXRSDKController GetOrAddController(InputDevice inputDevice) { using (GetOrAddControllerPerfMarker.Auto()) { // If a device is already registered with the ID provided, just return it. if (ActiveControllers.ContainsKey(inputDevice)) { var controller = ActiveControllers[inputDevice]; Debug.Assert(controller != null); return(controller); } Handedness controllingHand; if (inputDevice.characteristics.IsMaskSet(InputDeviceCharacteristics.Left)) { controllingHand = Handedness.Left; } else if (inputDevice.characteristics.IsMaskSet(InputDeviceCharacteristics.Right)) { controllingHand = Handedness.Right; } else { controllingHand = Handedness.None; } SupportedControllerType currentControllerType = GetCurrentControllerType(inputDevice); Type controllerType = GetControllerType(currentControllerType); if (controllerType == null) { return(null); } InputSourceType inputSourceType = GetInputSourceType(currentControllerType); IMixedRealityPointer[] pointers = RequestPointers(currentControllerType, controllingHand); IMixedRealityInputSource inputSource = Service?.RequestNewGenericInputSource($"{currentControllerType} Controller {controllingHand}", pointers, inputSourceType); GenericXRSDKController detectedController = Activator.CreateInstance(controllerType, TrackingState.NotTracked, controllingHand, inputSource, null) as GenericXRSDKController; if (detectedController == null || !detectedController.Enabled) { // Controller failed to be set up correctly. Debug.LogError($"Failed to create {controllerType.Name} controller"); // Return null so we don't raise the source detected. return(null); } for (int i = 0; i < detectedController.InputSource?.Pointers?.Length; i++) { detectedController.InputSource.Pointers[i].Controller = detectedController; } ActiveControllers.Add(inputDevice, detectedController); Service?.RaiseSourceDetected(detectedController.InputSource, detectedController); return(detectedController); } }
/// <summary> /// Gets the concrete type of the detected controller, based on the <see cref="Toolkit.Input.SupportedControllerType"/> and defined per-platform. /// </summary> /// <param name="supportedControllerType">The current controller type.</param> /// <returns>The concrete type of the currently detected controller.</returns> protected virtual Type GetControllerType(SupportedControllerType supportedControllerType) { return(typeof(GenericXRSDKController)); }
private void RenderControllerList(SerializedProperty controllerList) { if (thisProfile.MixedRealityControllerMappings.Length != controllerList.arraySize) { return; } if (InspectorUIUtility.RenderIndentedButton(ControllerAddButtonContent, EditorStyles.miniButton)) { AddController(controllerList, typeof(GenericJoystickController)); return; } controllerRenderList.Clear(); // Generating the set of controllers that belong to each Controller Mapping Signature Dictionary <ControllerMappingSignature, List <string> > controllersAffectedByMappingSignatures = new Dictionary <ControllerMappingSignature, List <string> >(); for (int i = 0; i < thisProfile.MixedRealityControllerMappings.Length; i++) { MixedRealityControllerMapping controllerMapping = thisProfile.MixedRealityControllerMappings[i]; Type controllerType = controllerMapping.ControllerType; if (controllerType == null) { continue; } Handedness handedness = controllerMapping.Handedness; SupportedControllerType supportedControllerType = controllerMapping.SupportedControllerType; ControllerMappingSignature currentSignature = new ControllerMappingSignature(supportedControllerType, handedness); if (!controllersAffectedByMappingSignatures.ContainsKey(currentSignature)) { controllersAffectedByMappingSignatures.Add(currentSignature, new List <string>()); } controllersAffectedByMappingSignatures[currentSignature].Add(controllerType.ToString()); } showControllerDefinitions = EditorGUILayout.Foldout(showControllerDefinitions, "Controller Definitions", true); if (showControllerDefinitions) { using (var outerVerticalScope = new GUILayout.VerticalScope()) { GUILayout.HorizontalScope horizontalScope = null; for (int i = 0; i < thisProfile.MixedRealityControllerMappings.Length; i++) { MixedRealityControllerMapping controllerMapping = thisProfile.MixedRealityControllerMappings[i]; Type controllerType = controllerMapping.ControllerType; if (controllerType == null) { continue; } Handedness handedness = controllerMapping.Handedness; bool useCustomInteractionMappings = controllerMapping.HasCustomInteractionMappings; SupportedControllerType supportedControllerType = controllerMapping.SupportedControllerType; var controllerMappingProperty = controllerList.GetArrayElementAtIndex(i); var handednessProperty = controllerMappingProperty.FindPropertyRelative("handedness"); #region Profile Migration // Between MRTK v2 RC2 and GA, the HoloLens clicker and HoloLens voice select input were migrated from // SupportedControllerType.WindowsMixedReality && Handedness.None to SupportedControllerType.GGVHand && Handedness.None if (supportedControllerType == SupportedControllerType.WindowsMixedReality && handedness == Handedness.None) { for (int j = 0; j < thisProfile.MixedRealityControllerMappings.Length; j++) { if (thisProfile.MixedRealityControllerMappings[j].SupportedControllerType == SupportedControllerType.GGVHand && thisProfile.MixedRealityControllerMappings[j].Handedness == Handedness.None) { if (horizontalScope != null) { horizontalScope.Dispose(); horizontalScope = null; } serializedObject.ApplyModifiedProperties(); for (int k = 0; k < controllerMapping.Interactions.Length; k++) { MixedRealityInteractionMapping currentMapping = controllerMapping.Interactions[k]; if (currentMapping.InputType == DeviceInputType.Select) { thisProfile.MixedRealityControllerMappings[j].Interactions[0].MixedRealityInputAction = currentMapping.MixedRealityInputAction; } else if (currentMapping.InputType == DeviceInputType.SpatialGrip) { thisProfile.MixedRealityControllerMappings[j].Interactions[1].MixedRealityInputAction = currentMapping.MixedRealityInputAction; } } serializedObject.Update(); controllerList.DeleteArrayElementAtIndex(i); EditorUtility.DisplayDialog("Mappings updated", "The \"HoloLens Voice and Clicker\" mappings have been migrated to a new serialization. Please save this asset.", "Okay, thanks!"); return; } } } #endregion Profile Migration if (!useCustomInteractionMappings) { bool skip = false; // Merge controllers with the same supported controller type. for (int j = 0; j < controllerRenderList.Count; j++) { if (controllerRenderList[j].SupportedControllerType == supportedControllerType && controllerRenderList[j].Handedness == handedness) { try { thisProfile.MixedRealityControllerMappings[i].SynchronizeInputActions(controllerRenderList[j].Interactions); } catch (ArgumentException e) { Debug.LogError($"Controller mappings between {thisProfile.MixedRealityControllerMappings[i].Description} and {controllerMapping.Description} do not match. Error message: {e.Message}"); } serializedObject.ApplyModifiedProperties(); skip = true; } } if (skip) { continue; } } controllerRenderList.Add(new ControllerRenderProfile(supportedControllerType, handedness, thisProfile.MixedRealityControllerMappings[i].Interactions)); string controllerTitle = thisProfile.MixedRealityControllerMappings[i].Description; var interactionsProperty = controllerMappingProperty.FindPropertyRelative("interactions"); if (useCustomInteractionMappings) { if (horizontalScope != null) { horizontalScope.Dispose(); horizontalScope = null; } GUILayout.Space(24f); using (var verticalScope = new GUILayout.VerticalScope()) { using (horizontalScope = new GUILayout.HorizontalScope()) { EditorGUILayout.LabelField(controllerTitle, EditorStyles.boldLabel); if (GUILayout.Button(ControllerMinusButtonContent, EditorStyles.miniButtonRight, GUILayout.Width(24f))) { controllerList.DeleteArrayElementAtIndex(i); return; } } EditorGUI.BeginChangeCheck(); // Generic Type dropdown Type[] genericTypes = MixedRealityControllerMappingProfile.CustomControllerMappingTypes; var genericTypeListContent = new GUIContent[genericTypes.Length]; var genericTypeListIds = new int[genericTypes.Length]; int currentGenericType = -1; for (int genericTypeIdx = 0; genericTypeIdx < genericTypes.Length; genericTypeIdx++) { var attribute = MixedRealityControllerAttribute.Find(genericTypes[genericTypeIdx]); if (attribute != null) { genericTypeListContent[genericTypeIdx] = new GUIContent(attribute.SupportedControllerType.ToString().Replace("Generic", "").ToProperCase() + " Controller"); } else { genericTypeListContent[genericTypeIdx] = new GUIContent("Unknown Controller"); } genericTypeListIds[genericTypeIdx] = genericTypeIdx; if (controllerType == genericTypes[genericTypeIdx]) { currentGenericType = genericTypeIdx; } } Debug.Assert(currentGenericType != -1); currentGenericType = EditorGUILayout.IntPopup(GenericTypeContent, currentGenericType, genericTypeListContent, genericTypeListIds); controllerType = genericTypes[currentGenericType]; { // Handedness dropdown var attribute = MixedRealityControllerAttribute.Find(controllerType); if (attribute != null && attribute.SupportedHandedness.Length >= 1) { // Make sure handedness is valid for the selected controller type. if (Array.IndexOf(attribute.SupportedHandedness, (Handedness)handednessProperty.intValue) < 0) { handednessProperty.intValue = (int)attribute.SupportedHandedness[0]; } if (attribute.SupportedHandedness.Length >= 2) { var handednessListContent = new GUIContent[attribute.SupportedHandedness.Length]; var handednessListIds = new int[attribute.SupportedHandedness.Length]; for (int handednessIdx = 0; handednessIdx < attribute.SupportedHandedness.Length; handednessIdx++) { handednessListContent[handednessIdx] = new GUIContent(attribute.SupportedHandedness[handednessIdx].ToString()); handednessListIds[handednessIdx] = (int)attribute.SupportedHandedness[handednessIdx]; } handednessProperty.intValue = EditorGUILayout.IntPopup(HandednessTypeContent, handednessProperty.intValue, handednessListContent, handednessListIds); } } else { handednessProperty.intValue = (int)Handedness.None; } } if (EditorGUI.EndChangeCheck()) { interactionsProperty.ClearArray(); serializedObject.ApplyModifiedProperties(); thisProfile.MixedRealityControllerMappings[i].ControllerType.Type = genericTypes[currentGenericType]; thisProfile.MixedRealityControllerMappings[i].SetDefaultInteractionMapping(true); serializedObject.ApplyModifiedProperties(); return; } if (InspectorUIUtility.RenderIndentedButton("Edit Input Action Map")) { ControllerPopupWindow.Show(controllerMapping, interactionsProperty, handedness); } if (InspectorUIUtility.RenderIndentedButton("Reset Input Actions")) { ResetInputActions(ref thisProfile.MixedRealityControllerMappings[i]); } } } else { if (handedness != Handedness.Right) { if (horizontalScope != null) { horizontalScope.Dispose(); horizontalScope = null; } horizontalScope = new GUILayout.HorizontalScope(); } EditorGUILayout.BeginHorizontal(EditorStyles.helpBox); var buttonContent = new GUIContent(controllerTitle, ControllerMappingLibrary.GetControllerTextureScaled(controllerType, handedness)); if (GUILayout.Button(buttonContent, MixedRealityStylesUtility.ControllerButtonStyle, GUILayout.Height(128f), GUILayout.MinWidth(32), GUILayout.ExpandWidth(true))) { ControllerMappingSignature buttonSignature = new ControllerMappingSignature(supportedControllerType, handedness); ControllerPopupWindow.Show(controllerMapping, interactionsProperty, handedness, controllersAffectedByMappingSignatures[buttonSignature]); } if (GUILayout.Button(EditorGUIUtility.IconContent("_Menu"), new GUIStyle("iconButton"))) { // create the menu and add items to it GenericMenu menu = new GenericMenu(); // Caching the index of this controller mapping for the anonymous function int index = i; menu.AddItem(new GUIContent("Reset to default input actions"), false, () => ResetInputActions(ref thisProfile.MixedRealityControllerMappings[index])); menu.ShowAsContext(); } EditorGUILayout.EndHorizontal(); } } if (horizontalScope != null) { horizontalScope.Dispose(); horizontalScope = null; } } } }
public ControllerItem(SupportedControllerType controllerType, Handedness handedness, MixedRealityInteractionMapping[] interactions) { ControllerType = controllerType; Handedness = handedness; Interactions = interactions; }
public ControllerRenderProfile(SupportedControllerType supportedControllerType, Handedness handedness, MixedRealityInteractionMapping[] interactions) { SupportedControllerType = supportedControllerType; Handedness = handedness; Interactions = interactions; }
public ControllerMappingSignature(SupportedControllerType supportedControllerType, Handedness handedness) { SupportedControllerType = supportedControllerType; Handedness = handedness; }
/// <summary> /// Constructor. /// </summary> public PointerOption(SupportedControllerType controllerType, Handedness handedness, GameObject pointerPrefab) { this.controllerType = controllerType; this.handedness = handedness; this.pointerPrefab = pointerPrefab; }
protected SimulatedHand GetOrAddHandDevice(Handedness handedness, HandSimulationMode simulationMode) { var controller = GetHandDevice(handedness); if (controller != null) { if (controller.SimulationMode == simulationMode) { return(controller); } else { // Remove and recreate hand device if simulation mode doesn't match RemoveHandDevice(handedness); } } SupportedControllerType st = simulationMode == HandSimulationMode.Gestures ? SupportedControllerType.GGVHand : SupportedControllerType.ArticulatedHand; IMixedRealityPointer[] pointers = RequestPointers(st, handedness); var inputSource = InputSystem?.RequestNewGenericInputSource($"{handedness} Hand", pointers, InputSourceType.Hand); switch (simulationMode) { case HandSimulationMode.Articulated: controller = new SimulatedArticulatedHand(TrackingState.Tracked, handedness, inputSource); break; case HandSimulationMode.Gestures: controller = new SimulatedGestureHand(TrackingState.Tracked, handedness, inputSource); break; default: controller = null; break; } System.Type controllerType = simulationMode == HandSimulationMode.Gestures ? typeof(SimulatedGestureHand) : typeof(SimulatedArticulatedHand); if (controller == null) { Debug.LogError($"Failed to create {controllerType} controller"); return(null); } if (!controller.SetupConfiguration(controllerType, InputSourceType.Hand)) { // Controller failed to be setup correctly. Debug.LogError($"Failed to Setup {controllerType} controller"); // Return null so we don't raise the source detected. return(null); } for (int i = 0; i < controller.InputSource?.Pointers?.Length; i++) { controller.InputSource.Pointers[i].Controller = controller; } InputSystem?.RaiseSourceDetected(controller.InputSource, controller); trackedHands.Add(handedness, controller); UpdateActiveControllers(); return(controller); }
private void RenderControllerList(SerializedProperty controllerList) { if (thisProfile.MixedRealityControllerMappingProfiles.Length != controllerList.arraySize) { return; } EditorGUILayout.Space(); if (GUILayout.Button(ControllerAddButtonContent, EditorStyles.miniButton)) { AddController(controllerList, typeof(GenericJoystickController)); return; } controllerRenderList.Clear(); GUILayout.Space(12f); using (var outerVerticalScope = new GUILayout.VerticalScope()) { GUILayout.HorizontalScope horizontalScope = null; for (int i = 0; i < thisProfile.MixedRealityControllerMappingProfiles.Length; i++) { MixedRealityControllerMapping controllerMapping = thisProfile.MixedRealityControllerMappingProfiles[i]; Type controllerType = controllerMapping.ControllerType; if (controllerType == null) { continue; } Handedness handedness = controllerMapping.Handedness; bool useCustomInteractionMappings = controllerMapping.HasCustomInteractionMappings; SupportedControllerType supportedControllerType = controllerMapping.SupportedControllerType; var controllerMappingProperty = controllerList.GetArrayElementAtIndex(i); var handednessProperty = controllerMappingProperty.FindPropertyRelative("handedness"); if (!useCustomInteractionMappings) { bool skip = false; // Merge controllers with the same supported controller type. for (int j = 0; j < controllerRenderList.Count; j++) { if (controllerRenderList[j].SupportedControllerType == supportedControllerType && controllerRenderList[j].Handedness == handedness) { try { thisProfile.MixedRealityControllerMappingProfiles[i].SynchronizeInputActions(controllerRenderList[j].Interactions); } catch (ArgumentException e) { Debug.LogError($"Controller mappings between {thisProfile.MixedRealityControllerMappingProfiles[i].Description} and {controllerMapping.Description} do not match. Error message: {e.Message}"); } serializedObject.ApplyModifiedProperties(); skip = true; } } if (skip) { continue; } } controllerRenderList.Add(new ControllerRenderProfile(supportedControllerType, handedness, thisProfile.MixedRealityControllerMappingProfiles[i].Interactions)); string controllerTitle = thisProfile.MixedRealityControllerMappingProfiles[i].Description; var interactionsProperty = controllerMappingProperty.FindPropertyRelative("interactions"); if (useCustomInteractionMappings) { if (horizontalScope != null) { horizontalScope.Dispose(); horizontalScope = null; } GUILayout.Space(24f); using (var verticalScope = new GUILayout.VerticalScope()) { using (horizontalScope = new GUILayout.HorizontalScope()) { EditorGUIUtility.labelWidth = 64f; EditorGUIUtility.fieldWidth = 64f; EditorGUILayout.LabelField(controllerTitle); EditorGUIUtility.fieldWidth = defaultFieldWidth; EditorGUIUtility.labelWidth = defaultLabelWidth; if (GUILayout.Button(ControllerMinusButtonContent, EditorStyles.miniButtonRight, GUILayout.Width(24f))) { controllerList.DeleteArrayElementAtIndex(i); return; } } EditorGUI.indentLevel++; EditorGUIUtility.labelWidth = 128f; EditorGUIUtility.fieldWidth = 64f; EditorGUI.BeginChangeCheck(); // Generic Type dropdown Type[] genericTypes = MixedRealityControllerMappingProfile.CustomControllerMappingTypes; var genericTypeListContent = new GUIContent[genericTypes.Length]; var genericTypeListIds = new int[genericTypes.Length]; int currentGenericType = -1; for (int genericTypeIdx = 0; genericTypeIdx < genericTypes.Length; genericTypeIdx++) { var attribute = MixedRealityControllerAttribute.Find(genericTypes[genericTypeIdx]); if (attribute != null) { genericTypeListContent[genericTypeIdx] = new GUIContent(attribute.SupportedControllerType.ToString().Replace("Generic", "").ToProperCase() + " Controller"); } else { genericTypeListContent[genericTypeIdx] = new GUIContent("Unknown Controller"); } genericTypeListIds[genericTypeIdx] = genericTypeIdx; if (controllerType == genericTypes[genericTypeIdx]) { currentGenericType = genericTypeIdx; } } Debug.Assert(currentGenericType != -1); currentGenericType = EditorGUILayout.IntPopup(GenericTypeContent, currentGenericType, genericTypeListContent, genericTypeListIds); controllerType = genericTypes[currentGenericType]; { // Handedness dropdown var attribute = MixedRealityControllerAttribute.Find(controllerType); if (attribute != null && attribute.SupportedHandedness.Length >= 1) { // Make sure handedness is valid for the selected controller type. if (Array.IndexOf(attribute.SupportedHandedness, (Handedness)handednessProperty.intValue) < 0) { handednessProperty.intValue = (int)attribute.SupportedHandedness[0]; } if (attribute.SupportedHandedness.Length >= 2) { var handednessListContent = new GUIContent[attribute.SupportedHandedness.Length]; var handednessListIds = new int[attribute.SupportedHandedness.Length]; for (int handednessIdx = 0; handednessIdx < attribute.SupportedHandedness.Length; handednessIdx++) { handednessListContent[handednessIdx] = new GUIContent(attribute.SupportedHandedness[handednessIdx].ToString()); handednessListIds[handednessIdx] = (int)attribute.SupportedHandedness[handednessIdx]; } handednessProperty.intValue = EditorGUILayout.IntPopup(HandednessTypeContent, handednessProperty.intValue, handednessListContent, handednessListIds); } } else { handednessProperty.intValue = (int)Handedness.None; } } if (EditorGUI.EndChangeCheck()) { interactionsProperty.ClearArray(); serializedObject.ApplyModifiedProperties(); thisProfile.MixedRealityControllerMappingProfiles[i].ControllerType.Type = genericTypes[currentGenericType]; thisProfile.MixedRealityControllerMappingProfiles[i].SetDefaultInteractionMapping(true); serializedObject.ApplyModifiedProperties(); return; } EditorGUIUtility.labelWidth = defaultLabelWidth; EditorGUIUtility.fieldWidth = defaultFieldWidth; EditorGUI.indentLevel--; if (GUILayout.Button("Edit Input Action Map")) { ControllerPopupWindow.Show(controllerMapping, interactionsProperty, handedness); } if (GUILayout.Button("Reset Input Actions")) { interactionsProperty.ClearArray(); serializedObject.ApplyModifiedProperties(); thisProfile.MixedRealityControllerMappingProfiles[i].SetDefaultInteractionMapping(true); serializedObject.ApplyModifiedProperties(); } } } else { if (supportedControllerType == SupportedControllerType.WindowsMixedReality && handedness == Handedness.None) { controllerTitle = "HoloLens Voice and Clicker"; } if (handedness != Handedness.Right) { if (horizontalScope != null) { horizontalScope.Dispose(); horizontalScope = null; } horizontalScope = new GUILayout.HorizontalScope(); } var buttonContent = new GUIContent(controllerTitle, ControllerMappingLibrary.GetControllerTextureScaled(controllerType, handedness)); if (GUILayout.Button(buttonContent, controllerButtonStyle, GUILayout.Height(128f), GUILayout.MinWidth(32f), GUILayout.ExpandWidth(true))) { ControllerPopupWindow.Show(controllerMapping, interactionsProperty, handedness); } } } if (horizontalScope != null) { horizontalScope.Dispose(); horizontalScope = null; } } }