Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Retrieving joystick values from controllers via VrInput or GetControllerState results in invalid handlers #1833

Open
alex-freeaim opened this issue May 17, 2024 · 0 comments

Comments

@alex-freeaim
Copy link

Summary

In my overlay app, I tried retrieving the joystick values of the controllers via GetControllerState (deprecated) and separately GetAnalogActionData. However, both result in errors saying the handlers are invalid.

  • OpenVR version: 2.5.1
  • HMD: Meta Quest 3
  • Wireless method: I tried Steam Link, Meta Air Link, and Virtual Desktop

Detailed Explanation

I have both an overlay app and driver that are used to send joystick values from a treadmill like peripheral to games. I'm now working on being able to retrieve joystick values from the controllers and sending that to the peripheral device.

I have tried both the deprecated method of using GetControllerState and using action handles in VRInput, but I'm not able to get either method working. I'll go through simplified snippets of my code and explain what I'm doing, and at the end of this post I'll also show all the code in one block.

For the VRInput method I'm first calling GetInputSourceHandle.

auto controllerError = vr::VRInput()->GetInputSourceHandle("/user/hand/right",&controllerHandle);
if (controllerError != vr::VRInputError_None)
{
	//log error
}

I then call GetActionSetHandle.

auto controllerActionSetError = vr::VRInput()->GetActionSetHandle("/actions/dualanalog", &actionSetHandle);
if (controllerActionSetError != vr::VRInputError_None)
{
	//log error
}

I got the action set and actions string by looking at the action manifest file here: C:\Program Files (x86)\Steam\steamapps\common\SteamVR\resources\config\vrcompositor_actions.json

I also tried using the action manifest file for a game, Arizona Sunshine 2, but that did not work either. The file was located at:
C:\Program Files (x86)\Steam\steamapps\common\Arizona Sunshine 2\ArizonaSunshine2_Data\StreamingAssets\SteamVR\actions.json

I then call GetActionHandle.

auto controllerActionError = vr::VRInput()->GetActionHandle("/actions/dualanalog/in/RightValue", &actionHandle);
if (controllerActionError != vr::VRInputError_None)
{
	//log error
}

When I want to retrieve the joystick values I first call UpdateActionState.

vr::VRActiveActionSet_t actionSet[1];
actionSet[0].ulRestrictedToDevice = RightControllerHandler;
actionSet[0].ulActionSet = RightControllerActionSetHandler;
actionSet[0].nPriority = vr::k_nActionSetOverlayGlobalPriorityMin;
auto updateStateForRightControllerError = vr::VRInput()->UpdateActionState(actionSet, sizeof(vr::VRActiveActionSet_t), 1);
if (updateStateForRightControllerError != vr::VRInputError_None)
{
	//log error
}

All of the calls above do not return any errors. Once I try to call GetAnalogActionData, that's when the error shows up.

auto getRightJoystickDataError = vr::VRInput()->GetAnalogActionData(
	RightControllerJoystickActionHandler,
	&RightControllerJoystickData,
	sizeof(RightControllerJoystickData),
	vr::k_ulInvalidInputValueHandle //I also tried controllerHandle
);
if (getRightJoystickDataError != vr::VRInputError_None)
{
	//log error
}

The call to GetAnalogActionData above returns 3, which is VRInputError_InvalidHandle.

Below is an alternative method I used to try to get the joystick values, via GetControllerState. But it always returns false.

RightControllerDeviceIndex = vr::VRSystem()->GetTrackedDeviceIndexForControllerRole(vr::ETrackedControllerRole::TrackedControllerRole_RightHand);
if (!vr::VRSystem()->GetControllerState(RightControllerDeviceIndex, RightControllerState, sizeof(RightControllerState)))
{
	//log issue
}

Finally, I tried this method to get the handler to pass to GetControllerState, but it still returns false.

vr::TrackedDeviceIndex_t indices[10];
auto size = vr::VRSystem()->GetSortedTrackedDeviceIndicesOfClass(
	vr::ETrackedDeviceClass::TrackedDeviceClass_Controller,
	indices,
	10
);
if (size > 10)
{
	//log
	return false;
}
else
{
	if (size < 2)
	{
		//log
		return false;
	}
	RightControllerDeviceIndex = indices[0];
}

if (!vr::VRSystem()->GetControllerState(RightControllerDeviceIndex, RightControllerState, sizeof(RightControllerState)))
{
	//log issue
}

Is there an issue with these methods for retrieving the controller joystick values, or am I doing something wrong?

Full Code

Here is my code again, but in two blocks and not simplified. I've commented out my logging calls so you can copy paste this code more easily if you want.

ControllersAxesGetter.h

#pragma once

#include <openvr/headers/openvr.h>
#include <vector>
//#include "Logging.h"

