191 qWarning() <<
"QOpenXRInputManager: Trying to initialize an already initialized session";
198 m_disableGamepad =
false;
207 XrInstanceProperties instanceProperties = {};
208 instanceProperties.type = XR_TYPE_INSTANCE_PROPERTIES;
209 if (xrGetInstanceProperties(m_instance, &instanceProperties) == XR_SUCCESS) {
210 if (strstr(instanceProperties.runtimeName,
"Meta XR Simulator")) {
211 qDebug(
"QOpenXRInputManager: Disabling gamepad actions due to running on the Simulator");
212 m_disableGamepad =
true;
217#ifdef XR_USE_PLATFORM_ANDROID
218 qDebug(
"QOpenXRInputManager: Disabling gamepad actions due to running on Android");
219 m_disableGamepad =
true;
224 QXRHandComponentPath aClick = makeHandInputPaths(
"input/a/click");
225 QXRHandComponentPath bClick = makeHandInputPaths(
"input/b/click");
226 QXRHandComponentPath aTouch = makeHandInputPaths(
"input/a/touch");
227 QXRHandComponentPath bTouch = makeHandInputPaths(
"input/b/touch");
229 QXRHandComponentPath xClick = makeHandInputPaths(
"input/x/click");
230 QXRHandComponentPath yClick = makeHandInputPaths(
"input/y/click");
231 QXRHandComponentPath xTouch = makeHandInputPaths(
"input/x/touch");
232 QXRHandComponentPath yTouch = makeHandInputPaths(
"input/y/touch");
234 QXRHandComponentPath menuClick = makeHandInputPaths(
"input/menu/click");
235 QXRHandComponentPath systemClick = makeHandInputPaths(
"input/system/click");
236 QXRHandComponentPath systemTouch = makeHandInputPaths(
"input/system/touch");
238 QXRHandComponentPath squeezeValue = makeHandInputPaths(
"input/squeeze/value");
239 QXRHandComponentPath squeezeForce = makeHandInputPaths(
"input/squeeze/force");
240 QXRHandComponentPath squeezeClick = makeHandInputPaths(
"input/squeeze/click");
242 QXRHandComponentPath triggerValue = makeHandInputPaths(
"input/trigger/value");
243 QXRHandComponentPath triggerTouch = makeHandInputPaths(
"input/trigger/touch");
244 QXRHandComponentPath triggerClick = makeHandInputPaths(
"input/trigger/click");
246 QXRHandComponentPath thumbstickX = makeHandInputPaths(
"input/thumbstick/x");
247 QXRHandComponentPath thumbstickY = makeHandInputPaths(
"input/thumbstick/y");
248 QXRHandComponentPath thumbstickClick = makeHandInputPaths(
"input/thumbstick/click");
249 QXRHandComponentPath thumbstickTouch = makeHandInputPaths(
"input/thumbstick/touch");
250 QXRHandComponentPath thumbrestTouch = makeHandInputPaths(
"input/thumbrest/touch");
252 QXRHandComponentPath trackpadX = makeHandInputPaths(
"input/trackpad/x");
253 QXRHandComponentPath trackpadY = makeHandInputPaths(
"input/trackpad/y");
254 QXRHandComponentPath trackpadForce = makeHandInputPaths(
"input/trackpad/force");
255 QXRHandComponentPath trackpadClick = makeHandInputPaths(
"input/trackpad/click");
256 QXRHandComponentPath trackpadTouch = makeHandInputPaths(
"input/trackpad/touch");
258 XrPath handLeftGripPose;
259 XrPath handLeftAimPose;
260 XrPath handLeftHaptic;
262 XrPath handRightGripPose;
263 XrPath handRightAimPose;
264 XrPath handRightHaptic;
266 XrPath gamepadMenuClick = makeInputPath(
"/user/gamepad/input/menu/click");
267 XrPath gamepadViewClick = makeInputPath(
"/user/gamepad/input/view/click");
268 XrPath gamepadAClick = makeInputPath(
"/user/gamepad/input/a/click");
269 XrPath gamepadBClick = makeInputPath(
"/user/gamepad/input/b/click");
270 XrPath gamepadXClick = makeInputPath(
"/user/gamepad/input/x/click");
271 XrPath gamepadYClick = makeInputPath(
"/user/gamepad/input/y/click");
272 XrPath gamepadDpadDownClick = makeInputPath(
"/user/gamepad/input/dpad_down/click");
273 XrPath gamepadDpadRightClick = makeInputPath(
"/user/gamepad/input/dpad_right/click");
274 XrPath gamepadDpadUpClick = makeInputPath(
"/user/gamepad/input/dpad_up/click");
275 XrPath gamepadDpadLeftClick = makeInputPath(
"/user/gamepad/input/dpad_left/click");
276 XrPath gamepadShoulderLeftClick = makeInputPath(
"/user/gamepad/input/shoulder_left/click");
277 XrPath gamepadShoulderRightClick = makeInputPath(
"/user/gamepad/input/shoulder_right/click");
278 XrPath gamepadThumbstickLeftClick = makeInputPath(
"/user/gamepad/input/thumbstick_left/click");
279 XrPath gamepadThumbstickRightClick = makeInputPath(
"/user/gamepad/input/thumbstick_right/click");
280 XrPath gamepadTriggerLeftValue = makeInputPath(
"/user/gamepad/input/trigger_left/value");
281 XrPath gamepadTriggerRightValue = makeInputPath(
"/user/gamepad/input/trigger_right/value");
282 XrPath gamepadThumbstickLeftX = makeInputPath(
"/user/gamepad/input/thumbstick_left/x");
283 XrPath gamepadThumbstickLeftY = makeInputPath(
"/user/gamepad/input/thumbstick_left/y");
284 XrPath gamepadThumbstickRightX = makeInputPath(
"/user/gamepad/input/thumbstick_right/x");
285 XrPath gamepadThumbstickRightY = makeInputPath(
"/user/gamepad/input/thumbstick_right/y");
286 XrPath gamepadHapticLeft = makeInputPath(
"/user/gamepad/output/haptic_left");
287 XrPath gamepadHapticRight = makeInputPath(
"/user/gamepad/output/haptic_right");
288 XrPath gamepadHapticLeftTrigger = makeInputPath(
"/user/gamepad/output/haptic_left_trigger");
289 XrPath gamepadHapticRightTrigger = makeInputPath(
"/user/gamepad/output/haptic_right_trigger");
293 setPath(handLeftGripPose,
"/user/hand/left/input/grip/pose");
294 setPath(handLeftAimPose,
"/user/hand/left/input/aim/pose");
295 setPath(handLeftHaptic,
"/user/hand/left/output/haptic");
297 setPath(handRightGripPose,
"/user/hand/right/input/grip/pose");
298 setPath(handRightAimPose,
"/user/hand/right/input/aim/pose");
299 setPath(handRightHaptic,
"/user/hand/right/output/haptic");
303 using XrActionBindings = std::vector<XrActionSuggestedBinding>;
304 using HandInputMapping = std::vector<std::tuple<QOpenXRActionMapper::InputAction, QXRHandComponentPath, SubPathSelector>>;
305 using GamepadInputMapping = std::vector<std::tuple<QOpenXRActionMapper::InputAction, XrPath>>;
306 auto addToBindings = [
this](XrActionBindings &bindings,
const HandInputMapping &defs){
309 bindings.push_back({ m_inputActions[actionId],
path.paths[
LeftHand] });
311 bindings.push_back({ m_inputActions[actionId],
path.paths[
RightHand] });
317 HandInputMapping mappingDefs {
338 XrPath oculusTouchProfile;
339 setPath(oculusTouchProfile,
"/interaction_profiles/oculus/touch_controller");
340 std::vector<XrActionSuggestedBinding> bindings {{
341 {m_handActions.gripPoseAction, handLeftGripPose},
342 {m_handActions.aimPoseAction, handLeftAimPose},
343 {m_handActions.hapticAction, handLeftHaptic},
345 {m_handActions.gripPoseAction, handRightGripPose},
346 {m_handActions.aimPoseAction, handRightAimPose},
347 {m_handActions.hapticAction, handRightHaptic},
350 addToBindings(bindings, mappingDefs);
352 XrInteractionProfileSuggestedBinding suggestedBindings{};
353 suggestedBindings.type = XR_TYPE_INTERACTION_PROFILE_SUGGESTED_BINDING;
354 suggestedBindings.interactionProfile = oculusTouchProfile;
355 suggestedBindings.suggestedBindings = bindings.data();
356 suggestedBindings.countSuggestedBindings = (uint32_t)bindings.size();
357 checkXrResult(xrSuggestInteractionProfileBindings(m_instance, &suggestedBindings),
"suggested bindings: Oculus touch");
363 XrPath handInteractionProfile;
364 setPath(handInteractionProfile,
"/interaction_profiles/microsoft/hand_interaction");
365 std::vector<XrActionSuggestedBinding> bindings {{
366 {m_handActions.gripPoseAction, handLeftGripPose},
367 {m_handActions.aimPoseAction, handLeftAimPose},
368 {m_handActions.gripPoseAction, handRightGripPose},
369 {m_handActions.aimPoseAction, handRightAimPose},
372 HandInputMapping mappingDefs {
376 addToBindings(bindings, mappingDefs);
378 XrInteractionProfileSuggestedBinding suggestedBindings{};
379 suggestedBindings.type = XR_TYPE_INTERACTION_PROFILE_SUGGESTED_BINDING;
380 suggestedBindings.interactionProfile = handInteractionProfile;
381 suggestedBindings.suggestedBindings = bindings.data();
382 suggestedBindings.countSuggestedBindings = (uint32_t)bindings.size();
384 checkXrResult(xrSuggestInteractionProfileBindings(m_instance, &suggestedBindings),
"suggested bindings: MSFT hand interaction");
388 XrPath htcViveProfile;
389 setPath(htcViveProfile,
"/interaction_profiles/htc/vive_controller");
391 HandInputMapping mappingDefs {
403 std::vector<XrActionSuggestedBinding> bindings {{
404 {m_handActions.gripPoseAction, handLeftGripPose},
405 {m_handActions.aimPoseAction, handLeftAimPose},
406 {m_handActions.hapticAction, handLeftHaptic},
408 {m_handActions.gripPoseAction, handRightGripPose},
409 {m_handActions.aimPoseAction, handRightAimPose},
410 {m_handActions.hapticAction, handRightHaptic},
413 addToBindings(bindings, mappingDefs);
415 XrInteractionProfileSuggestedBinding suggestedBindings{};
416 suggestedBindings.type = XR_TYPE_INTERACTION_PROFILE_SUGGESTED_BINDING;
417 suggestedBindings.interactionProfile = htcViveProfile;
418 suggestedBindings.suggestedBindings = bindings.data();
419 suggestedBindings.countSuggestedBindings = (uint32_t)bindings.size();
420 checkXrResult(xrSuggestInteractionProfileBindings(m_instance, &suggestedBindings),
"suggested bindings: Vive controller");
425 XrPath microsoftMotionProfile;
426 setPath(microsoftMotionProfile,
"/interaction_profiles/microsoft/motion_controller");
431 XrPath valveIndexProfile;
432 setPath(valveIndexProfile,
"/interaction_profiles/valve/index_controller");
436 if (!m_disableGamepad) {
437 XrPath xboxControllerProfile;
438 setPath(xboxControllerProfile,
"/interaction_profiles/microsoft/xbox_controller");
440 GamepadInputMapping mappingDefs {
463 std::vector<XrActionSuggestedBinding> bindings {{
464 {m_gamepadActions.hapticLeftAction, gamepadHapticLeft},
465 {m_gamepadActions.hapticRightAction, gamepadHapticRight},
466 {m_gamepadActions.hapticLeftTriggerAction, gamepadHapticLeftTrigger},
467 {m_gamepadActions.hapticRightTriggerAction, gamepadHapticRightTrigger},
470 for (
const auto &[actionId,
path] : mappingDefs) {
471 bindings.push_back({ m_inputActions[actionId],
path });
474 XrInteractionProfileSuggestedBinding suggestedBindings{};
475 suggestedBindings.type = XR_TYPE_INTERACTION_PROFILE_SUGGESTED_BINDING;
476 suggestedBindings.interactionProfile = xboxControllerProfile;
477 suggestedBindings.suggestedBindings = bindings.data();
478 suggestedBindings.countSuggestedBindings = (uint32_t)bindings.size();
479 checkXrResult(xrSuggestInteractionProfileBindings(m_instance, &suggestedBindings),
"suggested bindings: XBox controller");
484 XrActionSpaceCreateInfo actionSpaceInfo{};
485 actionSpaceInfo.type = XR_TYPE_ACTION_SPACE_CREATE_INFO;
486 actionSpaceInfo.action = m_handActions.gripPoseAction;
487 actionSpaceInfo.poseInActionSpace.orientation.w = 1.0f;
489 actionSpaceInfo.subactionPath = m_handSubactionPath[0];
490 checkXrResult(xrCreateActionSpace(m_session, &actionSpaceInfo, &m_handGripSpace[0]),
"action space: handGripSpace[0]");
491 actionSpaceInfo.subactionPath = m_handSubactionPath[1];
492 checkXrResult(xrCreateActionSpace(m_session, &actionSpaceInfo, &m_handGripSpace[1]),
"action space: handGripSpace[1]");
494 actionSpaceInfo.action = m_handActions.aimPoseAction;
495 actionSpaceInfo.subactionPath = m_handSubactionPath[0];
496 checkXrResult(xrCreateActionSpace(m_session, &actionSpaceInfo, &m_handAimSpace[0]),
"action space: handAimSpace[0]");
497 actionSpaceInfo.subactionPath = m_handSubactionPath[1];
498 checkXrResult(xrCreateActionSpace(m_session, &actionSpaceInfo, &m_handAimSpace[1]),
"action space: handAimSpace[1]");
502 XrSessionActionSetsAttachInfo attachInfo{};
503 attachInfo.type = XR_TYPE_SESSION_ACTION_SETS_ATTACH_INFO;
504 attachInfo.countActionSets = 1;
505 attachInfo.actionSets = &m_actionSet;
506 checkXrResult(xrAttachSessionActionSets(m_session, &attachInfo),
"attach action set");
508 m_initialized =
true;
540 const XrActiveActionSet activeActionSet{m_actionSet, XR_NULL_PATH};
541 XrActionsSyncInfo syncInfo{};
542 syncInfo.type = XR_TYPE_ACTIONS_SYNC_INFO;
543 syncInfo.countActiveActionSets = 1;
544 syncInfo.activeActionSets = &activeActionSet;
545 XrResult
result = xrSyncActions(m_session, &syncInfo);
546 if (!(
result == XR_SUCCESS ||
547 result == XR_SESSION_LOSS_PENDING ||
548 result == XR_SESSION_NOT_FOCUSED)) {
549 checkXrResult(
result,
"xrSyncActions");
554 XrActionStateGetInfo getInfo{};
555 getInfo.type = XR_TYPE_ACTION_STATE_GET_INFO;
556 for (
int i = 0;
i < 2; ++
i) {
558 getInfo.subactionPath = m_handSubactionPath[
i];
559 auto &inputState = m_handInputState[
i];
561 for (
const auto &def : m_handInputActionDefs) {
562 getInfo.action = m_inputActions[def.id];
564 case XR_ACTION_TYPE_BOOLEAN_INPUT: {
565 XrActionStateBoolean boolValue{};
566 boolValue.type = XR_TYPE_ACTION_STATE_BOOLEAN;
567 checkXrResult(xrGetActionStateBoolean(m_session, &getInfo, &boolValue),
"bool hand input");
568 if (boolValue.isActive && boolValue.changedSinceLastSync) {
570 m_handInputState[
i]->
setInputValue(def.id, def.shortName,
float(boolValue.currentState));
574 case XR_ACTION_TYPE_FLOAT_INPUT: {
575 XrActionStateFloat floatValue{};
576 floatValue.type = XR_TYPE_ACTION_STATE_FLOAT;
577 checkXrResult(xrGetActionStateFloat(m_session, &getInfo, &floatValue),
"float hand input");
578 if (floatValue.isActive && floatValue.changedSinceLastSync) {
580 m_handInputState[
i]->
setInputValue(def.id, def.shortName,
float(floatValue.currentState));
584 case XR_ACTION_TYPE_VECTOR2F_INPUT:
585 case XR_ACTION_TYPE_POSE_INPUT:
586 case XR_ACTION_TYPE_VIBRATION_OUTPUT:
587 case XR_ACTION_TYPE_MAX_ENUM:
593 getInfo.action = m_handActions.gripPoseAction;
594 XrActionStatePose poseState{};
595 poseState.type = XR_TYPE_ACTION_STATE_POSE;
596 checkXrResult(xrGetActionStatePose(m_session, &getInfo, &poseState),
"xrGetActionStatePose XR_TYPE_ACTION_STATE_POSE");
597 inputState->setIsActive(poseState.isActive);
607 if (!m_disableGamepad) {
608 getInfo.subactionPath = m_gamepadSubactionPath;
611 for (
const auto &def : m_gamepadInputActionDefs) {
612 getInfo.action = m_inputActions[def.id];
614 case XR_ACTION_TYPE_BOOLEAN_INPUT: {
615 XrActionStateBoolean boolValue{};
616 boolValue.type = XR_TYPE_ACTION_STATE_BOOLEAN;
617 checkXrResult(xrGetActionStateBoolean(m_session, &getInfo, &boolValue),
"bool hand input");
618 if (boolValue.isActive && boolValue.changedSinceLastSync) {
620 m_gamepadInputState->
setInputValue(def.id, def.shortName,
float(boolValue.currentState));
624 case XR_ACTION_TYPE_FLOAT_INPUT: {
625 XrActionStateFloat floatValue{};
626 floatValue.type = XR_TYPE_ACTION_STATE_FLOAT;
627 checkXrResult(xrGetActionStateFloat(m_session, &getInfo, &floatValue),
"float hand input");
628 if (floatValue.isActive && floatValue.changedSinceLastSync) {
630 m_gamepadInputState->
setInputValue(def.id, def.shortName,
float(floatValue.currentState));
634 case XR_ACTION_TYPE_VECTOR2F_INPUT:
635 case XR_ACTION_TYPE_POSE_INPUT:
636 case XR_ACTION_TYPE_VIBRATION_OUTPUT:
637 case XR_ACTION_TYPE_MAX_ENUM: