VR_ARCHITECTURE.md: the Frame controller map as one table, what the grips rely on (dev only)

This commit is contained in:
Madison committed 2026-10-05 16:47:07 +09:00
1 parent a5c1c07503
commit 3843dda03e
1 file changed
+90 -6
+90 -6
View File
@@ -96,12 +96,93 @@ and only does the client frame. Per-frame client state runs on the left eye (`cl
## 4. Controls
`OpenXrInput.c`: actions are the Quest ones plus `viewkey` and `bumperkey`. Profiles suggested on the Frame build,
each logged with the runtime's answer: Frame, Index, Touch (Pico isn't touched). `TBXR_UpdateFrameLayout` maps the Frame's
buttons into the Quest shape when the runtime reports the Frame profile active: A crouch, B jump, left bumper or right X
torch, View tap or right Y screen view, right Menu pause, View held 1 s / 3 s recentre. Left-handed schemes swap which
state the bits land on. Compared with `standard.md`: Menu and View follow it; A and B keep the game's crouch and jump
rather than the standard's jump/back; there's no VR settings page and no dominant-hand setting beyond `vr_control_scheme`.
Source of the layout: Half-Life's own gamepad layout from the 25th anniversary update (`valve/controller_configs/xbox_controller_config_standard.vdf`),
with the VR parts added (grips, head look). It replaced the first Frame map (the Quest layout moved around) after the second wear, and replaces
`standard.md` sections 1 and 2 where they differ: B is crouch (not back), A jump, X use, Y reload, bumpers and D-pad pick weapons, right stick click is the
flashlight. Menu and View kept their system jobs (Menu pause, View recentre) as in the standard.
Code: `VrFrameMap.c` is the map as one table (`rows[]`: physical input, context, action); `VrInputFrame.c` turns it into the Quest-shaped states that
`VrInputDefault.c` reads (dominant hand: trigger, backpack grip, turn stick, use on the stick-click bit, crouch and jump on its two buttons; other hand: steady on
the grip, move stick, torch and screen view on its two buttons, laser on its stick-click bit) and into commands for what the scheme code doesn't have
(alt fire, reload, weapon select, last weapon, crowbar, quick save, menu keys, recentre). `OpenXrInput.c` reads the physical buttons (new `dpad*` actions) and logs the
profile. It only runs when the runtime reports the Frame profile active (or `diag_press` is in use). Contexts: menu (`cls.key_dest != key_game`), weapon hand
behind the head, other hand behind the head (not in multiplayer), multiplayer, and the other grip's mode (decided at press time).
Scheme code kept as it was: aim from the controller, crowbar swing (weapon velocity), flashlight beam from the off hand, two-handed hold and scope (`vr_weapon_stabilised`,
`+alt1`), backpack grab, physical ducking (`vr_enable_crouching`), room-scale walking, haptics, usable-object highlight. Server side (`hlsdk-xash3d/dlls/player.cpp`,
`PlayerUse`): `+use` finds usable things within `PLAYER_HAND_SEARCH_RADIUS` of the *weapon hand's* position in front of the hand's direction (64 units; 24 and a wide cone
when `vr_gesture_triggered_use` is 1), and `+use2` does the same from the off hand but only when that cvar is 1. So hand-origin use already exists and needs no DLL change; the
grips need the cvar at 1 and the client's automatic gesture use switched off (`VR_FrameHandUse()`, `VrInputDefault.c`). The reach for `+use` is therefore 24 units (0.6 m), which also
applies to X.
Changed defaults on the Frame (saved settings are updated once, `vr_frame_map`): `vr_quick_crouchjump` 0 (double clicking A would be a second crouch input), `vr_gesture_triggered_use` 1 (see above).
Not carried: walk/slow (`+speed`, was the off trigger; the stick is analog), weapon select on the turn stick (it fought the turn).
Not kept from the standard: dominant-hand setting beyond `vr_control_scheme`, no VR settings page.
The table, generated by `tools/steam_frame/tests/test_frame_map --markdown`:
| Frame input | Playing | Notes |
| --- | --- | --- |
| weapon hand trigger | fire | weapon hand trigger |
| other hand trigger | alt fire | other hand trigger |
| A | jump | |
| B | crouch (hold) | |
| X | use | |
| Y | reload | |
| left stick click | crouch (toggle) | |
| right stick click | quick save | off hand behind the head |
| right stick click | flashlight | |
| View (short) | quick save | off hand behind the head |
| View (short) | screen view / scoreboard | the scoreboard |
| View (short) | flashlight | |
| left stick up | move | move |
| left stick down | move | move |
| left stick left | move | move |
| left stick right | move | move |
| right stick left | turn | snap or smooth turn |
| right stick right | turn | snap or smooth turn |
| right stick up | quick load | off hand behind the head |
| right stick up | screen view / scoreboard | flat screen view, the scoreboard in multiplayer |
| right stick down | laser sight / scope steady | laser sight, steadies a scope |
| left bumper | previous weapon | |
| right bumper | next weapon | |
| D-pad up | previous weapon | alias of the left bumper |
| D-pad down | next weapon | alias of the right bumper |
| D-pad right | last weapon | |
| D-pad left | crowbar | |
| weapon hand grip | backpack weapon | the crowbar, from behind the head |
| weapon hand grip | use | alias of X: grab, push, pull, press |
| other hand grip | hold the gun steady | two-handed hold, scope: near the weapon |
| other hand grip | use (other hand) | grab with this hand: well away from the weapon |
| Menu (short) | pause | |
| Menu (hold 0.5 s) | quick save | held for half a second |
| View (hold 1 s) | recentre | |
| View (hold 3 s) | recentre and set height | |
| Frame input | In a menu | Notes |
| --- | --- | --- |
| weapon hand trigger | menu click | pointer click |
| A | menu confirm | |
| B | menu back | |
| Menu (short) | menu back | alias of B |
| View (short) | menu back | alias of B |
| D-pad up | menu up | |
| D-pad down | menu down | |
| D-pad left | menu left | |
| D-pad right | menu right | |
| left stick up | menu up | alias of the D-pad |
| left stick down | menu down | alias of the D-pad |
| left stick left | menu left | alias of the D-pad |
| left stick right | menu right | alias of the D-pad |
| left bumper | menu previous tab | previous tab or page |
| right bumper | menu next tab | next tab or page |
| right stick up | menu scroll up | scroll |
| right stick down | menu scroll down | scroll |
Aliases (one action, two inputs): use on X and the weapon hand's grip; previous / next weapon on the bumpers and D-pad up / down; flashlight on the right stick click and View;
quick save on Menu held and (hand behind the head) the right stick click and View; menu back on B, Menu and View; menu up/down/left/right on the D-pad and left stick. The host
test fails on any other action with two inputs, on any input doing two things in one context, and on an action nothing reaches.
## 5. Diagnostics (Frame build, `vr-diag.ini` in the data folder)
@@ -113,6 +194,9 @@ Set with `tools/steam_frame/deploy.sh --diag KEY=VAL`, removed with `--diag-rese
| `diag_yaw` | synthetic head yaw in degrees (turning left is positive); the hands follow |
| `autostart`, `map` | load a map without the menus after 150 rendered frames (`map` implies `autostart`; default `c1a0`) |
| `dump_frame` | on rendered frame N: `vr-dumps/vr-eye0.bmp`, `vr-eye1.bmp` (one synchronous readback each, with the driver's GL) and `vr-state.txt` (poses, FOVs, each eye's pose in head space, connection state, and 80 `probe` lines: rays from the left eye through a pixel grid traced into the world, with depth and the disparity a correct pair should show; `tools/steam_frame/analyze_stereo.py` matches the right eye there and compares). The log gets the driver's framebuffer bindings, viewport and scissor and the percentage of pixels that aren't black |
| `diag_roll` | synthetic head roll in degrees (tilting left is positive); with `force_render`. The HUD should stay level with the world |
| `diag_press` | holds buttons down: `A@300+30, LG@400+20` is A from 300 frames after the map starts for 30 frames, then the left grip (names: LT RT LG RG LB RB LC RC A B X Y MENU MENUHOLD VIEW UP DOWN LEFT RIGHT, LS/RS + UP DOWN LEFT RIGHT). Runs the map with no controllers; each press is logged `[vr] input -> action` |
| `diag_gap` | metres between the synthetic hands (default 0.5), for the two-handed hold (under 0.35) against the grab (over 0.55) |
| `cmd` | console commands (`;` between them) about 300 rendered frames after the map starts: `sv_cheats 1; impulse 101` for the suit and weapons, `vr_hud_distance 2`, `vr_hand_model 0` |
| `probe` | right before the dump, clear each eye to a flat colour (red, blue) instead: tests the readback and the swapchain, not the game |
| `exit_after` | after N XR frames, leave through the normal shutdown |