struct ControllerAxes
{
	int8_t RightControllerX, RightControllerY;
	int8_t LeftControllerX, LeftControllerY;
};
class ControllerAxesGetter
{
public:
	ControllerAxesGetter()
	{
		RightControllerDeviceIndex = vr::k_unTrackedDeviceIndexInvalid;
		LeftControllerDeviceIndex = vr::k_unTrackedDeviceIndexInvalid;
	};
	bool GetControllerAxesViaVrInputSystem(ControllerAxes& axes);
	bool GetControllerAxesViaVrSystem(ControllerAxes& axes);
private:
	bool GetControllerHandlers(
		vr::VRInputValueHandle_t& controllerHandle, 
		vr::VRActionSetHandle_t& actionSetHandle,
		vr::VRActionHandle_t& actionHandle, 
		std::string controllerSide
	);
	bool UpdateActionStates();
	bool GetJoystickData();
	void Reset();
	vr::VRInputValueHandle_t RightControllerHandler, LeftControllerHandler;
	vr::VRActionSetHandle_t RightControllerActionSetHandler, LeftControllerActionSetHandler;
	vr::VRActionHandle_t RightControllerJoystickActionHandler, LeftControllerJoystickActionHandler;
	vr::InputAnalogActionData_t RightControllerJoystickData, LeftControllerJoystickData;
	vr::TrackedDeviceIndex_t RightControllerDeviceIndex, LeftControllerDeviceIndex;
	vr::VRControllerState_t RightControllerState, LeftControllerState;
};

ControllersAxesGetter.cpp

#include "ControllersAxesGetter.h"

bool ControllerAxesGetter::GetControllerAxesViaVrSystem(ControllerAxes& axes)
{
	if (RightControllerDeviceIndex == 0 || LeftControllerDeviceIndex == 0)
	{
		//method 1
		RightControllerDeviceIndex = vr::VRSystem()->GetTrackedDeviceIndexForControllerRole(vr::ETrackedControllerRole::TrackedControllerRole_RightHand);
		LeftControllerDeviceIndex = vr::VRSystem()->GetTrackedDeviceIndexForControllerRole(vr::ETrackedControllerRole::TrackedControllerRole_LeftHand);

		//method 2

		//vr::TrackedDeviceIndex_t indices[10];

		//auto size = vr::VRSystem()->GetSortedTrackedDeviceIndicesOfClass(
		//	vr::ETrackedDeviceClass::TrackedDeviceClass_Controller,
		//	indices,
		//	10
		//);
		//if (size > 10)
		//{
		//	Logging::Error(std::string("A larger array is needed to store all controller devices: ") + std::to_string(size));
		//	return false;
		//}
		//else
		//{
		//	if (size < 2)
		//	{
		//		Logging::Error(std::string("Not enough controller devices found: ") + std::to_string(size));
		//		return false;
		//	}
		//	RightControllerDeviceIndex = indices[0];
		//	LeftControllerDeviceIndex = indices[1];
		//}
	}
	if (!vr::VRSystem()->GetControllerState(RightControllerDeviceIndex, &RightControllerState, sizeof(RightControllerState)))
	{
		//Logging::Error("Error getting right controller state");
		Reset();
		return false;
	}
	if (!vr::VRSystem()->GetControllerState(LeftControllerDeviceIndex, &RightControllerState, sizeof(RightControllerState)))
	{
		//Logging::Error("Error getting left controller state");
		Reset();
		return false;
	}

	axes.RightControllerX = RightControllerState.rAxis[0].x;
	axes.RightControllerY = RightControllerState.rAxis[0].y;
	axes.LeftControllerX = LeftControllerState.rAxis[0].x;
	axes.LeftControllerY = LeftControllerState.rAxis[0].y;
	return true;
}

bool ControllerAxesGetter::GetControllerAxesViaVrInputSystem(ControllerAxes& axes)
{
	if (
		(
			RightControllerHandler == vr::k_ulInvalidInputValueHandle && 
			!GetControllerHandlers(RightControllerHandler, RightControllerActionSetHandler, RightControllerJoystickActionHandler, "Right")
		) ||
		(
			LeftControllerHandler == vr::k_ulInvalidInputValueHandle && 
			!GetControllerHandlers(LeftControllerHandler, LeftControllerActionSetHandler, LeftControllerJoystickActionHandler, "Left")
		)
	)
	{
		return false;
	}
	if (!UpdateActionStates())
	{
		return false;
	}
	if (!GetJoystickData())
	{
		return false;
	}
	axes.RightControllerX = RightControllerJoystickData.x;
	axes.RightControllerY = RightControllerJoystickData.y;
	axes.LeftControllerX = LeftControllerJoystickData.x;
	axes.LeftControllerY = LeftControllerJoystickData.y;
	return true;
}

void ControllerAxesGetter::Reset()
{
	RightControllerHandler = vr::k_ulInvalidInputValueHandle;
	LeftControllerHandler = vr::k_ulInvalidInputValueHandle;
	RightControllerActionSetHandler = vr::k_ulInvalidActionSetHandle;
	LeftControllerActionSetHandler = vr::k_ulInvalidActionSetHandle;
	RightControllerJoystickActionHandler = vr::k_ulInvalidActionHandle;
	LeftControllerJoystickActionHandler = vr::k_ulInvalidActionHandle;
	RightControllerDeviceIndex = vr::k_unTrackedDeviceIndexInvalid;
	LeftControllerDeviceIndex = vr::k_unTrackedDeviceIndexInvalid;
}

