devNotes 6-22-16 cursor swap, tool selection, editor functions

Splash

Into Environment – Default Settings – (init config)

Tap – brings up Main Menu. (optional info dialogs – modal dialog – on by default)

Tools – four on top

0) default navigation – blue circle – navigation menu active

1) grabber – selects object holds and places at desired location Menus/waypoints/transforms

2) paint – current paint mode

3) operating mode

dgfdbgb39

 

 

sdfgfdgf2-1

fghfmhmhm5

Cllb_0jWgAApTQ-

ParticleGazeCursor

using UnityEngine;
using System.Collections;

[RequireComponent(typeof(OVRGazePointer))]
public class ParticleGazeCursor : MonoBehaviour
{
    public float emissionScale;
    public float maxSpeed;
    [Header("Particle emission curves")]
    // The scale on the x axis of the curves runs from 0 to maxSpeed
    [Tooltip("Curve for trailing edge of pointer")]
    public AnimationCurve halfEmission;
    [Tooltip("Curve for full perimeter of pointer")]
    public AnimationCurve fullEmission;

    [Tooltip("Curve for full perimeter of pointer")]
    public bool particleTrail;
    public float particleScale = 0.68f;

    Vector3 lastPos;
    ParticleSystem psHalf;
    ParticleSystem psFull;
    MeshRenderer quadRenderer;
    Color particleStartColor;
    

    OVRGazePointer gazePointer;

    // Use this for initialization
    void Start()
    {
        gazePointer = GetComponent<OVRGazePointer>();
        foreach (Transform child in transform)
        {
            if (child.name.Equals("Half"))
                psHalf = child.GetComponent<ParticleSystem>();
            if (child.name.Equals("Full"))
                psFull = child.GetComponent<ParticleSystem>();
            if (child.name.Equals("Quad"))
                quadRenderer = child.GetComponent<MeshRenderer>();
        }
        float scale =  transform.lossyScale.x;
        psHalf.startSize *= scale;
        psHalf.startSpeed *= scale;
        psFull.startSize *= scale;
        psFull.startSpeed *= scale;

        particleStartColor = psFull.startColor;

        if (!particleTrail)
        {
            GameObject.Destroy(psHalf);
            GameObject.Destroy(psFull);
        }

    }

    // Update is called once per frame
    void Update()
    {
        var delta = GetComponent<OVRGazePointer>().positionDelta;

        if (particleTrail)
        {
            // Evaluate these curves to decide the emission rate of the two sources of particles.
            psHalf.emissionRate = halfEmission.Evaluate((delta.magnitude / Time.deltaTime) / maxSpeed) * emissionScale;
            psFull.emissionRate = fullEmission.Evaluate((delta.magnitude / Time.deltaTime) / maxSpeed) * emissionScale;

            // Make the particles fade out with visibitly the same way the main ring does
            Color color = particleStartColor;
            color.a = gazePointer.visibilityStrength;
            psHalf.startColor = color;
            psFull.startColor = color;

            // Particles also scale when the gaze pointer scales
            psFull.startSize = particleScale * transform.lossyScale.x;
            psHalf.startSize = particleScale * transform.lossyScale.x;
        }

        // Set the main pointers alpha value to the correct level to achieve the desired level of fade
        quadRenderer.material.SetColor("_TintColor",new Color(1, 1, 1, gazePointer.visibilityStrength));
        
    }
}

OVRGazePointer

using UnityEngine;
using System.Collections;

public class OVRGazePointer : MonoBehaviour {

    [Tooltip("Should the pointer be hidden when not over interactive objects.")]
    public bool hideByDefault = true;

    [Tooltip("Time after leaving interactive object before pointer fades.")]
    public float showTimeoutPeriod = 1;

    [Tooltip("Time after mouse pointer becoming inactive before pointer unfades.")]
    public float hideTimeoutPeriod = 0.1f;

    [Tooltip("Keep a faint version of the pointer visible while using a mouse")]
    public bool dimOnHideRequest = true;

    [Tooltip("Angular scale of pointer")]
    public float depthScaleMultiplier = 0.03f;

    [Tooltip("Used for positioning pointer in scene")]
    public OVRCameraRig cameraRig;

    /// <summary>
    /// Is gaze pointer current visible
    /// </summary>
    public bool hidden { get; private set; }

    /// <summary>
    /// Current scale applied to pointer
    /// </summary>
    public float currentScale { get; private set; }

    /// <summary>
    /// Current depth of pointer from camera
    /// </summary>
    private float depth;
    /// <summary>
    /// How many times position has been set this frame. Used to detect when there are no position sets in a frame.
    /// </summary>
    private int positionSetsThisFrame = 0;
    /// <summary>
    /// Position last frame.
    /// </summary>
    private Vector3 lastPosition;
    /// <summary>
    /// Last time code requested the pointer be shown. Usually when pointer passes over interactive elements.
    /// </summary>
    private float lastShowRequestTime;
    /// <summary>
    /// Last time pointer was requested to be hidden. Usually mouse pointer activity.
    /// </summary>
    private float lastHideRequestTime;
    

    // How much the gaze pointer moved in the last frame
    private Vector3 _positionDelta;
    public Vector3 positionDelta { get { return _positionDelta; } }

    private static OVRGazePointer _instance;
    public static OVRGazePointer instance 
    { 
        // If there's no GazePointer already in the scene, instanciate one now.
        get
        {
            if (_instance == null)
            {
                Debug.Log(string.Format("Instanciating GazePointer", 0));
                _instance = (OVRGazePointer)GameObject.Instantiate((OVRGazePointer)Resources.Load("Prefabs/GazePointerRing", typeof(OVRGazePointer)));
            }
            return _instance;
        }
            
    }

    public float visibilityStrength 
    { 
        get 
        {
            float strengthFromShowRequest;
            if (hideByDefault)
            {
                strengthFromShowRequest =  Mathf.Clamp01(1 - (Time.time - lastShowRequestTime) / showTimeoutPeriod);
            }
            else
            {
                strengthFromShowRequest = 1;
            }

            // Now consider factors requesting pointer to be hidden
            float strengthFromHideRequest;
            if (dimOnHideRequest)
            {
                strengthFromHideRequest = (lastHideRequestTime + hideTimeoutPeriod > Time.time) ? 0.1f : 1;
            }
            else
            {
                strengthFromHideRequest = (lastHideRequestTime + hideTimeoutPeriod > Time.time) ? 0 : 1;
            }

            // Hide requests take priority
            return Mathf.Min(strengthFromShowRequest, strengthFromHideRequest);
        } 
    }


    private void Awake()
    {
        currentScale = 1;
        // Only allow one instance at runtime.
        if (_instance != null && _instance != this)
        {
            enabled = false;
            DestroyImmediate(this);
            return;
        }

        _instance = this;
        
    }

	
	// Update is called once per frame
	void Update () {
        // Even if this runs after SetPosition, it will work out to be the same position
        // Keep pointer at same distance from camera rig
        transform.position = cameraRig.centerEyeAnchor.transform.position + cameraRig.centerEyeAnchor.transform.forward * depth;

       
        if (visibilityStrength == 0 && !hidden)
        {
            Hide();
        }
        else if (visibilityStrength > 0 && hidden)
        {
            Show();
        }
	}

    /// <summary>
    /// Set position and orientation of pointer
    /// </summary>
    /// <param name="pos"></param>
    /// <param name="normal"></param>
    public void SetPosition(Vector3 pos, Vector3 normal)
    {
        transform.position = pos;

        // Set the rotation to match the normal of the surface it's on. For the other degree of freedom use
        // the direction of movement so that trail effects etc are easier
        Quaternion newRot = transform.rotation;
        newRot.SetLookRotation(normal, Vector3.up);//(lastPosition - transform.position).normalized
        transform.rotation = newRot;

        // record depth so that distance doesn't pop when pointer leaves an object
        depth = (cameraRig.centerEyeAnchor.transform.position - pos).magnitude;

        //set scale based on depth
        currentScale = depth * depthScaleMultiplier;
        transform.localScale = new Vector3(currentScale, currentScale, currentScale);

        positionSetsThisFrame++;
    }

    /// <summary>
    /// SetPosition overload without normal. Just makes cursor face user
    /// </summary>
    /// <param name="pos"></param>
    public void SetPosition(Vector3 pos)
    {
        SetPosition(pos, cameraRig.centerEyeAnchor.transform.forward);
    }

    
    void LateUpdate()
    {
        // This happens after all Updates so we know nothing set the position this frame
        if (positionSetsThisFrame == 0)
        {
            // No geometry intersections, so gazing into space. Make the cursor face directly at the camera
            Quaternion newRot = transform.rotation;
            newRot.SetLookRotation(cameraRig.centerEyeAnchor.transform.forward, Vector3.up);//(lastPosition - transform.position).normalized
            transform.rotation = newRot;
        }
        // Keep track of cursor movement direction
        _positionDelta = transform.position - lastPosition;
        lastPosition = transform.position;
        
        positionSetsThisFrame = 0;
    }
   
    /// <summary>
    /// Request the pointer be hidden
    /// </summary>
    public void RequestHide()
    {
        if (!dimOnHideRequest)
        {
            Hide();
        }
        lastHideRequestTime = Time.time;
    }

    /// <summary>
    /// Request the pointer be shown. Hide requests take priority
    /// </summary>
    public void RequestShow()
    {
        Show();
        lastShowRequestTime = Time.time;
    }

    private void Hide()
    {
        foreach (Transform child in transform)
        {
            child.gameObject.SetActive(false);
        }
        if (GetComponent<Renderer>())
            GetComponent<Renderer>().enabled = false;
        hidden = true;
    }
    
    private void Show()
    {
        foreach (Transform child in transform)
        {
            child.gameObject.SetActive(true);
        }
        if (GetComponent<Renderer>())
            GetComponent<Renderer>().enabled = true;
        hidden = false;
    }
}

OVRRaycaster

using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
using UnityEngine.Serialization;

[RequireComponent(typeof(Canvas))]
public class OVRRaycaster : GraphicRaycaster, IPointerEnterHandler
{
    [Tooltip("A world space pointer for this canvas")]
    public GameObject pointer;
    

    protected OVRRaycaster()
    { }

    [NonSerialized]
    private Canvas m_Canvas;

    private Canvas canvas
    {
        get
        {
            if (m_Canvas != null)
                return m_Canvas;

            m_Canvas = GetComponent<Canvas>();
            return m_Canvas;
        }
    }

    public override Camera eventCamera
    {
        get
        {
            return canvas.worldCamera;
        }
    }


    /// <summary>
    /// For the given ray, find graphics on this canvas which it intersects and are not blocked by other
    /// world objects
    /// </summary>
    [NonSerialized]
    private List<RaycastHit> m_RaycastResults = new List<RaycastHit>();
    private void Raycast(PointerEventData eventData, List<RaycastResult> resultAppendList, Ray ray, bool checkForBlocking)
    {
        //This function is closely based on 
        //void GraphicRaycaster.Raycast(PointerEventData eventData, List<RaycastResult> resultAppendList)
        
        if (canvas == null)
            return;

        float hitDistance = float.MaxValue;

        if (checkForBlocking && blockingObjects != BlockingObjects.None)
        {
            float dist = eventCamera.farClipPlane;

            if (blockingObjects == BlockingObjects.ThreeD || blockingObjects == BlockingObjects.All)
            {
                var hits = Physics.RaycastAll(ray, dist, m_BlockingMask);

                if (hits.Length > 0 && hits[0].distance < hitDistance)
                {
                    hitDistance = hits[0].distance;
                }
            }

            if (blockingObjects == BlockingObjects.TwoD || blockingObjects == BlockingObjects.All)
            {
                var hits = Physics2D.GetRayIntersectionAll(ray, dist, m_BlockingMask);

                if (hits.Length > 0 && hits[0].fraction * dist < hitDistance)
                {
                    hitDistance = hits[0].fraction * dist;
                }
            }
        }

        m_RaycastResults.Clear();

        GraphicRaycast(canvas, ray, m_RaycastResults);

        for (var index = 0; index < m_RaycastResults.Count; index++)
        {
            var go = m_RaycastResults[index].graphic.gameObject;
            bool appendGraphic = true;

            if (ignoreReversedGraphics)
            {
                // If we have a camera compare the direction against the cameras forward.
                var cameraFoward = ray.direction;
                var dir = go.transform.rotation * Vector3.forward;
                appendGraphic = Vector3.Dot(cameraFoward, dir) > 0;
            }

            // Ignore points behind us (can happen with a canvas pointer)
            if (eventCamera.transform.InverseTransformPoint(m_RaycastResults[index].worldPos).z <= 0)
            {
                appendGraphic = false;
            }

            if (appendGraphic)
            {
                float distance = Vector3.Distance(ray.origin, m_RaycastResults[index].worldPos);

                if (distance >= hitDistance)
                {
                    continue;
                }

                var castResult = new RaycastResult
                {
                    gameObject = go,
                    module = this,
                    distance = distance,
                    index = resultAppendList.Count,
                    depth = m_RaycastResults[index].graphic.depth,

                    worldPosition = m_RaycastResults[index].worldPos
                };
                resultAppendList.Add(castResult);
            }
        }
    }

