From d03e0c3ba58835efb89e3ca8d588dffb1061b173 Mon Sep 17 00:00:00 2001 From: FirEmerald Date: Mon, 9 Feb 2026 11:01:16 -0600 Subject: [PATCH 1/2] Inputs improvements move grab, rune, inventory/map, mod menu, controller pose, and rumble to a shared action set dpad menus remain open exclusively with the input used to open them allow rebinding of rune button and sort button without breaking rune button dpad menu add input for inventory character model rotate simplify in-game grip interact logic --- src/hooking/controls.cpp | 78 +++++++------- src/hooking/weapon.cpp | 2 +- src/rendering/openxr.cpp | 214 ++++++++++++++++++++++----------------- src/rendering/openxr.h | 57 +++++++---- 4 files changed, 194 insertions(+), 157 deletions(-) diff --git a/src/hooking/controls.cpp b/src/hooking/controls.cpp index df10a92..06ae27e 100644 --- a/src/hooking/controls.cpp +++ b/src/hooking/controls.cpp @@ -204,12 +204,13 @@ bool openDpadMenuRuneButton(ButtonState::Event lastEvent, uint32_t& buttonHold, buttonHold |= VPAD_BUTTON_UP; gameState.last_dpad_menu_open = EquipType::SheikahSlate; gameState.dpad_menu_open_requested = true; + gameState.current_dpad_menu_button = OpenXR::DpadMenuButton::Rune; return true; } return false; } -bool openDpadMenuBodySlots(ButtonState::Event lastEvent, HandGestureState handGesture, uint32_t& buttonHold, OpenXR::GameState& gameState) { +bool openDpadMenuBodySlots(ButtonState::Event lastEvent, HandGestureState handGesture, uint32_t& buttonHold, OpenXR::GameState& gameState, bool (*gripButton)(OpenXR::InputState)) { if (lastEvent == ButtonState::Event::LongPress && !gameState.dpad_menu_open_requested) { if (isHandOverRightShoulderSlot(handGesture)) { //open arrow menu if bow is equipped in left hand @@ -252,6 +253,7 @@ bool openDpadMenuBodySlots(ButtonState::Event lastEvent, HandGestureState handGe gameState.last_dpad_menu_open = EquipType::SheikahSlate; } gameState.dpad_menu_open_requested = true; + gameState.current_dpad_menu_button = gripButton; return true; } return false; @@ -278,15 +280,15 @@ void keepDpadMenuOpen(uint32_t& buttonHold, OpenXR::GameState& gameState) { } } -bool closeDpadMenu(OpenXR::InputState& inputs, uint32_t& buttonHold, OpenXR::GameState& gameState) { +void closeDpadMenu(OpenXR::InputState& inputs, uint32_t& buttonHold, OpenXR::GameState& gameState) { if (!gameState.dpad_menu_open_requested) - return false; + return; - if (!inputs.inMenu.leftGrip.currentState && !inputs.inMenu.rightGrip.currentState && !inputs.inMenu.sort.currentState) { + if (!gameState.current_dpad_menu_button(inputs)) { gameState.dpad_menu_open_requested = false; gameState.was_dpad_menu_open = true; + gameState.current_dpad_menu_button = nullptr; } - return true; } void equipWeaponOnDpadMenuExit(uint32_t& buttonHold, OpenXR::GameState& gameState, float dt) { @@ -349,9 +351,10 @@ void processLeftHandInGameInput( constexpr RumbleParameters RuneRumble = { true, 0, RumbleType::OscillationSmooth, 1.0f, false, 1.0, 0.25f, 0.25f }; auto* rumbleMgr = VRManager::instance().XR->GetRumbleManager(); - bool isGrabPressed = inputs.inGame.grabState[0].lastEvent == ButtonState::Event::ShortPress; - bool isGrabPressedLong = inputs.inGame.grabState[0].lastEvent == ButtonState::Event::LongPress; - bool isCurrentGrabPressed = inputs.inGame.grabState[0].wasDownLastFrame; + bool isGrabPressed = inputs.shared.grabState[0].lastEvent == ButtonState::Event::ShortPress; + bool isGrabPressedLong = inputs.shared.grabState[0].lastEvent == ButtonState::Event::LongPress; + bool isCurrentGrabPressed = inputs.shared.grabState[0].wasDownLastFrame; + bool isCurrentInteractPressed = inputs.shared.grabState[0].wasDownLastFrame; // Rune rumbles if (gameState.left_hand_current_equip_type == EquipType::SheikahSlate) @@ -386,7 +389,7 @@ void processLeftHandInGameInput( // Handle shoulder slot interactions if (isHandOverLeftShoulderSlot(leftGesture) || isHandOverRightShoulderSlot(leftGesture)) { - if (openDpadMenuBodySlots(inputs.inGame.grabState[0].lastEvent, leftGesture, buttonHold, gameState)) + if (openDpadMenuBodySlots(inputs.shared.grabState[0].lastEvent, leftGesture, buttonHold, gameState, OpenXR::DpadMenuButton::LGrab)) // Don't process normal input when opening dpad menu return; @@ -421,7 +424,7 @@ void processLeftHandInGameInput( // Handle waist slot interaction (Rune) if (isHandOverLeftWaistSlot(leftGesture)) { // Handle dpad menu - if (openDpadMenuBodySlots(inputs.inGame.grabState[0].lastEvent, leftGesture, buttonHold, gameState)) + if (openDpadMenuBodySlots(inputs.shared.grabState[0].lastEvent, leftGesture, buttonHold, gameState, OpenXR::DpadMenuButton::LGrab)) // Don't process normal input when opening dpad menu return; @@ -498,17 +501,10 @@ void processLeftHandInGameInput( // } // return; //} - - if (isGrabPressed) { - // Handle grab action. is_riding_mount check added to prevent conflict with master cycle brake function - if (!gameState.prevent_grab_inputs && !gameState.is_riding_mount) { - buttonHold |= VPAD_BUTTON_A; - } - } - // Master Sword QTE fix. is_riding_mount check to prevent conflict with master cycle brake function - if (isHandNotOverAnySlot(leftGesture) && isGrabPressedLong && !gameState.is_riding_mount) { - if (!gameState.prevent_grab_inputs) { + // Handle interact action. is_riding_mount check added to prevent conflict with master cycle brake function + if (!gameState.prevent_grab_inputs && !gameState.is_riding_mount) { + if (isHandNotOverAnySlot(leftGesture) && isCurrentInteractPressed) { buttonHold |= VPAD_BUTTON_A; } } @@ -529,15 +525,16 @@ void processRightHandInGameInput( constexpr RumbleParameters rightRumbleInfiniteRaise = { true, 1, RumbleType::Raising, 0.5f, true, 1.0, 0.25f, 0.25f }; auto* rumbleMgr = VRManager::instance().XR->GetRumbleManager(); - bool isGrabPressedShort = inputs.inGame.grabState[1].lastEvent == ButtonState::Event::ShortPress; - bool isGrabPressedLong = inputs.inGame.grabState[1].lastEvent == ButtonState::Event::LongPress; - bool isCurrentGrabPressed = inputs.inGame.grabState[1].wasDownLastFrame; + bool isGrabPressedShort = inputs.shared.grabState[1].lastEvent == ButtonState::Event::ShortPress; + bool isGrabPressedLong = inputs.shared.grabState[1].lastEvent == ButtonState::Event::LongPress; + bool isCurrentGrabPressed = inputs.shared.grabState[1].wasDownLastFrame; + bool isCurrentInteractPressed = inputs.inGame.interactState[1].wasDownLastFrame; bool isTriggerPressed = inputs.inGame.useRightItem.currentState; // Handle shoulder slot interactions if (isHandOverLeftShoulderSlot(rightGesture) || isHandOverRightShoulderSlot(rightGesture)) { // Handle dpad menu - if (openDpadMenuBodySlots(inputs.inGame.grabState[1].lastEvent, rightGesture, buttonHold, gameState)) + if (openDpadMenuBodySlots(inputs.shared.grabState[1].lastEvent, rightGesture, buttonHold, gameState, OpenXR::DpadMenuButton::RGrab)) // Don't process normal input when opening dpad menu return; @@ -598,7 +595,7 @@ void processRightHandInGameInput( // Handle waist slot interaction (Rune) if (isHandOverLeftWaistSlot(rightGesture)) { // Handle dpad menu - if (openDpadMenuBodySlots(inputs.inGame.grabState[1].lastEvent, rightGesture, buttonHold, gameState)) + if (openDpadMenuBodySlots(inputs.shared.grabState[1].lastEvent, rightGesture, buttonHold, gameState, OpenXR::DpadMenuButton::RGrab)) // Don't process normal input when opening dpad menu return; @@ -676,16 +673,8 @@ void processRightHandInGameInput( else gameState.right_hand_position_stored = false; - if (isGrabPressedShort) { - // Handle grab action - if (!gameState.prevent_grab_inputs) { - buttonHold |= VPAD_BUTTON_A; - } - } - - // Master Sword QTE fix - if (isHandNotOverAnySlot(rightGesture) && isGrabPressedLong) { - if (!gameState.prevent_grab_inputs) { + if (!gameState.prevent_grab_inputs) { + if (isHandNotOverAnySlot(rightGesture) && isCurrentInteractPressed) { buttonHold |= VPAD_BUTTON_A; } } @@ -802,8 +791,7 @@ void processMenuInput( return state.currentState ? btn : 0; }; - if (!closeDpadMenu(inputs, buttonHold, gameState)) - buttonHold |= mapButton(inputs.inMenu.sort, VPAD_BUTTON_Y); + closeDpadMenu(inputs, buttonHold, gameState); if (!gameState.prevent_inputs) { buttonHold |= mapButton(inputs.inMenu.back, VPAD_BUTTON_B); @@ -814,8 +802,10 @@ void processMenuInput( } buttonHold |= mapButton(inputs.inMenu.select, VPAD_BUTTON_A); + buttonHold |= mapButton(inputs.inMenu.sort, VPAD_BUTTON_Y); buttonHold |= mapButton(inputs.inMenu.leftTrigger, VPAD_BUTTON_L); buttonHold |= mapButton(inputs.inMenu.rightTrigger, VPAD_BUTTON_R); + buttonHold |= mapButton(inputs.inMenu.rotate, VPAD_BUTTON_STICK_R); if (inputs.inMenu.holdState.lastEvent == ButtonState::Event::ShortPress) buttonHold |= VPAD_BUTTON_X; @@ -1048,8 +1038,8 @@ void CemuHooks::hook_InjectXRInput(PPCInterpreter_t* hCPU) { } // Optional rune inputs (for seated players) - openDpadMenuRuneButton(inputs.inGame.useRune_runeMenuState.lastEvent, newXRBtnHold, gameState); - if (inputs.inGame.useRune_runeMenuState.lastEvent == ButtonState::Event::ShortPress) { + openDpadMenuRuneButton(inputs.shared.useRune_runeMenuState.lastEvent, newXRBtnHold, gameState); + if (inputs.shared.useRune_runeMenuState.lastEvent == ButtonState::Event::ShortPress) { newXRBtnHold |= VPAD_BUTTON_L; // Equip rune gameState.last_equip_type_held = EquipType::SheikahSlate; } @@ -1063,9 +1053,9 @@ void CemuHooks::hook_InjectXRInput(PPCInterpreter_t* hCPU) { // A button to interact when riding a mount newXRBtnHold |= mapXRButtonToVpad(inputs.inGame.run_interact, VPAD_BUTTON_A); // grabs to accelerate and brake when riding master cycle - if (inputs.inGame.grab[1].currentState) + if (inputs.inGame.interact[1].currentState) newXRBtnHold |= VPAD_BUTTON_A; - if (inputs.inGame.grab[0].currentState) + if (inputs.inGame.interact[0].currentState) newXRBtnHold |= VPAD_BUTTON_B; } else { @@ -1078,7 +1068,7 @@ void CemuHooks::hook_InjectXRInput(PPCInterpreter_t* hCPU) { // Whistle gesture if (isHandOverMouthSlot(leftGesture) && isHandOverMouthSlot(rightGesture)) { - if (inputs.inGame.grabState[0].wasDownLastFrame && inputs.inGame.grabState[1].wasDownLastFrame) { + if (inputs.shared.grabState[0].wasDownLastFrame && inputs.shared.grabState[1].wasDownLastFrame) { rumbleMgr->enqueueInputsRumbleCommand({ true, 0, RumbleType::OscillationRaisingSawtoothWave, 1.0f, false, 0.25, 0.2f, 0.2f }); newXRBtnHold |= VPAD_BUTTON_DOWN; } @@ -1159,11 +1149,11 @@ void CemuHooks::hook_CreateNewActor(PPCInterpreter_t* hCPU) { // } // // // test if controller is connected - // if (inputs.inGame.grab[OpenXR::EyeSide::LEFT].currentState == XR_TRUE && inputs.inGame.grab[OpenXR::EyeSide::LEFT].changedSinceLastSync == XR_TRUE) { + // if (inputs.shared.grab[OpenXR::EyeSide::LEFT].currentState == XR_TRUE && inputs.shared.grab[OpenXR::EyeSide::LEFT].changedSinceLastSync == XR_TRUE) { // Log::print("Trying to spawn new thing!"); // hCPU->gpr[3] = 1; // } - // else if (inputs.inGame.grab[OpenXR::EyeSide::RIGHT].currentState == XR_TRUE && inputs.inGame.grab[OpenXR::EyeSide::RIGHT].changedSinceLastSync == XR_TRUE) { + // else if (inputs.shared.grab[OpenXR::EyeSide::RIGHT].currentState == XR_TRUE && inputs.shared.grab[OpenXR::EyeSide::RIGHT].changedSinceLastSync == XR_TRUE) { // Log::print("Trying to spawn new thing!"); // hCPU->gpr[3] = 1; // } diff --git a/src/hooking/weapon.cpp b/src/hooking/weapon.cpp index 82a55b0..76132c0 100644 --- a/src/hooking/weapon.cpp +++ b/src/hooking/weapon.cpp @@ -471,7 +471,7 @@ void CemuHooks::hook_EquipWeapon(PPCInterpreter_t* hCPU) { auto input = VRManager::instance().XR->m_input.load(); // Check both hands for a short press to pick up weapon for (int side = 0; side < 2; ++side) { - auto& grabState = input.inGame.grabState[side]; + auto& grabState = input.shared.grabState[side]; // todo: Make sword smaller while its equipped. I think this might be a member value, but otherwise we can just scale the weapon matrix. //if (input.inGame.in_game && grabState.shortPress) { diff --git a/src/rendering/openxr.cpp b/src/rendering/openxr.cpp index 3f08b86..ecee020 100644 --- a/src/rendering/openxr.cpp +++ b/src/rendering/openxr.cpp @@ -275,6 +275,25 @@ void OpenXR::CreateActions() { checkXRResult(xrCreateAction(actionSet, &actionInfo, &action), std::format("Failed to create action for {}", id).c_str()); }; + { + XrActionSetCreateInfo actionSetInfo = { XR_TYPE_ACTION_SET_CREATE_INFO }; + strcpy_s(actionSetInfo.actionSetName, "shared"); + strcpy_s(actionSetInfo.localizedActionSetName, "Shared"); + actionSetInfo.priority = 0; + checkXRResult(xrCreateActionSet(m_instance, &actionSetInfo, &m_sharedActionSet), "Failed to create controller actions for shared!"); + + createAction(m_sharedActionSet, "pose", "Grip Pose", XR_ACTION_TYPE_POSE_INPUT, m_gripPoseAction); + createAction(m_sharedActionSet, "aim_pose", "Aim Pose", XR_ACTION_TYPE_POSE_INPUT, m_aimPoseAction); + + createAction(m_sharedActionSet, "modmenu", "Mod Menu", XR_ACTION_TYPE_BOOLEAN_INPUT, m_modMenuAction); + createAction(m_sharedActionSet, "inventory_map", "Open/Close Inventory (Quick press) - Open/Close Map (Long press)", XR_ACTION_TYPE_BOOLEAN_INPUT, m_inventory_mapAction); + + createAction(m_sharedActionSet, "grab", "Grab or select weapon/rune from body slots", XR_ACTION_TYPE_FLOAT_INPUT, m_grabAction); + createAction(m_sharedActionSet, "userune_dpadmenu", "Use Rune (Quick press) - Rune menu (Long press)", XR_ACTION_TYPE_BOOLEAN_INPUT, m_useRune_dpadMenu_Action); + + createAction(m_sharedActionSet, "rumble", "Rumble", XR_ACTION_TYPE_VIBRATION_OUTPUT, m_rumbleAction); + } + { XrActionSetCreateInfo actionSetInfo = { XR_TYPE_ACTION_SET_CREATE_INFO }; strcpy_s(actionSetInfo.actionSetName, "gameplay_fps"); @@ -282,24 +301,17 @@ void OpenXR::CreateActions() { actionSetInfo.priority = 0; checkXRResult(xrCreateActionSet(m_instance, &actionSetInfo, &m_gameplayActionSet), "Failed to create controller actions for gameplay_fps!"); - createAction(m_gameplayActionSet, "pose", "Grip Pose", XR_ACTION_TYPE_POSE_INPUT, m_inGameGripPoseAction); - createAction(m_gameplayActionSet, "aim_pose", "Aim Pose", XR_ACTION_TYPE_POSE_INPUT, m_inGameAimPoseAction); createAction(m_gameplayActionSet, "move", "Move", XR_ACTION_TYPE_VECTOR2F_INPUT, m_moveAction); createAction(m_gameplayActionSet, "camera", "Camera Rotation", XR_ACTION_TYPE_VECTOR2F_INPUT, m_cameraAction); - createAction(m_gameplayActionSet, "ingame_modmenu", "Mod Menu", XR_ACTION_TYPE_BOOLEAN_INPUT, m_inGame_modMenuAction); - createAction(m_gameplayActionSet, "grab_interact", "Interact / Pick up objects from floor or weapon from body slots", XR_ACTION_TYPE_FLOAT_INPUT, m_grab_interactAction); + createAction(m_gameplayActionSet, "interact", "Interact / Pick up objects from floor", XR_ACTION_TYPE_FLOAT_INPUT, m_interactAction); createAction(m_gameplayActionSet, "jump", "Jump", XR_ACTION_TYPE_BOOLEAN_INPUT, m_jumpAction); createAction(m_gameplayActionSet, "run_interact_cancel", "Interact (Quick press) - Run/Cancel Interaction (Long press)", XR_ACTION_TYPE_BOOLEAN_INPUT, m_run_interactAction); - createAction(m_gameplayActionSet, "userune_dpadmenu", "Use Rune (Quick press) - Dpad menu (Long press)", XR_ACTION_TYPE_BOOLEAN_INPUT, m_useRune_dpadMenu_Action); createAction(m_gameplayActionSet, "userighthanditem", "Use/Attack/Throw item held in right hand (Melee attacks/Draw bow/Throw object)", XR_ACTION_TYPE_BOOLEAN_INPUT, m_useRightItemAction); createAction(m_gameplayActionSet, "uselefthanditem", "Use item held in left hand (Rune/Shield Parry)", XR_ACTION_TYPE_BOOLEAN_INPUT, m_useLeftItemAction); createAction(m_gameplayActionSet, "crouch_scope", "Crouch (Quick press) - Open Scope (Long press)", XR_ACTION_TYPE_BOOLEAN_INPUT, m_crouch_scopeAction); - createAction(m_gameplayActionSet, "ingame_inventory_map", "Open Inventory (Quick press) - Open Map (Long press)", XR_ACTION_TYPE_BOOLEAN_INPUT, m_inGame_inventory_mapAction); - - createAction(m_gameplayActionSet, "rumble", "Rumble", XR_ACTION_TYPE_VIBRATION_OUTPUT, m_rumbleAction); } { @@ -309,11 +321,8 @@ void OpenXR::CreateActions() { actionSetInfo.priority = 0; checkXRResult(xrCreateActionSet(m_instance, &actionSetInfo, &m_menuActionSet), "Failed to create controller bindings for the menu!"); - createAction(m_menuActionSet, "pose", "Grip Pose", XR_ACTION_TYPE_POSE_INPUT, m_inMenuGripPoseAction); - createAction(m_menuActionSet, "aim_pose", "Aim Pose", XR_ACTION_TYPE_POSE_INPUT, m_inMenuAimPoseAction); - - createAction(m_menuActionSet, "scroll", "Scroll (Left Thumbstick)", XR_ACTION_TYPE_VECTOR2F_INPUT, m_scrollAction); - createAction(m_menuActionSet, "navigate", "Navigate (Right Thumbstick)", XR_ACTION_TYPE_VECTOR2F_INPUT, m_navigateAction); + createAction(m_menuActionSet, "scroll", "Scroll (Right Thumbstick)", XR_ACTION_TYPE_VECTOR2F_INPUT, m_scrollAction); + createAction(m_menuActionSet, "navigate", "Navigate (Left Thumbstick)", XR_ACTION_TYPE_VECTOR2F_INPUT, m_navigateAction); createAction(m_menuActionSet, "select", "Select (A Button)", XR_ACTION_TYPE_BOOLEAN_INPUT, m_selectAction); createAction(m_menuActionSet, "cancel", "Back/Cancel (B Button)", XR_ACTION_TYPE_BOOLEAN_INPUT, m_backAction); createAction(m_menuActionSet, "sort", "Sort (Y Button)", XR_ACTION_TYPE_BOOLEAN_INPUT, m_sortAction); @@ -322,22 +331,25 @@ void OpenXR::CreateActions() { createAction(m_menuActionSet, "right_grip", "Switch To Right Tab (R Button)", XR_ACTION_TYPE_BOOLEAN_INPUT, m_rightGripAction); createAction(m_menuActionSet, "lefttrigger", "Left Trigger", XR_ACTION_TYPE_BOOLEAN_INPUT, m_leftTriggerAction); createAction(m_menuActionSet, "righttrigger", "Right Trigger", XR_ACTION_TYPE_BOOLEAN_INPUT, m_rightTriggerAction); - - createAction(m_menuActionSet, "inmenu_inventory_map", "Close Inventory (Wii U - Start Button) - Close Map (Wii U - Select Button)", XR_ACTION_TYPE_BOOLEAN_INPUT, m_inMenu_inventory_mapAction); - createAction(m_menuActionSet, "inmenu_modmenu", "Mod Menu", XR_ACTION_TYPE_BOOLEAN_INPUT, m_inMenu_modMenuAction); + createAction(m_menuActionSet, "rotate", "Rotate (In inventory) (Right Thumbstick Click)", XR_ACTION_TYPE_BOOLEAN_INPUT, m_rotateAction); } { std::array suggestedBindings = { + // === shared suggestions === + XrActionSuggestedBinding{ .action = m_gripPoseAction, .binding = GetXRPath("/user/hand/left/input/grip/pose") }, + XrActionSuggestedBinding{ .action = m_gripPoseAction, .binding = GetXRPath("/user/hand/right/input/grip/pose") }, + XrActionSuggestedBinding{ .action = m_aimPoseAction, .binding = GetXRPath("/user/hand/left/input/aim/pose") }, + XrActionSuggestedBinding{ .action = m_aimPoseAction, .binding = GetXRPath("/user/hand/right/input/aim/pose") }, + + XrActionSuggestedBinding{ .action = m_grabAction, .binding = GetXRPath("/user/hand/left/input/select/click") }, + XrActionSuggestedBinding{ .action = m_grabAction, .binding = GetXRPath("/user/hand/right/input/select/click") }, + // === gameplay suggestions === - XrActionSuggestedBinding{ .action = m_inGameGripPoseAction, .binding = GetXRPath("/user/hand/left/input/grip/pose") }, - XrActionSuggestedBinding{ .action = m_inGameGripPoseAction, .binding = GetXRPath("/user/hand/right/input/grip/pose") }, - XrActionSuggestedBinding{ .action = m_inGameAimPoseAction, .binding = GetXRPath("/user/hand/left/input/aim/pose") }, - XrActionSuggestedBinding{ .action = m_inGameAimPoseAction, .binding = GetXRPath("/user/hand/right/input/aim/pose") }, XrActionSuggestedBinding{ .action = m_crouch_scopeAction, .binding = GetXRPath("/user/hand/left/input/menu/click") }, - XrActionSuggestedBinding{ .action = m_grab_interactAction, .binding = GetXRPath("/user/hand/left/input/select/click") }, - XrActionSuggestedBinding{ .action = m_grab_interactAction, .binding = GetXRPath("/user/hand/right/input/select/click") }, + XrActionSuggestedBinding{ .action = m_interactAction, .binding = GetXRPath("/user/hand/left/input/select/click") }, + XrActionSuggestedBinding{ .action = m_interactAction, .binding = GetXRPath("/user/hand/right/input/select/click") }, // === menu suggestions === //XrActionSuggestedBinding{ .action = m_inMenu_mapAction, .binding = GetXRPath("/user/hand/right/input/menu/click") }, @@ -355,35 +367,37 @@ void OpenXR::CreateActions() { { std::array suggestedBindings = { + // === shared suggestions === + XrActionSuggestedBinding{ .action = m_gripPoseAction, .binding = GetXRPath("/user/hand/left/input/grip/pose") }, + XrActionSuggestedBinding{ .action = m_gripPoseAction, .binding = GetXRPath("/user/hand/right/input/grip/pose") }, + XrActionSuggestedBinding{ .action = m_aimPoseAction, .binding = GetXRPath("/user/hand/left/input/aim/pose") }, + XrActionSuggestedBinding{ .action = m_aimPoseAction, .binding = GetXRPath("/user/hand/right/input/aim/pose") }, + + XrActionSuggestedBinding{ .action = m_grabAction, .binding = GetXRPath("/user/hand/left/input/squeeze/value") }, + XrActionSuggestedBinding{ .action = m_grabAction, .binding = GetXRPath("/user/hand/right/input/squeeze/value") }, + + XrActionSuggestedBinding{ .action = m_useRune_dpadMenu_Action, .binding = GetXRPath("/user/hand/left/input/y/click") }, + XrActionSuggestedBinding{ .action = m_modMenuAction, .binding = GetXRPath("/user/hand/left/input/x/click") }, + XrActionSuggestedBinding{ .action = m_inventory_mapAction, .binding = GetXRPath("/user/hand/right/input/thumbstick/click") }, + + XrActionSuggestedBinding{ .action = m_rumbleAction, .binding = GetXRPath("/user/hand/left/output/haptic") }, + XrActionSuggestedBinding{ .action = m_rumbleAction, .binding = GetXRPath("/user/hand/right/output/haptic") }, + // === gameplay suggestions === - XrActionSuggestedBinding{ .action = m_inGameGripPoseAction, .binding = GetXRPath("/user/hand/left/input/grip/pose") }, - XrActionSuggestedBinding{ .action = m_inGameGripPoseAction, .binding = GetXRPath("/user/hand/right/input/grip/pose") }, - XrActionSuggestedBinding{ .action = m_inGameAimPoseAction, .binding = GetXRPath("/user/hand/left/input/aim/pose") }, - XrActionSuggestedBinding{ .action = m_inGameAimPoseAction, .binding = GetXRPath("/user/hand/right/input/aim/pose") }, XrActionSuggestedBinding{ .action = m_moveAction, .binding = GetXRPath("/user/hand/left/input/thumbstick") }, XrActionSuggestedBinding{ .action = m_cameraAction, .binding = GetXRPath("/user/hand/right/input/thumbstick") }, - XrActionSuggestedBinding{ .action = m_grab_interactAction, .binding = GetXRPath("/user/hand/left/input/squeeze/value") }, - XrActionSuggestedBinding{ .action = m_grab_interactAction, .binding = GetXRPath("/user/hand/right/input/squeeze/value") }, + XrActionSuggestedBinding{ .action = m_interactAction, .binding = GetXRPath("/user/hand/left/input/squeeze/value") }, + XrActionSuggestedBinding{ .action = m_interactAction, .binding = GetXRPath("/user/hand/right/input/squeeze/value") }, XrActionSuggestedBinding{ .action = m_jumpAction, .binding = GetXRPath("/user/hand/right/input/b/click") }, XrActionSuggestedBinding{ .action = m_run_interactAction, .binding = GetXRPath("/user/hand/right/input/a/click") }, - XrActionSuggestedBinding{ .action = m_useRune_dpadMenu_Action, .binding = GetXRPath("/user/hand/left/input/y/click") }, - XrActionSuggestedBinding{ .action = m_inGame_modMenuAction, .binding = GetXRPath("/user/hand/left/input/x/click") }, XrActionSuggestedBinding{ .action = m_useLeftItemAction, .binding = GetXRPath("/user/hand/left/input/trigger/value") }, XrActionSuggestedBinding{ .action = m_useRightItemAction, .binding = GetXRPath("/user/hand/right/input/trigger/value") }, XrActionSuggestedBinding{ .action = m_crouch_scopeAction, .binding = GetXRPath("/user/hand/left/input/thumbstick/click") }, - XrActionSuggestedBinding{ .action = m_inGame_inventory_mapAction, .binding = GetXRPath("/user/hand/right/input/thumbstick/click") }, - - XrActionSuggestedBinding{ .action = m_rumbleAction, .binding = GetXRPath("/user/hand/left/output/haptic") }, - XrActionSuggestedBinding{ .action = m_rumbleAction, .binding = GetXRPath("/user/hand/right/output/haptic") }, // === menu suggestions === - XrActionSuggestedBinding{ .action = m_inMenuGripPoseAction, .binding = GetXRPath("/user/hand/left/input/grip/pose") }, - XrActionSuggestedBinding{ .action = m_inMenuGripPoseAction, .binding = GetXRPath("/user/hand/right/input/grip/pose") }, - XrActionSuggestedBinding{ .action = m_inMenuAimPoseAction, .binding = GetXRPath("/user/hand/left/input/aim/pose") }, - XrActionSuggestedBinding{ .action = m_inMenuAimPoseAction, .binding = GetXRPath("/user/hand/right/input/aim/pose") }, XrActionSuggestedBinding{ .action = m_scrollAction, .binding = GetXRPath("/user/hand/right/input/thumbstick") }, XrActionSuggestedBinding{ .action = m_navigateAction, .binding = GetXRPath("/user/hand/left/input/thumbstick") }, XrActionSuggestedBinding{ .action = m_selectAction, .binding = GetXRPath("/user/hand/right/input/a/click") }, @@ -394,8 +408,7 @@ void OpenXR::CreateActions() { XrActionSuggestedBinding{ .action = m_rightGripAction, .binding = GetXRPath("/user/hand/right/input/squeeze/value") }, XrActionSuggestedBinding{ .action = m_leftTriggerAction, .binding = GetXRPath("/user/hand/left/input/trigger/value") }, XrActionSuggestedBinding{ .action = m_rightTriggerAction, .binding = GetXRPath("/user/hand/right/input/trigger/value") }, - XrActionSuggestedBinding{ .action = m_inMenu_inventory_mapAction, .binding = GetXRPath("/user/hand/right/input/thumbstick/click") }, - XrActionSuggestedBinding{ .action = m_inMenu_modMenuAction, .binding = GetXRPath("/user/hand/left/input/x/click") }, + XrActionSuggestedBinding{ .action = m_rotateAction, .binding = GetXRPath("/user/hand/left/input/thumbstick/click") }, }; XrInteractionProfileSuggestedBinding suggestedBindingsInfo = { XR_TYPE_INTERACTION_PROFILE_SUGGESTED_BINDING }; suggestedBindingsInfo.interactionProfile = GetXRPath("/interaction_profiles/oculus/touch_controller"); @@ -406,35 +419,37 @@ void OpenXR::CreateActions() { { std::array suggestedBindings = { + // === shared suggestions === + XrActionSuggestedBinding{ .action = m_gripPoseAction, .binding = GetXRPath("/user/hand/left/input/grip/pose") }, + XrActionSuggestedBinding{ .action = m_gripPoseAction, .binding = GetXRPath("/user/hand/right/input/grip/pose") }, + XrActionSuggestedBinding{ .action = m_aimPoseAction, .binding = GetXRPath("/user/hand/left/input/aim/pose") }, + XrActionSuggestedBinding{ .action = m_aimPoseAction, .binding = GetXRPath("/user/hand/right/input/aim/pose") }, + + XrActionSuggestedBinding{ .action = m_grabAction, .binding = GetXRPath("/user/hand/left/input/squeeze/force") }, + XrActionSuggestedBinding{ .action = m_grabAction, .binding = GetXRPath("/user/hand/right/input/squeeze/force") }, + + XrActionSuggestedBinding{ .action = m_useRune_dpadMenu_Action, .binding = GetXRPath("/user/hand/left/input/b/click") }, + XrActionSuggestedBinding{ .action = m_modMenuAction, .binding = GetXRPath("/user/hand/left/input/a/click") }, + XrActionSuggestedBinding{ .action = m_inventory_mapAction, .binding = GetXRPath("/user/hand/right/input/thumbstick/click") }, + + XrActionSuggestedBinding{ .action = m_rumbleAction, .binding = GetXRPath("/user/hand/left/output/haptic") }, + XrActionSuggestedBinding{ .action = m_rumbleAction, .binding = GetXRPath("/user/hand/right/output/haptic") }, + // === gameplay suggestions === - XrActionSuggestedBinding{ .action = m_inGameGripPoseAction, .binding = GetXRPath("/user/hand/left/input/grip/pose") }, - XrActionSuggestedBinding{ .action = m_inGameGripPoseAction, .binding = GetXRPath("/user/hand/right/input/grip/pose") }, - XrActionSuggestedBinding{ .action = m_inGameAimPoseAction, .binding = GetXRPath("/user/hand/left/input/aim/pose") }, - XrActionSuggestedBinding{ .action = m_inGameAimPoseAction, .binding = GetXRPath("/user/hand/right/input/aim/pose") }, XrActionSuggestedBinding{ .action = m_moveAction, .binding = GetXRPath("/user/hand/left/input/thumbstick") }, XrActionSuggestedBinding{ .action = m_cameraAction, .binding = GetXRPath("/user/hand/right/input/thumbstick") }, - XrActionSuggestedBinding{ .action = m_grab_interactAction, .binding = GetXRPath("/user/hand/left/input/squeeze/force") }, - XrActionSuggestedBinding{ .action = m_grab_interactAction, .binding = GetXRPath("/user/hand/right/input/squeeze/force") }, + XrActionSuggestedBinding{ .action = m_interactAction, .binding = GetXRPath("/user/hand/left/input/squeeze/force") }, + XrActionSuggestedBinding{ .action = m_interactAction, .binding = GetXRPath("/user/hand/right/input/squeeze/force") }, XrActionSuggestedBinding{ .action = m_jumpAction, .binding = GetXRPath("/user/hand/right/input/b/click") }, XrActionSuggestedBinding{ .action = m_run_interactAction, .binding = GetXRPath("/user/hand/right/input/a/click") }, - XrActionSuggestedBinding{ .action = m_useRune_dpadMenu_Action, .binding = GetXRPath("/user/hand/left/input/b/click") }, - XrActionSuggestedBinding{ .action = m_inGame_modMenuAction, .binding = GetXRPath("/user/hand/left/input/a/click") }, XrActionSuggestedBinding{ .action = m_useLeftItemAction, .binding = GetXRPath("/user/hand/left/input/trigger/value") }, XrActionSuggestedBinding{ .action = m_useRightItemAction, .binding = GetXRPath("/user/hand/right/input/trigger/value") }, XrActionSuggestedBinding{ .action = m_crouch_scopeAction, .binding = GetXRPath("/user/hand/left/input/thumbstick/click") }, - XrActionSuggestedBinding{ .action = m_inGame_inventory_mapAction, .binding = GetXRPath("/user/hand/right/input/thumbstick/click") }, - - XrActionSuggestedBinding{ .action = m_rumbleAction, .binding = GetXRPath("/user/hand/left/output/haptic") }, - XrActionSuggestedBinding{ .action = m_rumbleAction, .binding = GetXRPath("/user/hand/right/output/haptic") }, // === menu suggestions === - XrActionSuggestedBinding{ .action = m_inMenuGripPoseAction, .binding = GetXRPath("/user/hand/left/input/grip/pose") }, - XrActionSuggestedBinding{ .action = m_inMenuGripPoseAction, .binding = GetXRPath("/user/hand/right/input/grip/pose") }, - XrActionSuggestedBinding{ .action = m_inMenuAimPoseAction, .binding = GetXRPath("/user/hand/left/input/aim/pose") }, - XrActionSuggestedBinding{ .action = m_inMenuAimPoseAction, .binding = GetXRPath("/user/hand/right/input/aim/pose") }, XrActionSuggestedBinding{ .action = m_scrollAction, .binding = GetXRPath("/user/hand/right/input/thumbstick") }, XrActionSuggestedBinding{ .action = m_navigateAction, .binding = GetXRPath("/user/hand/left/input/thumbstick") }, XrActionSuggestedBinding{ .action = m_selectAction, .binding = GetXRPath("/user/hand/right/input/a/click") }, @@ -445,8 +460,7 @@ void OpenXR::CreateActions() { XrActionSuggestedBinding{ .action = m_rightGripAction, .binding = GetXRPath("/user/hand/right/input/squeeze/force") }, XrActionSuggestedBinding{ .action = m_leftTriggerAction, .binding = GetXRPath("/user/hand/left/input/trigger/value") }, XrActionSuggestedBinding{ .action = m_rightTriggerAction, .binding = GetXRPath("/user/hand/right/input/trigger/value") }, - XrActionSuggestedBinding{ .action = m_inMenu_inventory_mapAction, .binding = GetXRPath("/user/hand/right/input/thumbstick/click") }, - XrActionSuggestedBinding{ .action = m_inMenu_modMenuAction, .binding = GetXRPath("/user/hand/left/input/a/click") }, + XrActionSuggestedBinding{ .action = m_rotateAction, .binding = GetXRPath("/user/hand/left/input/thumbstick/click") }, }; XrInteractionProfileSuggestedBinding suggestedBindingsInfo = { XR_TYPE_INTERACTION_PROFILE_SUGGESTED_BINDING }; suggestedBindingsInfo.interactionProfile = GetXRPath("/interaction_profiles/valve/index_controller"); @@ -456,25 +470,17 @@ void OpenXR::CreateActions() { } XrSessionActionSetsAttachInfo attachInfo = { XR_TYPE_SESSION_ACTION_SETS_ATTACH_INFO }; - std::array actionSets = { m_gameplayActionSet, m_menuActionSet }; + std::array actionSets = { m_sharedActionSet, m_gameplayActionSet, m_menuActionSet }; attachInfo.countActionSets = (uint32_t)actionSets.size(); attachInfo.actionSets = actionSets.data(); checkXRResult(xrAttachSessionActionSets(m_session, &attachInfo), "Failed to attach action sets to session!"); for (EyeSide side : { EyeSide::LEFT, EyeSide::RIGHT }) { XrActionSpaceCreateInfo createInfo = { XR_TYPE_ACTION_SPACE_CREATE_INFO }; - createInfo.action = m_inGameGripPoseAction; - createInfo.subactionPath = m_handPaths[side]; - createInfo.poseInActionSpace = s_xrIdentityPose; - checkXRResult(xrCreateActionSpace(m_session, &createInfo, &m_inGameHandSpaces[side]), "Failed to create action space for hand pose!"); - } - - for (EyeSide side : { EyeSide::LEFT, EyeSide::RIGHT }) { - XrActionSpaceCreateInfo createInfo = { XR_TYPE_ACTION_SPACE_CREATE_INFO }; - createInfo.action = m_inMenuGripPoseAction; + createInfo.action = m_gripPoseAction; createInfo.subactionPath = m_handPaths[side]; createInfo.poseInActionSpace = s_xrIdentityPose; - checkXRResult(xrCreateActionSpace(m_session, &createInfo, &m_inMenuHandSpaces[side]), "Failed to create action space for hand pose!"); + checkXRResult(xrCreateActionSpace(m_session, &createInfo, &m_handSpaces[side]), "Failed to create action space for hand pose!"); } // initialize rumble manager @@ -527,11 +533,11 @@ void CheckButtonState(bool buttonPressed, ButtonState& buttonState) { } std::optional OpenXR::UpdateActions(XrTime predictedFrameTime, glm::fquat controllerRotation, bool inMenu) { - XrActiveActionSet activeActionSet = { (inMenu ? m_menuActionSet : m_gameplayActionSet), XR_NULL_PATH }; + XrActiveActionSet activeActionSets[2] = { { m_sharedActionSet, XR_NULL_PATH }, { (inMenu ? m_menuActionSet : m_gameplayActionSet), XR_NULL_PATH } }; XrActionsSyncInfo syncInfo = { XR_TYPE_ACTIONS_SYNC_INFO }; - syncInfo.countActiveActionSets = 1; - syncInfo.activeActionSets = &activeActionSet; + syncInfo.countActiveActionSets = 2; + syncInfo.activeActionSets = &activeActionSets[0]; checkXRResult(xrSyncActions(m_session, &syncInfo), "Failed to sync actions!"); InputState newState = m_input.load(); @@ -540,7 +546,7 @@ std::optional OpenXR::UpdateActions(XrTime predictedFrameTim for (EyeSide side : { EyeSide::LEFT, EyeSide::RIGHT }) { XrActionStateGetInfo getPoseInfo = { XR_TYPE_ACTION_STATE_GET_INFO }; - getPoseInfo.action = newState.shared.in_game ? m_inGameGripPoseAction : m_inMenuGripPoseAction; + getPoseInfo.action = m_gripPoseAction; getPoseInfo.subactionPath = m_handPaths[side]; newState.shared.pose[side] = { XR_TYPE_ACTION_STATE_POSE }; checkXRResult(xrGetActionStatePose(m_session, &getPoseInfo, &newState.shared.pose[side]), "Failed to get pose of controller!"); @@ -551,7 +557,7 @@ std::optional OpenXR::UpdateActions(XrTime predictedFrameTim spaceLocation.next = &spaceVelocity; newState.shared.poseVelocity[side].linearVelocity = { 0.0f, 0.0f, 0.0f }; newState.shared.poseVelocity[side].angularVelocity = { 0.0f, 0.0f, 0.0f }; - XrSpace handSpace = newState.shared.in_game ? m_inGameHandSpaces[side] : m_inMenuHandSpaces[side]; + XrSpace handSpace = m_handSpaces[side]; checkXRResult(xrLocateSpace(handSpace, m_stageSpace, predictedFrameTime, &spaceLocation), "Failed to get location from controllers!"); if ((spaceLocation.locationFlags & XR_SPACE_LOCATION_POSITION_VALID_BIT) != 0 && (spaceLocation.locationFlags & XR_SPACE_LOCATION_ORIENTATION_VALID_BIT) != 0) { newState.shared.poseLocation[side] = spaceLocation; @@ -574,7 +580,7 @@ std::optional OpenXR::UpdateActions(XrTime predictedFrameTim } // update shared actions XrActionStateGetInfo getInventoryMapInfo = { XR_TYPE_ACTION_STATE_GET_INFO }; - getInventoryMapInfo.action = newState.shared.in_game ? m_inGame_inventory_mapAction : m_inMenu_inventory_mapAction; + getInventoryMapInfo.action = m_inventory_mapAction; getInventoryMapInfo.subactionPath = XR_NULL_PATH; auto& inventory_mapAction = newState.shared.inventory_map; inventory_mapAction = { XR_TYPE_ACTION_STATE_BOOLEAN }; @@ -587,7 +593,7 @@ std::optional OpenXR::UpdateActions(XrTime predictedFrameTim } XrActionStateGetInfo getModMenuInfo = { XR_TYPE_ACTION_STATE_GET_INFO }; - getModMenuInfo.action = newState.shared.in_game ? m_inGame_modMenuAction : m_inMenu_modMenuAction; + getModMenuInfo.action = m_modMenuAction; getModMenuInfo.subactionPath = XR_NULL_PATH; auto& modMenuAction = newState.shared.modMenu; modMenuAction = { XR_TYPE_ACTION_STATE_BOOLEAN }; @@ -599,6 +605,32 @@ std::optional OpenXR::UpdateActions(XrTime predictedFrameTim CheckButtonState(buttonPressed, modMenuButtonState); } + for (EyeSide side : { EyeSide::LEFT, EyeSide::RIGHT }) { + XrActionStateGetInfo getGrabInfo = { XR_TYPE_ACTION_STATE_GET_INFO }; + getGrabInfo.action = m_grabAction; + getGrabInfo.subactionPath = m_handPaths[side]; + newState.shared.grab[side] = { XR_TYPE_ACTION_STATE_FLOAT }; + checkXRResult(xrGetActionStateFloat(m_session, &getGrabInfo, &newState.shared.grab[side]), "Failed to get grab action value!"); + + auto& buttonState = newState.shared.grabState[side]; + if (newState.shared.grab[side].isActive == XR_TRUE) { + auto buttonPressed = newState.shared.grab[side].currentState > 0.75f; + CheckButtonState(buttonPressed, buttonState); + } + } + + XrActionStateGetInfo getUseRuneInfo = { XR_TYPE_ACTION_STATE_GET_INFO }; + getUseRuneInfo.action = m_useRune_dpadMenu_Action; + getUseRuneInfo.subactionPath = XR_NULL_PATH; + newState.shared.useRune_dpadMenu = { XR_TYPE_ACTION_STATE_BOOLEAN }; + checkXRResult(xrGetActionStateBoolean(m_session, &getUseRuneInfo, &newState.shared.useRune_dpadMenu), "Failed to get use rune action value!"); + + auto& useRuneButtonState = newState.shared.useRune_runeMenuState; + if (newState.shared.useRune_dpadMenu.isActive == XR_TRUE) { + auto buttonPressed = newState.shared.useRune_dpadMenu.currentState == XR_TRUE; + CheckButtonState(buttonPressed, useRuneButtonState); + } + // update in-menu or in-game actions if (inMenu) { XrActionStateGetInfo getScrollInfo = { XR_TYPE_ACTION_STATE_GET_INFO }; @@ -666,18 +698,24 @@ std::optional OpenXR::UpdateActions(XrTime predictedFrameTim getRightTriggerInfo.subactionPath = XR_NULL_PATH; newState.inMenu.rightTrigger = { XR_TYPE_ACTION_STATE_BOOLEAN }; checkXRResult(xrGetActionStateBoolean(m_session, &getRightTriggerInfo, &newState.inMenu.rightTrigger), "Failed to get right trigger action value!"); + + XrActionStateGetInfo getRotateInfo = { XR_TYPE_ACTION_STATE_GET_INFO }; + getRotateInfo.action = m_rotateAction; + getRotateInfo.subactionPath = XR_NULL_PATH; + newState.inMenu.rotate = { XR_TYPE_ACTION_STATE_BOOLEAN }; + checkXRResult(xrGetActionStateBoolean(m_session, &getRotateInfo, &newState.inMenu.rotate), "Failed to get rotate action value!"); } else { for (EyeSide side : { EyeSide::LEFT, EyeSide::RIGHT }) { XrActionStateGetInfo getGrabInfo = { XR_TYPE_ACTION_STATE_GET_INFO }; - getGrabInfo.action = m_grab_interactAction; + getGrabInfo.action = m_interactAction; getGrabInfo.subactionPath = m_handPaths[side]; - newState.inGame.grab[side] = { XR_TYPE_ACTION_STATE_FLOAT }; - checkXRResult(xrGetActionStateFloat(m_session, &getGrabInfo, &newState.inGame.grab[side]), "Failed to get grab action value!"); + newState.inGame.interact[side] = { XR_TYPE_ACTION_STATE_FLOAT }; + checkXRResult(xrGetActionStateFloat(m_session, &getGrabInfo, &newState.inGame.interact[side]), "Failed to get grab action value!"); - auto& buttonState = newState.inGame.grabState[side]; - if (newState.inGame.grab[side].isActive == XR_TRUE) { - auto buttonPressed = newState.inGame.grab[side].currentState > 0.75f; + auto& buttonState = newState.inGame.interactState[side]; + if (newState.inGame.interact[side].isActive == XR_TRUE) { + auto buttonPressed = newState.inGame.interact[side].currentState > 0.75f; CheckButtonState(buttonPressed, buttonState); } } @@ -722,18 +760,6 @@ std::optional OpenXR::UpdateActions(XrTime predictedFrameTim CheckButtonState(buttonPressed, runButtonState); } - XrActionStateGetInfo getUseRuneInfo = { XR_TYPE_ACTION_STATE_GET_INFO }; - getUseRuneInfo.action = m_useRune_dpadMenu_Action; - getUseRuneInfo.subactionPath = XR_NULL_PATH; - newState.inGame.useRune_dpadMenu = { XR_TYPE_ACTION_STATE_BOOLEAN }; - checkXRResult(xrGetActionStateBoolean(m_session, &getUseRuneInfo, &newState.inGame.useRune_dpadMenu), "Failed to get use rune action value!"); - - auto& useRuneButtonState = newState.inGame.useRune_runeMenuState; - if (newState.inGame.useRune_dpadMenu.isActive == XR_TRUE) { - auto buttonPressed = newState.inGame.useRune_dpadMenu.currentState == XR_TRUE; - CheckButtonState(buttonPressed, useRuneButtonState); - } - XrActionStateGetInfo getUseRightItemInfo = { XR_TYPE_ACTION_STATE_GET_INFO }; getUseRightItemInfo.action = m_useRightItemAction; getUseRightItemInfo.subactionPath = XR_NULL_PATH; diff --git a/src/rendering/openxr.h b/src/rendering/openxr.h index ede8927..51a4171 100644 --- a/src/rendering/openxr.h +++ b/src/rendering/openxr.h @@ -65,6 +65,11 @@ class OpenXR { ButtonState inventory_mapState; XrActionStateBoolean modMenu; ButtonState modMenuState; + + std::array grab; + std::array grabState; // LEFT/RIGHT + XrActionStateBoolean useRune_dpadMenu; + ButtonState useRune_runeMenuState; } shared; struct InGame { @@ -74,19 +79,17 @@ class OpenXR { XrActionStateVector2f move; XrActionStateVector2f camera; - std::array grab; + std::array interact; XrActionStateBoolean jump_cancel; XrActionStateBoolean run_interact; ButtonState runState; - XrActionStateBoolean useRune_dpadMenu; - ButtonState useRune_runeMenuState; XrActionStateBoolean useLeftItem; XrActionStateBoolean useRightItem; std::array drop_weapon; // LEFT/RIGHT - std::array grabState; // LEFT/RIGHT + std::array interactState; // LEFT/RIGHT } inGame; struct InMenu { XrActionStateVector2f scroll; @@ -103,11 +106,26 @@ class OpenXR { XrActionStateBoolean leftTrigger; XrActionStateBoolean rightTrigger; + + XrActionStateBoolean rotate; } inMenu; }; std::atomic m_input = InputState{}; std::atomic m_inputCameraRotation = glm::identity(); + class DpadMenuButton { + public: + static bool LGrab(InputState inputState) { + return inputState.shared.grabState[0].wasDownLastFrame; + }; + static bool RGrab(InputState inputState) { + return inputState.shared.grabState[1].wasDownLastFrame; + }; + static bool Rune(InputState inputState) { + return inputState.shared.useRune_runeMenuState.wasDownLastFrame; + }; + }; + struct GameState { uint32_t previous_button_hold; bool in_game = false; @@ -116,6 +134,7 @@ class OpenXR { bool dpad_menu_open_requested = false; bool was_dpad_menu_open = false; EquipType last_dpad_menu_open = EquipType::None; + bool (*current_dpad_menu_button)(InputState) = nullptr; bool prevent_inputs = false; std::chrono::steady_clock::time_point prevent_inputs_time; @@ -196,33 +215,36 @@ class OpenXR { XrSession m_session = XR_NULL_HANDLE; XrSpace m_stageSpace = XR_NULL_HANDLE; XrSpace m_headSpace = XR_NULL_HANDLE; - std::array m_inGameHandSpaces = { XR_NULL_HANDLE, XR_NULL_HANDLE }; - std::array m_inMenuHandSpaces = { XR_NULL_HANDLE, XR_NULL_HANDLE }; + std::array m_handSpaces = { XR_NULL_HANDLE, XR_NULL_HANDLE }; std::array m_handPaths = { XR_NULL_PATH, XR_NULL_PATH }; - XrAction m_inGameGripPoseAction = XR_NULL_HANDLE; - XrAction m_inGameAimPoseAction = XR_NULL_HANDLE; - XrAction m_inMenuGripPoseAction = XR_NULL_HANDLE; - XrAction m_inMenuAimPoseAction = XR_NULL_HANDLE; + //shared actions + XrActionSet m_sharedActionSet = XR_NULL_HANDLE; + + XrAction m_gripPoseAction = XR_NULL_HANDLE; + XrAction m_aimPoseAction = XR_NULL_HANDLE; + + XrAction m_modMenuAction = XR_NULL_HANDLE; //imgui mod menu + XrAction m_inventory_mapAction = XR_NULL_HANDLE; + + XrAction m_grabAction = XR_NULL_HANDLE; + XrAction m_useRune_dpadMenu_Action = XR_NULL_HANDLE; + + XrAction m_rumbleAction = XR_NULL_HANDLE; // gameplay actions XrActionSet m_gameplayActionSet = XR_NULL_HANDLE; XrAction m_moveAction = XR_NULL_HANDLE; XrAction m_cameraAction = XR_NULL_HANDLE; - XrAction m_grab_interactAction = XR_NULL_HANDLE; + XrAction m_interactAction = XR_NULL_HANDLE; XrAction m_jumpAction = XR_NULL_HANDLE; XrAction m_run_interactAction = XR_NULL_HANDLE; - XrAction m_useRune_dpadMenu_Action = XR_NULL_HANDLE; - XrAction m_inGame_modMenuAction = XR_NULL_HANDLE; //imgui mod menu XrAction m_useLeftItemAction = XR_NULL_HANDLE; XrAction m_useRightItemAction = XR_NULL_HANDLE; XrAction m_crouch_scopeAction = XR_NULL_HANDLE; - XrAction m_inGame_inventory_mapAction = XR_NULL_HANDLE; - - XrAction m_rumbleAction = XR_NULL_HANDLE; // menu actions XrActionSet m_menuActionSet = XR_NULL_HANDLE; @@ -238,8 +260,7 @@ class OpenXR { XrAction m_leftTriggerAction= XR_NULL_HANDLE; XrAction m_rightTriggerAction = XR_NULL_HANDLE; - XrAction m_inMenu_modMenuAction = XR_NULL_HANDLE; //imgui mod menu - XrAction m_inMenu_inventory_mapAction = XR_NULL_HANDLE; + XrAction m_rotateAction = XR_NULL_HANDLE; //right stick click std::unique_ptr m_renderer; std::unique_ptr m_rumbleManager; From e8c705a7a0deaa58b52dfd4bcdce9c77e0a68b8a Mon Sep 17 00:00:00 2001 From: FirEmerald Date: Fri, 13 Feb 2026 22:19:00 -0600 Subject: [PATCH 2/2] fix incorrect use of "interact" instead of "interactState" --- src/hooking/controls.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hooking/controls.cpp b/src/hooking/controls.cpp index 6198b25..284846b 100644 --- a/src/hooking/controls.cpp +++ b/src/hooking/controls.cpp @@ -1046,9 +1046,9 @@ void CemuHooks::hook_InjectXRInput(PPCInterpreter_t* hCPU) { newXRBtnHold |= mapXRButtonToVpad(inputs.inGame.run_interact, VPAD_BUTTON_A); // grabs to accelerate and brake when riding master cycle // Skip when the respective hand is inside a body slot so grips can still equip/unequip - if (inputs.inGame.interact[1].wasDownLastFrame && isHandNotOverAnySlot(rightGesture)) + if (inputs.inGame.interactState[1].wasDownLastFrame && isHandNotOverAnySlot(rightGesture)) newXRBtnHold |= VPAD_BUTTON_A; - if (inputs.inGame.interact[0].wasDownLastFrame && isHandNotOverAnySlot(leftGesture)) + if (inputs.inGame.interactState[0].wasDownLastFrame && isHandNotOverAnySlot(leftGesture)) newXRBtnHold |= VPAD_BUTTON_B; } else {