fix(menu): a layout preset is applied whole after a face button was cleared #266
No reviewers
Labels
No labels
area/accessibility
area/audio
area/input
area/install
area/menu
area/renderer
area/saves
area/upscaling
good first issue
gpu/amd
gpu/igpu
gpu/intel
gpu/nvidia
help wanted
kind
bug
kind
chore
kind
docs
kind
feature
kind
performance
kind
question
needs measurements
platform/linux
platform/steam-deck
platform/windows
preview
priority
critical
priority
high
priority
low
status
blocked
status
confirmed
status
duplicate
status
invalid
status
needs-info
status
wontfix
testing wanted
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
MagicBeanDev/Longshot!266
Loading…
Reference in a new issue
No description provided.
Delete branch "jarynclouatre/Longshot:fix/pad-layout-whole"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Why
On the Controls page, a Layout preset could leave a face button with no gamepad input while the row named the preset. Clear A's Input 1, then choose Xbox / PC: A stays unbound, B moves to East, and the row says Xbox / PC.
apply_pad_layoutbinds A, B, X and Y's Input 1 one at a time throughhos_bind. The host leaves an empty Input 1 as it is when the input asked for is the only one of another button (host/nn_hid.c, so no button is left without a gamepad input). With A cleared, Xbox / PC asks for South while B still has it as its only input, so A keeps nothing. B then takes East, which frees South, but A is not asked again.set_rowhad already written the chosen value toopts.pad_layout.What changed
gpu/vk/vk_menu.cpp,apply_pad_layout): the three presets are a table, and the four binds run again while a face button's Input 1 is not the preset's, 4 passes at most. A face button that already has the preset's input is not bound again (a bind to the same input changes nothing inhos_bind), so the rules for Input 2 are the same as before. In the case above the second pass gives A South.set_row): after the preset, the row takes its value fromdetect_pad_layout(), so a preset that cannot be applied whole (South the only input of a button outside the four) shows Custom instead of the preset's name.tests/test_pad_layout.py(new) compilesapply_pad_layoutanddetect_pad_layoutwithhost/nn_hid.c's binding table andhos_bindas the host. From each preset, each face button's Input 1 is cleared in turn and each preset chosen: the four primaries are the preset's anddetect_pad_layoutnames it. With South the only input of ZL and A cleared, Xbox / PC leaves ZL's South alone and the row reads Custom. A's Input 2 survives a preset. It also checks that theset_rowbranch ends withdetect_pad_layout().tests/test_framegen_preset.py,tests/test_rumble_menu.pyandtests/test_upscaler_round_trip.pyextractset_rowand now get adetect_pad_layoutstub beside theirapply_pad_layoutone.Flags and settings
None.
Measurements
main:
f3fe1763(2026-11-13)this PR: fix/pad-layout-whole @
29c93738Hardware: none used (game-free checks on a Linux x86-64 PC, g++ 15.2, Python 3.14.4); the Windows back end cross-built with llvm-mingw 20261104
Scene: none, the game was not run
Method:
python3 -I -B tests/run_all.py, two runs each, interleaved (main, PR, main, PR, with another branch's runs between); both runs of a side gave the same counts. This PR'stests/test_pad_layout.pyalso run against main'svk_menu.cpp.How to reproduce: the commands above in a checkout of each commit
f3fe176329c93738tests/run_all.py(run 1, run 2)test_bake_portability.py,test_menu_i18n.pytest_pad_layout.pylongshot_vk.dllfor Windows (RX_VK_ONLY=1 RX_RELEASE=1 nx2/build.py --standalone)f3fe1763)test_bake_portability.pyfails here for a missing Python module (zstandard), on main as well.test_menu_i18n.pyfails on main itself: a pt_BR hint (the testing tools' row) is no longer a text ofvk_menu.cpp.Testing
Tested: the game-free suite on a Linux PC, as in Measurements. The Windows back end builds from this branch.
Not tested: the Controls page in the game. The fixture runs the menu's own preset code against the host's own binding rules, which is where the fault was.
Needs other testers: None.
Screenshots
None.
Risk and rollback
A preset now always ends with the preset's four inputs when they can be had, or with the row on Custom when they cannot; before, the row could name a preset the pad did not have. Reverting the commit puts the single pass back.
Reviewer notes
Issues
None.
Checklist
For everyone
type(scope): description).main.python -I -B tests/run_all.pyrun and passing (any failure that also fails onmainis named above).third_party/untouched (a new folder with aPROVENANCE.mdinstead).If applicable
tests/that reads changed source updated in this PR, not weakened.