    /// <summary>
    /// Performs a raycast using eventData.worldSpaceRay
    /// </summary>
    /// <param name="eventData"></param>
    /// <param name="resultAppendList"></param>
    public override void Raycast(PointerEventData eventData, List<RaycastResult> resultAppendList)
    {
        OVRRayPointerEventData rayPointerEventData = eventData as OVRRayPointerEventData;
        if (rayPointerEventData != null)
        {
            Raycast(eventData, resultAppendList, rayPointerEventData.worldSpaceRay, true);
        }
    }
    /// <summary>
    /// Performs a raycast using the pointer object attached to this OVRRaycaster 
    /// </summary>
    /// <param name="eventData"></param>
    /// <param name="resultAppendList"></param>
    public void RaycastPointer(PointerEventData eventData, List<RaycastResult> resultAppendList)
    {
        if (pointer != null)
        {
            Raycast(eventData, resultAppendList, new Ray(eventCamera.transform.position, (pointer.transform.position - eventCamera.transform.position).normalized), false);
        }
    }

  
    /// <summary>
    /// Perform a raycast into the screen and collect all graphics underneath it.
    /// </summary>
    [NonSerialized]
    static readonly List<RaycastHit> s_SortedGraphics = new List<RaycastHit>();
    private void GraphicRaycast(Canvas canvas, Ray ray, List<RaycastHit> results)
    {
        //This function is based closely on :
        // void GraphicRaycaster.Raycast(Canvas canvas, Camera eventCamera, Vector2 pointerPosition, List<Graphic> results)
        // But modified to take a Ray instead of a canvas pointer, and also to explicitly ignore
        // the graphic associated with the pointer

        // Necessary for the event system
        var foundGraphics = GraphicRegistry.GetGraphicsForCanvas(canvas);
        s_SortedGraphics.Clear();
        for (int i = 0; i < foundGraphics.Count; ++i)
        {
            Graphic graphic = foundGraphics[i];

            // -1 means it hasn't been processed by the canvas, which means it isn't actually drawn
            if (graphic.depth == -1 || (pointer == graphic.gameObject))
                continue;
            Vector3 worldPos;
            if (RayIntersectsRectTransform(graphic.rectTransform, ray, out worldPos))
            {
                //Work out where this is on the screen for compatibility with existing Unity UI code
                Vector2 screenPos = eventCamera.WorldToScreenPoint(worldPos);
                // mask/image intersection - See Unity docs on eventAlphaThreshold for when this does anything
                if (graphic.Raycast(screenPos, eventCamera))
                {
                    RaycastHit hit;
                    hit.graphic = graphic;
                    hit.worldPos = worldPos;
                    hit.fromMouse = false;
                    s_SortedGraphics.Add(hit);
                }
            }
        }

        s_SortedGraphics.Sort((g1, g2) => g2.graphic.depth.CompareTo(g1.graphic.depth));

        for (int i = 0; i < s_SortedGraphics.Count; ++i)
        {
            results.Add(s_SortedGraphics[i]);
        }
    }
    /// <summary>
    /// Get screen position of worldPosition contained in this RaycastResult
    /// </summary>
    /// <param name="worldPosition"></param>
    /// <returns></returns>
    public Vector2 GetScreenPosition(RaycastResult raycastResult)
    {
        // In future versions of Uinty RaycastResult will contain screenPosition so this will not be necessary
        return eventCamera.WorldToScreenPoint(raycastResult.worldPosition);
    }


    /// <summary>
    /// Detects whether a ray intersects a RectTransform and if it does also 
    /// returns the world position of the intersection.
    /// </summary>
    /// <param name="rectTransform"></param>
    /// <param name="ray"></param>
    /// <param name="worldPos"></param>
    /// <returns></returns>
    static bool RayIntersectsRectTransform(RectTransform rectTransform, Ray ray, out Vector3 worldPos)
    {
        Vector3[] corners = new Vector3[4];
        rectTransform.GetWorldCorners(corners);
        Plane plane = new Plane(corners[0], corners[1], corners[2]);

        float enter;
        if (!plane.Raycast(ray, out enter))
        {
            worldPos = Vector3.zero;
            return false;
        }

        Vector3 intersection = ray.GetPoint(enter);

        Vector3 BottomEdge = corners[3] - corners[0];
        Vector3 LeftEdge = corners[1] - corners[0];
        float BottomDot = Vector3.Dot(intersection - corners[0], BottomEdge);
        float LeftDot = Vector3.Dot(intersection - corners[0], LeftEdge);
        if (BottomDot < BottomEdge.sqrMagnitude && // Can use sqrMag because BottomEdge is not normalized
            LeftDot < LeftEdge.sqrMagnitude &&
                BottomDot >= 0 &&
                LeftDot >= 0)
        {
            worldPos = corners[0] + LeftDot * LeftEdge / LeftEdge.sqrMagnitude + BottomDot * BottomEdge / BottomEdge.sqrMagnitude;
            return true;
        }
        else
        {
            worldPos = Vector3.zero;
            return false;
        }
    }


    struct RaycastHit
    {
        public Graphic graphic;
        public Vector3 worldPos;
        public bool fromMouse;
    };


    /// <summary>
    /// Is this the currently focussed Raycaster according to the InputModule
    /// </summary>
    /// <returns></returns>
    public bool IsFocussed()
    {
        OVRInputModule inputModule = EventSystem.current.currentInputModule as OVRInputModule;
        return inputModule && inputModule.activeGraphicRaycaster == this;
    }
    
    public void OnPointerEnter(PointerEventData e)
    {
        PointerEventData ped = e as OVRRayPointerEventData;
        if (ped != null)
        {
            // Gaze has entered this canvas. We'll make it the active one so that canvas-mouse pointer can be used.
            OVRInputModule inputModule = EventSystem.current.currentInputModule as OVRInputModule;
            inputModule.activeGraphicRaycaster = this;
        }
    }
}

OVRPhysicsRaycaster

using System.Collections.Generic;

namespace UnityEngine.EventSystems
{
    /// <summary>
    /// Simple event system using physics raycasts.
    /// </summary>
    [RequireComponent(typeof(OVRCameraRig))]
    public class OVRPhysicsRaycaster : BaseRaycaster
    {
        /// <summary>
        /// Const to use for clarity when no event mask is set
        /// </summary>
        protected const int kNoEventMaskSet = -1;
        

        /// <summary>
        /// Layer mask used to filter events. Always combined with the camera's culling mask if a camera is used.
        /// </summary>
        [SerializeField]
        protected LayerMask m_EventMask = kNoEventMaskSet;

        protected OVRPhysicsRaycaster()
        { }

        public override Camera eventCamera
        {
            get
            {
                return GetComponent<OVRCameraRig>().leftEyeCamera;
            }
        }

        /// <summary>
        /// Depth used to determine the order of event processing.
        /// </summary>
        public virtual int depth
        {
            get { return (eventCamera != null) ? (int)eventCamera.depth : 0xFFFFFF; }
        }

