Skip to content

input: implement GetActionOrigins, GetActionBindingInfo and InputProfilePath - #418

Open
schlegp wants to merge 3 commits into
Supreeeme:mainfrom
schlegp:feat/button-prompts
Open

input: implement GetActionOrigins, GetActionBindingInfo and InputProfilePath#418
schlegp wants to merge 3 commits into
Supreeeme:mainfrom
schlegp:feat/button-prompts

Conversation

@schlegp

@schlegp schlegp commented Sep 1, 2026

Copy link
Copy Markdown

No Man's Sky did not properly draw the input glyphs in menus.

Added tracing throughout the input chain to find these functions responsible for input glyphs.

Really don't have experience with Rust, so might be terrible code, but it works at least.

Both were stubs that returned no data, so a game could not find out which
physical input an action was bound to. Games use this to label their controls,
and one that asks and gets nothing shows a placeholder instead of a glyph.

Origins are resolved to the hands an action is bound on, and binding info to the
device path, input path, mode and source type of each bound source. The field
semantics follow OpenComposite, which games are evidently written against: the
input path is the relative fragment ("/input/a") rather than the absolute path,
mode and source type come from the action's type rather than from the input it
happens to sit on, and the slot is left empty.

Inputs are named the way OpenVR names them rather than the way OpenXR does -
"grip" and "application_menu", not "squeeze" and "menu". A game looks a glyph up
by the name in its own binding files, so the OpenXR spelling finds nothing;
No Man's Sky loses exactly its grip prompts that way. The stick is left as
"thumbstick", which OpenVR uses for Index while calling the same input
"joystick" on Touch: by the time binding info is assembled the profile a source
came from is no longer known, and thumbstick is the safer of the two to report.
Reporting either faithfully would mean recording the binding file's own spelling
as the manifest is parsed.

Each input is reported once however many of its components an action sits on,
since binding info names the input rather than the component and a trigger bound
on both click and touch would otherwise come back as two identical entries.

The sources themselves are recorded while the action manifest is parsed, rather
than read back from the runtime with xrEnumerateBoundSourcesForAction. The
runtime cannot answer until the action sets are attached and synced, which in
No Man's Sky is around 60ms after it has already asked - too late to be of any
use. Both natively suggested bindings and xrizer's own synthesised ones
(thresholds, dpads, toggles, grabs) are recorded, the latter because they live
on a separate action the runtime never associates with the original. Only the
profile in use is answered for: filling that window from every profile in the
manifest would mean naming inputs of controllers the player isn't holding.

Includes a test that queries binding info directly after loading a manifest,
with fakexr's xrEnumerateBoundSourcesForAction returning no sources, so it only
passes if the manifest data alone is sufficient, and tests for the input naming
and for reporting each input once.
A dpad direction reads an action of its own - the parent stick's xy, shared
between the four directions - and the game's action is never suggested a binding
at all. Asking the runtime what it is bound to therefore returns nothing, and
unlike thresholds and toggles the shared action isn't in ExtraActionData either,
because it belongs to the stick rather than to any one direction. Only the
binding itself leads back to it, so ask that too.

Until now the sources recorded while parsing the manifest were the only thing
answering for dpad directions - a game asking about menu navigation bound to a
stick got nothing the moment those weren't consulted.

fakexr grows an opt-in for reporting bound sources the way a real runtime does
once action sets are attached and synced. It stays off by default, since some of
what xrizer does exists precisely because the runtime cannot answer yet and the
tests for that need a runtime that stays quiet, but with it on a test can check
that a dpad direction leads back to the trackpad driving it without the
manifest-recorded sources standing in.
Prop_InputProfilePath_String was answered with UnknownProperty. It is how a game
finds out which controller it is drawing button prompts for: No Man's Sky asks
for it the moment the interaction profile becomes known and rebuilds every
prompt immediately afterwards, so with no answer the lookup fails and every
prompt comes out as a placeholder, whatever else it reads later.

The property is the driver relative path of the controller's input profile, in
the form {drivername}/input/<device>_profile.json, and is now carried per
profile. Where there is no plausible value - the simple controller - it falls
back to the tracking system name, which is what the OpenVR docs say the property
defaults to, and what OpenComposite does.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant