Refactor OpenXR controller input handling and update settings panel interactions

This commit is contained in:
iChris4 committed 2026-09-19 15:28:20 +02:00
1 parent 60c443654f
commit e681294709
11 files changed
+163 -95

No files matched your search

+6 -5
View File
@@ -40,7 +40,8 @@ struct OpenXRPointerScreen {
// poses are located at the measured current time, turned into both
// accelerometers and the IR pointer (the right aim ray against the virtual
// screen the renderer is showing), and published through openxr_wii_remote.h.
// Buttons follow DolphinXR's "OpenXR Wii Remote" profile (see RemoteButtons).
// Buttons are adapted from DolphinXR's "OpenXR Wii Remote" profile (see
// RemoteButtons).
// The game's rumble drives both controllers' haptics.
//
// Gamepad: the virtual joystick is read through PAD as a GameCube controller,
@@ -55,10 +56,10 @@ struct OpenXRPointerScreen {
// Both are bound for the Oculus Touch profile; khr/simple_controller gets
// select/menu and the poses so an unknown runtime still offers something.
//
// Clicking both thumbsticks opens the in-headset settings panel
// (openxr_settings_panel.h). While it is open, and until every button has been
// released after it closes, the game sees idle controllers: the chord, the
// pointer and the triggers belong to the panel.
// Left Y (both thumbsticks clicked together as a gamepad) opens the in-headset
// settings panel (openxr_settings_panel.h). While it is open, and until every
// button has been released after it closes, the game sees idle controllers: the
// panel button, the pointer and the triggers belong to the panel.
//
// Lifetime: Create after the session exists (attaches the action set, which
// OpenXR permits once per session), Sync once per xrWaitFrame, Idle while the
+26 -14
View File
@@ -18,10 +18,11 @@ namespace mkw::vr {
// controllers, which are withheld from the game while it is open.
//
// The XR pacing thread owns the controllers: it opens and closes the panel from
// the controller chord, aims the pointer and publishes it here. The game thread
// draws the panel, may close it (its Close button) or open it (the F10 bar), and
// reads the pointer once per presented frame. Nothing in this header depends on
// OpenXR, so the settings overlay compiles the same in builds without it.
// the controllers' panel button, aims the pointer and publishes it here. The
// game thread draws the panel, may close it (its Close button) or open it (the
// F10 bar), and reads the pointer once per presented frame. Nothing in this
// header depends on OpenXR, so the settings overlay compiles the same in builds
// without it.
// The panel's canvas in ImGui pixels, drawn at twice the desktop menu's scale.
inline constexpr float kSettingsPanelWidthPixels = 1440.0f;
@@ -75,10 +76,20 @@ struct Frame {
float wheel = 0.0f;
};
// Whether the button that opens and closes the panel is held. As a Wii Remote
// that is left Y, which has no Wii button; as a gamepad left Y is GameCube Y, so
// both thumbsticks clicked together stand in for it.
inline bool ToggleHeld(const std::array<HandInputs, 2>& hands, OpenXRControllerMode mode) noexcept {
if (mode == OpenXRControllerMode::WiiRemote) {
return hands[0].secondary;
}
return hands[0].thumbstick_click && hands[1].thumbstick_click;
}
// The controller side of the panel, one Update per XR frame:
//
// - Clicking both thumbsticks together opens or closes it. Nothing else opens
// it from the controllers: every other button already means something to the
// - The panel button (ToggleHeld) opens or closes it. Nothing else opens it
// from the controllers: every other button already means something to the
// game.
// - While it is open, the left menu button also closes it, both triggers and
// the A / X buttons select, the thumbsticks scroll, and the hand whose trigger
@@ -87,15 +98,16 @@ struct Frame {
// press that closed the panel never lands in the game as well.
class Controls {
public:
// `open` is the shared flag: the chord flips it, and the game thread may
// have changed it since the last frame. `dt_seconds` is the time since the
// previous frame.
Frame Update(const std::array<HandInputs, 2>& hands, bool& open, float dt_seconds) noexcept {
const bool chord = hands[0].thumbstick_click && hands[1].thumbstick_click;
if (chord && !m_chord_held) {
// `open` is the shared flag: the panel button flips it, and the game thread
// may have changed it since the last frame. `dt_seconds` is the time since
// the previous frame; `mode` is how the game sees the controllers.
Frame Update(const std::array<HandInputs, 2>& hands, bool& open, float dt_seconds,
OpenXRControllerMode mode) noexcept {
const bool toggle = ToggleHeld(hands, mode);
if (toggle && !m_toggle_held) {
open = !open;
}
m_chord_held = chord;
m_toggle_held = toggle;
if (open && hands[0].menu && !m_menu_held && m_was_open) {
open = false;
@@ -152,7 +164,7 @@ public:
}
private:
bool m_chord_held = false;
bool m_toggle_held = false;
bool m_menu_held = false;
std::array<bool, 2> m_trigger_held{};
bool m_was_open = false;
+6 -5
View File
@@ -337,10 +337,12 @@ struct HandInputs {
float stick_y = 0.0f; // +up
};
// DolphinXR's default "OpenXR Wii Remote" profile (Data/Sys/Profiles/Wiimote):
// Adapted from DolphinXR's default "OpenXR Wii Remote" profile
// (Data/Sys/Profiles/Wiimote):
// right A -> A, right trigger -> B, right stick up/down -> 1/2,
// right stick left/right -> -/+, left menu -> HOME,
// left X -> -, left menu -> +,
// left grip -> C, left trigger -> Z, left stick -> Nunchuk stick.
// HOME has no button; left Y opens the settings panel (openxr_settings_panel.h).
inline uint32_t RemoteButtons(const HandInputs& left, const HandInputs& right) noexcept {
uint32_t hold = 0;
const auto press = [&hold](bool held, uint32_t bit) {
@@ -352,9 +354,8 @@ inline uint32_t RemoteButtons(const HandInputs& left, const HandInputs& right) n
press(right.trigger > kPressThreshold, kButtonB);
press(right.stick_y > kPressThreshold, kButtonOne);
press(right.stick_y < -kPressThreshold, kButtonTwo);
press(right.stick_x < -kPressThreshold, kButtonMinus);
press(right.stick_x > kPressThreshold, kButtonPlus);
press(left.menu, kButtonHome);
press(left.primary, kButtonMinus);
press(left.menu, kButtonPlus);
press(left.squeeze > kPressThreshold, kButtonC);
press(left.trigger > kPressThreshold, kButtonZ);
return hold;