        /// <summary>
        /// Event mask used to determine which objects will receive events.
        /// </summary>
        public int finalEventMask
        {
            get { return (eventCamera != null) ? eventCamera.cullingMask & m_EventMask : kNoEventMaskSet; }
        }

        /// <summary>
        /// Layer mask used to filter events. Always combined with the camera's culling mask if a camera is used.
        /// </summary>
        public LayerMask eventMask
        {
            get { return m_EventMask; }
            set { m_EventMask = value; }
        }
       

        /// <summary>
        /// Perform a raycast using the worldSpaceRay in eventData.
        /// </summary>
        /// <param name="eventData"></param>
        /// <param name="resultAppendList"></param>
        public override void Raycast(PointerEventData eventData, List<RaycastResult> resultAppendList)
        {
            // This function is closely based on PhysicsRaycaster.Raycast

            if (eventCamera == null)
                return;

            OVRRayPointerEventData rayPointerEventData = eventData as OVRRayPointerEventData;
            if (rayPointerEventData == null)
                return;

            var ray = rayPointerEventData.worldSpaceRay;

            float dist = eventCamera.farClipPlane - eventCamera.nearClipPlane;

            var hits = Physics.RaycastAll(ray, dist, finalEventMask);

            if (hits.Length > 1)
                System.Array.Sort(hits, (r1, r2) => r1.distance.CompareTo(r2.distance));

            if (hits.Length != 0)
            {
                for (int b = 0, bmax = hits.Length; b < bmax; ++b)
                {
                    var result = new RaycastResult
                    {
                        gameObject = hits[b].collider.gameObject,
                        module = this,
                        distance = hits[b].distance,
                        index = resultAppendList.Count,
                        worldPosition = hits[0].point,
                        worldNormal = hits[0].normal,
                    };
                    resultAppendList.Add(result);
                }
            }
        }

        /// <summary>
        ///  Perform a Spherecast using the worldSpaceRay in eventData.
        /// </summary>
        /// <param name="eventData"></param>
        /// <param name="resultAppendList"></param>
        /// <param name="radius">Radius of the sphere</param>
        public void Spherecast(PointerEventData eventData, List<RaycastResult> resultAppendList, float radius)
        {
            if (eventCamera == null)
                return;

            OVRRayPointerEventData rayPointerEventData = eventData as OVRRayPointerEventData;
            if (rayPointerEventData == null)
                return;

            var ray = rayPointerEventData.worldSpaceRay;

            float dist = eventCamera.farClipPlane - eventCamera.nearClipPlane;

            var hits = Physics.SphereCastAll(ray, radius, dist, finalEventMask);

            if (hits.Length > 1)
                System.Array.Sort(hits, (r1, r2) => r1.distance.CompareTo(r2.distance));

            if (hits.Length != 0)
            {
                for (int b = 0, bmax = hits.Length; b < bmax; ++b)
                {
                    var result = new RaycastResult
                    {
                        gameObject = hits[b].collider.gameObject,
                        module = this,
                        distance = hits[b].distance,
                        index = resultAppendList.Count,
                        worldPosition = hits[0].point,
                        worldNormal = hits[0].normal,
                    };
                    resultAppendList.Add(result);
                }
            }
        }
        /// <summary>
        /// Get screen position of this world position as seen by the event camera of this OVRPhysicsRaycaster
        /// </summary>
        /// <param name="worldPosition"></param>
        /// <returns></returns>
        public Vector2 GetScreenPos(Vector3 worldPosition)
        {
            // In future versions of Uinty RaycastResult will contain screenPosition so this will not be necessary
            return eventCamera.WorldToScreenPoint(worldPosition);
        }
    }
}

OVRInputModule

using System;
using System.Collections.Generic;

namespace UnityEngine.EventSystems
{
    public class OVRInputModule : PointerInputModule
    {
        [Tooltip("Object which points with Z axis. E.g. CentreEyeAnchor from OVRCameraRig")]
        public Transform rayTransform;

        [Tooltip("Gamepad button to act as gaze click")]
        public OVRInput.Button joyPadClickButton = OVRInput.Button.One;

        [Tooltip("Keyboard button to act as gaze click")]
        public KeyCode gazeClickKey = KeyCode.Space;

        [Header("Physics")]
        [Tooltip("Perform an sphere cast to determine correct depth for gaze pointer")]
        public bool performSphereCastForGazepointer;

        [Tooltip("Match the gaze pointer normal to geometry normal for physics colliders")]
        public bool matchNormalOnPhysicsColliders;

        [Header("Gamepad Stick Scroll")]
        [Tooltip("Enable scrolling with the left stick on a gamepad")]
        public bool useLeftStickScroll = true;

        [Tooltip("Deadzone for left stick to prevent accidental scrolling")]
        public float leftStickDeadZone = 0.15f;

        [Header("Touchpad Swipe Scroll")]
        [Tooltip("Enable scrolling by swiping the GearVR touchpad")]
        public bool useSwipeScroll = true;
        [Tooltip("Minimum swipe amount to trigger scrolling")]
        public float minSwipeMovement = 0;
        [Tooltip("Distance scrolled when swipe scroll occurs")]
        public float swipeScrollScale = 4f;

        #region GearVR swipe scroll
        private Vector2 swipeStartPos;
        private Vector2 unusedSwipe;
        #endregion

        // The raycaster that gets to do pointer interaction (e.g. with a mouse), gaze interaction always works
       // private OVRRaycaster _activeGraphicRaycaster;
        [NonSerialized]
        public OVRRaycaster activeGraphicRaycaster;
        [Header("Dragging")]
        [Tooltip("Minimum pointer movement in degrees to start dragging")]
        public float angleDragThreshold = 1;

        
        

        // The following region contains code exactly the same as the implementation
        // of StandaloneInputModule. It is copied here rather than inheriting from StandaloneInputModule
        // because most of StandaloneInputModule is private so it isn't possible to easily derive from.
        // Future changes from Unity to StandaloneInputModule will make it possible for this class to
        // derive from StandaloneInputModule instead of PointerInput module.
        // 
        // The following functions are not present in the following region since they have modified
        // versions in the next region:
        // Process
        // ProcessMouseEvent
        // UseMouse
        #region StandaloneInputModule code
        
         private float m_NextAction;

        private Vector2 m_LastMousePosition;
        private Vector2 m_MousePosition;

        protected OVRInputModule()
        {}

        void Reset()
        {
            allowActivationOnMobileDevice = true;
        }

        [Obsolete("Mode is no longer needed on input module as it handles both mouse and keyboard simultaneously.", false)]
        public enum InputMode
        {
            Mouse,
            Buttons
        }

        [Obsolete("Mode is no longer needed on input module as it handles both mouse and keyboard simultaneously.", false)]
        public InputMode inputMode
        {
            get { return InputMode.Mouse; }
        }
        [Header("Standalone Input Module")]
        [SerializeField]
        private string m_HorizontalAxis = "Horizontal";

