Skip to content

feat: hide the pointer and drive the mouse with the controller from the session menu - #145

Merged
lippdev merged 5 commits into
mainfrom
feat/session-cursor-controller-mouse
Oct 10, 2026
Merged

lippdev merged 5 commits into
mainfrom
feat/session-cursor-controller-mouse

Conversation

@lippdev

@lippdev lippdev commented Oct 10, 2026 •

Copy link
Copy Markdown
Owner

Why

Emulators (and some games) launched from a console session leave the mouse pointer in the middle of the TV, and some of them don't take the controller in their menus at all.

What

"Hide the mouse pointer", a new row in the session menu (live session only)

  • Manual on/off: the pointer stays hidden until the row is turned off, moving the mouse doesn't bring it back. Nothing automatic (owner's decision), so there is no setting in Settings or in the Console UI.
  • Per session: going back to the PC always restores the pointer and the row starts off in the next session.
  • Windows has no "hide the cursor for every app" call, so CursorHider swaps the system cursors for a blank one (SetSystemCursor) and reloads the user's own scheme afterwards (SPI_SETCURSORS). A marker file in the data folder covers a crash in between: the next start restores the cursors.

"Control the mouse with the controller", a new row in the session menu (live session only; off again when the session ends)

  • Left stick moves the pointer (squared curve, speed scaled to the game screen's height), right stick scrolls (vertical and horizontal, whole notches).
  • A = left click, A twice = right click, A held = left drag. The single click waits ~250 ms to rule out a double tap.
  • Reads XInput and Sony HID (SonyHidReader now also keeps both sticks), which both work while the game has the focus. Runs on its own thread with SendInput.
  • Paused while the session menu is open; the A that closes the menu doesn't click.

The two rows exclude each other: turning one on turns the other off (an invisible pointer can't be steered). The controller-mouse row grows to fit its hint.

Known limits

  • The game also receives A and the sticks.
  • No double left click with this mapping.
  • Windows running as administrator don't receive the input (UIPI; the app runs asInvoker).
  • Generic HID pads that Windows only reads in the foreground (e.g. Switch Pro over HID) don't drive the mouse.

Tests

  • Unit tests for the pure logic (ControllerMouseMath.cs: stick curve, pointer accumulation, wheel notches, the A gesture) and for ControllerMapping.SonySticks on every report layout.
  • Tested by the owner in a local preview build; manual checklist in docs/TESTING.md, section 1e.

🤖 Generated with Claude Code

lippdev and others added 2 commits October 10, 2026 12:14
During a session the mouse pointer now disappears after 3 seconds without
moving and comes back on the next move, for emulators and games that
leave it in the middle of the TV. Windows has no per-app call for this,
so the system cursors are swapped for a blank one and reloaded from the
user's scheme afterwards; a marker file restores them on the next start
if the app dies in between. On by default, with a toggle in both
settings screens.

The session menu gains "Control the mouse with the controller", for
games and emulators whose menus ignore the pad: left stick moves the
pointer, right stick scrolls, A clicks, A twice right-clicks and A held
drags. It reads XInput and Sony HID (both work without focus), pauses
while the menu is open, and lasts until the session ends.

The pure parts (stick curve, wheel notches, the A gesture, Sony stick
offsets) are covered by unit tests; the hardware checks are in
docs/TESTING.md section 1e.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Important

A failed cursor restore can leave the system cursor scheme hidden, and the recovery marker is removed before a later launch can retry.

Reviewed changes This review covers the idle-pointer hider, controller-driven mouse input, their session/settings integration, and associated tests and documentation.

  • Idle cursor hiding Replaces system cursors after inactivity during a session and restores the user's scheme when the pointer moves or the session ends.
  • Controller mouse mode Adds optional XInput/Sony HID pointer movement, scrolling, and click/drag input while the game has focus.
  • Integration and coverage Adds session-menu and settings controls, localization, manual test steps, and pure-logic/report-mapping unit tests.

Pullfrog  | Fix all ➔ | Fix 👍s ➔ | View workflow run | Using gpt-6-luna | 𝕏

// Reloads the user's own scheme (Settings → Mouse pointer), whatever it is.
if (!SystemParametersInfo(SpiSetCursors, 0, 0, 0))
AppLog.Write($"Cursor: não foi possível restaurar os cursores ({Marshal.GetLastWin32Error()})");
WriteMarker(false);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If SPI_SETCURSORS fails, this still deletes the recovery marker. Because SetSystemCursor may already have replaced some or all system cursors, the next launch then cannot retry restoring the user's scheme; retain the marker unless the restore succeeds.

lippdev and others added 2 commits October 10, 2026 12:27
The side rows have a fixed 74 px height, which cut the two-line hint.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The pointer no longer hides by itself after 3 s still. The session menu
has a "Hide the mouse pointer" row: on, the pointer stays hidden until
it is turned off or the session ends; moving the mouse doesn't bring it
back. It turns off the controller mouse and vice versa, since a hidden
pointer can't be steered. The Settings and Console interface options for
the automatic hiding are gone.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@lippdev lippdev changed the title feat: hide the idle pointer and drive the mouse with the controller feat: hide the pointer and drive the mouse with the controller from the session menu Oct 10, 2026

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ℹ️ No critical issues; one informational documentation mismatch.

Reviewed changes Reviewed the changes since the prior Pullfrog review, focusing on the shift from automatic idle hiding to a manual session-menu toggle and its session lifecycle.

  • Made cursor hiding manual Replaced the idle-triggered behavior and persistent setting with a per-session menu toggle.
  • Aligned pointer modes Made cursor hiding and controller mouse mode mutually exclusive and reset both when the session ends.
  • Updated related guidance Revised the changelogs, manual test checklist, localization, and session-menu layout.

ℹ️ README still describes automatic cursor hiding

The README feature bullets still say the pointer hides when idle, but the incremental changes make hiding an explicit session-menu action with no automatic behavior. This leaves the English and Portuguese feature summaries inconsistent with the shipped behavior.

Technical details
# Update the README feature summaries

## Affected sites
- README.md:52 — claims the pointer is hidden while idle.
- README.pt-BR.md:52 — claims the pointer disappears when idle.

## Required outcome
- Describe cursor hiding as a manual session-menu toggle, consistent with the current behavior.

Pullfrog  | Fix it ➔ | View workflow run | Using gpt-6-luna | 𝕏

…ontroller-mouse

# Conflicts:
#	src/ConsoleMode/SessionMenuWindow.xaml
#	tests/ConsoleMode.Tests/ConsoleMode.Tests.csproj
@lippdev
lippdev merged commit 2254b3f into main Oct 10, 2026
5 checks passed
@lippdev lippdev mentioned this pull request Oct 10, 2026
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