Skip to content

fix(macOS): move the pointer once per relative packet - #5778

Open
RodrickOMG wants to merge 1 commit into
LizardByte:masterfrom
RodrickOMG:fix/macos-relative-mouse
Open

RodrickOMG wants to merge 1 commit into
LizardByte:masterfrom
RodrickOMG:fix/macos-relative-mouse

Conversation

@RodrickOMG

Copy link
Copy Markdown

The libvirtualhid macOS backend performed three conflicting pointer updates per relative motion packet: a CGEvent carrying both an absolute location and kCGMouseEventDeltaX/Y (deltas run through pointer acceleration and were computed from the unclamped position), followed by CGWarpMouseCursorPosition(), which shifts the baseline the next packet reads. Relative motion therefore collapsed to near zero with visible jitter, while button and scroll events -- which are never warped -- kept working. Motion was also clamped to a single display.

Resolve relative motion against the live cursor position and post exactly one event with no warp on top. Re-base on the server position only on the first packet or after a gap: CGEventGetLocation() reports what the window server has already committed, so re-reading it for every packet in a 500-1000 Hz burst makes each packet overwrite the previous one's movement. Accumulate the chain locally in between instead.

Clamp to the full active-display layout, select the event type from the actual button state so drags keep working, and carry the live modifier flags so a drag started while holding Shift/Option/Ctrl keeps them on every motion event that follows the button press. Fall back to the libvirtualhid path when Accessibility is not granted, so behaviour there is unchanged.

Windows and Linux are unaffected.

Description

Screenshot

Issues Fixed or Closed

Roadmap Issues

Type of Change

  • feat: New feature (non-breaking change which adds functionality)
  • fix: Bug fix (non-breaking change which fixes an issue)
  • docs: Documentation only changes
  • style: Changes that do not affect the meaning of the code (white-space, formatting, missing semicolons, etc.)
  • refactor: Code change that neither fixes a bug nor adds a feature
  • perf: Code change that improves performance
  • test: Adding missing tests or correcting existing tests
  • build: Changes that affect the build system or external dependencies
  • ci: Changes to CI configuration files and scripts
  • chore: Other changes that don't modify src or test files
  • revert: Reverts a previous commit
  • BREAKING CHANGE: Introduces a breaking change (can be combined with any type above)

Checklist

  • Code follows the style guidelines of this project
  • Code has been self-reviewed
  • Code has been commented, particularly in hard-to-understand areas
  • Code docstring/documentation-blocks for new or existing methods/components have been added or updated
  • Unit tests have been added or updated for any new or modified functionality

AI Usage

See our AI usage policy.

  • None: No AI tools were used in creating this PR
  • Light: AI provided minor assistance (formatting, simple suggestions)
  • Moderate: AI helped with code generation or debugging specific parts
  • Heavy: AI generated most or all of the code changes

The libvirtualhid macOS backend performed three conflicting pointer updates
per relative motion packet: a CGEvent carrying both an absolute location and
kCGMouseEventDeltaX/Y (deltas run through pointer acceleration and were
computed from the unclamped position), followed by
CGWarpMouseCursorPosition(), which shifts the baseline the next packet reads.
Relative motion therefore collapsed to near zero with visible jitter, while
button and scroll events -- which are never warped -- kept working. Motion was
also clamped to a single display.

Resolve relative motion against the live cursor position and post exactly one
event with no warp on top. Re-base on the server position only on the first
packet or after a gap: CGEventGetLocation() reports what the window server has
already committed, so re-reading it for every packet in a 500-1000 Hz burst
makes each packet overwrite the previous one's movement. Accumulate the chain
locally in between instead.

Clamp to the full active-display layout, select the event type from the actual
button state so drags keep working, and carry the live modifier flags so a
drag started while holding Shift/Option/Ctrl keeps them on every motion event
that follows the button press. Fall back to the libvirtualhid path when
Accessibility is not granted, so behaviour there is unchanged.

Windows and Linux are unaffected.
@ReenigneArcher

Copy link
Copy Markdown
Member

I think you're trying to fix some of the same things as LizardByte/libvirtualhid#145 and #5739

Can you test #5739 ?

@sonarqubecloud

Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
1 New issue
1 New Code Smells (required ≤ 0)

See analysis details on SonarQube Cloud

Catch issues before they fail your Quality Gate with our IDE extension SonarQube for IDE

@RodrickOMG

Copy link
Copy Markdown
Author

Thanks for the pointers! I looked into this on my setup (macOS, single display, Moonlight on Windows):

I haven't tested #5739 yet.

This branch has not been deployed

No deployments
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.

2 participants