/****************************************************************************
* Copyright 2019 Nreal Techonology Limited. All rights reserved.
*
* This file is part of NRSDK.
*
* https://www.nreal.ai/
*
*****************************************************************************/
namespace NRKernal
{
using System;
using System.Collections.Generic;
using UnityEngine;
/// Values that represent controller types.
public enum ControllerType
{
/// An enum constant representing the controller type editor option.
CONTROLLER_TYPE_EDITOR = 1001,
/// An enum constant representing the controller type unknown option.
CONTROLLER_TYPE_UNKNOWN = -1,
/// An enum constant representing the controller type nreallight option.
CONTROLLER_TYPE_NREALLIGHT = 0,
/// An enum constant representing the controller type phone option.
CONTROLLER_TYPE_PHONE = 1,
/// An enum constant representing the controller type hand option.
CONTROLLER_TYPE_HAND = 2
}
/// Values that represent controller available features.
public enum ControllerAvailableFeature
{
/// The position is avaliable.
CONTROLLER_AVAILABLE_FEATURE_POSITION = (1 << 0),
/// The rotation is avaliable.
CONTROLLER_AVAILABLE_FEATURE_ROTATION = (1 << 1),
///
/// An enum constant representing the controller available feature gyro option.
CONTROLLER_AVAILABLE_FEATURE_GYRO = (1 << 2),
///
/// An enum constant representing the controller available feature accel option.
CONTROLLER_AVAILABLE_FEATURE_ACCEL = (1 << 3),
///
/// An enum constant representing the controller available feature Magnitude option.
CONTROLLER_AVAILABLE_FEATURE_MAG = (1 << 4),
///
/// An enum constant representing the controller available feature battery option.
CONTROLLER_AVAILABLE_FEATURE_BATTERY = (1 << 5),
///
/// An enum constant representing the controller available feature charging option.
CONTROLLER_AVAILABLE_FEATURE_CHARGING = (1 << 6),
///
/// An enum constant representing the controller available feature recenter option.
CONTROLLER_AVAILABLE_FEATURE_RECENTER = (1 << 7),
///
/// An enum constant representing the controller available feature haptic vibrate option.
CONTROLLER_AVAILABLE_FEATURE_HAPTIC_VIBRATE = (1 << 8)
}
/// Values that represent controller buttons.
public enum ControllerButton
{
/// An enum constant representing the first option.
BEGIN = 1 << 0,
/// An enum constant representing the trigger option.
TRIGGER = 1 << 0,
/// An enum constant representing the Application option.
APP = 1 << 1,
/// An enum constant representing the home option.
HOME = 1 << 2,
/// An enum constant representing the grip option.
GRIP = 1 << 3,
/// An enum constant representing the touchpad button option.
TOUCHPAD_BUTTON = 1 << 4,
/// An enum constant representing the last option.
END = 1 << 4,
}
/// Values that represent controller connection states.
public enum ControllerConnectionState
{
///
/// An enum constant representing the controller connection state error option.
CONTROLLER_CONNECTION_STATE_ERROR = -1,
///
/// An enum constant representing the controller connection state not initialized option.
CONTROLLER_CONNECTION_STATE_NOT_INITIALIZED = 0,
///
/// An enum constant representing the controller connection state disconnected option.
CONTROLLER_CONNECTION_STATE_DISCONNECTED = 1,
///
/// An enum constant representing the controller connection state connecting option.
CONTROLLER_CONNECTION_STATE_CONNECTING = 2,
///
/// An enum constant representing the controller connection state connected option.
CONTROLLER_CONNECTION_STATE_CONNECTED = 3
}
internal enum HandednessType
{
LEFT_HANDEDNESS = 1,
RIGHT_HANDEDNESS,
}
/// Values that represent button event types.
internal enum ButtonEventType
{
/// An enum constant representing the down option.
Down = 0,
/// An enum constant representing the pressing option.
Pressing,
/// An enum constant representing the up option.
Up,
/// An enum constant representing the click option.
Click,
}
/// A controller state.
public class ControllerState
{
/// Type of the controller.
internal ControllerType controllerType;
/// State of the connection.
internal ControllerConnectionState connectionState;
/// The rotation.
internal Quaternion rotation;
/// The position.
internal Vector3 position;
/// The gyro.
internal Vector3 gyro;
/// The accel.
internal Vector3 accel;
/// The magnitude.
internal Vector3 mag;
/// The touch position.
internal Vector2 touchPos;
/// The delta touch.
internal Vector2 deltaTouch;
/// True if is touching, false if not.
internal bool isTouching;
/// True if recentered.
internal bool recentered;
/// State of the buttons.
internal ControllerButton buttonsState;
/// The buttons down.
internal ControllerButton buttonsDown;
/// The buttons up.
internal ControllerButton buttonsUp;
/// True if is charging, false if not.
internal bool isCharging;
/// The battery level.
internal int batteryLevel;
/// The available feature.
internal ControllerAvailableFeature availableFeature;
/// The last touch position.
private Vector2 m_LastTouchPos;
/// Dictionary of last down times.
private Dictionary m_LastDownTimeDict = new Dictionary();
/// Array of listeners.
private Dictionary[] m_ListenersArr = new Dictionary[Enum.GetValues(typeof(ButtonEventType)).Length];
/// Default constructor.
public ControllerState()
{
Reset();
}
/// Gets a value indicating whether this object is 6dof.
/// True if this object is 6dof, false if not.
public bool Is6dof
{
get
{
return IsFeatureAvailable(ControllerAvailableFeature.CONTROLLER_AVAILABLE_FEATURE_POSITION) && IsFeatureAvailable(ControllerAvailableFeature.CONTROLLER_AVAILABLE_FEATURE_ROTATION);
}
}
/// Queries if a feature is available.
/// The feature.
/// True if the feature is available, false if not.
public bool IsFeatureAvailable(ControllerAvailableFeature feature)
{
return (availableFeature & feature) != 0;
}
/// Gets a button.
/// The button.
/// True if it succeeds, false if it fails.
public bool GetButton(ControllerButton button)
{
return (buttonsState & button) != 0;
}
/// Gets button down.
/// The button.
/// True if it succeeds, false if it fails.
public bool GetButtonDown(ControllerButton button)
{
return (buttonsDown & button) != 0;
}
/// Gets button up.
/// The button.
/// True if it succeeds, false if it fails.
public bool GetButtonUp(ControllerButton button)
{
return (buttonsUp & button) != 0;
}
/// Resets this object.
public void Reset()
{
controllerType = ControllerType.CONTROLLER_TYPE_UNKNOWN;
connectionState = ControllerConnectionState.CONTROLLER_CONNECTION_STATE_NOT_INITIALIZED;
rotation = Quaternion.identity;
position = Vector3.zero;
gyro = Vector3.zero;
accel = Vector3.zero;
mag = Vector3.zero;
touchPos = Vector2.zero;
isTouching = false;
recentered = false;
buttonsState = 0;
buttonsDown = 0;
buttonsUp = 0;
isCharging = false;
batteryLevel = 0;
availableFeature = 0;
}
/// Adds a button listener.
/// Type of the button event.
/// The button.
/// The action.
internal void AddButtonListener(ButtonEventType buttonEventType, ControllerButton button, Action action)
{
int buttonEventID = (int)buttonEventType;
if (m_ListenersArr[buttonEventID] == null)
{
m_ListenersArr[buttonEventID] = new Dictionary();
}
if (m_ListenersArr[buttonEventID].ContainsKey(button))
{
m_ListenersArr[buttonEventID][button] += action;
}
else
{
m_ListenersArr[buttonEventID].Add(button, action);
}
}
/// Removes the button listener.
/// Type of the button event.
/// The button.
/// The action.
internal void RemoveButtonListener(ButtonEventType buttonEventType, ControllerButton button, Action action)
{
int buttonEventID = (int)buttonEventType;
if (m_ListenersArr[buttonEventID] == null)
{
m_ListenersArr[buttonEventID] = new Dictionary();
}
if (m_ListenersArr[buttonEventID].ContainsKey(button) && m_ListenersArr[buttonEventID][button] != null)
{
m_ListenersArr[buttonEventID][button] -= action;
if (m_ListenersArr[buttonEventID][button] == null)
{
m_ListenersArr[buttonEventID].Remove(button);
}
}
}
/// Updates the delta touch.
internal void UpdateDeltaTouch()
{
if (m_LastTouchPos.Equals(Vector2.zero) || touchPos.Equals(Vector2.zero))
{
deltaTouch = Vector2.zero;
}
else
{
deltaTouch = touchPos - m_LastTouchPos;
}
m_LastTouchPos = touchPos;
}
/// Check button events.
internal void CheckButtonEvents()
{
UpdateDeltaTouch();
for (int i = (int)ControllerButton.BEGIN; i <= (int)ControllerButton.END; i <<= 1)
{
var button = (ControllerButton)i;
if (GetButtonDown(button))
{
if (m_LastDownTimeDict.ContainsKey(button))
{
m_LastDownTimeDict[button] = Time.unscaledTime;
}
else
{
m_LastDownTimeDict.Add(button, Time.unscaledTime);
}
TryInvokeListener(ButtonEventType.Down, button);
}
if (GetButton(button))
{
TryInvokeListener(ButtonEventType.Pressing, button);
}
else if (GetButtonUp(button))
{
TryInvokeListener(ButtonEventType.Up, button);
float lastDownTime;
if (m_LastDownTimeDict.TryGetValue(button, out lastDownTime) && Time.unscaledTime - lastDownTime < NRInput.ClickInterval)
{
TryInvokeListener(ButtonEventType.Click, button);
}
}
}
}
/// Try invoke listener.
/// Type of the button event.
/// The button.
private void TryInvokeListener(ButtonEventType buttonEventType, ControllerButton button)
{
int buttonEventID = (int)buttonEventType;
if (m_ListenersArr[buttonEventID] == null)
return;
if (m_ListenersArr[buttonEventID].ContainsKey(button) && m_ListenersArr[buttonEventID][button] != null)
{
m_ListenersArr[buttonEventID][button].Invoke();
}
}
}
}