657 lines
25 KiB
C++
657 lines
25 KiB
C++
// Copyright HTC Corporation. All Rights Reserved.
|
|
|
|
#include "ViveOpenXRWristTracker.h"
|
|
#include "IXRTrackingSystem.h"
|
|
#include "OpenXRCore.h"
|
|
#include "UObject/UObjectIterator.h"
|
|
#include "IOpenXRExtensionPlugin.h"
|
|
#include "Modules/ModuleManager.h"
|
|
#include "DrawDebugHelpers.h"
|
|
#include "Engine/Engine.h"
|
|
#include "Misc/ConfigCacheIni.h"
|
|
|
|
#include "EnhancedInputDeveloperSettings.h"
|
|
#include "EnhancedInputLibrary.h"
|
|
#include "EnhancedInputSubsystemInterface.h"
|
|
#include "EnhancedInputModule.h"
|
|
#include "InputAction.h"
|
|
#include "InputMappingContext.h"
|
|
#include "PlayerMappableInputConfig.h"
|
|
#include "GenericPlatform/GenericPlatformInputDeviceMapper.h"
|
|
|
|
#if WITH_EDITOR
|
|
#include "Editor/EditorEngine.h"
|
|
#include "Editor.h"
|
|
#include "EnhancedInputEditorSubsystem.h"
|
|
#endif
|
|
|
|
DEFINE_LOG_CATEGORY(LogViveOpenXRWristTracker);
|
|
|
|
/************************************************************************/
|
|
/* FViveOpenXRWristTracker */
|
|
/************************************************************************/
|
|
|
|
FViveOpenXRWristTracker* FViveOpenXRWristTracker::m_Instance = nullptr;
|
|
|
|
FViveOpenXRWristTracker::FViveWristTracker::FViveWristTracker()
|
|
: RolePath(XR_NULL_PATH)
|
|
, PoseAction(XR_NULL_HANDLE)
|
|
, PoseActionPath(XR_NULL_PATH)
|
|
, PrimaryAction(XR_NULL_HANDLE)
|
|
, PrimaryActionPath(XR_NULL_PATH)
|
|
, MenuAction(XR_NULL_HANDLE)
|
|
, MenuActionPath(XR_NULL_PATH)
|
|
, DeviceId(-1)
|
|
, PrimaryActionState({ XR_TYPE_ACTION_STATE_BOOLEAN })
|
|
, MenuActionState({ XR_TYPE_ACTION_STATE_BOOLEAN })
|
|
, PrimaryKey(TEXT(""))
|
|
, MenuKey(TEXT(""))
|
|
{
|
|
SubactionPaths.RemoveAll([](const int& num) {
|
|
return true;
|
|
});
|
|
PrimaryInputActions.Empty();
|
|
MenuInputActions.Empty();
|
|
}
|
|
|
|
void FViveOpenXRWristTracker::FViveWristTracker::SetupPath(FString InRolePath, FString InPoseActionPath, FString InPrimaryActionPath, FString InMenuActionPath)
|
|
{
|
|
RolePath = FOpenXRPath(InRolePath);
|
|
PoseActionPath = FOpenXRPath(InPoseActionPath);
|
|
PrimaryActionPath = FOpenXRPath(InPrimaryActionPath);
|
|
MenuActionPath = FOpenXRPath(InMenuActionPath);
|
|
SubactionPaths.Reset();
|
|
SubactionPaths.Emplace(RolePath);
|
|
}
|
|
|
|
int32 FViveOpenXRWristTracker::FViveWristTracker::AddTrackedDevices(FOpenXRHMD* HMD)
|
|
{
|
|
if (HMD)
|
|
{
|
|
DeviceId = HMD->AddTrackedDevice(PoseAction, PoseActionPath);
|
|
//UE_LOG(LogViveOpenXRWristTracker, Log, TEXT("AddTrackedDevices ID: %d"), DeviceId);
|
|
}
|
|
return DeviceId;
|
|
}
|
|
|
|
void FViveOpenXRWristTracker::FViveWristTracker::GetSuggestedBindings(TArray<XrActionSuggestedBinding>& OutSuggestedBindings)
|
|
{
|
|
OutSuggestedBindings.Add(XrActionSuggestedBinding{ PoseAction, PoseActionPath });
|
|
OutSuggestedBindings.Add(XrActionSuggestedBinding{ PrimaryAction, PrimaryActionPath });
|
|
OutSuggestedBindings.Add(XrActionSuggestedBinding{ MenuAction, MenuActionPath });
|
|
}
|
|
|
|
void FViveOpenXRWristTracker::FViveWristTracker::AddAction(XrActionSet& InActionSet, XrAction& OutAction, FOpenXRPath InBindingPath, XrActionType InActionType)//, const TArray<XrPath>& InSubactionPaths)
|
|
{
|
|
check(InActionSet != XR_NULL_HANDLE);
|
|
if (OutAction != XR_NULL_HANDLE) {
|
|
xrDestroyAction(OutAction);
|
|
OutAction = XR_NULL_HANDLE;
|
|
}
|
|
|
|
UE_LOG(LogViveOpenXRWristTracker, Log, TEXT("xrCreateAction %s"), *InBindingPath.ToString());
|
|
|
|
char ActionName[NAME_SIZE];
|
|
GetActionName(InBindingPath).GetPlainANSIString(ActionName);
|
|
|
|
XrActionCreateInfo Info;
|
|
Info.type = XR_TYPE_ACTION_CREATE_INFO;
|
|
Info.next = nullptr;
|
|
Info.actionType = InActionType;
|
|
Info.countSubactionPaths = SubactionPaths.Num();
|
|
Info.subactionPaths = SubactionPaths.GetData();
|
|
FCStringAnsi::Strcpy(Info.actionName, XR_MAX_ACTION_NAME_SIZE, ActionName);
|
|
FCStringAnsi::Strcpy(Info.localizedActionName, XR_MAX_LOCALIZED_ACTION_NAME_SIZE, ActionName);
|
|
XR_ENSURE(xrCreateAction(InActionSet, &Info, &OutAction));
|
|
|
|
}
|
|
|
|
void FViveOpenXRWristTracker::FViveWristTracker::AddActions(XrActionSet& InActionSet)
|
|
{
|
|
AddAction(InActionSet, PoseAction, PoseActionPath, XR_ACTION_TYPE_POSE_INPUT);
|
|
AddAction(InActionSet, PrimaryAction, PrimaryActionPath, XR_ACTION_TYPE_BOOLEAN_INPUT);
|
|
AddAction(InActionSet, MenuAction, MenuActionPath, XR_ACTION_TYPE_BOOLEAN_INPUT);
|
|
}
|
|
|
|
FName FViveOpenXRWristTracker::FViveWristTracker::GetActionName(FOpenXRPath ActionPath)
|
|
{
|
|
TArray<FString> Tokens;
|
|
ActionPath.ToString().ParseIntoArray(Tokens, TEXT("/"));
|
|
Tokens[4].RemoveFromEnd("_htc");
|
|
FString ActionNameString = Tokens[2] + "_" + Tokens[4] + "_" + Tokens[5];
|
|
//UE_LOG(LogViveOpenXRWristTracker, Log, TEXT("GetActionName %s"), *ActionNameString);
|
|
return FName(ActionNameString);
|
|
}
|
|
|
|
void FViveOpenXRWristTracker::FViveWristTracker::SyncActionStates(XrSession InSession)
|
|
{
|
|
// left button x click / right button a click
|
|
XrActionStateGetInfo PrimaryActionStateInfo{ XR_TYPE_ACTION_STATE_GET_INFO };
|
|
PrimaryActionStateInfo.action = PrimaryAction;
|
|
//PrimaryActionStateInfo.subactionPath = SubactionPaths[0];
|
|
XR_ENSURE(xrGetActionStateBoolean(InSession, &PrimaryActionStateInfo, &PrimaryActionState));
|
|
|
|
// left button menu click / right button system click
|
|
XrActionStateGetInfo MenuActionStateInfo{ XR_TYPE_ACTION_STATE_GET_INFO };
|
|
MenuActionStateInfo.action = MenuAction;
|
|
//MenuActionStateInfo.subactionPath = SubactionPaths[0];
|
|
XR_ENSURE(xrGetActionStateBoolean(InSession, &MenuActionStateInfo, &MenuActionState));
|
|
}
|
|
|
|
void FViveOpenXRWristTracker::FViveWristTracker::CheckAndAddEnhancedInputAction(FEnhancedActionKeyMapping EnhancedActionKeyMapping)
|
|
{
|
|
if (EnhancedActionKeyMapping.Key == PrimaryKey)
|
|
{
|
|
//UE_LOG(LogViveOpenXRWristTracker, Log, TEXT("CheckAndAddEnhanceInputAction() Key = %s."), *EnhancedActionKeyMapping.Key.GetFName().ToString());
|
|
//UE_LOG(LogViveOpenXRWristTracker, Log, TEXT("CheckAndAddEnhanceInputAction() Action = %s."), *EnhancedActionKeyMapping.Action.GetFName().ToString());
|
|
PrimaryInputActions.Emplace(EnhancedActionKeyMapping.Action);
|
|
}
|
|
|
|
if (EnhancedActionKeyMapping.Key == MenuKey)
|
|
{
|
|
//UE_LOG(LogViveOpenXRWristTracker, Log, TEXT("CheckAndAddEnhanceInputAction() Key = %s."), *EnhancedActionKeyMapping.Key.GetFName().ToString());
|
|
//UE_LOG(LogViveOpenXRWristTracker, Log, TEXT("CheckAndAddEnhanceInputAction() Action = %s."), *EnhancedActionKeyMapping.Action.GetFName().ToString());
|
|
MenuInputActions.Emplace(EnhancedActionKeyMapping.Action);
|
|
}
|
|
}
|
|
|
|
FViveOpenXRWristTracker::FViveOpenXRWristTracker(const TSharedRef<FGenericApplicationMessageHandler>& InMessageHandler)
|
|
: MessageHandler(InMessageHandler)
|
|
{
|
|
IModularFeatures::Get().RegisterModularFeature(IMotionController::GetModularFeatureName(), static_cast<IMotionController*>(this));
|
|
RegisterOpenXRExtensionModularFeature();
|
|
|
|
m_Instance = this;
|
|
UE_LOG(LogViveOpenXRWristTracker, Log, TEXT("FViveOpenXRWristTracker() register extension feature WristTracker %p."), m_Instance);
|
|
}
|
|
|
|
FViveOpenXRWristTracker::~FViveOpenXRWristTracker()
|
|
{
|
|
IModularFeatures::Get().UnregisterModularFeature(IMotionController::GetModularFeatureName(), static_cast<IMotionController*>(this));
|
|
UnregisterOpenXRExtensionModularFeature();
|
|
bActionsAttached = false;
|
|
}
|
|
|
|
bool FViveOpenXRWristTracker::GetRequiredExtensions(TArray<const ANSICHAR*>& OutExtensions)
|
|
{
|
|
if (m_bEnableWristTracker)
|
|
{
|
|
UE_LOG(LogViveOpenXRWristTracker, Log, TEXT("GetRequiredExtensions() XR_HTC_vive_wrist_tracker_interaction."));
|
|
OutExtensions.Add("XR_HTC_vive_wrist_tracker_interaction");
|
|
}
|
|
return true;
|
|
}
|
|
|
|
//bool FViveOpenXRWristTracker::GetInteractionProfile(XrInstance InInstance, FString& OutKeyPrefix, XrPath& OutPath, bool& OutHasHaptics)
|
|
//{
|
|
// if (!m_bEnableWristTracker) return false;
|
|
// UE_LOG(LogViveOpenXRWristTracker, Log, TEXT("GetInteractionProfile() /interaction_profiles/htc/vive_wrist_tracker."));
|
|
// OutKeyPrefix = "WristTracker";
|
|
// OutHasHaptics = false;
|
|
// return xrStringToPath(InInstance, "/interaction_profiles/htc/vive_wrist_tracker", &OutPath) == XR_SUCCESS;
|
|
//}
|
|
|
|
void FViveOpenXRWristTracker::AttachActionSets(TSet<XrActionSet>& OutActionSets)
|
|
{
|
|
if (!m_bEnableWristTracker) return;
|
|
|
|
check(Instance != XR_NULL_HANDLE);
|
|
|
|
LeftWristTracker.AddTrackedDevices(OpenXRHMD);
|
|
RightWristTracker.AddTrackedDevices(OpenXRHMD);
|
|
OutActionSets.Add(WristTrackerActionSet);
|
|
|
|
PRAGMA_DISABLE_DEPRECATION_WARNINGS
|
|
// For enhanced input
|
|
const UEnhancedInputDeveloperSettings* InputSettings = GetDefault<UEnhancedInputDeveloperSettings>();
|
|
if (InputSettings)
|
|
{
|
|
for (const auto& Context : InputSettings->DefaultMappingContexts)
|
|
{
|
|
if (Context.InputMappingContext)
|
|
{
|
|
TStrongObjectPtr<const UInputMappingContext> Obj(Context.InputMappingContext.LoadSynchronous());
|
|
InputMappingContextToPriorityMap.Add(Obj, Context.Priority);
|
|
}
|
|
else
|
|
{
|
|
UE_LOG(LogHMD, Warning, TEXT("Default Mapping Contexts contains an Input Mapping Context set to \"None\", ignoring while building OpenXR actions."));
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!InputMappingContextToPriorityMap.IsEmpty())
|
|
{
|
|
for (const auto& MappingContext : InputMappingContextToPriorityMap)
|
|
{
|
|
for (const FEnhancedActionKeyMapping& Mapping : MappingContext.Key->GetMappings())
|
|
{
|
|
LeftWristTracker.CheckAndAddEnhancedInputAction(Mapping);
|
|
RightWristTracker.CheckAndAddEnhancedInputAction(Mapping);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Setup Key to ActionState map
|
|
KeyActionStates.Emplace(WristTrackerKeys::WristTracker_Left_X_Click.GetFName(), &LeftWristTracker.PrimaryActionState);
|
|
KeyActionStates.Emplace(WristTrackerKeys::WristTracker_Right_A_Click.GetFName(), &RightWristTracker.PrimaryActionState);
|
|
KeyActionStates.Emplace(WristTrackerKeys::WristTracker_Left_Menu_Click.GetFName(), &LeftWristTracker.MenuActionState);
|
|
KeyActionStates.Emplace(WristTrackerKeys::WristTracker_Right_System_Click.GetFName(), &RightWristTracker.MenuActionState);
|
|
}
|
|
PRAGMA_ENABLE_DEPRECATION_WARNINGS
|
|
|
|
bActionsAttached = true;
|
|
}
|
|
|
|
void FViveOpenXRWristTracker::GetActiveActionSetsForSync(TArray<XrActiveActionSet>& OutActiveSets)
|
|
{
|
|
if (!m_bEnableWristTracker) return;
|
|
|
|
check(WristTrackerActionSet != XR_NULL_HANDLE);
|
|
OutActiveSets.Add(XrActiveActionSet{WristTrackerActionSet, XR_NULL_PATH});
|
|
}
|
|
|
|
void FViveOpenXRWristTracker::PostCreateInstance(XrInstance InInstance)
|
|
{
|
|
Instance = InInstance;
|
|
}
|
|
|
|
const void* FViveOpenXRWristTracker::OnCreateSession(XrInstance InInstance, XrSystemId InSystem, const void* InNext)
|
|
{
|
|
if (m_bEnableWristTracker)
|
|
{
|
|
Instance = InInstance;
|
|
|
|
static FName SystemName(TEXT("OpenXR"));
|
|
if (GEngine->XRSystem.IsValid() && (GEngine->XRSystem->GetSystemName() == SystemName))
|
|
{
|
|
OpenXRHMD = (FOpenXRHMD*)GEngine->XRSystem.Get();
|
|
}
|
|
|
|
bSessionStarted = true;
|
|
|
|
// Setup FKey
|
|
LeftWristTracker.PrimaryKey = WristTrackerKeys::WristTracker_Left_X_Click;
|
|
LeftWristTracker.MenuKey = WristTrackerKeys::WristTracker_Left_Menu_Click;
|
|
RightWristTracker.PrimaryKey = WristTrackerKeys::WristTracker_Right_A_Click;
|
|
RightWristTracker.MenuKey = WristTrackerKeys::WristTracker_Right_System_Click;
|
|
|
|
// Setup XrPath (include SubActionPaths)
|
|
LeftWristTracker.SetupPath(WristTrackerRolePath::Left, WristTrackerActionPath::LeftPose, WristTrackerActionPath::LeftPrimary, WristTrackerActionPath::LeftMenu);
|
|
RightWristTracker.SetupPath(WristTrackerRolePath::Right, WristTrackerActionPath::RightPose, WristTrackerActionPath::RightPrimary, WristTrackerActionPath::RightMenu);
|
|
|
|
// Create ActionSet
|
|
if (WristTrackerActionSet != XR_NULL_HANDLE)
|
|
{
|
|
xrDestroyActionSet(WristTrackerActionSet);
|
|
WristTrackerActionSet = XR_NULL_HANDLE;
|
|
}
|
|
{
|
|
XrActionSetCreateInfo Info;
|
|
Info.type = XR_TYPE_ACTION_SET_CREATE_INFO;
|
|
Info.next = nullptr;
|
|
FCStringAnsi::Strcpy(Info.actionSetName, XR_MAX_ACTION_SET_NAME_SIZE, "viveopenxrwristtrackeractionset");
|
|
FCStringAnsi::Strcpy(Info.localizedActionSetName, XR_MAX_LOCALIZED_ACTION_SET_NAME_SIZE, "VIVE OpenXR Wrist Tracker Action Set");
|
|
Info.priority = 0;
|
|
XR_ENSURE(xrCreateActionSet(Instance, &Info, &WristTrackerActionSet));
|
|
}
|
|
|
|
// Create Action
|
|
LeftWristTracker.AddActions(WristTrackerActionSet);
|
|
RightWristTracker.AddActions(WristTrackerActionSet);
|
|
|
|
// Create suggested bindings
|
|
UE_LOG(LogViveOpenXRWristTracker, Log, TEXT("xrSuggestInteractionProfileBindings()"));
|
|
TArray<XrActionSuggestedBinding> Bindings;
|
|
LeftWristTracker.GetSuggestedBindings(Bindings);
|
|
RightWristTracker.GetSuggestedBindings(Bindings);
|
|
XrInteractionProfileSuggestedBinding InteractionProfileSuggestedBindings{ XR_TYPE_INTERACTION_PROFILE_SUGGESTED_BINDING };
|
|
InteractionProfileSuggestedBindings.interactionProfile = FOpenXRPath("/interaction_profiles/htc/vive_wrist_tracker");
|
|
InteractionProfileSuggestedBindings.suggestedBindings = Bindings.GetData();
|
|
InteractionProfileSuggestedBindings.countSuggestedBindings = Bindings.Num();
|
|
XR_ENSURE(xrSuggestInteractionProfileBindings(Instance, &InteractionProfileSuggestedBindings));
|
|
}
|
|
|
|
return InNext;
|
|
}
|
|
|
|
void FViveOpenXRWristTracker::OnDestroySession(XrSession InSession)
|
|
{
|
|
if (bActionsAttached)
|
|
{
|
|
// If the session shut down, clean up.
|
|
bActionsAttached = false;
|
|
bSessionStarted = false;
|
|
KeyActionStates.Reset();
|
|
}
|
|
}
|
|
|
|
const void* FViveOpenXRWristTracker::OnBeginSession(XrSession InSession, const void* InNext)
|
|
{
|
|
if (m_bEnableWristTracker)
|
|
{
|
|
bSessionStarted = true;
|
|
}
|
|
|
|
return InNext;
|
|
}
|
|
|
|
void FViveOpenXRWristTracker::PostSyncActions(XrSession InSession)
|
|
{
|
|
if (!m_bEnableWristTracker) return;
|
|
|
|
WorldToMetersScale_ = OpenXRHMD->GetWorldToMetersScale();
|
|
|
|
LeftWristTracker.SyncActionStates(InSession);
|
|
RightWristTracker.SyncActionStates(InSession);
|
|
|
|
SendInputEvent_Legacy();
|
|
SendInputEvent_EnhancedInput();
|
|
}
|
|
|
|
void FViveOpenXRWristTracker::UpdateDeviceLocations(XrSession InSession, XrTime DisplayTime, XrSpace TrackingSpace)
|
|
{
|
|
}
|
|
|
|
#pragma region
|
|
bool FViveOpenXRWristTracker::GetControllerOrientationAndPosition(const int32 ControllerIndex, const FName MotionSource, FRotator& OutOrientation, FVector& OutPosition, float WorldToMetersScale) const
|
|
{
|
|
if (!bActionsAttached || OpenXRHMD == nullptr)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (ControllerIndex == DeviceIndex)
|
|
{
|
|
if (MotionSource == WristTrackerMotionSource::Left || MotionSource == WristTrackerMotionSource::Right)
|
|
{
|
|
int32 DeviceId = LeftWristTracker.DeviceId;
|
|
if (MotionSource == WristTrackerMotionSource::Right) DeviceId = RightWristTracker.DeviceId;
|
|
|
|
FQuat Orientation;
|
|
bool Success = OpenXRHMD->GetCurrentPose(DeviceId, Orientation, OutPosition);
|
|
OutOrientation = FRotator(Orientation);
|
|
return Success;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool FViveOpenXRWristTracker::GetControllerOrientationAndPosition(const int32 ControllerIndex, const FName MotionSource, FRotator& OutOrientation, FVector& OutPosition, bool& OutbProvidedLinearVelocity, FVector& OutLinearVelocity, bool& OutbProvidedAngularVelocity, FVector& OutAngularVelocityAsAxisAndLength, bool& OutbProvidedLinearAcceleration, FVector& OutLinearAcceleration, float WorldToMetersScale) const
|
|
{
|
|
// FTimespan initializes to 0 and GetControllerOrientationAndPositionForTime with time 0 will return the latest data.
|
|
FTimespan Time;
|
|
bool OutTimeWasUsed = false;
|
|
return GetControllerOrientationAndPositionForTime(ControllerIndex, MotionSource, Time, OutTimeWasUsed, OutOrientation, OutPosition, OutbProvidedLinearVelocity, OutLinearVelocity, OutbProvidedAngularVelocity, OutAngularVelocityAsAxisAndLength, OutbProvidedLinearAcceleration, OutLinearAcceleration, WorldToMetersScale);
|
|
}
|
|
|
|
bool FViveOpenXRWristTracker::GetControllerOrientationAndPositionForTime(const int32 ControllerIndex, const FName MotionSource, FTimespan Time, bool& OutTimeWasUsed, FRotator& OutOrientation, FVector& OutPosition, bool& OutbProvidedLinearVelocity, FVector& OutLinearVelocity, bool& OutbProvidedAngularVelocity, FVector& OutAngularVelocityRadPerSec, bool& OutbProvidedLinearAcceleration, FVector& OutLinearAcceleration, float WorldToMetersScale) const
|
|
{
|
|
if (!bActionsAttached || OpenXRHMD == nullptr)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (ControllerIndex == DeviceIndex)
|
|
{
|
|
if (MotionSource == WristTrackerMotionSource::Left || MotionSource == WristTrackerMotionSource::Right)
|
|
{
|
|
int32 DeviceId = LeftWristTracker.DeviceId;
|
|
if (MotionSource == WristTrackerMotionSource::Right) DeviceId = RightWristTracker.DeviceId;
|
|
|
|
FQuat Orientation;
|
|
bool Success = OpenXRHMD->GetPoseForTime(DeviceId, Time, OutTimeWasUsed, Orientation, OutPosition, OutbProvidedLinearVelocity, OutLinearVelocity, OutbProvidedAngularVelocity, OutAngularVelocityRadPerSec, OutbProvidedLinearAcceleration, OutLinearAcceleration, WorldToMetersScale);
|
|
OutOrientation = FRotator(Orientation);
|
|
return Success;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
ETrackingStatus FViveOpenXRWristTracker::GetControllerTrackingStatus(const int32 ControllerIndex, const FName MotionSource) const
|
|
{
|
|
if (!bActionsAttached || OpenXRHMD == nullptr)
|
|
{
|
|
return ETrackingStatus::NotTracked;
|
|
}
|
|
|
|
XrSession Session = OpenXRHMD->GetSession();
|
|
if (Session == XR_NULL_HANDLE)
|
|
{
|
|
return ETrackingStatus::NotTracked;
|
|
}
|
|
|
|
XrActionStateGetInfo PoseActionStateInfo{ XR_TYPE_ACTION_STATE_GET_INFO };
|
|
|
|
if (MotionSource == WristTrackerMotionSource::Left)
|
|
{
|
|
// left entity pose
|
|
PoseActionStateInfo.action = LeftWristTracker.PoseAction;
|
|
}
|
|
else if (MotionSource == WristTrackerMotionSource::Right)
|
|
{
|
|
// right entity pose
|
|
PoseActionStateInfo.action = RightWristTracker.PoseAction;
|
|
}
|
|
else
|
|
{
|
|
return ETrackingStatus::NotTracked;
|
|
}
|
|
PoseActionStateInfo.subactionPath = XR_NULL_PATH;
|
|
|
|
XrActionStatePose State = { XR_TYPE_ACTION_STATE_POSE };
|
|
if (!XR_ENSURE(xrGetActionStatePose(Session, &PoseActionStateInfo, &State)))
|
|
{
|
|
return ETrackingStatus::NotTracked;
|
|
}
|
|
|
|
return State.isActive ? ETrackingStatus::Tracked : ETrackingStatus::NotTracked;
|
|
}
|
|
|
|
FName FViveOpenXRWristTracker::GetMotionControllerDeviceTypeName() const
|
|
{
|
|
const static FName DefaultName(TEXT("OpenXRViveWristTracker"));
|
|
return DefaultName;
|
|
}
|
|
|
|
void FViveOpenXRWristTracker::EnumerateSources(TArray<FMotionControllerSource>& SourcesOut) const
|
|
{
|
|
check(IsInGameThread());
|
|
|
|
SourcesOut.Add(FMotionControllerSource(WristTrackerMotionSource::Left));
|
|
SourcesOut.Add(FMotionControllerSource(WristTrackerMotionSource::Right));
|
|
}
|
|
|
|
PRAGMA_DISABLE_DEPRECATION_WARNINGS
|
|
bool FViveOpenXRWristTracker::SetPlayerMappableInputConfig(TObjectPtr<class UPlayerMappableInputConfig> InputConfig)
|
|
{
|
|
if (bActionsAttached)
|
|
{
|
|
UE_LOG(LogHMD, Error, TEXT("Attempted to attach an input config while one is already attached for the current session."));
|
|
|
|
return false;
|
|
}
|
|
|
|
TSet<TObjectPtr<UInputMappingContext>> MappingContexts;
|
|
InputConfig->GetMappingContexts().GetKeys(MappingContexts);
|
|
return AttachInputMappingContexts(MappingContexts);
|
|
}
|
|
PRAGMA_ENABLE_DEPRECATION_WARNINGS
|
|
|
|
bool FViveOpenXRWristTracker::AttachInputMappingContexts(const TSet<TObjectPtr<UInputMappingContext>>& MappingContexts)
|
|
{
|
|
if (bActionsAttached)
|
|
{
|
|
UE_LOG(LogHMD, Error, TEXT("Attempted to attach input mapping contexts when action sets are already attached for the current session."));
|
|
|
|
return false;
|
|
}
|
|
|
|
for (const auto& Context : MappingContexts)
|
|
{
|
|
InputMappingContextToPriorityMap.Add(TStrongObjectPtr<UInputMappingContext>(Context), 0);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void FViveOpenXRWristTracker::SendInputEvent_Legacy()
|
|
{
|
|
if (!m_bEnableWristTracker) return;
|
|
|
|
IPlatformInputDeviceMapper& DeviceMapper = IPlatformInputDeviceMapper::Get();
|
|
|
|
for (auto &KeyActionState : KeyActionStates)
|
|
{
|
|
XrActionStateBoolean state = *KeyActionState.Value;
|
|
if (state.changedSinceLastSync)
|
|
{
|
|
FName keyName = KeyActionState.Key;
|
|
//UE_LOG(LogViveOpenXRWristTracker, Log, TEXT("SendControllerEvents() %s = %d."), *keyName.ToString(), (uint8_t)state.currentState);
|
|
if (state.isActive && state.currentState)
|
|
{
|
|
MessageHandler->OnControllerButtonPressed(keyName, DeviceMapper.GetPrimaryPlatformUser(), DeviceMapper.GetDefaultInputDevice(), /*IsRepeat =*/false);
|
|
}
|
|
else
|
|
{
|
|
MessageHandler->OnControllerButtonReleased(keyName, DeviceMapper.GetPrimaryPlatformUser(), DeviceMapper.GetDefaultInputDevice(), /*IsRepeat =*/false);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void FViveOpenXRWristTracker::SendInputEvent_EnhancedInput()
|
|
{
|
|
if (!m_bEnableWristTracker) return;
|
|
|
|
auto InjectEnhancedInput = [](XrActionStateBoolean& State, TArray<TObjectPtr<const UInputAction>>& Actions)
|
|
{
|
|
FInputActionValue InputValue;
|
|
TArray<TObjectPtr<UInputTrigger>> Triggers = {};
|
|
TArray<TObjectPtr<UInputModifier>> Modifiers = {};
|
|
|
|
InputValue = FInputActionValue(State.isActive ? (bool)State.currentState : false);
|
|
//UE_LOG(LogViveOpenXRWristTracker, Log, TEXT("SendInputEvent_EnhancedInput()."));
|
|
|
|
for (auto InputAction : Actions)
|
|
{
|
|
//if(State.isActive) UE_LOG(LogViveOpenXRWristTracker, Log, TEXT("SendInputEvent_EnhancedInput() Action: %s, Value: %d"), *InputAction.GetFName().ToString(), (uint8_t)State.currentState);
|
|
auto InjectSubsystemInput = [InputAction, InputValue, Triggers, Modifiers](IEnhancedInputSubsystemInterface* Subsystem)
|
|
{
|
|
if (Subsystem)
|
|
{
|
|
Subsystem->InjectInputForAction(InputAction, InputValue, Modifiers, Triggers);
|
|
}
|
|
};
|
|
IEnhancedInputModule::Get().GetLibrary()->ForEachSubsystem(InjectSubsystemInput);
|
|
|
|
#if WITH_EDITOR
|
|
if (GEditor)
|
|
{
|
|
// UEnhancedInputLibrary::ForEachSubsystem only enumerates runtime subsystems.
|
|
InjectSubsystemInput(GEditor->GetEditorSubsystem<UEnhancedInputEditorSubsystem>());
|
|
}
|
|
#endif
|
|
}
|
|
|
|
};
|
|
|
|
InjectEnhancedInput(LeftWristTracker.PrimaryActionState, LeftWristTracker.PrimaryInputActions);
|
|
InjectEnhancedInput(LeftWristTracker.MenuActionState, LeftWristTracker.MenuInputActions);
|
|
InjectEnhancedInput(RightWristTracker.PrimaryActionState, RightWristTracker.PrimaryInputActions);
|
|
InjectEnhancedInput(RightWristTracker.MenuActionState, RightWristTracker.MenuInputActions);
|
|
}
|
|
#pragma endregion IInputDevice overrides
|
|
|
|
/************************************************************************/
|
|
/* FViveOpenXRWristTrackerModule */
|
|
/************************************************************************/
|
|
|
|
#define LOCTEXT_NAMESPACE "FViveOpenXRWristTrackerModule"
|
|
|
|
FName IViveOpenXRWristTrackerModule::ViveOpenXRWristTrackerModularKeyName = FName(TEXT("ViveOpenXRWristTracker"));
|
|
|
|
FViveOpenXRWristTrackerModule::FViveOpenXRWristTrackerModule()
|
|
{
|
|
}
|
|
|
|
void FViveOpenXRWristTrackerModule::StartupModule()
|
|
{
|
|
UE_LOG(LogViveOpenXRWristTracker, Log, TEXT("StartupModule()"));
|
|
IViveOpenXRWristTrackerModule::StartupModule();
|
|
|
|
TSharedPtr<FGenericApplicationMessageHandler> DummyMessageHandler(new FGenericApplicationMessageHandler());
|
|
CreateInputDevice(DummyMessageHandler.ToSharedRef());
|
|
|
|
EKeys::AddMenuCategoryDisplayInfo("Wrist Tracker", LOCTEXT("WristTrackerSubCategory", "HTC Wrist Tracker"), TEXT("GraphEditor.PadEvent_16x"));
|
|
|
|
/// ---- Left hand only ----
|
|
// "/input/menu/click"
|
|
EKeys::AddKey(FKeyDetails(WristTrackerKeys::WristTracker_Left_Menu_Click, LOCTEXT("WristTracker_Left_Menu_Click", "Wrist Tracker (L) Menu Press"), FKeyDetails::GamepadKey | FKeyDetails::NotBlueprintBindableKey, "Wrist Tracker"));
|
|
// "/input/x/click"
|
|
EKeys::AddKey(FKeyDetails(WristTrackerKeys::WristTracker_Left_X_Click, LOCTEXT("WristTracker_Left_X_Click", "Wrist Tracker (L) Primary Press"), FKeyDetails::GamepadKey | FKeyDetails::NotBlueprintBindableKey, "Wrist Tracker"));
|
|
|
|
/// ---- Right hand only ----
|
|
// "/input/system/click"
|
|
EKeys::AddKey(FKeyDetails(WristTrackerKeys::WristTracker_Right_System_Click, LOCTEXT("WristTracker_Right_System_Click", "Wrist Tracker (R) Menu Press"), FKeyDetails::GamepadKey | FKeyDetails::NotBlueprintBindableKey, "Wrist Tracker"));
|
|
// "/input/a/click"
|
|
EKeys::AddKey(FKeyDetails(WristTrackerKeys::WristTracker_Right_A_Click, LOCTEXT("WristTracker_Right_A_Click", "Wrist Tracker (R) Primary Press"), FKeyDetails::GamepadKey | FKeyDetails::NotBlueprintBindableKey, "Wrist Tracker"));
|
|
|
|
check(GConfig && GConfig->IsReadyForUse());
|
|
FString modeName;
|
|
if (GConfig->GetString(TEXT("/Script/ViveOpenXRRuntimeSettings.ViveOpenXRRuntimeSettings"), TEXT("bEnableWristTracker"), modeName, GEngineIni))
|
|
{
|
|
if (modeName.Equals("False"))
|
|
{
|
|
GetWristTracker()->m_bEnableWristTracker = false;
|
|
}
|
|
else if (modeName.Equals("True"))
|
|
{
|
|
GetWristTracker()->m_bEnableWristTracker = true;
|
|
}
|
|
}
|
|
|
|
if (GetWristTracker()->m_bEnableWristTracker)
|
|
{
|
|
UE_LOG(LogViveOpenXRWristTracker, Log, TEXT("Enable Wrist controller."));
|
|
}
|
|
else
|
|
{
|
|
UE_LOG(LogViveOpenXRWristTracker, Log, TEXT("Disable Wrist controller."));
|
|
}
|
|
}
|
|
|
|
void FViveOpenXRWristTrackerModule::ShutdownModule()
|
|
{
|
|
UE_LOG(LogViveOpenXRWristTracker, Log, TEXT("ShutdownModule()"));
|
|
}
|
|
|
|
TSharedPtr<class IInputDevice> FViveOpenXRWristTrackerModule::CreateInputDevice(const TSharedRef<FGenericApplicationMessageHandler>& InMessageHandler)
|
|
{
|
|
if (!WristTracker.IsValid())
|
|
{
|
|
auto InputDevice = new FViveOpenXRWristTracker(InMessageHandler);
|
|
WristTracker = TSharedPtr<FViveOpenXRWristTracker>(InputDevice);
|
|
UE_LOG(LogViveOpenXRWristTracker, Log, TEXT("CreateInputDevice() new WristTracker %p"), WristTracker.Get());
|
|
|
|
return WristTracker;
|
|
}
|
|
else
|
|
{
|
|
WristTracker.Get()->SetMessageHandler(InMessageHandler);
|
|
UE_LOG(LogViveOpenXRWristTracker, Log, TEXT("CreateInputDevice() update WristTracker %p"), WristTracker.Get());
|
|
|
|
return WristTracker;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
FViveOpenXRWristTracker* FViveOpenXRWristTrackerModule::GetWristTracker()
|
|
{
|
|
return FViveOpenXRWristTracker::GetInstance();
|
|
}
|
|
|
|
IMPLEMENT_MODULE(FViveOpenXRWristTrackerModule, ViveOpenXRWristTracker);
|
|
|