        /// <summary>
        /// Name of the vertical axis for movement (if axis events are used).
        /// </summary>
        [SerializeField]
        private string m_VerticalAxis = "Vertical";

        /// <summary>
        /// Name of the submit button.
        /// </summary>
        [SerializeField]
        private string m_SubmitButton = "Submit";

        /// <summary>
        /// Name of the submit button.
        /// </summary>
        [SerializeField]
        private string m_CancelButton = "Cancel";

        [SerializeField]
        private float m_InputActionsPerSecond = 10;

        [SerializeField]
        private bool m_AllowActivationOnMobileDevice;

        public bool allowActivationOnMobileDevice
        {
            get { return m_AllowActivationOnMobileDevice; }
            set { m_AllowActivationOnMobileDevice = value; }
        }

        public float inputActionsPerSecond
        {
            get { return m_InputActionsPerSecond; }
            set { m_InputActionsPerSecond = value; }
        }

        /// <summary>
        /// Name of the horizontal axis for movement (if axis events are used).
        /// </summary>
        public string horizontalAxis
        {
            get { return m_HorizontalAxis; }
            set { m_HorizontalAxis = value; }
        }

        /// <summary>
        /// Name of the vertical axis for movement (if axis events are used).
        /// </summary>
        public string verticalAxis
        {
            get { return m_VerticalAxis; }
            set { m_VerticalAxis = value; }
        }

        public string submitButton
        {
            get { return m_SubmitButton; }
            set { m_SubmitButton = value; }
        }

        public string cancelButton
        {
            get { return m_CancelButton; }
            set { m_CancelButton = value; }
        }

        public override void UpdateModule()
        {
            m_LastMousePosition = m_MousePosition;
            m_MousePosition = Input.mousePosition;
        }

        public override bool IsModuleSupported()
        {
            // Check for mouse presence instead of whether touch is supported,
            // as you can connect mouse to a tablet and in that case we'd want
            // to use StandaloneInputModule for non-touch input events.
            return m_AllowActivationOnMobileDevice || Input.mousePresent;
        }

        public override bool ShouldActivateModule()
        {
            if (!base.ShouldActivateModule())
                return false;

            var shouldActivate = Input.GetButtonDown(m_SubmitButton);
            shouldActivate |= Input.GetButtonDown(m_CancelButton);
            shouldActivate |= !Mathf.Approximately(Input.GetAxisRaw(m_HorizontalAxis), 0.0f);
            shouldActivate |= !Mathf.Approximately(Input.GetAxisRaw(m_VerticalAxis), 0.0f);
            shouldActivate |= (m_MousePosition - m_LastMousePosition).sqrMagnitude > 0.0f;
            shouldActivate |= Input.GetMouseButtonDown(0);
            return shouldActivate;
        }

        public override void ActivateModule()
        {
            base.ActivateModule();
            m_MousePosition = Input.mousePosition;
            m_LastMousePosition = Input.mousePosition;

            var toSelect = eventSystem.currentSelectedGameObject;
            if (toSelect == null)
                toSelect = eventSystem.firstSelectedGameObject;

            eventSystem.SetSelectedGameObject(toSelect, GetBaseEventData());
        }

        public override void DeactivateModule()
        {
            base.DeactivateModule();
            ClearSelection();
        }

        

        /// <summary>
        /// Process submit keys.
        /// </summary>
        private bool SendSubmitEventToSelectedObject()
        {
            if (eventSystem.currentSelectedGameObject == null)
                return false;

            var data = GetBaseEventData();
            if (Input.GetButtonDown(m_SubmitButton))
                ExecuteEvents.Execute(eventSystem.currentSelectedGameObject, data, ExecuteEvents.submitHandler);

            if (Input.GetButtonDown(m_CancelButton))
                ExecuteEvents.Execute(eventSystem.currentSelectedGameObject, data, ExecuteEvents.cancelHandler);
            return data.used;
        }

        private bool AllowMoveEventProcessing(float time)
        {
            bool allow = Input.GetButtonDown(m_HorizontalAxis);
            allow |= Input.GetButtonDown(m_VerticalAxis);
            allow |= (time > m_NextAction);
            return allow;
        }

        private Vector2 GetRawMoveVector()
        {
            Vector2 move = Vector2.zero;
            move.x = Input.GetAxisRaw(m_HorizontalAxis);
            move.y = Input.GetAxisRaw(m_VerticalAxis);

            if (Input.GetButtonDown(m_HorizontalAxis))
            {
                if (move.x < 0)
                    move.x = -1f;
                if (move.x > 0)
                    move.x = 1f;
            }
            if (Input.GetButtonDown(m_VerticalAxis))
            {
                if (move.y < 0)
                    move.y = -1f;
                if (move.y > 0)
                    move.y = 1f;
            }
            return move;
        }

        /// <summary>
        /// Process keyboard events.
        /// </summary>
        private bool SendMoveEventToSelectedObject()
        {
            float time = Time.unscaledTime;

            if (!AllowMoveEventProcessing(time))
                return false;

            Vector2 movement = GetRawMoveVector();
            // Debug.Log(m_ProcessingEvent.rawType + " axis:" + m_AllowAxisEvents + " value:" + "(" + x + "," + y + ")");
            var axisEventData = GetAxisEventData(movement.x, movement.y, 0.6f);
            if (!Mathf.Approximately(axisEventData.moveVector.x, 0f)
                || !Mathf.Approximately(axisEventData.moveVector.y, 0f))
            {
                ExecuteEvents.Execute(eventSystem.currentSelectedGameObject, axisEventData, ExecuteEvents.moveHandler);
            }
            m_NextAction = time + 1f / m_InputActionsPerSecond;
            return axisEventData.used;
        }

        

        

        private bool SendUpdateEventToSelectedObject()
        {
            if (eventSystem.currentSelectedGameObject == null)
                return false;

            var data = GetBaseEventData();
            ExecuteEvents.Execute(eventSystem.currentSelectedGameObject, data, ExecuteEvents.updateSelectedHandler);
            return data.used;
        }

