コード例 #1
0
ファイル: main.cpp プロジェクト: GainLee/OculusSDK
    void MainLoop()
    {
	    Layer[0] = new VRLayer(Session);

	    // Create a trivial model to represent the left controller
	    TriangleSet cube;
	    cube.AddSolidColorBox(0.05f, -0.05f, 0.05f, -0.05f, 0.05f, -0.05f, 0xff404040);
	    Model * controller = new Model(&cube, XMFLOAT3(0, 0, 0), XMFLOAT4(0, 0, 0, 1), new Material(new Texture(false, 256, 256, Texture::AUTO_CEILING)));
	
	    // Main loop
	    while (HandleMessages())
	    {
		    // We don't allow yaw change for now, as this sample is too simple to cater for it.
		    ActionFromInput(1.0f,false);
		    ovrTrackingState hmdState = Layer[0]->GetEyePoses();

		    //Write position and orientation into controller model.
		    controller->Pos = XMFLOAT3(XMVectorGetX(MainCam->Pos) + hmdState.HandPoses[ovrHand_Left].ThePose.Position.x,
			                           XMVectorGetY(MainCam->Pos) + hmdState.HandPoses[ovrHand_Left].ThePose.Position.y,
			                           XMVectorGetZ(MainCam->Pos) + hmdState.HandPoses[ovrHand_Left].ThePose.Position.z);
		    controller->Rot = XMFLOAT4(hmdState.HandPoses[ovrHand_Left].ThePose.Orientation.x, 
                                       hmdState.HandPoses[ovrHand_Left].ThePose.Orientation.y,
			                           hmdState.HandPoses[ovrHand_Left].ThePose.Orientation.z, 
                                       hmdState.HandPoses[ovrHand_Left].ThePose.Orientation.w);

		    //Button presses are modifying the colour of the controller model below
		    ovrInputState inputState;
		    ovr_GetInputState(Session, ovrControllerType_Touch, &inputState);

		    for (int eye = 0; eye < 2; ++eye)
		    {
			    XMMATRIX viewProj = Layer[0]->RenderSceneToEyeBuffer(MainCam, RoomScene, eye);

			    // Render the controller model
			    controller->Render(&viewProj, 1, inputState.Buttons & ovrTouch_X ? 1.0f : 0.0f,
				                                 inputState.Buttons & ovrTouch_Y ? 1.0f : 0.0f, 1, true);
		    }

		    Layer[0]->PrepareLayerHeader();
		    DistortAndPresent(1);
	    }

        delete controller;
    }
コード例 #2
0
ファイル: RiftRemote.cpp プロジェクト: dborel/RiftRemote
int main()
{
	// Register a callback to clean up when the process exits.
    atexit(Shutdown);

    while (true)
    {
		// Retry initialization each frame until it succeeds. It will early-out thereafter.
		Initialize();

		// Each frame is 10ms to save CPU.
        Sleep(10);

		// Handle button input from LibOVR.

        ovrInputState inputState;
        memset(&inputState, 0, sizeof(ovrInputState));

        if (OVR_SUCCESS(ovr_GetInputState(g_session, g_controllerType, &inputState)))
			SendKeysForInputState(inputState);
    }
}
コード例 #3
0
ファイル: main.cpp プロジェクト: GainLee/OculusSDK
    void MainLoop()
    {
	    Layer[0] = new VRLayer(Session);

	    while (HandleMessages())
	    {
		    ActionFromInput();
		    Layer[0]->GetEyePoses();


			// Read the remote state 
			ovrInputState inputState;
			ovr_GetInputState(Session, ovrControllerType_Remote, &inputState);
			unsigned int result = ovr_GetConnectedControllerTypes(Session);
			bool isRemoteConnected = (result & ovrControllerType_Remote) ? true : false;

			// Some auxiliary controls we're going to read from the remote. 
			XMVECTOR forward = XMVector3Rotate(XMVectorSet(0, 0, -0.05f, 0), MainCam->Rot);
			XMVECTOR right = XMVector3Rotate(XMVectorSet(0.05f, 0, 0, 0), MainCam->Rot);
			if (inputState.Buttons & ovrButton_Up)	  MainCam->Pos = XMVectorAdd(MainCam->Pos, forward);
			if (inputState.Buttons & ovrButton_Down)  MainCam->Pos = XMVectorSubtract(MainCam->Pos, forward);
			if (inputState.Buttons & ovrButton_Left)  MainCam->Pos = XMVectorSubtract(MainCam->Pos, right);
			if (inputState.Buttons & ovrButton_Right)  MainCam->Pos = XMVectorAdd(MainCam->Pos, right);


			for (int eye = 0; eye < 2; ++eye)
		    {
				//Tint the world, green for it the controller is attached, otherwise red
				if (isRemoteConnected)
					Layer[0]->RenderSceneToEyeBuffer(MainCam, RoomScene, eye, 0, 0, 1,/**/ 1, 0.5f, 1, 0.5f /*green*/);
				else 
					Layer[0]->RenderSceneToEyeBuffer(MainCam, RoomScene, eye, 0, 0, 1,/**/ 1, 1, 0, 0 /*red*/);
			}

		    Layer[0]->PrepareLayerHeader();
		    DistortAndPresent(1);
	    }
    }
