context: /************************************************************************************
  
  Copyright   :   Copyright 2014 Oculus VR, LLC. All Rights reserved.
  
  Licensed under the Oculus VR Rift SDK License Version 3.3 (the "License");
  you may not use the Oculus VR Rift SDK except in compliance with the License,
  which is provided at the time of installation or download, or which
  otherwise accompanies this software in either electronic or hard copy form.
  
  You may obtain a copy of the License at
  
  http://www.oculus.com/licenses/LICENSE-3.3
  
  Unless required by applicable law or agreed to in writing, the Oculus VR SDK
  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 System;
  using System.Collections;
  using System.Collections.Generic;
  using System.Runtime.InteropServices;
  using UnityEngine;
  
  /// <summary>
  /// Provides a unified input system for Oculus controllers and gamepads.
  /// </summary>
  public static class OVRInput
  {
  	[Flags]
  	/// Virtual button mappings that allow the same input bindings to work across different controllers.
  	public enum Button
  	{
  		None                      = 0,          ///< Maps to RawButton: [Gamepad, Touch, LTouch, RTouch, LTrackedRemote, RTrackedRemote, Touchpad, Remote: None]
  		One                       = 0x00000001, ///< Maps to RawButton: [Gamepad, Touch, RTouch: A], [LTouch: X], [LTrackedRemote: LTouchpad], [RTrackedRemote: RTouchpad], [Touchpad, Remote: Start]
  		Two                       = 0x00000002, ///< Maps to RawButton: [Gamepad, Touch, RTouch: B], [LTouch: Y], [LTrackedRemote, RTrackedRemote, Touchpad, Remote: Back]
  		Three                     = 0x00000004, ///< Maps to RawButton: [Gamepad, Touch: X], [LTouch, RTouch, LTrackedRemote, RTrackedRemote, Touchpad, Remote: None]
  		Four                      = 0x00000008, ///< Maps to RawButton: [Gamepad, Touch: Y], [LTouch, RTouch, LTrackedRemote, RTrackedRemote, Touchpad, Remote: None]
  		Start                     = 0x00000100, ///< Maps to RawButton: [Gamepad: Start], [Touch, LTouch, LTrackedRemote, RTrackedRemote, Touchpad, Remote: Start], [RTouch: None]
  		Back                      = 0x00000200, ///< Maps to RawButton: [Gamepad, LTrackedRemote, RTrackedRemote, Touchpad, Remote: Back], [Touch, LTouch, RTouch: None]
  		PrimaryShoulder           = 0x00001000, ///< Maps to RawButton: [Gamepad: LShoulder], [Touch, LTouch, RTouch, LTrackedRemote, RTrackedRemote, Touchpad, Remote: None]
  		PrimaryIndexTrigger       = 0x00002000, ///< Maps to RawButton: [Gamepad, Touch, LTouch, LTrackedRemote: LIndexTrigger], [RTouch, RTrackedRemote: RIndexTrigger], [Touchpad, Remote: None]
  		PrimaryHandTrigger        = 0x00004000, ///< Maps to RawButton: [Touch, LTouch: LHandTrigger], [RTouch: RHandTrigger], [Gamepad, LTrackedRemote, RTrackedRemote, Touchpad, Remote: None]
  		PrimaryThumbstick         = 0x00008000, ///< Maps to RawButton: [Gamepad, Touch, LTouch: LThumbstick], [RTouch: RThumbstick], [LTrackedRemote, RTrackedRemote, Touchpad, Remote: None]
  		PrimaryThumbstickUp       = 0x00010000, ///< Maps to RawButton: [Gamepad, Touch, LTouch: LThumbstickUp], [RTouch: RThumbstickUp], [LTrackedRemote, RTrackedRemote, Touchpad, Remote: None]
  		PrimaryThumbstickDown     = 0x00020000, ///< Maps to RawButton: [Gamepad, Touch, LTouch: LThumbstickDown], [RTouch: RThumbstickDown], [LTrackedRemote, RTrackedRemote, Touchpad, Remote: None]
  		PrimaryThumbstickLeft     = 0x00040000, ///< Maps to RawButton: [Gamepad, Touch, LTouch: LThumbstickLeft], [RTouch: RThumbstickLeft], [LTrackedRemote, RTrackedRemote, Touchpad, Remote: None]
  		PrimaryThumbstickRight    = 0x00080000, ///< Maps to RawButton: [Gamepad, Touch, LTouch: LThumbstickRight], [RTouch: RThumbstickRight], [LTrackedRemote, RTrackedRemote, Touchpad, Remote: None]
  		PrimaryTouchpad           = 0x00000400, ///< Maps to RawButton: [LTrackedRemote, Touchpad: LTouchpad], [RTrackedRemote: RTouchpad], [Gamepad, Touch, LTouch, RTouch, Remote: None]
  		SecondaryShoulder         = 0x00100000, ///< Maps to RawButton: [Gamepad: RShoulder], [Touch, LTouch, RTouch, LTrackedRemote, RTrackedRemote, Touchpad, Remote: None]
  		SecondaryIndexTrigger     = 0x00200000, ///< Maps to RawButton: [Gamepad, Touch: RIndexTrigger], [LTouch, RTouch, LTrackedRemote, RTrackedRemote, Touchpad, Remote: None]
  		SecondaryHandTrigger      = 0x00400000, ///< Maps to RawButton: [Touch: RHandTrigger], [Gamepad, LTouch, RTouch, LTrackedRemote, RTrackedRemote, Touchpad, Remote: None]
  		SecondaryThumbstick       = 0x00800000, ///< Maps to RawButton: [Gamepad, Touch: RThumbstick], [LTouch, RTouch, LTrackedRemote, RTrackedRemote, Touchpad, Remote: None]
  		SecondaryThumbstickUp     = 0x01000000, ///< Maps to RawButton: [Gamepad, Touch: RThumbstickUp], [LTouch, RTouch, LTrackedRemote, RTrackedRemote, Touchpad, Remote: None]
  		SecondaryThumbstickDown   = 0x02000000, ///< Maps to RawButton: [Gamepad, Touch: RThumbstickDown], [LTouch, RTouch, LTrackedRemote, RTrackedRemote, Touchpad, Remote: None]
  		SecondaryThumbstickLeft   = 0x04000000, ///< Maps to RawButton: [Gamepad, Touch: RThumbstickLeft], [LTouch, RTouch, LTrackedRemote, RTrackedRemote, Touchpad, Remote: None]
  		SecondaryThumbstickRight  = 0x08000000, ///< Maps to RawButton: [Gamepad, Touch: RThumbstickRight], [LTouch, RTouch, LTrackedRemote, RTrackedRemote, Touchpad, Remote: None]
  		SecondaryTouchpad         = 0x00000800, ///< Maps to RawButton: [Gamepad, Touch, LTouch, RTouch, LTrackedRemote, RTrackedRemote, Touchpad, Remote: None]
  		DpadUp                    = 0x00000010, ///< Maps to RawButton: [Gamepad, LTrackedRemote, RTrackedRemote, Touchpad, Remote: DpadUp], [Touch, LTouch, RTouch: None]
  		DpadDown                  = 0x00000020, ///< Maps to RawButton: [Gamepad, LTrackedRemote, RTrackedRemote, Touchpad, Remote: DpadDown], [Touch, LTouch, RTouch: None]
  		DpadLeft                  = 0x00000040, ///< Maps to RawButton: [Gamepad, LTrackedRemote, RTrackedRemote, Touchpad, Remote: DpadLeft], [Touch, LTouch, RTouch: None]
  		DpadRight                 = 0x00000080, ///< Maps to RawButton: [Gamepad, LTrackedRemote, RTrackedRemote, Touchpad, Remote: DpadRight], [Touch, LTouch, RTouch: None]
  		Up                        = 0x10000000, ///< Maps to RawButton: [Gamepad, Touch, LTouch: LThumbstickUp], [RTouch: RThumbstickUp], [LTrackedRemote, RTrackedRemote, Touchpad, Remote: DpadUp]
  		Down                      = 0x20000000, ///< Maps to RawButton: [Gamepad, Touch, LTouch: LThumbstickDown], [RTouch: RThumbstickDown], [LTrackedRemote, RTrackedRemote, Touchpad, Remote: DpadDown]
  		Left                      = 0x40000000, ///< Maps to RawButton: [Gamepad, Touch, LTouch: LThumbstickLeft], [RTouch: RThumbstickLeft], [LTrackedRemote, RTrackedRemote, Touchpad, Remote: DpadLeft]
  		Right      = unchecked((int)0x80000000),///< Maps to RawButton: [Gamepad, Touch, LTouch: LThumbstickRight], [RTouch: RThumbstickRight], [LTrackedRemote, RTrackedRemote, Touchpad, Remote: DpadRight]
  		Any                       = ~None,      ///< Maps to RawButton: [Gamepad, Touch, LTouch, RTouch: Any]
  	}
  
  	[Flags]
  	/// Raw button mappings that can be used to directly query the state of a controller.
  	public enum RawButton
  	{
  		None                      = 0,          ///< Maps to Physical Button: [Gamepad, Touch, LTouch, RTouch, LTrackedRemote, RTrackedRemote, Touchpad, Remote: None]
  		A                         = 0x00000001, ///< Maps to Physical Button: [Gamepad, Touch, RTouch: A], [LTrackedRemote: LIndexTrigger], [RTrackedRemote: RIndexTrigger], [LTouch, Touchpad, Remote: None]
  		B                         = 0x00000002, ///< Maps to Physical Button: [Gamepad, Touch, RTouch: B], [LTouch, LTrackedRemote, RTrackedRemote, Touchpad, Remote: None]
  		X                         = 0x00000100, ///< Maps to Physical Button: [Gamepad, Touch, LTouch: X], [RTouch, LTrackedRemote, RTrackedRemote, Touchpad, Remote: None]
  		Y                         = 0x00000200, ///< Maps to Physical Button: [Gamepad, Touch, LTouch: Y], [RTouch, LTrackedRemote, RTrackedRemote, Touchpad, Remote: None]
  		Start                     = 0x00100000, ///< Maps to Physical Button: [Gamepad, Touch, LTouch, LTrackedRemote, RTrackedRemote, Touchpad, Remote: Start], [RTouch: None]
  		Back                      = 0x00200000, ///< Maps to Physical Button: [Gamepad, LTrackedRemote, RTrackedRemote, Touchpad, Remote: Back], [Touch, LTouch, RTouch: None]
  		LShoulder                 = 0x00000800, ///< Maps to Physical Button: [Gamepad: LShoulder], [Touch, LTouch, RTouch, LTrackedRemote, RTrackedRemote, Touchpad, Remote: None]
  		LIndexTrigger             = 0x10000000, ///< Maps to Physical Button: [Gamepad, Touch, LTouch, LTrackedRemote: LIndexTrigger], [RTouch, RTrackedRemote, Touchpad, Remote: None]
  		LHandTrigger              = 0x20000000, ///< Maps to Physical Button: [Touch, LTouch: LHandTrigger], [Gamepad, RTouch, LTrackedRemote, RTrackedRemote, Touchpad, Remote: None]
  		LThumbstick               = 0x00000400, ///< Maps to Physical Button: [Gamepad, Touch, LTouch: LThumbstick], [RTouch, LTrackedRemote, RTrackedRemote, Touchpad, Remote: None]
  		LThumbstickUp             = 0x00000010, ///< Maps to Physical Button: [Gamepad, Touch, LTouch: LThumbstickUp], [RTouch, LTrackedRemote, RTrackedRemote, Touchpad, Remote: None]
  		LThumbstickDown           = 0x00000020, ///< Maps to Physical Button: [Gamepad, Touch, LTouch: LThumbstickDown], [RTouch, LTrackedRemote, RTrackedRemote, Touchpad, Remote: None]
  		LThumbstickLeft           = 0x00000040, ///< Maps to Physical Button: [Gamepad, Touch, LTouch: LThumbstickLeft], [RTouch, LTrackedRemote, RTrackedRemote, Touchpad, Remote: None]
  		LThumbstickRight          = 0x00000080, ///< Maps to Physical Button: [Gamepad, Touch, LTouch: LThumbstickRight], [RTouch, LTrackedRemote, RTrackedRemote, Touchpad, Remote: None]
  		LTouchpad                 = 0x40000000, ///< Maps to Physical Button: [LTrackedRemote: LTouchpad], [Gamepad, Touch, LTouch, RTouch, RTrackedRemote, Touchpad, Remote: None]
  		RShoulder                 = 0x00000008, ///< Maps to Physical Button: [Gamepad: RShoulder], [Touch, LTouch, RTouch, LTrackedRemote, RTrackedRemote, Touchpad, Remote: None]
  		RIndexTrigger             = 0x04000000, ///< Maps to Physical Button: [Gamepad, Touch, RTouch, RTrackedRemote: RIndexTrigger], [LTouch, LTrackedRemote, Touchpad, Remote: None]
  		RHandTrigger              = 0x08000000, ///< Maps to Physical Button: [Touch, RTouch: RHandTrigger], [Gamepad, LTouch, LTrackedRemote, RTrackedRemote, Touchpad, Remote: None]
  		RThumbstick               = 0x00000004, ///< Maps to Physical Button: [Gamepad, Touch, RTouch: RThumbstick], [LTouch, LTrackedRemote, RTrackedRemote, Touchpad, Remote: None]
  		RThumbstickUp             = 0x00001000, ///< Maps to Physical Button: [Gamepad, Touch, RTouch: RThumbstickUp], [LTouch, LTrackedRemote, RTrackedRemote, Touchpad, Remote: None]
  		RThumbstickDown           = 0x00002000, ///< Maps to Physical Button: [Gamepad, Touch, RTouch: RThumbstickDown], [LTouch, LTrackedRemote, RTrackedRemote, Touchpad, Remote: None]
  		RThumbstickLeft           = 0x00004000, ///< Maps to Physical Button: [Gamepad, Touch, RTouch: RThumbstickLeft], [LTouch, LTrackedRemote, RTrackedRemote, Touchpad, Remote: None]
  		RThumbstickRight          = 0x00008000, ///< Maps to Physical Button: [Gamepad, Touch, RTouch: RThumbstickRight], [LTouch, LTrackedRemote, RTrackedRemote, Touchpad, Remote: None]
  		RTouchpad  = unchecked((int)0x80000000),///< Maps to Physical Button: [Gamepad, Touch, LTouch, RTouch, LTrackedRemote, RTrackedRemote, Touchpad, Remote: None]
  		DpadUp                    = 0x00010000, ///< Maps to Physical Button: [Gamepad, LTrackedRemote, RTrackedRemote, Touchpad, Remote: DpadUp], [Touch, LTouch, RTouch: None]
  		DpadDown                  = 0x00020000, ///< Maps to Physical Button: [Gamepad, LTrackedRemote, RTrackedRemote, Touchpad, Remote: DpadDown], [Touch, LTouch, RTouch: None]
  		DpadLeft                  = 0x00040000, ///< Maps to Physical Button: [Gamepad, LTrackedRemote, RTrackedRemote, Touchpad, Remote: DpadLeft], [Touch, LTouch, RTouch: None]
  		DpadRight                 = 0x00080000, ///< Maps to Physical Button: [Gamepad, LTrackedRemote, RTrackedRemote, Touchpad, Remote: DpadRight], [Touch, LTouch, RTouch: None]
  		Any                       = ~None,      ///< Maps to Physical Button: [Gamepad, Touch, LTouch, RTouch, LTrackedRemote, RTrackedRemote, Touchpad, Remote: Any]
  	}
  
      [Flags]
  	/// Virtual capacitive touch mappings that allow the same input bindings to work across different controllers with capacitive touch support.
  	public enum Touch
  	{
  		None                      = 0,                            ///< Maps to RawTouch: [Gamepad, Touch, LTouch, RTouch, LTrackedRemote, RTrackedRemote, Touchpad, Remote: None]
  		One                       = Button.One,                   ///< Maps to RawTouch: [Touch, RTouch: A], [LTouch: X], [Gamepad, LTrackedRemote, RTrackedRemote, Touchpad, Remote: None]
  		Two                       = Button.Two,                   ///< Maps to RawTouch: [Touch, RTouch: B], [LTouch: Y], [Gamepad, LTrackedRemote, RTrackedRemote, Touchpad, Remote: None]
  		Three                     = Button.Three,                 ///< Maps to RawTouch: [Touch: X], [Gamepad, LTouch, RTouch, LTrackedRemote, RTrackedRemote, Touchpad, Remote: None]
  		Four                      = Button.Four,                  ///< Maps to RawTouch: [Touch: Y], [Gamepad, LTouch, RTouch, LTrackedRemote, RTrackedRemote, Touchpad, Remote: None]
  		PrimaryIndexTrigger       = Button.PrimaryIndexTrigger,   ///< Maps to RawTouch: [Touch, LTouch: LIndexTrigger], [RTouch: RIndexTrigger], [Gamepad, LTrackedRemote, RTrackedRemote, Touchpad, Remote: None]
  		PrimaryThumbstick         = Button.PrimaryThumbstick,     ///< Maps to RawTouch: [Touch, LTouch: LThumbstick], [RTouch: RThumbstick], [Gamepad, LTrackedRemote, RTrackedRemote, Touchpad, Remote: None]
  		PrimaryThumbRest          = 0x00001000,                   ///< Maps to RawTouch: [Touch, LTouch: LThumbRest], [RTouch: RThumbRest], [Gamepad, LTrackedRemote, RTrackedRemote, Touchpad, Remote: None]
  		PrimaryTouchpad           = Button.PrimaryTouchpad,       ///< Maps to RawTouch: [LTrackedRemote, Touchpad: LTouchpad], [RTrackedRemote: RTouchpad], [Gamepad, Touch, LTouch, RTouch, Remote: None]
  		SecondaryIndexTrigger     = Button.SecondaryIndexTrigger, ///< Maps to RawTouch: [Touch: RIndexTrigger], [Gamepad, LTouch, RTouch, LTrackedRemote, RTrackedRemote, Touchpad, Remote: None]
  		SecondaryThumbstick       = Button.SecondaryThumbstick,   ///< Maps to RawTouch: [Touch: RThumbstick], [Gamepad, LTouch, RTouch, LTrackedRemote, RTrackedRemote, Touchpad, Remote: None]
  		SecondaryThumbRest        = 0x00100000,                   ///< Maps to RawTouch: [Touch: RThumbRest], [Gamepad, LTouch, RTouch, LTrackedRemote, RTrackedRemote, Touchpad, Remote: None]
  		SecondaryTouchpad         = Button.SecondaryTouchpad,     ///< Maps to RawTouch: [Gamepad, Touch, LTouch, RTouch, LTrackedRemote, RTrackedRemote, Touchpad, Remote: None]
  		Any                       = ~None,                        ///< Maps to RawTouch: [Touch, LTouch, RTouch, LTrackedRemote, RTrackedRemote, Touchpad: Any], [Gamepad, Remote: None]
  	}
  
      [Flags]
  	/// Raw capacitive touch mappings that can be used to directly query the state of a controller.
  	public enum RawTouch
  	{
  		None                      = 0,                            ///< Maps to Physical Touch: [Gamepad, Touch, LTouch, RTouch, LTrackedRemote, RTrackedRemote, Touchpad, Remote: None]
  		A                         = RawButton.A,                  ///< Maps to Physical Touch: [Touch, RTouch: A], [Gamepad, LTouch, LTrackedRemote, RTrackedRemote, Touchpad, Remote: None]
  		B                         = RawButton.B,                  ///< Maps to Physical Touch: [Touch, RTouch: B], [Gamepad, LTouch, LTrackedRemote, RTrackedRemote, Touchpad, Remote: None]
  		X                         = RawButton.X,                  ///< Maps to Physical Touch: [Touch, LTouch: X], [Gamepad, RTouch, LTrackedRemote, RTrackedRemote, Touchpad, Remote: None]
  		Y                         = RawButton.Y,                  ///< Maps to Physical Touch: [Touch, LTouch: Y], [Gamepad, RTouch, LTrackedRemote, RTrackedRemote, Touchpad, Remote: None]
  		LIndexTrigger             = 0x00001000,                   ///< Maps to Physical Touch: [Touch, LTouch: LIndexTrigger], [Gamepad, RTouch, LTrackedRemote, RTrackedRemote, Touchpad, Remote: None]
  		LThumbstick               = RawButton.LThumbstick,        ///< Maps to Physical Touch: [Touch, LTouch: LThumbstick], [Gamepad, RTouch, LTrackedRemote, RTrackedRemote, Touchpad, Remote: None]
  		LThumbRest                = 0x00000800,                   ///< Maps to Physical Touch: [Touch, LTouch: LThumbRest], [Gamepad, RTouch, LTrackedRemote, RTrackedRemote, Touchpad, Remote: None]
  		LTouchpad                 = RawButton.LTouchpad,          ///< Maps to Physical Touch: [LTrackedRemote, Touchpad: LTouchpad], [Gamepad, Touch, LTouch, RTouch, RTrackedRemote, Remote: None]
  		RIndexTrigger             = 0x00000010,                   ///< Maps to Physical Touch: [Touch, RTouch: RIndexTrigger], [Gamepad, LTouch, LTrackedRemote, RTrackedRemote, Touchpad, Remote: None]
  		RThumbstick               = RawButton.RThumbstick,        ///< Maps to Physical Touch: [Touch, RTouch: RThumbstick], [Gamepad, LTouch, LTrackedRemote, RTrackedRemote, Touchpad, Remote: None]
  		RThumbRest                = 0x00000008,                   ///< Maps to Physical Touch: [Touch, RTouch: RThumbRest], [Gamepad, LTouch, LTrackedRemote, RTrackedRemote, Touchpad, Remote: None]
  		RTouchpad                 = RawButton.RTouchpad,          ///< Maps to Physical Touch: [RTrackedRemote: RTouchpad], [Gamepad, Touch, LTouch, RTouch, LTrackedRemote, Touchpad, Remote: None]
  		Any                       = ~None,                        ///< Maps to Physical Touch: [Touch, LTouch, RTouch, LTrackedRemote, RTrackedRemote, Touchpad: Any], [Gamepad, Remote: None]
  	}
  
      [Flags]
  	/// Virtual near touch mappings that allow the same input bindings to work across different controllers with near touch support.
  	/// A near touch uses the capacitive touch sensors of a controller to detect approximate finger proximity prior to a full touch being reported.
  	public enum NearTouch
  	{
  		None                      = 0,          ///< Maps to RawNearTouch: [Gamepad, Touch, LTouch, RTouch, LTrackedRemote, RTrackedRemote, Touchpad, Remote: None]
  		PrimaryIndexTrigger       = 0x00000001, ///< Maps to RawNearTouch: [Touch, LTouch: LIndexTrigger], [RTouch: RIndexTrigger], [Gamepad, LTrackedRemote, RTrackedRemote, Touchpad, Remote: None]
  		PrimaryThumbButtons       = 0x00000002, ///< Maps to RawNearTouch: [Touch, LTouch: LThumbButtons], [RTouch: RThumbButtons], [Gamepad, LTrackedRemote, RTrackedRemote, Touchpad, Remote: None]
  		SecondaryIndexTrigger     = 0x00000004, ///< Maps to RawNearTouch: [Touch: RIndexTrigger], [Gamepad, LTouch, RTouch, LTrackedRemote, RTrackedRemote, Touchpad, Remote: None]
  		SecondaryThumbButtons     = 0x00000008, ///< Maps to RawNearTouch: [Touch: RThumbButtons], [Gamepad, LTouch, RTouch, LTrackedRemote, RTrackedRemote, Touchpad, Remote: None]
  		Any                       = ~None,      ///< Maps to RawNearTouch: [Touch, LTouch, RTouch: Any], [Gamepad, LTrackedRemote, RTrackedRemote, Touchpad, Remote: None]
  	}
  
      [Flags]
  	/// Raw near touch mappings that can be used to directly query the state of a controller.
  	public enum RawNearTouch
  	{
  		None                      = 0,          ///< Maps to Physical NearTouch: [Gamepad, Touch, LTouch, RTouch, LTrackedRemote, RTrackedRemote, Touchpad, Remote: None]
  		LIndexTrigger             = 0x00000001, ///< Maps to Physical NearTouch: [Touch, LTouch: Implies finger is in close proximity to LIndexTrigger.], [Gamepad, RTouch, LTrackedRemote, RTrackedRemote, Touchpad, Remote: None]
  		LThumbButtons             = 0x00000002, ///< Maps to Physical NearTouch: [Touch, LTouch: Implies thumb is in close proximity to LThumbstick OR X/Y buttons.], [Gamepad, RTouch, LTrackedRemote, RTrackedRemote, Touchpad, Remote: None]
  		RIndexTrigger             = 0x00000004, ///< Maps to Physical NearTouch: [Touch, RTouch: Implies finger is in close proximity to RIndexTrigger.], [Gamepad, LTouch, LTrackedRemote, RTrackedRemote, Touchpad, Remote: None]
  		RThumbButtons             = 0x00000008, ///< Maps to Physical NearTouch: [Touch, RTouch: Implies thumb is in close proximity to RThumbstick OR A/B buttons.], [Gamepad, LTouch, LTrackedRemote, RTrackedRemote, Touchpad, Remote: None]
  		Any                       = ~None,      ///< Maps to Physical NearTouch: [Touch, LTouch, RTouch: Any], [Gamepad, LTrackedRemote, RTrackedRemote, Touchpad, Remote: None]
  	}
  
      [Flags]
  	/// Virtual 1-dimensional axis (float) mappings that allow the same input bindings to work across different controllers.
  	public enum Axis1D
  	{
  		None                      = 0,     ///< Maps to RawAxis1D: [Gamepad, Touch, LTouch, RTouch, LTrackedRemote, RTrackedRemote, Touchpad, Remote: None]
  		PrimaryIndexTrigger       = 0x01,  ///< Maps to RawAxis1D: [Gamepad, Touch, LTouch: LIndexTrigger], [RTouch: RIndexTrigger], [LTrackedRemote, RTrackedRemote, Touchpad, Remote: None]
  		PrimaryHandTrigger        = 0x04,  ///< Maps to RawAxis1D: [Touch, LTouch: LHandTrigger], [RTouch: RHandTrigger], [Gamepad, LTrackedRemote, RTrackedRemote, Touchpad, Remote: None]
  		SecondaryIndexTrigger     = 0x02,  ///< Maps to RawAxis1D: [Gamepad, Touch: RIndexTrigger], [LTouch, RTouch, LTrackedRemote, RTrackedRemote, Touchpad, Remote: None]
  		SecondaryHandTrigger      = 0x08,  ///< Maps to RawAxis1D: [Touch: RHandTrigger], [Gamepad, LTouch, RTouch, LTrackedRemote, RTrackedRemote, Touchpad, Remote: None]
  		Any                       = ~None, ///< Maps to RawAxis1D: [Gamepad, Touch, LTouch, RTouch: Any], [LTrackedRemote, RTrackedRemote, Touchpad, Remote: None]
  	}
  
      [Flags]
  	/// Raw 1-dimensional axis (float) mappings that can be used to directly query the state of a controller.
  	public enum RawAxis1D
  	{
  		None                      = 0,     ///< Maps to Physical Axis1D: [Gamepad, Touch, LTouch, RTouch, LTrackedRemote, RTrackedRemote, Touchpad, Remote: None]
  		LIndexTrigger             = 0x01,  ///< Maps to Physical Axis1D: [Gamepad, Touch, LTouch: LIndexTrigger], [RTouch, LTrackedRemote, RTrackedRemote, Touchpad, Remote: None]
  		LHandTrigger              = 0x04,  ///< Maps to Physical Axis1D: [Touch, LTouch: LHandTrigger], [Gamepad, RTouch, LTrackedRemote, RTrackedRemote, Touchpad, Remote: None]
  		RIndexTrigger             = 0x02,  ///< Maps to Physical Axis1D: [Gamepad, Touch, RTouch: RIndexTrigger], [LTouch, LTrackedRemote, RTrackedRemote, Touchpad, Remote: None]
  		RHandTrigger              = 0x08,  ///< Maps to Physical Axis1D: [Touch, RTouch: RHandTrigger], [Gamepad, LTouch, LTrackedRemote, RTrackedRemote, Touchpad, Remote: None]
  		Any                       = ~None, ///< Maps to Physical Axis1D: [Gamepad, Touch, LTouch, RTouch: Any], [LTrackedRemote, RTrackedRemote, Touchpad, Remote: None]
  	}
  
      [Flags]
  	/// Virtual 2-dimensional axis (Vector2) mappings that allow the same input bindings to work across different controllers.
  	public enum Axis2D
  	{
  		None                      = 0,     ///< Maps to RawAxis2D: [Gamepad, Touch, LTouch, RTouch, LTrackedRemote, RTrackedRemote, Touchpad, Remote: None]
  		PrimaryThumbstick         = 0x01,  ///< Maps to RawAxis2D: [Gamepad, Touch, LTouch: LThumbstick], [RTouch: RThumbstick], [LTrackedRemote, RTrackedRemote, Touchpad, Remote: None]
  		PrimaryTouchpad           = 0x04,  ///< Maps to RawAxis2D: [LTrackedRemote, Touchpad: LTouchpad], RTrackedRemote: RTouchpad], [Gamepad, Touch, LTouch, RTouch, Remote: None]
  		SecondaryThumbstick       = 0x02,  ///< Maps to RawAxis2D: [Gamepad, Touch: RThumbstick], [LTouch, RTouch, LTrackedRemote, RTrackedRemote, Touchpad, Remote: None]
  		SecondaryTouchpad         = 0x08,  ///< Maps to RawAxis2D: [Gamepad, Touch, LTouch, RTouch, LTrackedRemote, RTrackedRemote, Touchpad, Remote: None]
  		Any                       = ~None, ///< Maps to RawAxis2D: [Gamepad, Touch, LTouch, RTouch, LTrackedRemote, RTrackedRemote, Touchpad: Any], [Remote: None]
  	}
  
      [Flags]
  	/// Raw 2-dimensional axis (Vector2) mappings that can be used to directly query the state of a controller.
  	public enum RawAxis2D
  	{
  		None                      = 0,     ///< Maps to Physical Axis2D: [Gamepad, Touch, LTouch, RTouch, LTrackedRemote, RTrackedRemote, Touchpad, Remote: None]
  		LThumbstick               = 0x01,  ///< Maps to Physical Axis2D: [Gamepad, Touch, LTouch: LThumbstick], [RTouch, LTrackedRemote, RTrackedRemote, Touchpad, Remote: None]
  		LTouchpad                 = 0x04,  ///< Maps to Physical Axis2D: [LTrackedRemote, Touchpad: LTouchpad], [Gamepad, Touch, LTouch, RTouch, RTrackedRemote, Remote: None]
  		RThumbstick               = 0x02,  ///< Maps to Physical Axis2D: [Gamepad, Touch, RTouch: RThumbstick], [LTouch, LTrackedRemote, RTrackedRemote, Touchpad, Remote: None]
  		RTouchpad                 = 0x08,  ///< Maps to Physical Axis2D: [RTrackedRemote: RTouchpad], [Gamepad, Touch, LTouch, RTouch, LTrackedRemote, Touchpad, Remote: None]
  		Any                       = ~None, ///< Maps to Physical Axis2D: [Gamepad, Touch, LTouch, RTouch, LTrackedRemote, RTrackedRemote: Any], [Touchpad, Remote: None]
  	}
  
  	[Flags]
  	/// Identifies a controller which can be used to query the virtual or raw input state.
  	public enum Controller
  	{
  		None                      = OVRPlugin.Controller.None,           ///< Null controller.
  		LTouch                    = OVRPlugin.Controller.LTouch,         ///< Left Oculus Touch controller. Virtual input mapping differs from the combined L/R Touch mapping.
  		RTouch                    = OVRPlugin.Controller.RTouch,         ///< Right Oculus Touch controller. Virtual input mapping differs from the combined L/R Touch mapping.
  		Touch                     = OVRPlugin.Controller.Touch,          ///< Combined Left/Right pair of Oculus Touch controllers.
  		Remote                    = OVRPlugin.Controller.Remote,         ///< Oculus Remote controller.
  		Gamepad                   = OVRPlugin.Controller.Gamepad,        ///< Xbox 360 or Xbox One gamepad on PC. Generic gamepad on Android.
  		Touchpad                  = OVRPlugin.Controller.Touchpad,       ///< GearVR touchpad on Android.
  		LTrackedRemote            = OVRPlugin.Controller.LTrackedRemote, ///< Left GearVR tracked remote on Android.
  		RTrackedRemote            = OVRPlugin.Controller.RTrackedRemote, ///< Right GearVR tracked remote on Android.
  		Active                    = OVRPlugin.Controller.Active,         ///< Default controller. Represents the controller that most recently registered a button press from the user.
  		All                       = OVRPlugin.Controller.All,            ///< Represents the logical OR of all controllers.
  	}
  
  	private static readonly float AXIS_AS_BUTTON_THRESHOLD = 0.5f;
  	private static readonly float AXIS_DEADZONE_THRESHOLD = 0.2f;
  	private static List<OVRControllerBase> controllers;
  	private static Controller activeControllerType = Controller.None;
  	private static Controller connectedControllerTypes = Controller.None;
  	private static OVRPlugin.Step stepType = OVRPlugin.Step.Render;
      private static int fixedUpdateCount = 0;
  
  
  	private static bool _pluginSupportsActiveController = false;
  	private static bool _pluginSupportsActiveControllerCached = false;
  	private static System.Version _pluginSupportsActiveControllerMinVersion = new System.Version(1, 9, 0);
  	private static bool pluginSupportsActiveController
  	{
  		get
  		{
  			if (!_pluginSupportsActiveControllerCached)
  			{
  				bool isSupportedPlatform = true;
  #if (UNITY_ANDROID && !UNITY_EDITOR) || UNITY_STANDALONE_OSX || UNITY_EDITOR_OSX
  				isSupportedPlatform = false;
  #endif
  				_pluginSupportsActiveController = isSupportedPlatform && (OVRPlugin.version >= _pluginSupportsActiveControllerMinVersion);
  				_pluginSupportsActiveControllerCached = true;
  			}
  
  			return _pluginSupportsActiveController;
  		}
  	}
  
  	/// <summary>
  	/// Creates an instance of OVRInput.
  	/// </summary>
  	static OVRInput()
  	{
  		controllers = new List<OVRControllerBase>
  		{
  #if UNITY_ANDROID && !UNITY_EDITOR
  			new OVRControllerGamepadAndroid(),
  			new OVRControllerTouchpad(),
  			new OVRControllerLTrackedRemote(),
  			new OVRControllerRTrackedRemote(),
  #elif UNITY_STANDALONE_OSX || UNITY_EDITOR_OSX
  			new OVRControllerGamepadMac(),
  #else
              new OVRControllerGamepadPC(),
  			new OVRControllerTouch(),
  			new OVRControllerLTouch(),
  			new OVRControllerRTouch(),
  			new OVRControllerRemote(),
  #endif
  		};
  	}
  
      /// <summary>
      /// Updates the internal state of OVRInput. Must be called manually if used independently from OVRManager.
      /// </summary>
      public static void Update()
  	{
  		connectedControllerTypes = Controller.None;
  		stepType = OVRPlugin.Step.Render;
  		fixedUpdateCount = 0;
  
  		for (int i = 0; i < controllers.Count; i++)
  		{
  			OVRControllerBase controller = controllers[i];
  
  			connectedControllerTypes |= controller.Update();
  
  			if ((connectedControllerTypes & controller.controllerType) != 0)
  			{
  				if (Get(RawButton.Any, controller.controllerType)
  					|| Get(RawTouch.Any, controller.controllerType))
  				{
  					activeControllerType = controller.controllerType;
  				}
  			}
  		}
  
  		if ((activeControllerType == Controller.LTouch) || (activeControllerType == Controller.RTouch))
  		{
  			// If either Touch controller is Active, set both to Active.
  			activeControllerType = Controller.Touch;
  		}
  
  		if ((connectedControllerTypes & activeControllerType) == 0)
  		{
  			activeControllerType = Controller.None;
  		}
  
          // Promote TrackedRemote to Active if one is connected and no other controller is active
  		if (activeControllerType == Controller.None)
  		{
              if ((connectedControllerTypes & Controller.RTrackedRemote) != 0)
              {
                  activeControllerType = Controller.RTrackedRemote;
              }
              else if ((connectedControllerTypes & Controller.LTrackedRemote) != 0)
              {
                  activeControllerType = Controller.LTrackedRemote;
              }
  		}
  
  		if (pluginSupportsActiveController)
  		{
  			// override locally derived active and connected controllers if plugin provides more accurate data
  			connectedControllerTypes = (OVRInput.Controller)OVRPlugin.GetConnectedControllers();
  			activeControllerType = (OVRInput.Controller)OVRPlugin.GetActiveController();
  		}
  	}
  
  	/// <summary>
  	/// Updates the internal physics state of OVRInput. Must be called manually if used independently from OVRManager.
  	/// </summary>
  	public static void FixedUpdate()
  	{
  		stepType = OVRPlugin.Step.Physics;
  
  		double predictionSeconds = (double)fixedUpdateCount * Time.fixedDeltaTime / Mathf.Max(Time.timeScale, 1e-6f);
  		fixedUpdateCount++;
  		
  		OVRPlugin.UpdateNodePhysicsPoses(0, predictionSeconds);
  	}
  
  	/// <summary>
  	/// Returns true if the given Controller's orientation is currently tracked.
  	/// Only supported for Oculus LTouch and RTouch controllers. Non-tracked controllers will return false.
  	/// </summary>
  	public static bool GetControllerOrientationTracked(OVRInput.Controller controllerType)
  	{
  		switch (controllerType)
  		{
  			case Controller.LTouch:
              case Controller.LTrackedRemote:
                  return OVRPlugin.GetNodeOrientationTracked(OVRPlugin.Node.HandLeft);
              case Controller.RTouch:
              case Controller.RTrackedRemote:
                  return OVRPlugin.GetNodeOrientationTracked(OVRPlugin.Node.HandRight);
              default:
  				return false;
  		}
  	}
  
  	/// <summary>
  	/// Returns true if the given Controller's position is currently tracked.
  	/// Only supported for Oculus LTouch and RTouch controllers. Non-tracked controllers will return false.
  	/// </summary>
  	public static bool GetControllerPositionTracked(OVRInput.Controller controllerType)
  	{
  		switch (controllerType)
  		{
  			case Controller.LTouch:
  			case Controller.LTrackedRemote:
                  return OVRPlugin.GetNodePositionTracked(OVRPlugin.Node.HandLeft);
              case Controller.RTouch:
              case Controller.RTrackedRemote:
                  return OVRPlugin.GetNodePositionTracked(OVRPlugin.Node.HandRight);
              default:
  				return false;
  		}
  	}
  
  	/// <summary>
  	/// Gets the position of the given Controller local to its tracking space.
  	/// Only supported for Oculus LTouch and RTouch controllers. Non-tracked controllers will return Vector3.zero.
  	/// </summary>
  	public static Vector3 GetLocalControllerPosition(OVRInput.Controller controllerType)
  	{
  		switch (controllerType)
  		{
  			case Controller.LTouch:
  			case Controller.LTrackedRemote:
                  return OVRPlugin.GetNodePose(OVRPlugin.Node.HandLeft, stepType).ToOVRPose().position;
              case Controller.RTouch:
  			case Controller.RTrackedRemote:
                  return OVRPlugin.GetNodePose(OVRPlugin.Node.HandRight, stepType).ToOVRPose().position;
              default:
  				return Vector3.zero;
  		}
  	}
  
  	/// <summary>
      /// Gets the linear velocity of the given Controller local to its tracking space.
      /// Only supported for Oculus LTouch and RTouch controllers. Non-tracked controllers will return Vector3.zero.
      /// </summary>
      public static Vector3 GetLocalControllerVelocity(OVRInput.Controller controllerType)
      {
          switch (controllerType)
          {
              case Controller.LTouch:
  			case Controller.LTrackedRemote:
  				return OVRPlugin.GetNodeVelocity(OVRPlugin.Node.HandLeft, stepType).FromFlippedZVector3f();
              case Controller.RTouch:
  			case Controller.RTrackedRemote:
  				return OVRPlugin.GetNodeVelocity(OVRPlugin.Node.HandRight, stepType).FromFlippedZVector3f();
              default:
                  return Vector3.zero;
          }
      }
  
      /// <summary>
      /// Gets the linear acceleration of the given Controller local to its tracking space.
      /// Only supported for Oculus LTouch and RTouch controllers. Non-tracked controllers will return Vector3.zero.
      /// </summary>
      public static Vector3 GetLocalControllerAcceleration(OVRInput.Controller controllerType)
      {
          switch (controllerType)
          {
              case Controller.LTouch:
  			case Controller.LTrackedRemote:
  				return OVRPlugin.GetNodeAcceleration(OVRPlugin.Node.HandLeft, stepType).FromFlippedZVector3f();
              case Controller.RTouch:
  			case Controller.RTrackedRemote:
  				return OVRPlugin.GetNodeAcceleration(OVRPlugin.Node.HandRight, stepType).FromFlippedZVector3f();
              default:
                  return Vector3.zero;
          }
      }
  
  	/// <summary>
  	/// Gets the rotation of the given Controller local to its tracking space.
  	/// Only supported for Oculus LTouch and RTouch controllers. Non-tracked controllers will return Quaternion.identity.
  	/// </summary>
  	public static Quaternion GetLocalControllerRotation(OVRInput.Controller controllerType)
  	{
  		switch (controllerType)
  		{
  			case Controller.LTouch:
  			case Controller.LTrackedRemote:
  				return OVRPlugin.GetNodePose(OVRPlugin.Node.HandLeft, stepType).ToOVRPose().orientation;
              case Controller.RTouch:
  			case Controller.RTrackedRemote:
  				return OVRPlugin.GetNodePose(OVRPlugin.Node.HandRight, stepType).ToOVRPose().orientation;
              default:
  				return Quaternion.identity;
  		}
  	}
  
  	/// <summary>
  	/// Gets the angular velocity of the given Controller local to its tracking space in radians per second around each axis.
  	/// Only supported for Oculus LTouch and RTouch controllers. Non-tracked controllers will return Quaternion.identity.
  	/// </summary>
  	public static Vector3 GetLocalControllerAngularVelocity(OVRInput.Controller controllerType)
  	{
  		switch (controllerType)
  		{
  		case Controller.LTouch:
  		case Controller.LTrackedRemote:
  			return OVRPlugin.GetNodeAngularVelocity(OVRPlugin.Node.HandLeft, stepType).FromFlippedZVector3f();
  		case Controller.RTouch:
  		case Controller.RTrackedRemote:
  			return OVRPlugin.GetNodeAngularVelocity(OVRPlugin.Node.HandRight, stepType).FromFlippedZVector3f();
  		default:
  			return Vector3.zero;
  		}
  	}
  
  	/// <summary>
  	/// Gets the angular acceleration of the given Controller local to its tracking space in radians per second per second around each axis.
  	/// Only supported for Oculus LTouch and RTouch controllers. Non-tracked controllers will return Quaternion.identity.
  	/// </summary>
  	public static Vector3 GetLocalControllerAngularAcceleration(OVRInput.Controller controllerType)
  	{
  		switch (controllerType)
  		{
  		case Controller.LTouch:
  		case Controller.LTrackedRemote:
  			return OVRPlugin.GetNodeAngularAcceleration(OVRPlugin.Node.HandLeft, stepType).FromFlippedZVector3f();
  		case Controller.RTouch:
  		case Controller.RTrackedRemote:
  			return OVRPlugin.GetNodeAngularAcceleration(OVRPlugin.Node.HandRight, stepType).FromFlippedZVector3f();
  		default:
  			return Vector3.zero;
  		}
  	}
  
  	/// <summary>
  	/// Gets the current state of the given virtual button mask with the given controller mask.
  	/// Returns true if any masked button is down on any masked controller.
  	/// </summary>
  	public static bool Get(Button virtualMask, Controller controllerMask = Controller.Active)
  	{
  		return GetResolvedButton(virtualMask, RawButton.None, controllerMask);
  	}
  
  	/// <summary>
  	/// Gets the current state of the given raw button mask with the given controller mask.
  	/// Returns true if any masked button is down on any masked controllers.
  	/// </summary>
  	public static bool Get(RawButton rawMask, Controller controllerMask = Controller.Active)
  	{
  		return GetResolvedButton(Button.None, rawMask, controllerMask);
  	}
  
  	private static bool GetResolvedButton(Button virtualMask, RawButton rawMask, Controller controllerMask)
  	{
  		if ((controllerMask & Controller.Active) != 0)
  			controllerMask |= activeControllerType;
  
  		for (int i = 0; i < controllers.Count; i++)
  		{
  			OVRControllerBase controller = controllers[i];
  
  			if (ShouldResolveController(controller.controllerType, controllerMask))
  			{
  				RawButton resolvedMask = rawMask | controller.ResolveToRawMask(virtualMask);
  
  				if (((RawButton)controller.currentState.Buttons & resolvedMask) != 0)
  				{
  					return true;
  				}
  			}
  		}
  
  		return false;
  	}
  
  	/// <summary>
  	/// Gets the current down state of the given virtual button mask with the given controller mask.
  	/// Returns true if any masked button was pressed this frame on any masked controller and no masked button was previously down last frame.
  	/// </summary>
  	public static bool GetDown(Button virtualMask, Controller controllerMask = Controller.Active)
  	{
  		return GetResolvedButtonDown(virtualMask, RawButton.None, controllerMask);
  	}
  
  	/// <summary>
  	/// Gets the current down state of the given raw button mask with the given controller mask.
  	/// Returns true if any masked button was pressed this frame on any masked controller and no masked button was previously down last frame.
  	/// </summary>
  	public static bool GetDown(RawButton rawMask, Controller controllerMask = Controller.Active)
  	{
  		return GetResolvedButtonDown(Button.None, rawMask, controllerMask);
  	}
  
  	private static bool GetResolvedButtonDown(Button virtualMask, RawButton rawMask, Controller controllerMask)
  	{
  		bool down = false;
  
  		if ((controllerMask & Controller.Active) != 0)
  			controllerMask |= activeControllerType;
  
  		for (int i = 0; i < controllers.Count; i++)
  		{
  			OVRControllerBase controller = controllers[i];
  
  			if (ShouldResolveController(controller.controllerType, controllerMask))
  			{
  				RawButton resolvedMask = rawMask | controller.ResolveToRawMask(virtualMask);
  
  				if (((RawButton)controller.previousState.Buttons & resolvedMask) != 0)
  				{
  					return false;
  				}
  
  				if ((((RawButton)controller.currentState.Buttons & resolvedMask) != 0)
  					&& (((RawButton)controller.previousState.Buttons & resolvedMask) == 0))
  				{
  					down = true;
  				}
  			}
  		}
  
  		return down;
  	}
  
  	/// <summary>
  	/// Gets the current up state of the given virtual button mask with the given controller mask.
  	/// Returns true if any masked button was released this frame on any masked controller and no other masked button is still down this frame.
  	/// </summary>
  	public static bool GetUp(Button virtualMask, Controller controllerMask = Controller.Active)
  	{
  		return GetResolvedButtonUp(virtualMask, RawButton.None, controllerMask);
  	}
  
  	/// <summary>
  	/// Gets the current up state of the given raw button mask with the given controller mask.
  	/// Returns true if any masked button was released this frame on any masked controller and no other masked button is still down this frame.
  	/// </summary>
  	public static bool GetUp(RawButton rawMask, Controller controllerMask = Controller.Active)
  	{
  		return GetResolvedButtonUp(Button.None, rawMask, controllerMask);
  	}
  
  	private static bool GetResolvedButtonUp(Button virtualMask, RawButton rawMask, Controller controllerMask)
  	{
  		bool up = false;
  
  		if ((controllerMask & Controller.Active) != 0)
  			controllerMask |= activeControllerType;
  
  		for (int i = 0; i < controllers.Count; i++)
  		{
  
gt: 			OVRControllerBase controller = controllers[i];