Skip to content

Fix low-speed Android mouse precision - #738

Open
zortos293 wants to merge 2 commits into
android-nativefrom
capy/android-mouse-precision
Open

Fix low-speed Android mouse precision#738
zortos293 wants to merge 2 commits into
android-nativefrom
capy/android-mouse-precision

Conversation

@zortos293

@zortos293 zortos293 commented Aug 10, 2026

Copy link
Copy Markdown
Collaborator

Reported by Discord user <@898574017726922802> (𝓡3 | ASTA).

What changed

  • Keep external-mouse deltas in floating-point form through sensitivity and acceleration, then retain the subpixel residual after the GFN protocol’s required integer quantization.
  • Consume every historical sample in Android’s coalesced MotionEvent batches before sending one low-latency packet.
  • Reset residual state when the physical device/source changes or an absolute-position discontinuity is rebased.
  • Generalize the existing finger-mouse accumulator so touch keeps its current 8 ms batching behavior while external mice use the same precision logic with no added send delay.
  • Add regressions for very slow fractional input, reduced sensitivity, fast linear movement, reset behavior, and invalid input.

Root cause

Pointer capture delivers raw AXIS_RELATIVE_X/Y values as floats. The Android path rejected each axis below 0.5f, rounded the surviving value to an integer before applying sensitivity, and read only the newest sample in a potentially coalesced event. Very slow movement and low sensitivity therefore lost most or all motion, while larger deltas survived and felt disproportionately faster.

The physical mouse path does not consult the decoded GFN resolution or touch-coordinate conversion. A resolution mismatch could only produce a constant scale error, not the observed speed-dependent loss, so this change does not add speculative resolution scaling. Configured acceleration also only boosts larger deltas and defaults to 1; it remains opt-in and is now applied before quantization.

Touch routing, native touch, direct click, controller input, and mouse buttons are unchanged.

Cursor size assessment

Android deliberately hides its local pointer during pointer capture. The cursor visible during gameplay is rendered by the remote GFN session inside the decoded video, so this Android client has no safe cursor-size rendering control to adjust here. No cursor-size change is included.

Validation

  • ./gradlew testDebugUnitTest --tests '*MouseMotionAccumulatorTest' --tests '*ExternalMousePointerCaptureTest' assembleDebug --no-daemon — passes on the latest android-native base.
  • Full unit suite — 527/528 pass. The sole failure is the unchanged StreamPointForTouchTest.stretchAndZoomMapTheVisibleFilledSurface expectation (405 expected, 360 actual); it reproduces alone and neither that test nor its mapping path changed in this PR.
  • Installed the final generated debug APK on an API 35 x86_64 emulator and rendered the native app after merging the latest base.

The supplied Discord MP4 currently returns HTTP 404 from both cdn.discordapp.com and media.discordapp.net, so its frames could not be inspected. The authenticated stream/cursor surface also requires a real NVIDIA/GFN account, which was not available in the emulator. Because this is an input-event pipeline fix with no static visual delta, the screenshots below are honest runtime smoke proof from the final fixed APK rather than a fabricated cursor comparison.

Visual proof

Final fixed APK first-run screen:

OpenNOW Android diagnostics consent

Final fixed APK sign-in screen:

OpenNOW Android sign-in

@cursor

cursor Bot commented Aug 10, 2026

Copy link
Copy Markdown

Bugbot is not enabled for your account, so this pull request was not reviewed.

Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs.

@coderabbitai

coderabbitai Bot commented Aug 10, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 9a47b512-abb5-494f-b530-565c303d65e4

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@zortos293
zortos293 requested a review from Kief5555 August 10, 2026 22:43
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