コード例 #4
0
ファイル: OculusOVR.cpp プロジェクト: bjth/xenko
	DLL_EXPORT_API void xnOvrGetInputProperties(xnOvrSession* session, xnOvrInputProperties* properties)
	{
		ovrInputState state;
		auto res = ovr_GetInputState(session->Session, ovrControllerType_Touch, &state);
		if(OVR_SUCCESS(res))
		{
			properties->Valid = true;
			properties->Buttons = state.Buttons;
			properties->Touches = state.Touches;
			properties->HandTriggerLeft = state.HandTrigger[0];
			properties->HandTriggerRight = state.HandTrigger[1];
			properties->IndexTriggerLeft = state.IndexTrigger[0];
			properties->IndexTriggerRight = state.IndexTrigger[1];
			properties->ThumbstickLeft[0] = state.Thumbstick[0].x;
			properties->ThumbstickLeft[1] = state.Thumbstick[0].y;
			properties->ThumbstickRight[0] = state.Thumbstick[1].x;
			properties->ThumbstickRight[1] = state.Thumbstick[1].y;
		}
		else
		{
			properties->Valid = false;
		}
	}
コード例 #5
0
/**
* Render the Virtual Cinema Theatre.
***/
void* OculusTracker::Provoke(void* pThis, int eD3D, int eD3DInterface, int eD3DMethod, DWORD dwNumberConnected, int& nProvokerIndex)
{
	// update game timer
	m_cGameTimer.Tick();

	static UINT unFrameSkip = 200;
	if (unFrameSkip > 0)
	{
		unFrameSkip--;
		return nullptr;
	}

	// #define _DEBUG_OTR
#ifdef _DEBUG_OTR
	{ wchar_t buf[128]; wsprintf(buf, L"[OTR] ifc %u mtd %u", eD3DInterface, eD3DMethod); OutputDebugString(buf); }
#endif

	// save ini file ?
	if (m_nIniFrameCount)
	{
		if (m_nIniFrameCount == 1)
			SaveIniSettings();
		m_nIniFrameCount--;
	}

	// main menu update ?
	if (m_sMenu.bOnChanged)
	{
		// set back event bool, set ini file frame count
		m_sMenu.bOnChanged = false;
		m_nIniFrameCount = 300;

		// loop through entries
		for (size_t nIx = 0; nIx < m_sMenu.asEntries.size(); nIx++)
		{
			// entry index changed ?
			if (m_sMenu.asEntries[nIx].bOnChanged)
			{
				m_sMenu.asEntries[nIx].bOnChanged = false;

				// touch entries ?
				if (nIx < 25)
				{
					// set new vk code by string
					m_aaunKeys[1][nIx] = GetVkCodeByString(m_sMenu.asEntries[nIx].astrValueEnumeration[m_sMenu.asEntries[nIx].unValue]);
				}
			}
		}
	}

	if (m_hSession)
	{
#pragma region controller
		// controller indices
		static const uint32_t s_unIndexRemote = 0;
		static const uint32_t s_unIndexTouch = 1;
		static const uint32_t s_unIndexXBox = 2;

		// get all connected input states
		ovrInputState sInputState[3] = {};
		unsigned int unControllersConnected = ovr_GetConnectedControllerTypes(m_hSession);
#pragma region Remote
		if (unControllersConnected & ovrControllerType_Remote)
		{
			ovr_GetInputState(m_hSession, ovrControllerType_Remote, &sInputState[s_unIndexRemote]);

			// handle all remote buttons except Oculus private ones
			if (sInputState[s_unIndexRemote].Buttons & ovrButton_Up)
				m_sMenu.bOnUp = true;
			if (sInputState[s_unIndexRemote].Buttons & ovrButton_Down)
				m_sMenu.bOnDown = true;
			if (sInputState[s_unIndexRemote].Buttons & ovrButton_Left)
				m_sMenu.bOnLeft = true;
			if (sInputState[s_unIndexRemote].Buttons & ovrButton_Right)
				m_sMenu.bOnRight = true;
			if (sInputState[s_unIndexRemote].Buttons & ovrButton_Enter)
				m_sMenu.bOnAccept = true;
			if (sInputState[s_unIndexRemote].Buttons & ovrButton_Back)
				m_sMenu.bOnBack = true;
		}
#pragma endregion
#pragma region touch
		if (unControllersConnected & ovrControllerType_Touch)
		{
			// get input state
			ovr_GetInputState(m_hSession, ovrControllerType_Touch, &sInputState[s_unIndexTouch]);

			// loop through controller buttons
			for (UINT unButtonIx = 0; unButtonIx < unButtonNo; unButtonIx++)
			{
				// cast keyboard event
				if (sInputState[s_unIndexTouch].Buttons & aunButtonIds[unButtonIx])
				{
					if (!m_aabKeys[s_unIndexTouch][unButtonIx])
						MapButtonDown(s_unIndexTouch, unButtonIx);
				}
				else
				if (m_aabKeys[s_unIndexTouch][unButtonIx])
					MapButtonUp(s_unIndexTouch, unButtonIx);
			}
		}
#pragma endregion
		if (unControllersConnected & ovrControllerType_XBox)
			ovr_GetInputState(m_hSession, ovrControllerType_XBox, &sInputState[s_unIndexXBox]);



#pragma endregion
#pragma region hmd
		/*// Start the sensor which informs of the Rift's pose and motion   .... obsolete for SDK 1.3.x ??
		ovr_ConfigureTracking(m_hSession, ovrTrackingCap_Orientation | ovrTrackingCap_MagYawCorrection |
		ovrTrackingCap_Position, 0);*/

		// get the current tracking state
		ovrTrackingState sTrackingState = ovr_GetTrackingState(m_hSession, ovr_GetTimeInSeconds(), false);

		if (TRUE)//(sTrackingState.StatusFlags & (ovrStatus_OrientationTracked | ovrStatus_PositionTracked))
		{
			// get pose
			ovrPoseStatef sPoseState = sTrackingState.HeadPose;
			m_sPose = sPoseState.ThePose;
			m_sOrientation.x = m_sPose.Orientation.x;
			m_sOrientation.y = m_sPose.Orientation.y;
			m_sOrientation.z = m_sPose.Orientation.z;
			m_sOrientation.w = m_sPose.Orientation.w;

			// backup old euler angles and velocity
			float fEulerOld[3];
			float fEulerVelocityOld[3];
			memcpy(&fEulerOld[0], &m_fEuler[0], sizeof(float)* 3);
			memcpy(&fEulerVelocityOld[0], &m_fEulerVelocity[0], sizeof(float)* 3);

			// predicted euler angles ? for Oculus, due to ATW, we do not predict the euler angles
			if (FALSE)
			{
				// get angles
				m_sOrientation.GetEulerAngles<Axis::Axis_Y, Axis::Axis_X, Axis::Axis_Z, RotateDirection::Rotate_CW, HandedSystem::Handed_R >(&m_fEuler[1], &m_fEuler[0], &m_fEuler[2]);

				// quick fix here...
				m_fEuler[1] *= -1.0f;
				m_fEuler[0] *= -1.0f;
				m_fEuler[2] *= -1.0f;

				// get euler velocity + acceleration
				float fEulerAcceleration[3];
				for (UINT unI = 0; unI < 3; unI++)
				{
					// get the velocity
					m_fEulerVelocity[unI] = (m_fEuler[unI] - fEulerOld[unI]) / (float)m_cGameTimer.DeltaTime();

					// get the acceleration
					fEulerAcceleration[unI] = (m_fEulerVelocity[unI] - fEulerVelocityOld[unI]) / (float)m_cGameTimer.DeltaTime();
				}

				// get predicted euler
				for (UINT unI = 0; unI < 3; unI++)
				{
					// compute predicted euler
					m_fEulerPredicted[unI] = (0.5f * fEulerAcceleration[unI] * ((float)m_cGameTimer.DeltaTime() * (float)m_cGameTimer.DeltaTime())) + (m_fEulerVelocity[unI] * (float)m_cGameTimer.DeltaTime()) + m_fEuler[unI];
				}
			}
			else
			{
				// get angles
				m_sOrientation.GetEulerAngles<Axis::Axis_Y, Axis::Axis_X, Axis::Axis_Z, RotateDirection::Rotate_CW, HandedSystem::Handed_R >(&m_fEulerPredicted[1], &m_fEulerPredicted[0], &m_fEulerPredicted[2]);

				// quick fix here...
				m_fEulerPredicted[1] *= -1.0f;
				m_fEulerPredicted[0] *= -1.0f;
				m_fEulerPredicted[2] *= -1.0f;
			}

			// set the drawing update to true
			m_bControlUpdate = true;

			// set position
			m_afPosition[0] = (float)-m_sPose.Position.x - m_afPositionOrigin[0];
			m_afPosition[1] = (float)-m_sPose.Position.y - m_afPositionOrigin[1];
			m_afPosition[2] = (float)m_sPose.Position.z + m_afPositionOrigin[2];

			// get eye render pose and other fields
			ovrEyeRenderDesc asEyeRenderDesc[2];
			asEyeRenderDesc[0] = ovr_GetRenderDesc(m_hSession, ovrEye_Left, m_sHMDDesc.DefaultEyeFov[0]);
			asEyeRenderDesc[1] = ovr_GetRenderDesc(m_hSession, ovrEye_Right, m_sHMDDesc.DefaultEyeFov[1]);
			ovrPosef asHmdToEyePose[2] = { asEyeRenderDesc[0].HmdToEyePose,asEyeRenderDesc[1].HmdToEyePose };
			//ovrVector3f      asHmdToEyeViewOffset[2] = { asEyeRenderDesc[0].HmdToEyePose, asEyeRenderDesc[1].HmdToEyePose };
			ovrPosef         asEyeRenderPose[2];
			static long long s_frameIndex = 0;
			static double s_sensorSampleTime = 0.0;    // sensorSampleTime is fed into the layer later
			ovr_GetEyePoses(m_hSession, s_frameIndex, ovrTrue, asHmdToEyePose, asEyeRenderPose, &s_sensorSampleTime);
			// ovr_CalcEyePoses(sTrackingState.HeadPose.ThePose, asHmdToEyePose, asEyeRenderPose);

			// create rotation matrix from euler angles
			D3DXMATRIX sRotation;
			D3DXMATRIX sPitch, sYaw, sRoll;
			D3DXMatrixRotationX(&sPitch, m_fEulerPredicted[0]);
			D3DXMatrixRotationY(&sYaw, m_fEulerPredicted[1]);
			D3DXMatrixRotationZ(&sRoll, -m_fEulerPredicted[2]);
			sRotation = sYaw * sPitch * sRoll;

			// create per eye view matrix from rotation and position
			D3DXMATRIX sView[2];
			for (UINT unEye = 0; unEye < 2; unEye++)
			{
				D3DXMATRIX sTranslation;
				D3DXMatrixTranslation(&sTranslation, (float)-asEyeRenderPose[unEye].Position.x - m_afPositionOrigin[0], (float)-asEyeRenderPose[unEye].Position.y - m_afPositionOrigin[1], (float)asEyeRenderPose[unEye].Position.z + m_afPositionOrigin[2]);
				sView[unEye] = sTranslation * sRotation;
			}

			// create head pose view matrix
			D3DXMATRIX sTranslation;
			D3DXMatrixTranslation(&sTranslation, (float)-sTrackingState.HeadPose.ThePose.Position.x - m_afPositionOrigin[0], (float)-sTrackingState.HeadPose.ThePose.Position.y - m_afPositionOrigin[1], (float)sTrackingState.HeadPose.ThePose.Position.z + m_afPositionOrigin[2]);
			m_sView = sTranslation * sRotation;

			// create inverse view matrix
			D3DXMATRIX sVInv = {};
			D3DXMatrixInverse(&sVInv, nullptr, &m_sView);

			// get projection matrices left/right
			D3DXMATRIX asToEye[2];
			D3DXMATRIX asProjection[2];
			for (UINT unEye = 0; unEye < 2; unEye++)
			{
				// get ovr projection
				ovrMatrix4f sProj = ovrMatrix4f_Projection(m_sHMDDesc.DefaultEyeFov[unEye], 0.01f, 30.0f, ovrProjection_LeftHanded);

				// create dx projection
				asProjection[unEye] = D3DXMATRIX(&sProj.M[0][0]);
				D3DXMatrixTranspose(&asProjection[unEye], &asProjection[unEye]);

				// create eventual projection using inverse matrix of the head pose view matrix
				m_asProjection[unEye] = sVInv * sView[unEye] * asProjection[unEye];
			}
		}
#pragma endregion
	}
	else
	{
		// Initialize LibOVR, and the Rift... then create hmd handle
		ovrResult result = ovr_Initialize(nullptr);
		if (!OVR_SUCCESS(result))
		{
			OutputDebugString(L"[OVR] Failed to initialize libOVR.");
			return nullptr;
		}

		result = ovr_Create(&m_hSession, &m_sLuid);
		if (!OVR_SUCCESS(result))
		{
			OutputDebugString(L"[OVR] Failed to retreive HMD handle.");
			return nullptr;
		}
		else
			OutputDebugString(L"[OVR] HMD handle initialized !");

		if (m_hSession)
		{
			// get the description and set pointers
			m_sHMDDesc = ovr_GetHmdDesc(m_hSession);

			// Configure Stereo settings.
			ovrSizei sRecommenedTex0Size = ovr_GetFovTextureSize(m_hSession, ovrEye_Left,
				m_sHMDDesc.DefaultEyeFov[0], 1.0f);
			ovrSizei sRecommenedTex1Size = ovr_GetFovTextureSize(m_hSession, ovrEye_Right,
				m_sHMDDesc.DefaultEyeFov[1], 1.0f);

			ovrSizei sTextureSize;
			sTextureSize.w = max(sRecommenedTex0Size.w, sRecommenedTex1Size.w);
			sTextureSize.h = max(sRecommenedTex0Size.h, sRecommenedTex1Size.h);
			m_unRenderTextureWidth = (UINT)sTextureSize.w;
			m_unRenderTextureHeight = (UINT)sTextureSize.h;

			// get view offset
			ovrEyeRenderDesc asEyeRenderDesc[2];
			asEyeRenderDesc[0] = ovr_GetRenderDesc(m_hSession, ovrEye_Left, m_sHMDDesc.DefaultEyeFov[0]);
			asEyeRenderDesc[1] = ovr_GetRenderDesc(m_hSession, ovrEye_Right, m_sHMDDesc.DefaultEyeFov[1]);
			ovrVector3f asViewOffset[2] = { asEyeRenderDesc[0].HmdToEyePose.Position, asEyeRenderDesc[1].HmdToEyePose.Position };

			// get projection matrices left/right
			D3DXMATRIX asToEye[2];
			D3DXMATRIX asProjection[2];
			for (UINT unEye = 0; unEye < 2; unEye++)
			{
				// get ovr projection
				ovrMatrix4f sProj = ovrMatrix4f_Projection(m_sHMDDesc.DefaultEyeFov[unEye], 0.01f, 30.0f, ovrProjection_LeftHanded);

				// create dx projection
				asProjection[unEye] = D3DXMATRIX(&sProj.M[0][0]);
				D3DXMatrixTranspose(&asProjection[unEye], &asProjection[unEye]);

				// create view offset translation matrix
				D3DXMatrixTranslation(&asToEye[unEye], -asViewOffset[unEye].x, -asViewOffset[unEye].y, -asViewOffset[unEye].z);

				// create eventual projection
				m_asProjection[unEye] = asToEye[unEye] * asProjection[unEye];
			}
		}
	}

	return nullptr;
}
コード例 #6
0
// OVR Remote controller input
void HandleRemote()
{
    ovrInputState currentRemoteInputState;
    ovr_GetInputState(g_session, ovrControllerType_Remote, &currentRemoteInputState);
    const unsigned int b = currentRemoteInputState.Buttons;
    const unsigned int b0 = lastRemoteInputState.Buttons;
    const int toggleShaderButton = ovrButton_Enter;
    const int toggleMenuButton = ovrButton_Back;
    if (b & toggleShaderButton)
    {
        if (!(b0 & toggleShaderButton))
        {
            if (g_tweakbarQuad.m_showQuadInWorld == true)
            {
                g_tweakbarQuad.MouseClick(1);
            }
            else
            {
                g_gallery.ToggleShaderWorld();
            }
        }
    }
    else if (!(b & toggleShaderButton))
    {
        if (b0 & toggleShaderButton)
        {
            // Released button
            if (g_tweakbarQuad.m_showQuadInWorld == true)
            {
                g_tweakbarQuad.MouseClick(0);
            }
            else
            {
            }
        }
    }

    if (b & toggleMenuButton)
    {
        if (!(b0 & toggleMenuButton))
        {
            g_tweakbarQuad.m_showQuadInWorld = !g_tweakbarQuad.m_showQuadInWorld;
        }
    }
    else if (!(b & toggleMenuButton))
    {
        if (b0 & toggleMenuButton)
        {
            // Released button
        }
    }

    glm::vec3 remoteMove(0.0f, 0.0f, 0.0f);
    if (b & ovrButton_Up) { remoteMove += glm::vec3(0.f, 0.f, -1.f); }
    if (b & ovrButton_Down) { remoteMove += glm::vec3(0.f, 0.f, 1.f); }
    if (b & ovrButton_Left) { remoteMove += glm::vec3(-1.f, 0.f, 0.f); }
    if (b & ovrButton_Right) { remoteMove += glm::vec3(1.f, 0.f, 0.f); }
    m_remoteMove = remoteMove;

    lastRemoteInputState = currentRemoteInputState;
}
コード例 #7
0
void HandleXboxController()
{
    ovrInputState currentXboxControllerInputState;
    ovr_GetInputState(g_session, ovrControllerType_XBox, &currentXboxControllerInputState);
    const unsigned int b = currentXboxControllerInputState.Buttons;
    const unsigned int b0 = lastXboxControllerInputState.Buttons;
    const int32_t Abut = ovrButton_A;
    const int32_t toggleShaderButton = ovrButton_Enter;
    const int32_t toggleTweakbarButton = ovrButton_Y;
    const int32_t togglePerfHudButton = ovrButton_Back;
    const int32_t holdTweakbarButton = ovrButton_RThumb;

    if (b & toggleShaderButton)
    {
        if (!(b0 & toggleShaderButton))
        {
            g_gallery.ToggleShaderWorld();
        }
    }

    if (b & toggleTweakbarButton)
    {
        if (!(b0 & toggleTweakbarButton))
        {
            g_tweakbarQuad.m_showQuadInWorld = !g_tweakbarQuad.m_showQuadInWorld;
        }
    }

    if (b & Abut)
    {
        if (!(b0 & Abut))
        {
            g_tweakbarQuad.MouseClick(1);
        }
    }
    else if (!(b & Abut))
    {
        if (b0 & Abut)
        {
            g_tweakbarQuad.MouseClick(0);
        }
    }

    if ((b & toggleTweakbarButton) && !(b0 & toggleTweakbarButton))
    {
        g_tweakbarQuad.m_showQuadInWorld = !g_tweakbarQuad.m_showQuadInWorld;
    }
    if ((b & togglePerfHudButton) && !(b0 & togglePerfHudButton))
    {
        TogglePerfHud();
    }

    if (b & holdTweakbarButton)
    {
        if (!(b0 & holdTweakbarButton))
        {
            g_tweakbarQuad.SetHoldingFlag(m_eyePoses[0], true);
        }
    }
    else if (!(b & holdTweakbarButton))
    {
        if (b0 & holdTweakbarButton)
        {
            g_tweakbarQuad.SetHoldingFlag(m_eyePoses[0], false);
        }
    }

    lastXboxControllerInputState = currentXboxControllerInputState;
}
コード例 #8
0
ファイル: OculusInput.cpp プロジェクト: ErwinT6/T6Engine
void FOculusInput::SendControllerEvents()
{
	const double CurrentTime = FPlatformTime::Seconds();

	// @todo: Should be made configurable and unified with other controllers handling of repeat
	const float InitialButtonRepeatDelay = 0.2f;
	const float ButtonRepeatDelay = 0.1f;
	const float AnalogButtonPressThreshold = TriggerThreshold;

	IOculusRiftPlugin& OculusRiftPlugin = IOculusRiftPlugin::Get();
	ovrSession OvrSession = OculusRiftPlugin.GetSession();
	UE_CLOG(OVR_DEBUG_LOGGING, LogOcInput, Log, TEXT("SendControllerEvents: OvrSession = %p"), OvrSession);
	if (OvrSession)
	{
		ovrInputState OvrInput;
		ovrTrackingState OvrTrackingState;

		const ovrResult OvrRes = ovr_GetInputState(OvrSession, ovrControllerType_Touch, &OvrInput);
		const bool bOvrGCTRes = OculusRiftPlugin.GetCurrentTrackingState(&OvrTrackingState);

		UE_CLOG(OVR_DEBUG_LOGGING, LogOcInput, Log, TEXT("SendControllerEvents: ovr_GetInputState() ret = %d, GetCurrentTrackingState ret = %d"), int(OvrRes), int(bOvrGCTRes));

		if (OvrRes == ovrSuccess && bOvrGCTRes)
		{
			UE_CLOG(OVR_DEBUG_LOGGING, LogOcInput, Log, TEXT("SendControllerEvents: ConnectedControllerTypes 0x%X"), OvrInput.ConnectedControllerTypes);
			UE_CLOG(OVR_DEBUG_LOGGING, LogOcInput, Log, TEXT("SendControllerEvents: ButtonState = 0x%X"), OvrInput.Buttons);
			UE_CLOG(OVR_DEBUG_LOGGING, LogOcInput, Log, TEXT("SendControllerEvents: Touches = 0x%X"), OvrInput.Touches);

			for (FOculusTouchControllerPair& ControllerPair : ControllerPairs)
			{
				for( int32 HandIndex = 0; HandIndex < ARRAY_COUNT( ControllerPair.ControllerStates ); ++HandIndex )
				{
					FOculusTouchControllerState& State = ControllerPair.ControllerStates[ HandIndex ];

					const bool bIsLeft = (HandIndex == (int32)EControllerHand::Left);
					bool bIsCurrentlyTracked = (bIsLeft ? (OvrInput.ConnectedControllerTypes & ovrControllerType_LTouch) != 0 : (OvrInput.ConnectedControllerTypes & ovrControllerType_RTouch) != 0);

#if OVR_TESTING
					bIsCurrentlyTracked = true;
					static float _angle = 0;
					OvrTrackingState.HandPoses[HandIndex].ThePose.Orientation = OVR::Quatf(OVR::Vector3f(0, 0, 1), _angle);
					_angle += 0.1f;

					OvrTrackingState.HandPoses[HandIndex].ThePose = OvrTrackingState.HeadPose.ThePose;
					UE_CLOG(OVR_DEBUG_LOGGING, LogOcInput, Error, TEXT("SendControllerEvents: OVR_TESTING is enabled!"));
#endif

					if (bIsCurrentlyTracked)
					{
						State.bIsCurrentlyTracked = true;

						const float OvrTriggerAxis = OvrInput.IndexTrigger[HandIndex];
						const float OvrGripAxis = OvrInput.HandTrigger[HandIndex];

						UE_CLOG(OVR_DEBUG_LOGGING, LogOcInput, Log, TEXT("SendControllerEvents: IndexTrigger[%d] = %f"), int(HandIndex), OvrTriggerAxis);
						UE_CLOG(OVR_DEBUG_LOGGING, LogOcInput, Log, TEXT("SendControllerEvents: HandTrigger[%d] = %f"), int(HandIndex), OvrGripAxis);
						UE_CLOG(OVR_DEBUG_LOGGING, LogOcInput, Log, TEXT("SendControllerEvents: ThumbStick[%d] = { %f, %f }"), int(HandIndex), OvrInput.Thumbstick[HandIndex].x, OvrInput.Thumbstick[HandIndex].y );

						if (OvrTriggerAxis != State.TriggerAxis)
						{
							State.TriggerAxis = OvrTriggerAxis;
							MessageHandler->OnControllerAnalog(bIsLeft ? FGamepadKeyNames::MotionController_Left_TriggerAxis : FGamepadKeyNames::MotionController_Right_TriggerAxis, ControllerPair.UnrealControllerIndex, State.TriggerAxis);
						}

						if (OvrGripAxis != State.GripAxis)
						{
							State.GripAxis = OvrGripAxis;
							MessageHandler->OnControllerAnalog(bIsLeft ? FGamepadKeyNames::MotionController_Left_Grip1Axis : FGamepadKeyNames::MotionController_Right_Grip1Axis, ControllerPair.UnrealControllerIndex, State.GripAxis);
						}

						if (OvrInput.Thumbstick[HandIndex].x != State.ThumbstickAxes.X)
						{
							State.ThumbstickAxes.X = OvrInput.Thumbstick[HandIndex].x;
							MessageHandler->OnControllerAnalog(bIsLeft ? FGamepadKeyNames::MotionController_Left_Thumbstick_X : FGamepadKeyNames::MotionController_Right_Thumbstick_X, ControllerPair.UnrealControllerIndex, State.ThumbstickAxes.X);
						}

						if (OvrInput.Thumbstick[HandIndex].y != State.ThumbstickAxes.Y)
						{
							State.ThumbstickAxes.Y = OvrInput.Thumbstick[HandIndex].y;
							// we need to negate Y value to match XBox controllers
							MessageHandler->OnControllerAnalog(bIsLeft ? FGamepadKeyNames::MotionController_Left_Thumbstick_Y : FGamepadKeyNames::MotionController_Right_Thumbstick_Y, ControllerPair.UnrealControllerIndex, -State.ThumbstickAxes.Y);
						}

						for (int32 ButtonIndex = 0; ButtonIndex < (int32)EOculusTouchControllerButton::TotalButtonCount; ++ButtonIndex)
						{
							FOculusButtonState& ButtonState = State.Buttons[ButtonIndex];
							check(!ButtonState.Key.IsNone()); // is button's name initialized?

							// Determine if the button is pressed down
							bool bButtonPressed = false;
							switch ((EOculusTouchControllerButton)ButtonIndex)
							{
							case EOculusTouchControllerButton::Trigger:
								bButtonPressed = State.TriggerAxis >= AnalogButtonPressThreshold;
								break;

							case EOculusTouchControllerButton::Grip:
								bButtonPressed = State.GripAxis >= AnalogButtonPressThreshold;
								break;

							case EOculusTouchControllerButton::XA:
								bButtonPressed = bIsLeft ? (OvrInput.Buttons & ovrButton_X) != 0 : (OvrInput.Buttons & ovrButton_A) != 0;
								break;

							case EOculusTouchControllerButton::YB:
								bButtonPressed = bIsLeft ? (OvrInput.Buttons & ovrButton_Y) != 0 : (OvrInput.Buttons & ovrButton_B) != 0;
								break;

							case EOculusTouchControllerButton::Thumbstick:
								bButtonPressed = bIsLeft ? (OvrInput.Buttons & ovrButton_LThumb) != 0 : (OvrInput.Buttons & ovrButton_RThumb) != 0;
								break;

							default:
								check(0);
								break;
							}

							// Update button state
							if (bButtonPressed != ButtonState.bIsPressed)
							{
								const bool bIsRepeat = false;

								ButtonState.bIsPressed = bButtonPressed;
								if (ButtonState.bIsPressed)
								{
									MessageHandler->OnControllerButtonPressed(ButtonState.Key, ControllerPair.UnrealControllerIndex, bIsRepeat);

									// Set the timer for the first repeat
									ButtonState.NextRepeatTime = CurrentTime + ButtonRepeatDelay;
								}
								else
								{
									MessageHandler->OnControllerButtonReleased(ButtonState.Key, ControllerPair.UnrealControllerIndex, bIsRepeat);
								}
							}

							// Apply key repeat, if its time for that
							if (ButtonState.bIsPressed && ButtonState.NextRepeatTime <= CurrentTime)
							{
								const bool bIsRepeat = true;
								MessageHandler->OnControllerButtonPressed(ButtonState.Key, ControllerPair.UnrealControllerIndex, bIsRepeat);

								// Set the timer for the next repeat
								ButtonState.NextRepeatTime = CurrentTime + ButtonRepeatDelay;
							}
						}

						// Handle Capacitive States
						for (int32 CapTouchIndex = 0; CapTouchIndex < (int32)EOculusTouchCapacitiveAxes::TotalAxisCount; ++CapTouchIndex)
						{
							FOculusTouchCapacitiveState& CapState = State.CapacitiveAxes[CapTouchIndex];

							float CurrentAxisVal = 0.f;
							switch ((EOculusTouchCapacitiveAxes)CapTouchIndex)
							{
							case EOculusTouchCapacitiveAxes::XA:
							{
								const uint32 mask = (bIsLeft) ? ovrTouch_X : ovrTouch_A;
								CurrentAxisVal = (OvrInput.Touches & mask) != 0 ? 1.f : 0.f;
								break;
							}
							case EOculusTouchCapacitiveAxes::YB:
							{
								const uint32 mask = (bIsLeft) ? ovrTouch_Y : ovrTouch_B;
								CurrentAxisVal = (OvrInput.Touches & mask) != 0 ? 1.f : 0.f;
								break;
							}
							case EOculusTouchCapacitiveAxes::Thumbstick:
							{
								const uint32 mask = (bIsLeft) ? ovrTouch_LThumb : ovrTouch_RThumb;
								CurrentAxisVal = (OvrInput.Touches & mask) != 0 ? 1.f : 0.f;
								break;
							}
							case EOculusTouchCapacitiveAxes::Trigger:
							{
								const uint32 mask = (bIsLeft) ? ovrTouch_LIndexTrigger : ovrTouch_RIndexTrigger;
								CurrentAxisVal = (OvrInput.Touches & mask) != 0 ? 1.f : 0.f;
								break;
							}
							case EOculusTouchCapacitiveAxes::IndexPointing:
							{
								const uint32 mask = (bIsLeft) ? ovrTouch_LIndexPointing : ovrTouch_RIndexPointing;
								CurrentAxisVal = (OvrInput.Touches & mask) != 0 ? 1.f : 0.f;
								break;
							}
							case EOculusTouchCapacitiveAxes::ThumbUp:
							{
								const uint32 mask = (bIsLeft) ? ovrTouch_LThumbUp : ovrTouch_RThumbUp;
								CurrentAxisVal = (OvrInput.Touches & mask) != 0 ? 1.f : 0.f;
								break;
							}
							default:
								check(0);
							}
							
							if (CurrentAxisVal != CapState.State)
							{
								MessageHandler->OnControllerAnalog(CapState.Axis, ControllerPair.UnrealControllerIndex, CurrentAxisVal);

								CapState.State = CurrentAxisVal;
							}
						}

						const ovrPosef& OvrHandPose = OvrTrackingState.HandPoses[HandIndex].ThePose;
						FVector NewLocation;
						FQuat NewOrientation;
						if (OculusRiftPlugin.PoseToOrientationAndPosition(OvrHandPose, /* Out */ NewOrientation, /* Out */ NewLocation))
						{
							// OK, we have up to date positional data!
							State.Orientation = NewOrientation;
							State.Location = NewLocation;

							UE_CLOG(OVR_DEBUG_LOGGING, LogOcInput, Log, TEXT("SendControllerEvents: HandPOSE[%d]: Pos %.3f %.3f %.3f"), HandIndex, NewLocation.X, NewLocation.Y, NewLocation.Y);
							UE_CLOG(OVR_DEBUG_LOGGING, LogOcInput, Log, TEXT("SendControllerEvents: HandPOSE[%d]: Yaw %.3f Pitch %.3f Roll %.3f"), HandIndex, NewOrientation.Rotator().Yaw, NewOrientation.Rotator().Pitch, NewOrientation.Rotator().Roll);
						}
						else
						{
							// HMD wasn't ready.  This can currently happen if we try to grab motion data before we've rendered at least one frame
							UE_CLOG(OVR_DEBUG_LOGGING, LogOcInput, Log, TEXT("SendControllerEvents: PoseToOrientationAndPosition returned false"));
						}
					}
					else
					{
						// Controller isn't available right now.  Zero out input state, so that if it comes back it will send fresh event deltas
						State = FOculusTouchControllerState((EControllerHand)HandIndex);
						UE_CLOG(OVR_DEBUG_LOGGING, LogOcInput, Log, TEXT("SendControllerEvents: Controller for the hand %d is not tracked"), int(HandIndex));
					}
				}
			}
		}
	}
	UE_CLOG(OVR_DEBUG_LOGGING, LogOcInput, Log, TEXT(""));
}