FittsLaw/Assets/GoogleVR/Scripts/Controller/GvrControllerInputDevice.cs
2018-10-08 23:54:11 -04:00

251 lines
8.4 KiB
C#

// Copyright 2018 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using UnityEngine;
using System;
using System.Collections;
using Gvr.Internal;
/// Device instance of the Daydream controller API.
public class GvrControllerInputDevice {
private IControllerProvider controllerProvider;
private int controllerId;
private ControllerState controllerState = new ControllerState();
private Vector2 touchPosCentered = Vector2.zero;
private int lastUpdatedFrameCount = -1;
private bool valid;
/// Event handler for when the connection state of the controller changes.
public event GvrControllerInput.OnStateChangedEvent OnStateChanged;
internal GvrControllerInputDevice(IControllerProvider provider, int controller_id) {
controllerProvider = provider;
controllerId = controller_id;
valid = true;
}
internal void Invalidate() {
valid = false;
}
public bool IsDominantHand {
get {
return controllerId == 0;
}
}
public bool IsRightHand {
get {
if (controllerId == 0) {
return GvrSettings.Handedness == GvrSettings.UserPrefsHandedness.Right;
} else {
return GvrSettings.Handedness == GvrSettings.UserPrefsHandedness.Left;
}
}
}
/// Returns the controller's current connection state.
public GvrConnectionState State {
get {
Update();
return controllerState.connectionState;
}
}
/// Returns the API status of the current controller state.
public GvrControllerApiStatus ApiStatus {
get {
Update();
return controllerState.apiStatus;
}
}
/// Returns the controller's current orientation in space, as a quaternion.
/// The rotation is provided in 'orientation space' which means the rotation is given relative
/// to the last time the user recentered their controller. To make a game object in your scene
/// have the same orientation as the controller, simply assign this quaternion to the object's
/// `transform.rotation`. To match the relative rotation, use `transform.localRotation` instead.
public Quaternion Orientation {
get {
Update();
return controllerState.orientation;
}
}
public Vector3 Position {
get {
Update();
return controllerState.position;
}
}
/// Returns the controller's current angular speed in radians per second, using the right-hand
/// rule (positive means a right-hand rotation about the given axis), as measured by the
/// controller's gyroscope.
/// The controller's axes are:
/// - X points to the right,
/// - Y points perpendicularly up from the controller's top surface
/// - Z lies along the controller's body, pointing towards the front
public Vector3 Gyro {
get {
Update();
return controllerState.gyro;
}
}
/// Returns the controller's current acceleration in meters per second squared.
/// The controller's axes are:
/// - X points to the right,
/// - Y points perpendicularly up from the controller's top surface
/// - Z lies along the controller's body, pointing towards the front
/// Note that gravity is indistinguishable from acceleration, so when the controller is resting
/// on a surface, expect to measure an acceleration of 9.8 m/s^2 on the Y axis. The accelerometer
/// reading will be zero on all three axes only if the controller is in free fall, or if the user
/// is in a zero gravity environment like a space station.
public Vector3 Accel {
get {
Update();
return controllerState.accel;
}
}
/// Position of the current touch, if touching the touchpad.
/// If not touching, this is the position of the last touch (when the finger left the touchpad).
/// The X and Y range is from -1.0 to 1.0. (0, 0) is the center of the touchpad.
/// (-.707, -.707) is bottom left, (.707, .707) is upper right.
/// The magnitude of the touch vector is guaranteed to be <= 1.0.
public Vector2 TouchPos {
get {
Update();
return touchPosCentered;
}
}
/// Returns true if the user just completed the recenter gesture. The headset and
/// the controller's orientation are now being reported in the new recentered
/// coordinate system. This is an event flag (it is true for only one frame
/// after the event happens, then reverts to false).
public bool Recentered {
get {
Update();
return controllerState.recentered;
}
}
/// Returns true if the user is holding down any of the buttons specified in `buttons`.
/// GvrControllerButton types can be OR-ed together to check for multiple buttons at once.
public bool GetButton(GvrControllerButton buttons) {
Update();
return (controllerState.buttonsState & buttons) != 0;
}
/// Returns true in the frame the user starts pressing down any of the buttons specified
/// in `buttons`. For an individual button enum, every ButtonDown event is guaranteed to be
/// followed by exactly one ButtonUp event in a later frame. Also, ButtonDown and ButtonUp
/// will never both be true in the same frame for an individual button. Using multiple button
/// enums OR'ed together can result in multiple ButtonDowns before a ButtonUp.
public bool GetButtonDown(GvrControllerButton buttons) {
Update();
return (controllerState.buttonsDown & buttons) != 0;
}
/// Returns true the frame after the user stops pressing down any of the buttons specified
/// in `buttons`. For an individual button enum, every ButtonUp event is guaranteed to be
/// preceded by exactly one ButtonDown event in an earlier frame. Also, ButtonDown and
/// ButtonUp will never both be true in the same frame for an individual button. Using
/// multiple button enums OR'ed together can result in multiple ButtonUps after multiple
/// ButtonDowns.
public bool GetButtonUp(GvrControllerButton buttons) {
Update();
return (controllerState.buttonsUp & buttons) != 0;
}
/// If State == GvrConnectionState.Error, this contains details about the error.
public string ErrorDetails {
get {
Update();
return controllerState.connectionState == GvrConnectionState.Error ?
controllerState.errorDetails : "";
}
}
/// Returns the GVR C library controller state pointer (gvr_controller_state*).
public IntPtr StatePtr {
get {
Update();
return controllerState.gvrPtr;
}
}
/// Returns true if the controller is currently being charged.
public bool IsCharging {
get {
Update();
return controllerState.isCharging;
}
}
/// Returns the controller's current battery charge level.
public GvrControllerBatteryLevel BatteryLevel {
get {
Update();
return controllerState.batteryLevel;
}
}
internal void Update() {
if (lastUpdatedFrameCount != Time.frameCount) {
if (!valid) {
Debug.LogError("Using an invalid GvrControllerInputDevice. Please acquire a new one from GvrControllerInput.GetDevice().");
return;
}
// The controller state must be updated prior to any function using the
// controller API to ensure the state is consistent throughout a frame.
lastUpdatedFrameCount = Time.frameCount;
GvrConnectionState oldState = State;
controllerProvider.ReadState(controllerState, controllerId);
UpdateTouchPosCentered();
#if UNITY_EDITOR
if (IsDominantHand) {
// Make sure the EditorEmulator is updated immediately.
if (GvrEditorEmulator.Instance != null) {
GvrEditorEmulator.Instance.UpdateEditorEmulation();
}
}
#endif // UNITY_EDITOR
if (OnStateChanged != null && State != oldState) {
OnStateChanged(State, oldState);
}
}
}
private void UpdateTouchPosCentered() {
touchPosCentered.x = (controllerState.touchPos.x - 0.5f) * 2.0f;
touchPosCentered.y = -(controllerState.touchPos.y - 0.5f) * 2.0f;
float magnitude = touchPosCentered.magnitude;
if (magnitude > 1) {
touchPosCentered.x /= magnitude;
touchPosCentered.y /= magnitude;
}
}
}