// ENABLE_VR is not defined on Game Core but the assembly is available with limited features when the XR module is enabled. // These are the guards that Input System uses in GenericXRDevice.cs to define the XRController and XRHMD classes. #if ((ENABLE_VR || UNITY_GAMECORE) && AR_FOUNDATION_PRESENT) || PACKAGE_DOCS_GENERATION using System.Text; using UnityEngine.InputSystem.Controls; using UnityEngine.InputSystem.EnhancedTouch; using UnityEngine.InputSystem.Layouts; using UnityEngine.InputSystem.LowLevel; using UnityEngine.Scripting; namespace UnityEngine.XR.Interaction.Toolkit.AR.Inputs { /// /// An input device representing mobile 2D screen gestures. /// [InputControlLayout(stateType = typeof(TouchscreenGestureInputControllerState), displayName = "Touchscreen Gesture Input Controller", isGenericTypeOfDevice = true, updateBeforeRender = false)] [Preserve] public class TouchscreenGestureInputController : InputSystem.XR.XRController, IInputUpdateCallbackReceiver { /// /// The screen position where the tap gesture started. /// public Vector2Control tapStartPosition { get; private set; } /// /// The screen position where the drag gesture started. /// public Vector2Control dragStartPosition { get; private set; } /// /// The current screen position of the drag gesture. /// public Vector2Control dragCurrentPosition { get; private set; } /// /// The delta screen position of the drag gesture. /// public Vector2Control dragDelta { get; private set; } /// /// The screen position of the first finger where the pinch gesture started. /// public Vector2Control pinchStartPosition1 { get; private set; } /// /// The screen position of the second finger where the pinch gesture started. /// public Vector2Control pinchStartPosition2 { get; private set; } /// /// The gap between then position of the first and second fingers for the pinch gesture. /// public AxisControl pinchGap { get; private set; } /// /// The gap delta between then position of the first and second fingers for the pinch gesture. /// public AxisControl pinchGapDelta { get; private set; } /// /// The screen position of the first finger where the twist gesture started. /// public Vector2Control twistStartPosition1 { get; private set; } /// /// The screen position of the second finger where the twist gesture started. /// public Vector2Control twistStartPosition2 { get; private set; } /// /// The delta rotation of the twist gesture. /// public AxisControl twistDeltaRotation { get; private set; } /// /// The screen position of the first finger where the two-finger drag gesture started. /// public Vector2Control twoFingerDragStartPosition1 { get; private set; } /// /// The screen position of the second finger where the two-finger drag gesture started. /// public Vector2Control twoFingerDragStartPosition2 { get; private set; } /// /// The current screen position of the two-finger drag gesture. /// public Vector2Control twoFingerDragCurrentPosition { get; private set; } /// /// The delta screen position of the two-finger drag gesture. /// public Vector2Control twoFingerDragDelta { get; private set; } /// /// The number of fingers on the touchscreen. /// public IntegerControl fingerCount { get; private set; } /// /// (Read Only) The Tap gesture recognizer. /// public TapGestureRecognizer tapGestureRecognizer { get; private set; } /// /// (Read Only) The Drag gesture recognizer. /// public DragGestureRecognizer dragGestureRecognizer { get; private set; } /// /// (Read Only) The Pinch gesture recognizer. /// public PinchGestureRecognizer pinchGestureRecognizer { get; private set; } /// /// (Read Only) The Twist gesture recognizer. /// public TwistGestureRecognizer twistGestureRecognizer { get; private set; } /// /// (Read Only) The two-finger Drag gesture recognizer. /// public TwoFingerDragGestureRecognizer twoFingerDragGestureRecognizer { get; private set; } TouchscreenGestureInputControllerState m_ControllerState; /// /// Finishes setting up all the input values for the controller. /// protected override void FinishSetup() { base.FinishSetup(); tapStartPosition = GetChildControl(nameof(tapStartPosition)); dragStartPosition = GetChildControl(nameof(dragStartPosition)); dragCurrentPosition = GetChildControl(nameof(dragCurrentPosition)); dragDelta = GetChildControl(nameof(dragDelta)); pinchStartPosition1 = GetChildControl(nameof(pinchStartPosition1)); pinchStartPosition2 = GetChildControl(nameof(pinchStartPosition2)); pinchGap = GetChildControl(nameof(pinchGap)); pinchGapDelta = GetChildControl(nameof(pinchGapDelta)); twistStartPosition1 = GetChildControl(nameof(twistStartPosition1)); twistStartPosition2 = GetChildControl(nameof(twistStartPosition2)); twistDeltaRotation = GetChildControl(nameof(twistDeltaRotation)); twoFingerDragStartPosition1 = GetChildControl(nameof(twoFingerDragStartPosition1)); twoFingerDragStartPosition2 = GetChildControl(nameof(twoFingerDragStartPosition2)); twoFingerDragCurrentPosition = GetChildControl(nameof(twoFingerDragCurrentPosition)); twoFingerDragDelta = GetChildControl(nameof(twoFingerDragDelta)); fingerCount = GetChildControl(nameof(fingerCount)); tapGestureRecognizer = new TapGestureRecognizer(); tapGestureRecognizer.onGestureStarted += OnGestureStarted; dragGestureRecognizer = new DragGestureRecognizer(); dragGestureRecognizer.onGestureStarted += OnGestureStarted; pinchGestureRecognizer = new PinchGestureRecognizer(); pinchGestureRecognizer.onGestureStarted += OnGestureStarted; twistGestureRecognizer = new TwistGestureRecognizer(); twistGestureRecognizer.onGestureStarted += OnGestureStarted; twoFingerDragGestureRecognizer = new TwoFingerDragGestureRecognizer(); twoFingerDragGestureRecognizer.onGestureStarted += OnGestureStarted; } /// protected override void OnAdded() { EnhancedTouchSupport.Enable(); } /// protected override void OnRemoved() { EnhancedTouchSupport.Disable(); } /// public void OnUpdate() { tapGestureRecognizer.Update(); dragGestureRecognizer.Update(); pinchGestureRecognizer.Update(); twistGestureRecognizer.Update(); twoFingerDragGestureRecognizer.Update(); var updatedTouchCount = GestureTouchesUtility.touches.Count; if (m_ControllerState.fingerCount != updatedTouchCount) { m_ControllerState.fingerCount = updatedTouchCount; InputSystem.InputSystem.QueueStateEvent(this, m_ControllerState); } } void OnGestureStarted(Gesture gesture) where T : Gesture { gesture.onUpdated += OnGestureUpdated; gesture.onFinished += OnGestureFinished; switch (gesture) { case TapGesture tapGesture: m_ControllerState.tapStartPosition = Vector2.zero; break; } InputSystem.InputSystem.QueueStateEvent(this, m_ControllerState); } void OnGestureUpdated(Gesture gesture) where T : Gesture { switch (gesture) { case TapGesture tapGesture: // Don't set the tapStartPosition since it should only be set when the gesture is successfully finished. // We don't have another control to indicate tap status, so we have to use the position control // for both status and position, so we must wait to set until the gesture is finished. break; case DragGesture dragGesture: m_ControllerState.dragStartPosition = dragGesture.startPosition; m_ControllerState.dragCurrentPosition = dragGesture.position; m_ControllerState.dragDelta = dragGesture.delta; break; case PinchGesture pinchGesture: m_ControllerState.pinchStartPosition1 = pinchGesture.startPosition1; m_ControllerState.pinchStartPosition2 = pinchGesture.startPosition2; m_ControllerState.pinchGap = pinchGesture.gap; m_ControllerState.pinchGapDelta = pinchGesture.gapDelta; break; case TwistGesture twistGesture: m_ControllerState.twistStartPosition1 = twistGesture.startPosition1; m_ControllerState.twistStartPosition2 = twistGesture.startPosition2; m_ControllerState.twistDeltaRotation = twistGesture.deltaRotation; break; case TwoFingerDragGesture twoFingerDragGesture: m_ControllerState.twoFingerDragStartPosition1 = twoFingerDragGesture.startPosition1; m_ControllerState.twoFingerDragStartPosition2 = twoFingerDragGesture.startPosition2; m_ControllerState.twoFingerDragCurrentPosition = twoFingerDragGesture.position; m_ControllerState.twoFingerDragDelta = twoFingerDragGesture.delta; break; } InputSystem.InputSystem.QueueStateEvent(this, m_ControllerState); } void OnGestureFinished(Gesture gesture) where T : Gesture { switch (gesture) { case TapGesture tapGesture: m_ControllerState.tapStartPosition = !tapGesture.isCanceled ? tapGesture.startPosition : Vector2.zero; break; case DragGesture dragGesture: m_ControllerState.dragStartPosition = Vector2.zero; m_ControllerState.dragCurrentPosition = Vector2.zero; m_ControllerState.dragDelta = Vector2.zero; break; case PinchGesture pinchGesture: m_ControllerState.pinchStartPosition1 = Vector2.zero; m_ControllerState.pinchStartPosition2 = Vector2.zero; m_ControllerState.pinchGap = 0f; m_ControllerState.pinchGapDelta = 0f; break; case TwistGesture twistGesture: m_ControllerState.twistStartPosition1 = Vector2.zero; m_ControllerState.twistStartPosition2 = Vector2.zero; m_ControllerState.twistDeltaRotation = 0f; break; case TwoFingerDragGesture twoFingerDragGesture: m_ControllerState.twoFingerDragStartPosition1 = Vector2.zero; m_ControllerState.twoFingerDragStartPosition2 = Vector2.zero; m_ControllerState.twoFingerDragCurrentPosition = Vector2.zero; m_ControllerState.twoFingerDragDelta = Vector2.zero; break; } InputSystem.InputSystem.QueueStateEvent(this, m_ControllerState); } /// /// Converts state data to a string. /// /// Returns a string representation. public override string ToString() { var stringBuilder = new StringBuilder(); stringBuilder.Append($"tapStartPosition: {tapStartPosition.value}, dragStartPosition: {dragStartPosition.value}, dragCurrentPosition: {dragCurrentPosition.value}, dragDelta: {dragDelta.value}, "); stringBuilder.Append($"pinchStartPosition1: {pinchStartPosition1.value}, pinchStartPosition2: {pinchStartPosition2.value}, pinchGap: {pinchGap.value}, pinchGapDelta: {pinchGapDelta.value}, "); stringBuilder.Append($"twistStartPosition1: {twistStartPosition1.value}, twistStartPosition2: {twistStartPosition2.value}, twistDeltaRotation: {twistDeltaRotation.value}, "); stringBuilder.Append($"twoFingerDragStartPosition1: {twoFingerDragStartPosition1.value}, twoFingerDragStartPosition2: {twoFingerDragStartPosition2.value}, twoFingerDragCurrentPosition: {twoFingerDragCurrentPosition.value}, twoFingerDragDelta: {twoFingerDragDelta.value}"); return stringBuilder.ToString(); } } } #endif