        /// <summary>
        /// Process the current mouse press.
        /// </summary>
        private void ProcessMousePress(MouseButtonEventData data)
        {
            var pointerEvent = data.buttonData;
            var currentOverGo = pointerEvent.pointerCurrentRaycast.gameObject;

            // PointerDown notification
            if (data.PressedThisFrame())
            {
                pointerEvent.eligibleForClick = true;
                pointerEvent.delta = Vector2.zero;
                pointerEvent.dragging = false;
                pointerEvent.useDragThreshold = true;
                pointerEvent.pressPosition = pointerEvent.position;
                pointerEvent.pointerPressRaycast = pointerEvent.pointerCurrentRaycast;
                
                DeselectIfSelectionChanged(currentOverGo, pointerEvent);

                // search for the control that will receive the press
                // if we can't find a press handler set the press
                // handler to be what would receive a click.
                var newPressed = ExecuteEvents.ExecuteHierarchy(currentOverGo, pointerEvent, ExecuteEvents.pointerDownHandler);

                // didnt find a press handler... search for a click handler
                if (newPressed == null)
                    newPressed = ExecuteEvents.GetEventHandler<IPointerClickHandler>(currentOverGo);

                // Debug.Log("Pressed: " + newPressed);

                float time = Time.unscaledTime;

                if (newPressed == pointerEvent.lastPress)
                {
                    var diffTime = time - pointerEvent.clickTime;
                    if (diffTime < 0.3f)
                        ++pointerEvent.clickCount;
                    else
                        pointerEvent.clickCount = 1;

                    pointerEvent.clickTime = time;
                }
                else
                {
                    pointerEvent.clickCount = 1;
                }

                pointerEvent.pointerPress = newPressed;
                pointerEvent.rawPointerPress = currentOverGo;

                pointerEvent.clickTime = time;

                // Save the drag handler as well
                pointerEvent.pointerDrag = ExecuteEvents.GetEventHandler<IDragHandler>(currentOverGo);

                if (pointerEvent.pointerDrag != null)
                    ExecuteEvents.Execute(pointerEvent.pointerDrag, pointerEvent, ExecuteEvents.initializePotentialDrag);
            }

            // PointerUp notification
            if (data.ReleasedThisFrame())
            {
                // Debug.Log("Executing pressup on: " + pointer.pointerPress);
                ExecuteEvents.Execute(pointerEvent.pointerPress, pointerEvent, ExecuteEvents.pointerUpHandler);

                // Debug.Log("KeyCode: " + pointer.eventData.keyCode);

                // see if we mouse up on the same element that we clicked on...
                var pointerUpHandler = ExecuteEvents.GetEventHandler<IPointerClickHandler>(currentOverGo);

                // PointerClick and Drop events
                if (pointerEvent.pointerPress == pointerUpHandler && pointerEvent.eligibleForClick)
                {
                    ExecuteEvents.Execute(pointerEvent.pointerPress, pointerEvent, ExecuteEvents.pointerClickHandler);
                }
                else if (pointerEvent.pointerDrag != null)
                {
                    ExecuteEvents.ExecuteHierarchy(currentOverGo, pointerEvent, ExecuteEvents.dropHandler);
                }

                pointerEvent.eligibleForClick = false;
                pointerEvent.pointerPress = null;
                pointerEvent.rawPointerPress = null;

                if (pointerEvent.pointerDrag != null && pointerEvent.dragging)
                    ExecuteEvents.Execute(pointerEvent.pointerDrag, pointerEvent, ExecuteEvents.endDragHandler);

                pointerEvent.dragging = false;
                pointerEvent.pointerDrag = null;

                // redo pointer enter / exit to refresh state
                // so that if we moused over somethign that ignored it before
                // due to having pressed on something else
                // it now gets it.
                if (currentOverGo != pointerEvent.pointerEnter)
                {
                    HandlePointerExitAndEnter(pointerEvent, null);
                    HandlePointerExitAndEnter(pointerEvent, currentOverGo);
                }
            }
        }
#endregion
        #region Modified StandaloneInputModule methods
        
        /// <summary>
        /// Process all mouse events. This is the same as the StandaloneInputModule version except that
        /// it takes MouseState as a parameter, allowing it to be used for both Gaze and Mouse 
        /// pointerss.
        /// </summary>
        private void ProcessMouseEvent(MouseState mouseData)
        {
            var pressed = mouseData.AnyPressesThisFrame();
            var released = mouseData.AnyReleasesThisFrame();

            var leftButtonData = mouseData.GetButtonState(PointerEventData.InputButton.Left).eventData;

            if (!UseMouse(pressed, released, leftButtonData.buttonData))
                return;

            // Process the first mouse button fully
            ProcessMousePress(leftButtonData);
            ProcessMove(leftButtonData.buttonData);
            ProcessDrag(leftButtonData.buttonData);

            // Now process right / middle clicks
            ProcessMousePress(mouseData.GetButtonState(PointerEventData.InputButton.Right).eventData);
            ProcessDrag(mouseData.GetButtonState(PointerEventData.InputButton.Right).eventData.buttonData);
            ProcessMousePress(mouseData.GetButtonState(PointerEventData.InputButton.Middle).eventData);
            ProcessDrag(mouseData.GetButtonState(PointerEventData.InputButton.Middle).eventData.buttonData);

            if (!Mathf.Approximately(leftButtonData.buttonData.scrollDelta.sqrMagnitude, 0.0f))
            {
                var scrollHandler = ExecuteEvents.GetEventHandler<IScrollHandler>(leftButtonData.buttonData.pointerCurrentRaycast.gameObject);
                ExecuteEvents.ExecuteHierarchy(scrollHandler, leftButtonData.buttonData, ExecuteEvents.scrollHandler);
            }
        }
        
        /// <summary>
        /// Process this InputModule. Same as the StandaloneInputModule version, except that it calls
        /// ProcessMouseEvent twice, once for gaze pointers, and once for mouse pointers.
        /// </summary>
        public override void Process()
        {
            bool usedEvent = SendUpdateEventToSelectedObject();

            if (eventSystem.sendNavigationEvents)
            {
                if (!usedEvent)
                    usedEvent |= SendMoveEventToSelectedObject();

                if (!usedEvent)
                    SendSubmitEventToSelectedObject();
            }

            ProcessMouseEvent(GetGazePointerData());
#if !UNITY_ANDROID
            ProcessMouseEvent(GetCanvasPointerData());
#endif
        }
        /// <summary>
        /// Decide if mouse events need to be processed this frame. Same as StandloneInputModule except
        /// that the IsPointerMoving method from this class is used, instead of the method on PointerEventData
        /// </summary>
       private static bool UseMouse(bool pressed, bool released, PointerEventData pointerData)
        {
            if (pressed || released || IsPointerMoving(pointerData) || pointerData.IsScrolling())
                return true;

            return false;
        }
        #endregion

        
        /// <summary>
        /// Convenience function for cloning PointerEventData
        /// </summary>
        /// <param name="from">Copy this value</param>
        /// <param name="to">to this object</param>
        protected void CopyFromTo(OVRRayPointerEventData @from, OVRRayPointerEventData @to)
        {
            @to.position = @from.position;
            @to.delta = @from.delta;
            @to.scrollDelta = @from.scrollDelta;
            @to.pointerCurrentRaycast = @from.pointerCurrentRaycast;
            @to.pointerEnter = @from.pointerEnter;
            @to.worldSpaceRay = @from.worldSpaceRay;
        }
        /// <summary>
        /// Convenience function for cloning PointerEventData
        /// </summary>
        /// <param name="from">Copy this value</param>
        /// <param name="to">to this object</param>
        protected void CopyFromTo(PointerEventData @from, PointerEventData @to)
        {
            @to.position = @from.position;
            @to.delta = @from.delta;
            @to.scrollDelta = @from.scrollDelta;
            @to.pointerCurrentRaycast = @from.pointerCurrentRaycast;
            @to.pointerEnter = @from.pointerEnter;
        }
        