bool ControllerAxesGetter::GetJoystickData()
{
	auto getRightJoystickDataError = vr::VRInput()->GetAnalogActionData(
		RightControllerJoystickActionHandler,
		&RightControllerJoystickData,
		sizeof(RightControllerJoystickData),
		vr::k_ulInvalidInputValueHandle
	);
	if (getRightJoystickDataError != vr::VRInputError_None)
	{
		//Logging::Error(
		//	std::string("Error getting joystick data for right controller: ") +
		//	std::to_string(getRightJoystickDataError)
		//);
		if (getRightJoystickDataError == vr::VRInputError_InvalidHandle)
		{
			//Logging::Error("Joystick data couldn't be retrieved because of an invalid handler. Resetting handlers...");
			Reset();
		}
		return false;
	}
	auto getLeftJoystickDataError = vr::VRInput()->GetAnalogActionData(
		LeftControllerJoystickActionHandler,
		&LeftControllerJoystickData,
		sizeof(LeftControllerJoystickData),
		vr::k_ulInvalidInputValueHandle
	);
	if (getLeftJoystickDataError != vr::VRInputError_None)
	{
		//Logging::Error(
		//	std::string("Error getting joystick data for left controller: ") +
		//	std::to_string(getLeftJoystickDataError)
		//);
		if (getLeftJoystickDataError == vr::VRInputError_InvalidHandle)
		{
			//Logging::Error("Joystick data couldn't be retrieved because of an invalid handler. Resetting handlers...");
			Reset();
		}
		return false;
	}
	return true;
}

bool ControllerAxesGetter::UpdateActionStates()
{
	vr::VRActiveActionSet_t actionSet[1];
	actionSet[0].ulRestrictedToDevice = RightControllerHandler;
	actionSet[0].ulActionSet = RightControllerActionSetHandler;
	actionSet[0].nPriority = vr::k_nActionSetOverlayGlobalPriorityMin;
	auto updateStateForRightControllerError = vr::VRInput()->UpdateActionState(actionSet, sizeof(vr::VRActiveActionSet_t), 1);
	if (updateStateForRightControllerError != vr::VRInputError_None)
	{
		//Logging::Error(
		//	std::string("Error updating action state for right controller: ") +
		//	std::to_string(updateStateForRightControllerError)
		//);
		return false;
	}
	actionSet[0].ulRestrictedToDevice = LeftControllerJoystickActionHandler;
	actionSet[0].ulActionSet = LeftControllerActionSetHandler;
	auto updateStateForLeftControllerError = vr::VRInput()->UpdateActionState(actionSet, sizeof(vr::VRActiveActionSet_t), 1);
	if (updateStateForLeftControllerError != vr::VRInputError_None)
	{
		//Logging::Error(
		//	std::string("Error updating action state for left controller: ") +
		//	std::to_string(updateStateForLeftControllerError)
		//);
		return false;
	}
	return true;
}

bool ControllerAxesGetter::GetControllerHandlers(
	vr::VRInputValueHandle_t& controllerHandle, 
	vr::VRActionSetHandle_t& actionSetHandle,
	vr::VRActionHandle_t& actionHandle, 
	std::string controllerSide
)
{
	auto controllerError = vr::VRInput()->GetInputSourceHandle(
		(std::string("/user/hand/") + controllerSide).c_str(),
		&controllerHandle
	);
	if (controllerError != vr::VRInputError_None)
	{
		//Logging::Error(
		//	std::string("Could not get input source handler for ") +
		//	controllerSide +
		//	std::string(" controller: ") +
		//	std::to_string(controllerError)
		//);
		controllerHandle = vr::k_ulInvalidInputValueHandle;
		return false;
	}

	std::vector<std::string> actionSetHandlePaths;
	actionSetHandlePaths.push_back("/actions/dualanalog"); //just trying one for now
	bool actionSetHandleSet = false;
	for (std::string& path : actionSetHandlePaths)
	{
		auto controllerActionSetError = vr::VRInput()->GetActionSetHandle(path.c_str(), &actionSetHandle);
		if (controllerActionSetError == vr::VRInputError_None)
		{
			actionSetHandleSet = true;
			break;
		}
	}
	if (!actionSetHandleSet)
	{
		//Logging::Error("Could not find action set handle for joystick inputs");
		return false;
	}

	std::vector<std::string> actionHandlePaths;
	actionHandlePaths.push_back(std::string("/actions/dualanalog/in/") + controllerSide + std::string("Value")); //just trying one for now
	bool actionHandleSet = false;
	for (std::string& path : actionHandlePaths)
	{
		auto controllerActionError = vr::VRInput()->GetActionHandle(path.c_str(), &actionHandle);
		if (controllerActionError == vr::VRInputError_None)
		{
			actionHandleSet = true;
			break;
		}
	}
	if (!actionHandleSet)
	{ 
		//Logging::Error("Could not find action handle for joystick inputs");
		return false;
	}
	return true;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant