#if UNITY_2017_2_OR_NEWER
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.XR;
using ZenFulcrum.EmbeddedBrowser.VR;
namespace ZenFulcrum.EmbeddedBrowser {
///
/// Class for tracking (and optionally rendering) a tracked controller, usable for VR input to a browser.
///
/// Put two VRHand objects in the scene, one for each controller. Make sure they have the same transform parent
/// as the main camera so they will correctly move with the player.
/// (Also, make sure your main camera is centered on its local origin to start.)
///
/// If desired, you can also put some visible geometry under the VRHand. Set it as `visualization` and it will
/// move with the controller and disappear when untracked.
///
public class VRBrowserHand : MonoBehaviour {
[Tooltip("Which hand we should look to track.")]
public XRNode hand = XRNode.LeftHand;
[Tooltip("Optional visualization of this hand. It should be a child of the VRHand object and will be set active when the controller is tracking.")]
public GameObject visualization;
///
/// Are we currently tracking?
///
public bool Tracked { get; private set; }
///
/// Currently depressed buttons.
///
public MouseButton DepressedButtons { get; private set; }
///
/// How much we've scrolled since the last frame. Same units as Input.mouseScrollDelta.
///
public Vector2 ScrollDelta { get; private set; }
public string Name { get; private set; }
private XRNodeState nodeState;
public void OnEnable() {
VRInput.Init();
//VR poses update after LateUpdate and before OnPreCull
Camera.onPreCull += UpdatePreCull;
if (visualization) visualization.SetActive(false);
}
public void OnDisable() {
// ReSharper disable once DelegateSubtraction
Camera.onPreCull -= UpdatePreCull;
}
public virtual void Update() {
ReadInput();
}
protected virtual void ReadInput() {
DepressedButtons = 0;
ScrollDelta = Vector2.zero;
if (!nodeState.tracked) return;
var leftClick = VRInput.GetAxis(nodeState, InputAxis.MainTrigger);
if (leftClick > .9f) DepressedButtons |= MouseButton.Left;
var rightClick = VRInput.GetAxis(nodeState, InputAxis.Grip);
if (rightClick > .5f) DepressedButtons |= MouseButton.Right;
switch (VRInput.GetJoypadType(nodeState)) {
case JoyPadType.Joystick:
ReadJoystick();
break;
case JoyPadType.TouchPad:
ReadTouchpad();
break;
}
}
[Tooltip("How much we must slide a finger/joystick before we start scrolling.")]
public float scrollThreshold = .1f;
[Tooltip(@"How fast the page moves as we move our finger across the touchpad.
Set to a negative number to enable that infernal ""natural scrolling"" that's been making so many trackpads unusable lately.")]
public float trackpadScrollSpeed = .05f;
[Tooltip("How fast the page moves as we scroll with a joystick.")]
public float joystickScrollSpeed = 75f;
private Vector2 lastTouchPoint;
private bool touchIsScrolling;
protected virtual void ReadTouchpad() {
var touchPoint = new Vector2(VRInput.GetAxis(nodeState, InputAxis.JoypadX), VRInput.GetAxis(nodeState, InputAxis.JoypadY));
var touchButton = VRInput.GetTouch(nodeState, InputAxis.Joypad) > .5f;
if (touchButton) {
var delta = touchPoint - lastTouchPoint;
if (!touchIsScrolling) {
if (delta.magnitude * trackpadScrollSpeed > scrollThreshold) {
touchIsScrolling = true;
lastTouchPoint = touchPoint;
} else {
//don't start updating the touch point yet
}
} else {
ScrollDelta = new Vector2(-delta.x, delta.y) * trackpadScrollSpeed;
lastTouchPoint = touchPoint;
}
} else {
ScrollDelta = new Vector2();
lastTouchPoint = touchPoint;
touchIsScrolling = false;
}
}
protected virtual void ReadJoystick() {
ScrollDelta = new Vector2();
var offset = new Vector2(
-VRInput.GetAxis(nodeState, InputAxis.JoypadX),
VRInput.GetAxis(nodeState, InputAxis.JoypadY)
);
offset.x = Mathf.Abs(offset.x) > scrollThreshold ? offset.x - Mathf.Sign(offset.x) * scrollThreshold : 0;
offset.y = Mathf.Abs(offset.y) > scrollThreshold ? offset.y - Mathf.Sign(offset.y) * scrollThreshold : 0;
offset = offset * offset.magnitude * joystickScrollSpeed * Time.deltaTime;
ScrollDelta = offset;
}
private int lastFrame;
private List states = new List();
private bool hasTouchpad;
private void UpdatePreCull(Camera cam) {
if (lastFrame == Time.frameCount) return;
lastFrame = Time.frameCount;
InputTracking.GetNodeStates(states);
for (int i = 0; i < states.Count; i++) {
//Debug.Log("A thing: " + states[i].nodeType + " and " + InputTracking.GetNodeName(states[i].uniqueID));
if (states[i].nodeType != hand) continue;
nodeState = states[i];
Vector3 pos;
if (states[i].TryGetPosition(out pos)) transform.localPosition = pos;
Quaternion rot;
if (states[i].TryGetRotation(out rot)) transform.localRotation = rot;
if (visualization) visualization.SetActive(Tracked = states[i].tracked);
}
}
}
}
#endif