Skip to content

feat: XI2.1 smooth scroll support via xinput driver#12

Merged
hiroTamada merged 7 commits intomasterfrom
hiro/xi2-scroll
Apr 2, 2026
Merged

feat: XI2.1 smooth scroll support via xinput driver#12
hiroTamada merged 7 commits intomasterfrom
hiro/xi2-scroll

Conversation

@hiroTamada
Copy link
Copy Markdown

@hiroTamada hiroTamada commented Apr 1, 2026

Summary

Enable pixel-precise smooth scrolling by sending raw pixel deltas through the xf86-input-neko xinput driver instead of quantizing them into discrete XTest button events.

Changes

server/internal/desktop/xorg.goScroll() now sends raw pixel deltas directly to the xinput driver via Unix socket. Falls back to XTest if the driver connection fails.

server/internal/webrtc/legacyhandler.go — Support PayloadScrollWithCtrl (length=5) binary message format that includes a controlKey byte alongside deltaX/deltaY.

server/pkg/xinput/ — Add NEKO_SCROLL (0x80) message type and Scroll(deltaX, deltaY int32) method to send scroll events over the Unix socket to the Xorg driver.

server/pkg/xorg/xorg.c — Fix XTest fallback scroll direction (button 4/5 mapping was inverted).

server/internal/config/desktop.go — Add CDPScrollURL config option (unused by default, for optional CDP scroll bypass).

server/pkg/cdpscroll/ — Optional CDP-based scroll client (gated behind CDPScrollURL config, not active by default).

Context

Used by kernel/kernel-images#196 which extends the xf86-input-neko Xorg driver with XI2.1 scroll valuators. Together, this achieves 1:1 pixel mapping between client trackpad deltas and browser scroll.

Made with Cursor


Note

Medium Risk
Changes desktop input/scroll handling (including modifier behavior and X11 button mapping), which can impact core interaction and has platform-specific edge cases. Failover paths mitigate risk but need validation across driver/no-driver setups.

Overview
Adds XI2.1 smooth/pixel-precise scrolling support by routing scroll deltas through the xinput Unix-socket driver when desktop.input.enabled is set, including temporarily setting the Ctrl modifier before posting the event and falling back to XTest on driver errors.

Extends the legacy WebRTC data-channel scroll payload to optionally include a Ctrl flag (Length == 5) while keeping the existing scroll format for compatibility, and updates logging accordingly.

Expands server/pkg/xinput with a new NEKO_SCROLL message and Driver.Scroll() API (dummy returns a not-connected error), and fixes the XTest fallback scroll direction mapping in server/pkg/xorg/xorg.c.

Written by Cursor Bugbot for commit ae3594a. This will update automatically on new commits. Configure here.

When NEKO_DESKTOP_CDP_SCROLL_URL is set, scroll events are dispatched
via Chrome DevTools Protocol (Input.dispatchMouseEvent mouseWheel)
instead of X11 XTestFakeButtonEvent. This enables pixel-precise,
smooth scrolling for trackpads and high-resolution mice.

- Add cdpscroll package with auto-discovery of browser WebSocket URL
- Wire CDP scroll into DesktopManager with X11 fallback
- Add new scroll payload format (length=5) with controlKey support
- Existing legacy scroll format (length=4) continues to work

Made-with: Cursor
Route scroll events through the xinput socket to the Xorg driver
instead of using XTestFakeButtonEvent. The driver posts them as
native XInput2 scroll valuator changes, giving pixel-precise
smooth scrolling that Chromium handles identically to a real
trackpad.

Adds Scroll() method to xinput.Driver interface.
DesktopManager.Scroll() uses xinput when UseInputDriver is true,
falling back to XTest otherwise.

Made-with: Cursor
Remove the pixelsPerNotch conversion that quantized scroll events into
discrete notches. The xf86-input-neko driver now has scroll valuators
(axes 3/4), so raw pixel deltas produce 1:1 smooth scrolling in Chromium.
Also fix XTest fallback scroll direction (button 4/5 mapping was inverted).

Made-with: Cursor
The cdpscroll package and CDPScrollURL config were from an earlier
approach and are not used by the XI2.1 scroll path.

Made-with: Cursor
…lback

When UseInputDriver is false, the dummy driver's Scroll() previously
returned nil, silently dropping all scroll events. Now it returns
errNotConnected so the XTest fallback path in xorg.go is reached.

Made-with: Cursor
- Remove warn-level log on every scroll when xinput driver is unavailable
  (dummy driver returns error by design, not worth logging)
- Pass controlKey to xorg.Scroll() in the XTest fallback path so the
  modifier set/scroll/clear happens atomically under a single X11 lock

Made-with: Cursor
Copy link
Copy Markdown

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Branch on UseInputDriver to avoid dummy driver log spam while ensuring
the Ctrl modifier is set before xf86-input-neko posts the motion event.
The XTest fallback still handles controlKey atomically under a single lock.

Made-with: Cursor

int ydir;
if (deltaY > 0) {
ydir = 4; // button 4 is up
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

this is needed for scrolling direction

@hiroTamada hiroTamada requested review from Sayan- and rgarcia April 1, 2026 20:41
Copy link
Copy Markdown

@rgarcia rgarcia left a comment

Choose a reason for hiding this comment

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

🔥

@hiroTamada hiroTamada merged commit 41de6d6 into master Apr 2, 2026
4 checks passed
@hiroTamada hiroTamada deleted the hiro/xi2-scroll branch April 2, 2026 15:35
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