        // In the following region we extend the PointerEventData system implemented in PointerInputModule
        // We define an additional dictionary for ray(e.g. gaze) based pointers. Mouse pointers still use the dictionary
        // in PointerInputModule
#region PointerEventData pool

        // Pool for OVRRayPointerEventData for ray based pointers
        protected Dictionary<int, OVRRayPointerEventData> m_VRRayPointerData = new Dictionary<int, OVRRayPointerEventData>();

        
        protected bool GetPointerData(int id, out OVRRayPointerEventData data, bool create)
        {
            if (!m_VRRayPointerData.TryGetValue(id, out data) && create)
            {
                data = new OVRRayPointerEventData(eventSystem)
                {
                    pointerId = id,
                };

                m_VRRayPointerData.Add(id, data);
                return true;
            }
            return false;
        }

        /// <summary>
        /// Clear pointer state for both types of pointer
        /// </summary>
        protected new void ClearSelection()
        {
            var baseEventData = GetBaseEventData();

            foreach (var pointer in m_PointerData.Values)
            {
                // clear all selection
                HandlePointerExitAndEnter(pointer, null);
            }
            foreach (var pointer in m_VRRayPointerData.Values)
            {
                // clear all selection
                HandlePointerExitAndEnter(pointer, null);
            }

            m_PointerData.Clear();
            eventSystem.SetSelectedGameObject(null, baseEventData);
        }
#endregion

        /// <summary>
        /// For RectTransform, calculate it's normal in world space
        /// </summary>
        static Vector3 GetRectTransformNormal(RectTransform rectTransform)
        {
            Vector3[] corners = new Vector3[4];
            rectTransform.GetWorldCorners(corners);
            Vector3 BottomEdge = corners[3] - corners[0];
            Vector3 LeftEdge = corners[1] - corners[0];
            rectTransform.GetWorldCorners(corners);
            return Vector3.Cross(LeftEdge, BottomEdge).normalized;
        }
       
        private readonly MouseState m_MouseState = new MouseState();
        // Overridden so that we can process the two types of pointer separately


        // The following 2 functions are equivalent to PointerInputModule.GetMousePointerEventData but are customized to
        // get data for ray pointers and canvas mouse pointers.
        
        /// <summary>
        /// State for a pointer controlled by a world space ray. E.g. gaze pointer
        /// </summary>
        /// <returns></returns>
        protected MouseState GetGazePointerData()
        {
            // Get the OVRRayPointerEventData reference
            OVRRayPointerEventData leftData;
            GetPointerData(kMouseLeftId, out leftData, true );
            leftData.Reset();
            
            //Now set the world space ray. This ray is what the user uses to point at UI elements
            leftData.worldSpaceRay = new Ray(rayTransform.position, rayTransform.forward);
            leftData.scrollDelta = GetExtraScrollDelta();

            //Populate some default values
            leftData.button = PointerEventData.InputButton.Left;
            leftData.useDragThreshold = true;
            // Perform raycast to find intersections with world
            eventSystem.RaycastAll(leftData, m_RaycastResultCache);
            var raycast = FindFirstRaycast(m_RaycastResultCache);
            leftData.pointerCurrentRaycast = raycast;
            m_RaycastResultCache.Clear();

            OVRRaycaster ovrRaycaster = raycast.module as OVRRaycaster;
            // We're only interested in intersections from OVRRaycasters
            if (ovrRaycaster) 
            {
                // The Unity UI system expects event data to have a screen position
                // so even though this raycast came from a world space ray we must get a screen
                // space position for the camera attached to this raycaster for compatability
                leftData.position = ovrRaycaster.GetScreenPosition(raycast);
                

                // Find the world position and normal the Graphic the ray intersected
                RectTransform graphicRect = raycast.gameObject.GetComponent<RectTransform>();
                if (graphicRect != null)
                {
                    // Set are gaze indicator with this world position and normal
                    Vector3 worldPos = raycast.worldPosition;
                    Vector3 normal = GetRectTransformNormal(graphicRect);
                    OVRGazePointer.instance.SetPosition(worldPos, normal);
                    // Make sure it's being shown
                    OVRGazePointer.instance.RequestShow();
                }
            }
            OVRPhysicsRaycaster physicsRaycaster = raycast.module as OVRPhysicsRaycaster;
            if (physicsRaycaster)
            {
                leftData.position = physicsRaycaster.GetScreenPos(raycast.worldPosition);
                OVRGazePointer.instance.RequestShow();
                OVRGazePointer.instance.SetPosition(raycast.worldPosition, raycast.worldNormal);
            }




            // Stick default data values in right and middle slots for compatability

            // copy the apropriate data into right and middle slots
            OVRRayPointerEventData rightData;
            GetPointerData(kMouseRightId, out rightData, true );
            CopyFromTo(leftData, rightData);
            rightData.button = PointerEventData.InputButton.Right;

            OVRRayPointerEventData middleData;
            GetPointerData(kMouseMiddleId, out middleData, true );
            CopyFromTo(leftData, middleData);
            middleData.button = PointerEventData.InputButton.Middle;


            m_MouseState.SetButtonState(PointerEventData.InputButton.Left, GetGazeButtonState(), leftData);
            m_MouseState.SetButtonState(PointerEventData.InputButton.Right, PointerEventData.FramePressState.NotChanged, rightData);
            m_MouseState.SetButtonState(PointerEventData.InputButton.Middle, PointerEventData.FramePressState.NotChanged, middleData);
            return m_MouseState;
        }

