mirror of
https://github.com/mitch030504/Wiicompiled_VR_Frame.git
synced 2026-10-06 05:00:27 +02:00
Refactor OpenXR controller input handling and update settings panel interactions
This commit is contained in:
1 parent
60c443654f
commit
e681294709
11 files changed
+163
-95
No files matched your search
@@ -143,26 +143,27 @@ to a port like any other. `controller_mode` decides what the game finds on that
|
||||
from **F10 > VR > VR controllers**; the game sees a change as a controller reconnection.
|
||||
|
||||
`"wii_remote"`, the default, presents them as a Wii Remote with a Nunchuk, the way DolphinXR's
|
||||
OpenXR Wii Remote does, including its default `OpenXR Wii Remote` profile for the Touch
|
||||
controllers. The port is served through KPAD like a Bluetooth remote (`wii_remote_input.cpp`), so
|
||||
`WPADProbe` reports a Nunchuk and the game runs its own Wii Remote + Nunchuk control scheme:
|
||||
OpenXR Wii Remote does, with buttons adapted from its default `OpenXR Wii Remote` profile for the
|
||||
Touch controllers. The port is served through KPAD like a Bluetooth remote
|
||||
(`wii_remote_input.cpp`), so `WPADProbe` reports a Nunchuk and the game runs its own Wii Remote + Nunchuk control scheme:
|
||||
|
||||
| Controller | Wii |
|
||||
| --- | --- |
|
||||
| Right A | A |
|
||||
| Right trigger | B |
|
||||
| Right stick up / down | 1 / 2 |
|
||||
| Right stick left / right | − / + |
|
||||
| Left X | − |
|
||||
| Left menu | + |
|
||||
| Left stick | Nunchuk stick |
|
||||
| Left trigger | Z |
|
||||
| Left grip | C |
|
||||
| Left menu | HOME |
|
||||
| Left Y | Settings panel (not a Wii button) |
|
||||
| Right controller motion and aim | Wii Remote accelerometer and pointer |
|
||||
| Left controller motion | Nunchuk accelerometer |
|
||||
|
||||
Analog inputs count as pressed past half travel. Right B, left X/Y and the stick clicks are unbound,
|
||||
as in DolphinXR's profile. The game's Wii Remote rumble vibrates both controllers, subject to the
|
||||
ordinary controller-vibration switch.
|
||||
Analog inputs count as pressed past half travel. Right B, right stick left / right and the stick
|
||||
clicks are unbound, and no controller button presses HOME. The game's Wii Remote rumble vibrates
|
||||
both controllers, subject to the ordinary controller-vibration switch.
|
||||
|
||||
**Motion.** Each XR frame the aim and grip poses are located at the measured current time
|
||||
(`XR_KHR_win32_convert_performance_counter_time`, `XR_KHR_convert_timespec_time` on Android), not
|
||||
@@ -192,13 +193,14 @@ cursor for 100 ms before it disappears, so tracking spikes during fast motion do
|
||||
Raw IR camera dots in `KPADGetUnifiedWpadStatus` stay invalid; the game reads the pointer from
|
||||
`KPADStatus`.
|
||||
|
||||
**Settings in the headset.** Clicking both thumbsticks together opens the settings panel described
|
||||
below; while it is open the controllers operate the panel and the game sees them idle.
|
||||
**Settings in the headset.** Left Y opens the settings panel described below; while it is open the
|
||||
controllers operate the panel and the game sees them idle.
|
||||
|
||||
`"gamepad"` keeps the controllers one ordinary gamepad read through PAD as a GameCube controller:
|
||||
A/B → South/East, X/Y → West/North, index triggers → trigger axes, grips → shoulders, thumbsticks
|
||||
→ sticks (clicks → stick buttons), left menu → Start. Every binding in the F10 controller menu
|
||||
applies.
|
||||
applies. Left Y is GameCube Y here, so clicking both thumbsticks together opens the settings panel
|
||||
instead.
|
||||
|
||||
Bindings are suggested for `oculus/touch_controller` (Quest 2, 3 and Pro) and
|
||||
`khr/simple_controller`. `mkw_vr_wii_remote_tests` checks the accelerometer frame, the pointer
|
||||
@@ -208,8 +210,9 @@ raycast and debounce, the picture placement and the button profile without a hea
|
||||
|
||||
The F10 settings bar is only visible on the desktop window, so the same settings are also offered on
|
||||
a panel inside the headset, in menus and during an immersive race alike, including on the Quest.
|
||||
**Click both thumbsticks together** to open it, and again to close it; the left controller's menu
|
||||
button and the panel's *Close* button also close it. It can be opened from the desktop as well, with
|
||||
**Press left Y** to open it, and again to close it (with `controller_mode = "gamepad"`, **click both
|
||||
thumbsticks together** instead); the left controller's menu button and the panel's *Close* button
|
||||
also close it. It can be opened from the desktop as well, with
|
||||
**F10 → VR → Show these settings in the headset**.
|
||||
|
||||
The panel has the F10 bar's menus as tabs (VR, Graphics, Controllers, Audio, Diagnostics) and a
|
||||
@@ -219,8 +222,8 @@ pointing. Changes apply exactly as they do from the F10 bar, and the two stay in
|
||||
|
||||
While the panel is open, and until every button has been released after it closes, the game sees
|
||||
the VR controllers idle: no buttons, no pointer and a remote at rest. Nothing reaches the game from
|
||||
the chord, the trigger that clicked *Close*, or the menu press that closed the panel. The game is
|
||||
not paused, so a race carries on while you change settings. Other controllers (keyboard, desktop
|
||||
the panel button, the trigger that clicked *Close*, or the menu press that closed the panel. The
|
||||
game is not paused, so a race carries on while you change settings. Other controllers (keyboard, desktop
|
||||
gamepads, Bluetooth remotes) are not affected.
|
||||
|
||||
The panel sits centred on the virtual screen, three quarters of its width across (1.8 m with the
|
||||
@@ -240,8 +243,8 @@ backends already submit carry it, so no extra swapchain or composition layer is
|
||||
ImGui backend keeps a single projection uniform, so the panel's pass is submitted on its own command
|
||||
buffer before the desktop's ImGui pass of the same frame is recorded.
|
||||
|
||||
`mkw_vr_settings_panel_tests` covers the chord, the release latch, selection, scrolling and the
|
||||
canvas mapping; `gx_fifo_tests` covers where the panel lands in each eye.
|
||||
`mkw_vr_settings_panel_tests` covers the panel button in both controller modes, the release latch,
|
||||
selection, scrolling and the canvas mapping; `gx_fifo_tests` covers where the panel lands in each eye.
|
||||
|
||||
## The first-person camera
|
||||
|
||||
|
||||
@@ -252,7 +252,6 @@ class SettingsPage(
|
||||
info(R.string.controls_map_stick, activity.getString(R.string.controls_map_stick_value))
|
||||
info(R.string.controls_map_z, activity.getString(R.string.controls_map_z_value))
|
||||
info(R.string.controls_map_c, activity.getString(R.string.controls_map_c_value))
|
||||
info(R.string.controls_map_home, activity.getString(R.string.controls_map_home_value))
|
||||
info(R.string.controls_map_pointer, activity.getString(R.string.controls_map_pointer_value))
|
||||
info(R.string.controls_map_panel, activity.getString(R.string.controls_map_panel_value))
|
||||
}
|
||||
|
||||
@@ -130,7 +130,7 @@
|
||||
<string name="about_credit_title_dolphin">Dolphin</string>
|
||||
<string name="about_credit_title_logo">Logo</string>
|
||||
<string name="about_licence_title">GPL v3</string>
|
||||
<string name="settings_apply_note">Changes apply the next time the game starts. While playing, click both thumbsticks together to open the in-headset settings.</string>
|
||||
<string name="settings_apply_note">Changes apply the next time the game starts. While playing, press left Y to open the in-headset settings (click both thumbsticks together with Gamepad controllers).</string>
|
||||
<string name="settings_running_note">The game is running, so these changes wait until it is closed and started again.</string>
|
||||
<string name="settings_write_failed">Could not save Config.toml.</string>
|
||||
<string name="settings_custom_value">Custom (%1$s)</string>
|
||||
@@ -205,19 +205,17 @@
|
||||
<string name="controls_map_12">1 / 2</string>
|
||||
<string name="controls_map_12_value">Right stick up / down</string>
|
||||
<string name="controls_map_minus_plus">− / +</string>
|
||||
<string name="controls_map_minus_plus_value">Right stick left / right</string>
|
||||
<string name="controls_map_minus_plus_value">Left X / left menu</string>
|
||||
<string name="controls_map_stick">Nunchuk stick</string>
|
||||
<string name="controls_map_stick_value">Left stick</string>
|
||||
<string name="controls_map_z">Z</string>
|
||||
<string name="controls_map_z_value">Left trigger</string>
|
||||
<string name="controls_map_c">C</string>
|
||||
<string name="controls_map_c_value">Left grip</string>
|
||||
<string name="controls_map_home">HOME</string>
|
||||
<string name="controls_map_home_value">Left menu</string>
|
||||
<string name="controls_map_pointer">Pointer and motion</string>
|
||||
<string name="controls_map_pointer_value">Aim and move the right controller</string>
|
||||
<string name="controls_map_panel">Settings panel</string>
|
||||
<string name="controls_map_panel_value">Click both thumbsticks</string>
|
||||
<string name="controls_map_panel_value">Left Y</string>
|
||||
|
||||
<!-- Audio tab -->
|
||||
<string name="section_audio">Volume</string>
|
||||
|
||||
+1
-1
@@ -581,7 +581,7 @@ the app:
|
||||
| --- | --- |
|
||||
| `debug.wiicompiled.vtxpad 0` | Turns the stride padding off, to re-check a driver update |
|
||||
| `debug.wiicompiled.validation 1` | Keeps WebGPU validation and robustness on in release builds |
|
||||
| `debug.wiicompiled.inject <n>:<button>` | Presses `a`, `b`, `x`, `y`, `start`, `up`, `down`, `left` or `right` for 12 XR frames each time `<n>` changes. As a Wii Remote, `x`/`y`/`start` are 1/2/+, the directions push the Nunchuk stick, and `home`, `c` and `z` also exist. `panel` clicks both thumbsticks, opening or closing the settings panel (see `OPENXR.md`) |
|
||||
| `debug.wiicompiled.inject <n>:<button>` | Presses `a`, `b`, `x`, `y`, `start`, `up`, `down`, `left` or `right` for 12 XR frames each time `<n>` changes. As a Wii Remote, `x`/`y`/`start` are 1/2/+, the directions push the Nunchuk stick, and `home`, `c` and `z` also exist. `panel` presses the settings panel's button (left Y, or both thumbsticks as a gamepad), opening or closing it (see `OPENXR.md`) |
|
||||
| `debug.wiicompiled.fpslog 1` | Logs the game's rendered frame rate every 5 s, with per-frame averages of the producer's waits for the frame worker's DONE and SEALED phases and of the worker's seal, permit wait, prepare and encode stretches. The compositor's `VrApi` log line gives headset FPS, `GPU%`, `CPU%`, clock levels and app GPU time (`App=`) |
|
||||
|
||||
The injector makes headset tests possible with nobody wearing the headset.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -1240,7 +1240,8 @@ void DrawVrSettings() {
|
||||
if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled)) {
|
||||
ImGui::SetTooltip(
|
||||
"Opens these settings on a panel in front of you, in menus and races alike.\n"
|
||||
"In the headset, clicking both thumbsticks together opens and closes it too.\n"
|
||||
"In the headset, left Y opens and closes it too (with Gamepad VR controllers,\n"
|
||||
"click both thumbsticks together instead).\n"
|
||||
"Aim at it and pull a trigger to change a setting; push a thumbstick to scroll.\n"
|
||||
"While it is open the game does not see the VR controllers.");
|
||||
}
|
||||
@@ -1253,8 +1254,8 @@ void DrawVrSettings() {
|
||||
ImGui::SetTooltip(
|
||||
"Wii Remote + Nunchuk: the right controller is a Wii Remote, with motion and a pointer "
|
||||
"that lands where you aim on the virtual screen; the left one is the Nunchuk.\n"
|
||||
" Right: A = A, trigger = B, stick up/down = 1/2, stick left/right = -/+\n"
|
||||
" Left: stick = Nunchuk stick, trigger = Z, grip = C, menu = HOME\n"
|
||||
" Right: A = A, trigger = B, stick up/down = 1/2\n"
|
||||
" Left: stick = Nunchuk stick, trigger = Z, grip = C, X = -, menu = +, Y = settings panel\n"
|
||||
"Gamepad: both controllers are one ordinary controller, read as a GameCube pad.\n"
|
||||
"Applies immediately; the game sees the controller change as a reconnection.");
|
||||
}
|
||||
@@ -1967,7 +1968,10 @@ void DrawVrSettingsPanelWindow() {
|
||||
mkw::vr::OpenXRSetSettingsPanelOpen(false);
|
||||
}
|
||||
ImGui::TextDisabled("Aim and pull a trigger to change a setting, push a thumbstick to scroll.");
|
||||
ImGui::TextDisabled("Click both thumbsticks or press Menu to close. The game does not see the controllers meanwhile.");
|
||||
ImGui::TextDisabled("%s to close. The game does not see the controllers meanwhile.",
|
||||
mkw::vr::OpenXRGetControllerMode() == mkw::vr::OpenXRControllerMode::WiiRemote
|
||||
? "Press left Y or Menu"
|
||||
: "Click both thumbsticks or press Menu");
|
||||
ImGui::Separator();
|
||||
if (ImGui::BeginTabBar("Settings")) {
|
||||
const auto tab = [](const char* label, void (*draw)()) {
|
||||
|
||||
@@ -40,9 +40,10 @@ namespace {
|
||||
// A new sequence number holds the button for kInjectHoldFrames XR frames.
|
||||
// Buttons: a, b, x, y, start, up, down, left, right, and for the Wii Remote
|
||||
// presentation also home, c and z (x/y/start press 1/2/+ there, and the
|
||||
// directions push the Nunchuk stick). `panel` clicks both thumbsticks, opening
|
||||
// or closing the settings panel, where `a` then selects. The property is unset
|
||||
// in normal use, so this costs one property read every few frames.
|
||||
// directions push the Nunchuk stick). `panel` presses the settings panel's
|
||||
// button (left Y, or both thumbsticks for a gamepad), opening or closing it,
|
||||
// where `a` then selects. The property is unset in normal use, so this costs
|
||||
// one property read every few frames.
|
||||
constexpr uint32_t kInjectHoldFrames = 12;
|
||||
constexpr uint32_t kInjectPollFrames = 4;
|
||||
|
||||
@@ -594,6 +595,8 @@ void OpenXRInput::Sync(XrTime predicted_display_time, const OpenXRPointerScreen&
|
||||
m_last_input_time = input_time;
|
||||
std::array<wii_remote::HandInputs, kHands> panel_hands = hands;
|
||||
if (Injected("panel")) {
|
||||
// The panel button in either controller mode.
|
||||
panel_hands[0].secondary = true;
|
||||
panel_hands[0].thumbstick_click = true;
|
||||
panel_hands[1].thumbstick_click = true;
|
||||
}
|
||||
@@ -604,7 +607,8 @@ void OpenXRInput::Sync(XrTime predicted_display_time, const OpenXRPointerScreen&
|
||||
// is written back.
|
||||
const bool was_open = OpenXRSettingsPanelOpen();
|
||||
bool open = was_open;
|
||||
const settings_panel::Frame panel = m_panel_controls.Update(panel_hands, open, dt_seconds);
|
||||
const settings_panel::Frame panel =
|
||||
m_panel_controls.Update(panel_hands, open, dt_seconds, OpenXRGetControllerMode());
|
||||
// Pointer first: the game thread reads it as soon as it sees the panel open.
|
||||
PublishSettingsPanel(input_time, settings_panel, panel);
|
||||
if (open != was_open) {
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
//
|
||||
// The in-headset settings panel's controller handling, tested without a
|
||||
// headset: the thumbstick chord that opens and closes it, the release latch that
|
||||
// keeps a closing press out of the game, selection, scrolling, and where a hit
|
||||
// lands on the panel's canvas.
|
||||
// headset: the button that opens and closes it in each controller mode, the
|
||||
// release latch that keeps a closing press out of the game, selection,
|
||||
// scrolling, and where a hit lands on the panel's canvas.
|
||||
|
||||
#include "vr/openxr_settings_panel.h"
|
||||
|
||||
@@ -32,6 +32,8 @@ void CheckNear(float actual, float expected, const char* what, float tolerance =
|
||||
}
|
||||
|
||||
constexpr float kDt = 1.0f / 90.0f;
|
||||
constexpr OpenXRControllerMode kWiiRemote = OpenXRControllerMode::WiiRemote;
|
||||
constexpr OpenXRControllerMode kGamepad = OpenXRControllerMode::Gamepad;
|
||||
|
||||
std::array<HandInputs, 2> Released() {
|
||||
return {};
|
||||
@@ -44,46 +46,80 @@ std::array<HandInputs, 2> Chord() {
|
||||
return hands;
|
||||
}
|
||||
|
||||
void ChordOpensAndClosesOnce() {
|
||||
std::array<HandInputs, 2> LeftY() {
|
||||
std::array<HandInputs, 2> hands{};
|
||||
hands[0].secondary = true;
|
||||
return hands;
|
||||
}
|
||||
|
||||
void LeftYOpensAndClosesOnceAsAWiiRemote() {
|
||||
Controls controls;
|
||||
bool open = false;
|
||||
|
||||
auto right_b = Released();
|
||||
right_b[1].secondary = true;
|
||||
Frame frame = controls.Update(right_b, open, kDt, kWiiRemote);
|
||||
Check(!open && !frame.withheld, "right B neither opens nor withholds");
|
||||
frame = controls.Update(Chord(), open, kDt, kWiiRemote);
|
||||
Check(!open && !frame.withheld, "as a Wii Remote the thumbstick chord does not open the panel");
|
||||
controls.Update(Released(), open, kDt, kWiiRemote);
|
||||
|
||||
frame = controls.Update(LeftY(), open, kDt, kWiiRemote);
|
||||
Check(open && frame.open && frame.withheld, "left Y opens the panel");
|
||||
frame = controls.Update(LeftY(), open, kDt, kWiiRemote);
|
||||
Check(open, "holding left Y does not toggle again");
|
||||
frame = controls.Update(Released(), open, kDt, kWiiRemote);
|
||||
Check(open && frame.withheld, "the panel stays open and keeps the controllers after left Y is released");
|
||||
|
||||
frame = controls.Update(LeftY(), open, kDt, kWiiRemote);
|
||||
Check(!open && !frame.open, "left Y closes the panel again");
|
||||
Check(frame.withheld, "the closing press is still withheld from the game");
|
||||
frame = controls.Update(Released(), open, kDt, kWiiRemote);
|
||||
Check(!frame.withheld, "the game gets the controllers back once everything is released");
|
||||
}
|
||||
|
||||
void ChordOpensAndClosesOnceAsAGamepad() {
|
||||
Controls controls;
|
||||
bool open = false;
|
||||
|
||||
Frame frame = controls.Update(LeftY(), open, kDt, kGamepad);
|
||||
Check(!open && !frame.withheld, "as a gamepad left Y is GameCube Y, not the panel");
|
||||
auto one = Released();
|
||||
one[0].thumbstick_click = true;
|
||||
Frame frame = controls.Update(one, open, kDt);
|
||||
frame = controls.Update(one, open, kDt, kGamepad);
|
||||
Check(!open && !frame.withheld, "one thumbstick click alone neither opens nor withholds");
|
||||
|
||||
frame = controls.Update(Chord(), open, kDt);
|
||||
frame = controls.Update(Chord(), open, kDt, kGamepad);
|
||||
Check(open && frame.open && frame.withheld, "clicking both thumbsticks opens the panel");
|
||||
frame = controls.Update(Chord(), open, kDt);
|
||||
frame = controls.Update(Chord(), open, kDt, kGamepad);
|
||||
Check(open, "holding the chord does not toggle again");
|
||||
frame = controls.Update(Released(), open, kDt);
|
||||
frame = controls.Update(Released(), open, kDt, kGamepad);
|
||||
Check(open && frame.withheld, "the panel stays open and keeps the controllers after the chord is released");
|
||||
|
||||
frame = controls.Update(Chord(), open, kDt);
|
||||
frame = controls.Update(Chord(), open, kDt, kGamepad);
|
||||
Check(!open && !frame.open, "the chord closes the panel again");
|
||||
Check(frame.withheld, "the closing chord is still withheld from the game");
|
||||
frame = controls.Update(Released(), open, kDt);
|
||||
frame = controls.Update(Released(), open, kDt, kGamepad);
|
||||
Check(!frame.withheld, "the game gets the controllers back once everything is released");
|
||||
}
|
||||
|
||||
void MenuClosesAndItsPressStaysOutOfTheGame() {
|
||||
Controls controls;
|
||||
bool open = false;
|
||||
controls.Update(Chord(), open, kDt);
|
||||
controls.Update(Released(), open, kDt);
|
||||
controls.Update(LeftY(), open, kDt, kWiiRemote);
|
||||
controls.Update(Released(), open, kDt, kWiiRemote);
|
||||
|
||||
auto menu = Released();
|
||||
menu[0].menu = true;
|
||||
Frame frame = controls.Update(menu, open, kDt);
|
||||
Frame frame = controls.Update(menu, open, kDt, kWiiRemote);
|
||||
Check(!open, "the left menu button closes an open panel");
|
||||
frame = controls.Update(menu, open, kDt);
|
||||
Check(frame.withheld, "HOME held across the close does not reach the game");
|
||||
frame = controls.Update(menu, open, kDt, kWiiRemote);
|
||||
Check(frame.withheld, "+ held across the close does not reach the game");
|
||||
Check(!open, "a held menu button does not reopen the panel");
|
||||
frame = controls.Update(Released(), open, kDt);
|
||||
frame = controls.Update(Released(), open, kDt, kWiiRemote);
|
||||
Check(!frame.withheld, "released, the controllers go back to the game");
|
||||
|
||||
frame = controls.Update(menu, open, kDt);
|
||||
frame = controls.Update(menu, open, kDt, kWiiRemote);
|
||||
Check(!open && !frame.withheld, "with the panel closed the menu button is the game's");
|
||||
}
|
||||
|
||||
@@ -93,49 +129,49 @@ void SelectWaitsForAReleaseAndFollowsTheTrigger() {
|
||||
// Opened from the settings bar while a trigger is held for the game.
|
||||
auto trigger = Released();
|
||||
trigger[1].trigger = 1.0f;
|
||||
controls.Update(trigger, open, kDt);
|
||||
controls.Update(trigger, open, kDt, kWiiRemote);
|
||||
open = true;
|
||||
Frame frame = controls.Update(trigger, open, kDt);
|
||||
Frame frame = controls.Update(trigger, open, kDt, kWiiRemote);
|
||||
Check(frame.open && !frame.select, "a trigger held from before the panel opened does not click");
|
||||
frame = controls.Update(Released(), open, kDt);
|
||||
frame = controls.Update(Released(), open, kDt, kWiiRemote);
|
||||
Check(!frame.select, "nothing held, nothing selected");
|
||||
frame = controls.Update(trigger, open, kDt);
|
||||
frame = controls.Update(trigger, open, kDt, kWiiRemote);
|
||||
Check(frame.select && frame.pointing_hand == 1, "a fresh right trigger selects and points with the right hand");
|
||||
|
||||
auto left = Released();
|
||||
left[0].trigger = 0.9f;
|
||||
controls.Update(Released(), open, kDt);
|
||||
frame = controls.Update(left, open, kDt);
|
||||
controls.Update(Released(), open, kDt, kWiiRemote);
|
||||
frame = controls.Update(left, open, kDt, kWiiRemote);
|
||||
Check(frame.select && frame.pointing_hand == 0, "pulling the left trigger hands the pointer to the left hand");
|
||||
|
||||
auto button = Released();
|
||||
button[1].primary = true;
|
||||
controls.Update(Released(), open, kDt);
|
||||
frame = controls.Update(button, open, kDt);
|
||||
controls.Update(Released(), open, kDt, kWiiRemote);
|
||||
frame = controls.Update(button, open, kDt, kWiiRemote);
|
||||
Check(frame.select && frame.pointing_hand == 0, "A selects without moving the pointer to another hand");
|
||||
}
|
||||
|
||||
void ThumbstickScrolls() {
|
||||
Controls controls;
|
||||
bool open = true;
|
||||
controls.Update(Released(), open, kDt);
|
||||
controls.Update(Released(), open, kDt, kWiiRemote);
|
||||
|
||||
auto small = Released();
|
||||
small[1].stick_y = 0.2f;
|
||||
Check(controls.Update(small, open, kDt).wheel == 0.0f, "a resting thumbstick does not scroll");
|
||||
Check(controls.Update(small, open, kDt, kWiiRemote).wheel == 0.0f, "a resting thumbstick does not scroll");
|
||||
|
||||
auto up = Released();
|
||||
up[1].stick_y = 1.0f;
|
||||
CheckNear(controls.Update(up, open, 0.5f).wheel, kScrollStepsPerSecond * 0.1f,
|
||||
CheckNear(controls.Update(up, open, 0.5f, kWiiRemote).wheel, kScrollStepsPerSecond * 0.1f,
|
||||
"full deflection scrolls up at the full rate, with a long frame clamped");
|
||||
auto down = Released();
|
||||
down[0].stick_y = -1.0f;
|
||||
down[1].stick_y = 0.3f;
|
||||
Check(controls.Update(down, open, kDt).wheel < 0.0f, "the more deflected stick decides the direction");
|
||||
Check(controls.Update(down, open, kDt, kWiiRemote).wheel < 0.0f, "the more deflected stick decides the direction");
|
||||
|
||||
bool closed = false;
|
||||
Controls idle;
|
||||
Check(idle.Update(up, closed, kDt).wheel == 0.0f, "a closed panel does not scroll");
|
||||
Check(idle.Update(up, closed, kDt, kWiiRemote).wheel == 0.0f, "a closed panel does not scroll");
|
||||
}
|
||||
|
||||
void HitsMapOntoTheCanvas() {
|
||||
@@ -175,7 +211,8 @@ void BridgeAccumulatesWheelUntilTaken() {
|
||||
} // namespace
|
||||
|
||||
int main() {
|
||||
ChordOpensAndClosesOnce();
|
||||
LeftYOpensAndClosesOnceAsAWiiRemote();
|
||||
ChordOpensAndClosesOnceAsAGamepad();
|
||||
MenuClosesAndItsPressStaysOutOfTheGame();
|
||||
SelectWaitsForAReleaseAndFollowsTheTrigger();
|
||||
ThumbstickScrolls();
|
||||
|
||||
@@ -247,24 +247,33 @@ void TestButtons() {
|
||||
Check(RemoteButtons(left, right) == kButtonOne, "right stick up is 1");
|
||||
right.stick_y = -0.9f;
|
||||
Check(RemoteButtons(left, right) == kButtonTwo, "right stick down is 2");
|
||||
right.stick_y = 0.3f;
|
||||
Check(RemoteButtons(left, right) == 0, "a light push is no press");
|
||||
right.stick_y = 0.0f;
|
||||
right.stick_x = -0.9f;
|
||||
Check(RemoteButtons(left, right) == kButtonMinus, "right stick left is -");
|
||||
Check(RemoteButtons(left, right) == 0, "right stick left is unbound");
|
||||
right.stick_x = 0.9f;
|
||||
Check(RemoteButtons(left, right) == kButtonPlus, "right stick right is +");
|
||||
right.stick_x = 0.3f;
|
||||
Check(RemoteButtons(left, right) == 0, "a light push is no press");
|
||||
Check(RemoteButtons(left, right) == 0, "right stick right is unbound");
|
||||
|
||||
right = {};
|
||||
left.primary = true;
|
||||
left.menu = true;
|
||||
Check(RemoteButtons(left, right) == (kButtonMinus | kButtonPlus), "left X and menu are - and +");
|
||||
left = {};
|
||||
left.squeeze = 0.8f;
|
||||
left.trigger = 0.7f;
|
||||
Check(RemoteButtons(left, right) == (kButtonHome | kButtonC | kButtonZ), "left menu, grip, trigger are HOME, C, Z");
|
||||
// Left X and Y have no Wii button in the profile.
|
||||
Check(RemoteButtons(left, right) == (kButtonC | kButtonZ), "left grip and trigger are C and Z");
|
||||
// Left Y is the settings panel's button, and nothing presses HOME.
|
||||
left = {};
|
||||
left.primary = true;
|
||||
left.secondary = true;
|
||||
Check(RemoteButtons(left, right) == 0, "left X/Y are unbound");
|
||||
right.secondary = true;
|
||||
right.thumbstick_click = true;
|
||||
left.thumbstick_click = true;
|
||||
Check(RemoteButtons(left, right) == 0, "left Y, right B and the stick clicks are unbound");
|
||||
left = {};
|
||||
right = {};
|
||||
left.menu = true;
|
||||
Check((RemoteButtons(left, right) & kButtonHome) == 0, "left menu is no longer HOME");
|
||||
|
||||
left.stick_x = 1.0f;
|
||||
left.stick_y = 1.0f;
|
||||
|
||||
Reference in new issue
Block a user