feat(input): Mouse camera Off, for playing without the mouse #178

Merged
HumanBean merged 1 commit from HumanBean/Longshot:feat/mouse-off into main 2026-11-13 11:05:37 +00:00
Owner

Why

There is no way to keep the mouse out of play. A stray click captures it, and from then on it turns the camera and its buttons press game buttons. Players on a controller or on the keyboard alone want it off.

What changed

  • Menu: the Controls tab's Mouse camera row gets a third choice, Off, saved as mouse_camera=2 (gpu/vk/vk_menu.cpp: tx_mousecam, hn_mousecam, the row's range 0 to 2).
  • Window, Windows: mouse_capture() in host/display.c refuses to capture while option 6 is 2. A click doesn't capture, and a capture held before the Insert menu opened isn't taken back when it closes.
  • Window, Linux: the same check in mouse_capture() in host/posix/display_sdl.c.
  • Input: in host/nn_hid.c, npad_states treats only 1 as native mouse look and only 0 as As the stick, so Off feeds no motion.
  • Input: native_on() in host/mouse_native.c treats only 1 as native. Before, any value but 0 counted as native.
  • Docs: the README's option table and its Mouse camera bullet, the mouse_camera row in docs/development.md, and the comments for option 6 in vk_api.h and vk_menu.h.

Flags and settings

Flag What it does Default now Recommendation Helps on Doesn't help on Untested on
Mouse camera: Off (mouse_camera=2) The mouse is never captured: no camera, no mouse buttons As the stick (unchanged) Off by default: a player's choice Controller- or keyboard-only play - Windows, Linux (not run yet)

Measurements

main: c67cd4a0 (2026-11-13)
this PR: feat/mouse-off @ a42c0e14
Hardware: not measured yet
Scene: not measured yet
Method: not measured yet. This is an input option with no expected cost: one option read when a click would capture the mouse
How to reproduce: Insert → Controls → Mouse camera → Off, then click in the window

main @ c67cd4a0 this PR @ a42c0e14
A click in the window with Mouse camera Off (no Off choice) not run yet
not run yet

Testing

Tested: nothing yet. Not built, the checks not run, not run in the game.

Not tested:

  • Everything above.
  • The checks under tests/ that read vk_menu.cpp, nn_hid.c, display.c and mouse_native.c may need updating for the new lines.
  • The game's own menus on Windows (game_menu_press) still take clicks with Off. That is left as it is on purpose: the mouse isn't captured there.

Needs other testers:

  • Linux (SDL window): with Off, a click doesn't capture the mouse, and Native and As the stick still work (request to open)

Screenshots

Not taken yet (the Controls row with Off).

Risk and rollback

With Off chosen, the mouse can't be captured until the row is set back. Players who chose Off by mistake set it back in the Insert menu, which takes clicks without a capture. Reverting the commit is enough.

Reviewer notes

HOS_MOUSE_NATIVE still overrides the row as before (0 or 1 only).

Issues

None

Checklist

For everyone

  • One topic.
  • The title is a Conventional Commit (type(scope): description).
  • Rebased on current main.
  • python -I -B tests/run_all.py run and passing (any failure that also fails on main is named above). Not run yet.
  • Tested in the game, or what wasn't is named under Testing. Not run in the game yet.
  • Testing filled in: what was tested, what wasn't, and what needs other testers (with test requests). The test request is still to open.
  • Measured: main and this PR at named commits, on the same PC, scene and settings, at least 2 interleaved runs each, the median reported. Not measured yet.
  • No game files, dumps, build output or generated files.
  • third_party/ untouched (a new folder with a PROVENANCE.md instead).
  • The license is OK: GPL-3.0-or-later, nothing incompatible and nothing decompiled.

If applicable

  • AI assistance recorded with Assisted-by: / Co-Authored-By: trailers.
  • Flags noted, and the switch reference updated (docs/development.md, the README).
  • Screenshots for a change that shows on screen. Not taken yet.
  • A check under tests/ that reads changed source updated in this PR, not weakened. Not checked yet.
  • Host code builds on both Windows (llvm-mingw) and Linux, with UTF-8 paths. Not built yet.
  • Docs updated.

🤖 Generated with Claude Code