        /// <summary>
        /// Get state for pointer which is a pointer moving in world space across the surface of a world space canvas.
        /// </summary>
        /// <returns></returns>
        protected MouseState GetCanvasPointerData()
        {
            // Get the OVRRayPointerEventData reference
            PointerEventData leftData;
            GetPointerData(kMouseLeftId, out leftData, true );
            leftData.Reset();
            
            // Setup default values here. Set position to zero because we don't actually know the pointer
            // positions. Each canvas knows the position of its canvas pointer.
            leftData.position = Vector2.zero;
            leftData.scrollDelta = Input.mouseScrollDelta;
            leftData.button = PointerEventData.InputButton.Left;

            if (activeGraphicRaycaster)
            {
                // Let the active raycaster find intersections on its canvas
                activeGraphicRaycaster.RaycastPointer(leftData, m_RaycastResultCache);
                var raycast = FindFirstRaycast(m_RaycastResultCache);
                leftData.pointerCurrentRaycast = raycast;
                m_RaycastResultCache.Clear();
                
                OVRRaycaster ovrRaycaster = raycast.module as OVRRaycaster;
                if (ovrRaycaster) // raycast may not actually contain a result
                {
                    // The Unity UI system expects event data to have a screen position
                    // so even though this raycast came from a world space ray we must get a screen
                    // space position for the camera attached to this raycaster for compatability
                    Vector2 position = ovrRaycaster.GetScreenPosition(raycast);
                    
                    leftData.delta = position - leftData.position;
                    leftData.position = position;
                }
            }

            // copy the apropriate data into right and middle slots
            PointerEventData rightData;
            GetPointerData(kMouseRightId, out rightData, true );
            CopyFromTo(leftData, rightData);
            rightData.button = PointerEventData.InputButton.Right;

            PointerEventData middleData;
            GetPointerData(kMouseMiddleId, out middleData, true );
            CopyFromTo(leftData, middleData);
            middleData.button = PointerEventData.InputButton.Middle;

            m_MouseState.SetButtonState(PointerEventData.InputButton.Left, StateForMouseButton(0), leftData);
            m_MouseState.SetButtonState(PointerEventData.InputButton.Right, StateForMouseButton(1), rightData);
            m_MouseState.SetButtonState(PointerEventData.InputButton.Middle, StateForMouseButton(2), middleData);
            return m_MouseState;
        }

        /// <summary>
        /// New version of ShouldStartDrag implemented first in PointerInputModule. This version differs in that
        /// for ray based pointers it makes a decision about whether a drag should start based on the angular change
        /// the pointer has made so far, as seen from the camera. This also works when the world space ray is 
        /// translated rather than rotated, since the beginning and end of the movement are considered as angle from
        /// the same point.
        /// </summary>
        private bool ShouldStartDrag(PointerEventData pointerEvent)
        {
            if (!pointerEvent.useDragThreshold)
                return true;

            if (pointerEvent as OVRRayPointerEventData == null)
            {
                 // Same as original behaviour for canvas based pointers
                return (pointerEvent.pressPosition - pointerEvent.position).sqrMagnitude >= eventSystem.pixelDragThreshold * eventSystem.pixelDragThreshold;
            }
            else
            {
                // When it's not a screen space pointer we have to look at the angle it moved rather than the pixels distance
                // For gaze based pointing screen-space distance moved will always be near 0
                Vector3 cameraPos = pointerEvent.pressEventCamera.transform.position;
                Vector3 pressDir = (pointerEvent.pointerPressRaycast.worldPosition - cameraPos).normalized;
                Vector3 currentDir = (pointerEvent.pointerCurrentRaycast.worldPosition - cameraPos).normalized;
                return Vector3.Dot(pressDir, currentDir) < Mathf.Cos(Mathf.Deg2Rad * (angleDragThreshold));
            }
        }

        /// <summary>
        /// The purpose of this function is to allow us to switch between using the standard IsPointerMoving
        /// method for mouse driven pointers, but to always return true when it's a ray based pointer. 
        /// All real-world ray-based input devices are always moving so for simplicity we just return true
        /// for them. 
        /// 
        /// If PointerEventData.IsPointerMoving was virtual we could just override that in
        /// OVRRayPointerEventData.
        /// </summary>
        /// <param name="pointerEvent"></param>
        /// <returns></returns>
        static bool IsPointerMoving(PointerEventData pointerEvent)
        {
            OVRRayPointerEventData rayPointerEventData = pointerEvent as OVRRayPointerEventData;
            if (rayPointerEventData != null)
                return true;
            else
                return pointerEvent.IsPointerMoving();
        }

        /// <summary>
        /// Exactly the same as the code from PointerInputModule, except that we call our own
        /// IsPointerMoving.
        /// 
        /// This would also not be necessary if PointerEventData.IsPointerMoving was virtual
        /// </summary>
        /// <param name="pointerEvent"></param>
        protected override void ProcessDrag(PointerEventData pointerEvent)
        {
            bool moving = IsPointerMoving(pointerEvent);
            if (moving && pointerEvent.pointerDrag != null
                && !pointerEvent.dragging
                && ShouldStartDrag(pointerEvent))
            {
                ExecuteEvents.Execute(pointerEvent.pointerDrag, pointerEvent, ExecuteEvents.beginDragHandler);
                pointerEvent.dragging = true;
            }

            // Drag notification
            if (pointerEvent.dragging && moving && pointerEvent.pointerDrag != null)
            {
                // Before doing drag we should cancel any pointer down state
                // And clear selection!
                if (pointerEvent.pointerPress != pointerEvent.pointerDrag)
                {
                    ExecuteEvents.Execute(pointerEvent.pointerPress, pointerEvent, ExecuteEvents.pointerUpHandler);

                    pointerEvent.eligibleForClick = false;
                    pointerEvent.pointerPress = null;
                    pointerEvent.rawPointerPress = null;
                }
                ExecuteEvents.Execute(pointerEvent.pointerDrag, pointerEvent, ExecuteEvents.dragHandler);
            }
        }
       
        /// <summary>
        /// Get state of button corresponding to gaze pointer
        /// </summary>
        /// <returns></returns>
        protected PointerEventData.FramePressState GetGazeButtonState()
        {
            var pressed = Input.GetKeyDown(gazeClickKey) || OVRInput.GetDown(joyPadClickButton);
            var released = Input.GetKeyUp(gazeClickKey) || OVRInput.GetUp(joyPadClickButton);

#if UNITY_ANDROID && !UNITY_EDITOR
            pressed |= Input.GetMouseButtonDown(0);
            released |= Input.GetMouseButtonUp(0);
#endif

            if (pressed && released)
                return PointerEventData.FramePressState.PressedAndReleased;
            if (pressed)
                return PointerEventData.FramePressState.Pressed;
            if (released)
                return PointerEventData.FramePressState.Released;
            return PointerEventData.FramePressState.NotChanged;
        }
        
        /// <summary>
        /// Get extra scroll delta from gamepad
        /// </summary>
        protected Vector2 GetExtraScrollDelta()
        {
            Vector2 scrollDelta = new Vector2();
            if (useLeftStickScroll)
            {
                float x = OVRInput.Get(OVRInput.Axis2D.PrimaryThumbstick).x;
                float y = OVRInput.Get(OVRInput.Axis2D.PrimaryThumbstick).y;
                if (Mathf.Abs(x) < leftStickDeadZone) x = 0;
                if (Mathf.Abs(y) < leftStickDeadZone) y = 0;
                scrollDelta = new Vector2 (x,y);   
            }
            return scrollDelta;
        }
    };
}

sdfgfdgf2-1