Skip to content

fix(input): pointer pinned at (0,0) when frames present on the video sink in manual-resolution mode#268

Open
rmounce wants to merge 2 commits into
selkies-project:comprehensive-fixesfrom
rmounce:rmounce/cf-input-sink-fallback
Open

fix(input): pointer pinned at (0,0) when frames present on the video sink in manual-resolution mode#268
rmounce wants to merge 2 commits into
selkies-project:comprehensive-fixesfrom
rmounce:rmounce/cf-input-sink-fallback

Conversation

@rmounce

@rmounce rmounce commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

In manual-resolution mode _applySinkCoordinates maps pointer coordinates against #videoCanvas. ws-core hides that canvas (display: none) whenever decoded frames are presented on the <video>/worker sink (presentFrameToVideo / activateWorkerSinkDisplay), so the canvas measures 0×0 the moment any frame arrives. The function then set x = y = 0 and still returned true, suppressing the windowMath fallback — every subsequent pointer event streamed m,0,0 and the remote pointer was pinned at the top-left corner.

On a mostly static desktop this masquerades as "right-click breaks the mouse": decoder warm-up frames paint on the (visible) canvas, nothing changes on screen, input works — then the right-click menu appearing produces the first frame on the video sink, the canvas is hidden, and the pointer dies. A window resize heals it (resize handlers re-show the canvas) until the next frame. With continuously changing content the pointer is dead immediately.

Since the presenter mirrors the canvas box verbatim onto the visible sink, the fix measures the visible mirror (#videoStream / #videoWorkerCanvas) when the canvas rect is zero (the canvas buffer dimensions stay authoritative for scaling), falls back to the last valid measurement, and only if neither exists returns false so the caller uses windowMath instead of claiming success with (0, 0).

Tested on the comprehensive-fixes stack (selkies 40a5312 + pixelflux 968a4f4 + pcmflux 6aa227e) on an lsio-based image with a Firefox client at manual resolution 1920×1080: reproduced the pinned pointer, verified the fix gives correct absolute coordinates through right-click menus and continuous screen updates, with no offset on a fresh session.

🤖 Generated with Claude Code

@gemini-code-assist gemini-code-assist 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.

Code Review

This pull request updates coordinate calculation in addons/selkies-web-core/lib/input.js to handle hidden canvas sinks by falling back to visible mirror elements or the last cached valid bounding rect. The reviewer suggests caching the mirror elements on the class instance to avoid high-frequency DOM lookups via document.getElementById during pointer events.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment on lines +2008 to +2018
if (!(rect.width > 0 && rect.height > 0)) {
for (const mirrorId of ['videoStream', 'videoWorkerCanvas']) {
const mirror = document.getElementById(mirrorId);
if (!mirror) continue;
const mirrorRect = mirror.getBoundingClientRect();
if (mirrorRect.width > 0 && mirrorRect.height > 0) {
rect = mirrorRect;
break;
}
}
}

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.

medium

Calling document.getElementById on every high-frequency mouse/pointer event (such as mousemove or pointermove) when the main canvas is hidden can introduce unnecessary overhead and potential performance bottlenecks. Since the mirror elements are persistent, we can lazily cache them on the class instance and verify their connection status using isConnected to handle cases where they might be replaced in the DOM.

        if (!(rect.width > 0 && rect.height > 0)) {
            if (!this._mirrors) {
                this._mirrors = {};
            }
            for (const mirrorId of ['videoStream', 'videoWorkerCanvas']) {
                let mirror = this._mirrors[mirrorId];
                if (!mirror || !mirror.isConnected) {
                    mirror = document.getElementById(mirrorId);
                    this._mirrors[mirrorId] = mirror;
                }
                if (!mirror) continue;
                const mirrorRect = mirror.getBoundingClientRect();
                if (mirrorRect.width > 0 && mirrorRect.height > 0) {
                    rect = mirrorRect;
                    break;
                }
            }
        }

In manual-resolution mode _applySinkCoordinates maps pointer coordinates
against #videoCanvas. ws-core hides that canvas (display: none) whenever
decoded frames are presented on the <video>/worker sink instead, so the
canvas measures 0x0 the moment any frame arrives. The function then set
x = y = 0 and still returned true, suppressing the windowMath fallback —
every subsequent pointer event streamed m,0,0 and the remote pointer was
pinned at the top-left corner until a window resize re-showed the canvas
(and only until the next frame).

On a mostly static desktop this looks like "right-click breaks the
mouse" (the menu appearing is what triggers the next frame); with any
continuously changing content the pointer is dead immediately.

The presenter mirrors the canvas box verbatim onto the visible sink
(#videoStream or #videoWorkerCanvas), so when the canvas measures zero,
take the rect from the visible mirror (the canvas buffer dimensions stay
authoritative for scaling), then from the last valid measurement, and
only if neither exists return false so the caller falls back to
windowMath instead of claiming success with (0, 0).

Tested on the comprehensive-fixes stack (selkies 40a5312 + pixelflux
968a4f4 + pcmflux 6aa227e) on an lsio-based image, Firefox client,
manual resolution 1920x1080: reproduced the pinned pointer, verified the
fix restores correct absolute coordinates through right-click menus and
continuous screen updates.

Co-authored-by: Claude <noreply@anthropic.com>
@rmounce rmounce force-pushed the rmounce/cf-input-sink-fallback branch from e07efc9 to 9f2b734 Compare July 7, 2026 07:52
@ehfd ehfd force-pushed the comprehensive-fixes branch 2 times, most recently from 155eb0b to de77558 Compare July 7, 2026 10:25
@ehfd

ehfd commented Jul 7, 2026

Copy link
Copy Markdown
Member

Fixes incorporated in de77558, linuxserver/pixelflux@b32a178, linuxserver/pcmflux@0cbadcb.

@ehfd ehfd force-pushed the comprehensive-fixes branch 18 times, most recently from 3bab531 to 4de4c8a Compare July 9, 2026 07:07
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