## Why There is no way to keep the mouse out of play. A stray click captures it, and from then on it turns the camera and its buttons press game buttons. Players on a controller or on the keyboard alone want it off. ## What changed - Menu: the Controls tab's **Mouse camera** row gets a third choice, **Off**, saved as `mouse_camera=2` (`gpu/vk/vk_menu.cpp`: `tx_mousecam`, `hn_mousecam`, the row's range 0 to 2). - Window, Windows: `mouse_capture()` in `host/display.c` refuses to capture while option 6 is 2. A click doesn't capture, and a capture held before the Insert menu opened isn't taken back when it closes. - Window, Linux: the same check in `mouse_capture()` in `host/posix/display_sdl.c`. - Input: in `host/nn_hid.c`, `npad_states` treats only 1 as native mouse look and only 0 as As the stick, so Off feeds no motion. - Input: `native_on()` in `host/mouse_native.c` treats only 1 as native. Before, any value but 0 counted as native. - Docs: the README's option table and its Mouse camera bullet, the `mouse_camera` row in `docs/development.md`, and the comments for option 6 in `vk_api.h` and `vk_menu.h`. ## Flags and settings | Flag | What it does | Default now | Recommendation | Helps on | Doesn't help on | Untested on | |---|---|---|---|---|---|---| | Mouse camera: Off (`mouse_camera=2`) | The mouse is never captured: no camera, no mouse buttons | As the stick (unchanged) | Off by default: a player's choice | Controller- or keyboard-only play | - | Windows, Linux (not run yet) | ## Measurements main: c67cd4a0 (2026-11-13) this PR: feat/mouse-off @ a42c0e14 Hardware: not measured yet Scene: not measured yet Method: not measured yet. This is an input option with no expected cost: one option read when a click would capture the mouse How to reproduce: Insert → Controls → Mouse camera → Off, then click in the window | | main @ c67cd4a0 | this PR @ a42c0e14 | |---|---|---| | A click in the window with Mouse camera Off | (no Off choice) | not run yet | ``` not run yet ``` ## Testing **Tested:** nothing yet. Not built, the checks not run, not run in the game. **Not tested:** - Everything above. - The checks under `tests/` that read `vk_menu.cpp`, `nn_hid.c`, `display.c` and `mouse_native.c` may need updating for the new lines. - The game's own menus on Windows (`game_menu_press`) still take clicks with Off. That is left as it is on purpose: the mouse isn't captured there. **Needs other testers:** - Linux (SDL window): with Off, a click doesn't capture the mouse, and Native and As the stick still work (request to open) ## Screenshots Not taken yet (the Controls row with Off). ## Risk and rollback With Off chosen, the mouse can't be captured until the row is set back. Players who chose Off by mistake set it back in the Insert menu, which takes clicks without a capture. Reverting the commit is enough. ## Reviewer notes `HOS_MOUSE_NATIVE` still overrides the row as before (0 or 1 only). ## Issues None ## Checklist ### For everyone - [x] One topic. - [x] The title is a Conventional Commit (`type(scope): description`). - [x] Rebased on current `main`. - [ ] `python -I -B tests/run_all.py` run and passing (any failure that also fails on `main` is named above). Not run yet. - [ ] Tested in the game, or what wasn't is named under Testing. Not run in the game yet. - [ ] Testing filled in: what was tested, what wasn't, and what needs other testers (with test requests). The test request is still to open. - [ ] Measured: main and this PR at named commits, on the same PC, scene and settings, at least 2 interleaved runs each, the median reported. Not measured yet. - [x] No game files, dumps, build output or generated files. - [x] `third_party/` untouched (a new folder with a `PROVENANCE.md` instead). - [x] The license is OK: GPL-3.0-or-later, nothing incompatible and nothing decompiled. ### If applicable - [x] AI assistance recorded with `Assisted-by:` / `Co-Authored-By:` trailers. - [x] Flags noted, and the switch reference updated (docs/development.md, the README). - [ ] Screenshots for a change that shows on screen. Not taken yet. - [ ] A check under `tests/` that reads changed source updated in this PR, not weakened. Not checked yet. - [ ] Host code builds on both Windows (llvm-mingw) and Linux, with UTF-8 paths. Not built yet. - [x] Docs updated. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
feat(input): Mouse camera Off, for playing without the mouse
Some checks failed
CI / Python source checks (ubuntu-24.04, part 1/2) (pull_request) Has been skipped
CI / Python source checks (ubuntu-24.04, part 2/2) (pull_request) Has been skipped
CI / SPIR-V fixtures (global narrow load/store, direct surface atomics, F2I immediate) (pull_request) Has been skipped
Third-party parts / The same as upstream (pull_request) Has been skipped
CI / Conventional Commit title (pull_request) Successful in 7s
CI / Workflow lint (actionlint) (pull_request) Successful in 10s
Third-party parts / As their notes say (pull_request) Successful in 15s
PR description / Description follows the template (pull_request_target) Failing after 6s
a42c0e14e0
A third choice on the Controls tab's Mouse camera row. With it, a click in
the window no longer captures the mouse (host/display.c and
host/posix/display_sdl.c refuse the capture), so the mouse neither turns the
camera nor presses buttons. nn_hid.c and mouse_native.c treat only 1 as
native mouse look. Saved as mouse_camera=2.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
HumanBean changed title from WIP: feat(input): Mouse camera Off, for playing without the mouse to feat(input): Mouse camera Off, for playing without the mouse 2026-11-13 11:05:09 +00:00
HumanBean deleted branch feat/mouse-off 2026-11-13 11:05:38 +00:00
Author
Owner

Tested after merge (no test request was open for it): mixed. The feature works on Linux, but the PR breaks one check, tests/test_display_pointer.py, which still fails on main.

