// Copyright (c) Microsoft Corporation. // Licensed under the MIT License. using Microsoft.MixedReality.Toolkit.Input; using Microsoft.MixedReality.Toolkit.Utilities; using Unity.Profiling; using UnityEngine; using UnityEngine.XR; #if WINDOWS_UWP using Microsoft.MixedReality.Toolkit.WindowsMixedReality; #endif // WINDOWS_UWP namespace Microsoft.MixedReality.Toolkit.XRSDK.WindowsMixedReality { /// /// XR SDK implementation of Windows Mixed Reality motion controllers. /// [MixedRealityController( SupportedControllerType.WindowsMixedReality, new[] { Handedness.Left, Handedness.Right }, "Textures/MotionController", supportedUnityXRPipelines: SupportedUnityXRPipelines.XRSDK)] public class WindowsMixedRealityXRSDKMotionController : BaseWindowsMixedRealityXRSDKSource { /// /// Constructor. /// public WindowsMixedRealityXRSDKMotionController( TrackingState trackingState, Handedness controllerHandedness, IMixedRealityInputSource inputSource = null, MixedRealityInteractionMapping[] interactions = null) : this(trackingState, controllerHandedness, new WindowsMixedRealityControllerDefinition(controllerHandedness), inputSource, interactions) { } public WindowsMixedRealityXRSDKMotionController( TrackingState trackingState, Handedness controllerHandedness, IMixedRealityInputSourceDefinition definition, IMixedRealityInputSource inputSource = null, MixedRealityInteractionMapping[] interactions = null) : base(trackingState, controllerHandedness, inputSource, interactions, definition) { } private static readonly ProfilerMarker UpdateButtonDataPerfMarker = new ProfilerMarker("[MRTK] WindowsMixedRealityXRSDKMotionController.UpdateButtonData"); /// protected override void UpdateButtonData(MixedRealityInteractionMapping interactionMapping, InputDevice inputDevice) { using (UpdateButtonDataPerfMarker.Auto()) { Debug.Assert(interactionMapping.AxisType == AxisType.Digital); InputFeatureUsage buttonUsage; // These mappings are flipped from the base class, // where thumbstick is primary and touchpad is secondary. switch (interactionMapping.InputType) { case DeviceInputType.TouchpadTouch: buttonUsage = CommonUsages.primary2DAxisTouch; break; case DeviceInputType.TouchpadPress: buttonUsage = CommonUsages.primary2DAxisClick; break; case DeviceInputType.ThumbStickPress: buttonUsage = CommonUsages.secondary2DAxisClick; break; default: base.UpdateButtonData(interactionMapping, inputDevice); return; } if (inputDevice.TryGetFeatureValue(buttonUsage, out bool buttonPressed)) { interactionMapping.BoolData = buttonPressed; } // If our value changed raise it. if (interactionMapping.Changed) { // Raise input system event if it's enabled if (interactionMapping.BoolData) { CoreServices.InputSystem?.RaiseOnInputDown(InputSource, ControllerHandedness, interactionMapping.MixedRealityInputAction); } else { CoreServices.InputSystem?.RaiseOnInputUp(InputSource, ControllerHandedness, interactionMapping.MixedRealityInputAction); } } } } private static readonly ProfilerMarker UpdateDualAxisDataPerfMarker = new ProfilerMarker("[MRTK] WindowsMixedRealityXRSDKMotionController.UpdateDualAxisData"); /// protected override void UpdateDualAxisData(MixedRealityInteractionMapping interactionMapping, InputDevice inputDevice) { using (UpdateDualAxisDataPerfMarker.Auto()) { Debug.Assert(interactionMapping.AxisType == AxisType.DualAxis); InputFeatureUsage axisUsage; // These mappings are flipped from the base class, // where thumbstick is primary and touchpad is secondary. switch (interactionMapping.InputType) { case DeviceInputType.ThumbStick: axisUsage = CommonUsages.secondary2DAxis; break; case DeviceInputType.Touchpad: axisUsage = CommonUsages.primary2DAxis; break; default: base.UpdateDualAxisData(interactionMapping, inputDevice); return; } if (inputDevice.TryGetFeatureValue(axisUsage, out Vector2 axisData)) { // Update the interaction data source interactionMapping.Vector2Data = axisData; } // If our value changed raise it. if (interactionMapping.Changed) { // Raise input system event if it's enabled CoreServices.InputSystem?.RaisePositionInputChanged(InputSource, ControllerHandedness, interactionMapping.MixedRealityInputAction, interactionMapping.Vector2Data); } } } #if WINDOWS_UWP private WindowsMixedRealityControllerModelProvider controllerModelProvider; /// protected override bool TryRenderControllerModel(System.Type controllerType, InputSourceType inputSourceType) { if (GetControllerVisualizationProfile() == null || !GetControllerVisualizationProfile().GetUsePlatformModelsOverride(GetType(), ControllerHandedness)) { return base.TryRenderControllerModel(controllerType, inputSourceType); } else { TryRenderControllerModelWithModelProvider(); return true; } } private async void TryRenderControllerModelWithModelProvider() { if (controllerModelProvider == null) { controllerModelProvider = new WindowsMixedRealityControllerModelProvider(ControllerHandedness); } GameObject controllerModel = await controllerModelProvider.TryGenerateControllerModelFromPlatformSDK(); if (this != null) { if (controllerModel != null && MixedRealityControllerModelHelpers.TryAddVisualizationScript(controllerModel, GetType(), ControllerHandedness) && TryAddControllerModelToSceneHierarchy(controllerModel)) { controllerModel.SetActive(true); return; } Debug.LogWarning("Failed to create controller model from driver; defaulting to BaseController behavior."); base.TryRenderControllerModel(GetType(), InputSource.SourceType); } if (controllerModel != null) { // If we didn't successfully set up the model and add it to the hierarchy (which returns early), set it inactive. controllerModel.SetActive(false); } } #endif } }