Hardware: AMD Radeon RX 580 (8 GB, RADV Polaris10), Mesa 26.2.6, CachyOS (kernel 7.3.3), KDE Plasma 6 (KWin 6.8.2) on Wayland, SDL3. Built: a42c0e14 (the PR head) with make_game.py (RX_HOT_OPT=O1, a development build; the game started with RX_VK_PRECOMPILE=0). Not run on Windows.

In the game (Linux, SDL window on Wayland)

Clicks and pointer motion were sent through KWin's fake-input protocol, and the cursor's position was read back from KWin. A captured mouse is locked, so the cursor stays where it was clicked. Each run was a fresh start at the title screen: the pointer was moved to the window's middle (1280,705), clicked 3 times, then moved by +200,+100.

Mouse camera Cursor after the clicks and the move Captured?
Off (mouse_camera=2) 1480,805 (moved freely) no ✅
Native (mouse_camera=1) 1280,705 (locked) yes ✅ (as before)
As the stick (mouse_camera=0) 1280,705 (locked) yes ✅ (as before)
Native, captured, then Insert → Mouse camera → Off → Esc (RX_VK_MENU_SCRIPT) 1280,705 before the menu; 1480,805 after it closed, and still 1480,805 after 3 more clicks the capture held before the menu isn't taken back ✅
  • The menu row cycles As the stick → Native → Off. Off is saved as mouse_camera=2, and its hint shows (screenshot below).
  • mouse native: on is logged only in the runs that used Native.
  • Not checked: the camera's motion in play (only the title screen), and Windows.

Controls tab, Mouse camera: Off

Checks

python -I -B tests/run_all.py at a42c0e14: 516 passed, 1 failed, 19 skipped (Linux).

tests/test_display_pointer.py fails to link. Its fixture compiles host/posix/display_sdl.c's mouse_capture(), which now calls rx_option(), and the fixture has no stub for it:

fixture.cpp:(.text+0xd53): undefined reference to `win::rx_option(int, int)'
collect2: error: ld returned 1 exit status

It passes on the PR's base, c67cd4a0, and fails the same way on current main (000f19fb). The fix is an rx_option stub in the test's fixture (returning 0, or a settable value to cover Off as well).

Tested after merge (no test request was open for it): **mixed**. The feature works on Linux, but the PR breaks one check, `tests/test_display_pointer.py`, which still fails on main. **Hardware:** AMD Radeon RX 580 (8 GB, RADV Polaris10), Mesa 26.2.6, CachyOS (kernel 7.3.3), KDE Plasma 6 (KWin 6.8.2) on Wayland, SDL3. **Built:** a42c0e14 (the PR head) with `make_game.py` (`RX_HOT_OPT=O1`, a development build; the game started with `RX_VK_PRECOMPILE=0`). Not run on Windows. ### In the game (Linux, SDL window on Wayland) Clicks and pointer motion were sent through KWin's fake-input protocol, and the cursor's position was read back from KWin. A captured mouse is locked, so the cursor stays where it was clicked. Each run was a fresh start at the title screen: the pointer was moved to the window's middle (1280,705), clicked 3 times, then moved by +200,+100. | Mouse camera | Cursor after the clicks and the move | Captured? | |---|---|---| | **Off** (`mouse_camera=2`) | 1480,805 (moved freely) | no ✅ | | Native (`mouse_camera=1`) | 1280,705 (locked) | yes ✅ (as before) | | As the stick (`mouse_camera=0`) | 1280,705 (locked) | yes ✅ (as before) | | Native, captured, then Insert → Mouse camera → Off → Esc (`RX_VK_MENU_SCRIPT`) | 1280,705 before the menu; 1480,805 after it closed, and still 1480,805 after 3 more clicks | the capture held before the menu isn't taken back ✅ | - The menu row cycles As the stick → Native → Off. Off is saved as `mouse_camera=2`, and its hint shows (screenshot below). - `mouse native: on` is logged only in the runs that used Native. - Not checked: the camera's motion in play (only the title screen), and Windows. ![Controls tab, Mouse camera: Off](https://git.magicbean.dev/attachments/b31ced0b-6bba-4117-9650-f620c839f7f0) ### Checks `python -I -B tests/run_all.py` at a42c0e14: **516 passed, 1 failed, 19 skipped** (Linux). `tests/test_display_pointer.py` fails to link. Its fixture compiles `host/posix/display_sdl.c`'s `mouse_capture()`, which now calls `rx_option()`, and the fixture has no stub for it: ``` fixture.cpp:(.text+0xd53): undefined reference to `win::rx_option(int, int)' collect2: error: ld returned 1 exit status ``` It passes on the PR's base, c67cd4a0, and fails the same way on current main (000f19fb). The fix is an `rx_option` stub in the test's fixture (returning 0, or a settable value to cover Off as well).
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
MagicBeanDev/Longshot!178
No description provided.