Skip to content

fix(cursor): real magnified pointer over the emoji picker and other shell panels (#283) - #284

Merged
Maxaubert merged 5 commits into
mainfrom
fix/283-panel-pointer
Sep 29, 2026
Merged

Maxaubert merged 5 commits into
mainfrom
fix/283-panel-pointer

Conversation

@Maxaubert

Copy link
Copy Markdown
Owner

Closes #283.

The emoji picker (Win+.), clipboard history and touch keyboard are composed by the shell above every window band, so Wind's cursor went under them.

While such a panel is open (detected from TextInputHost's IME window UNCLOAKED/CLOAKED events):

  • Wind hides its cursor sprite and shows the real pointer, the only thing drawn above the panel.
  • One public MagSetFullscreenTransform write makes DWM draw that pointer magnified (measured: the private channel alone leaves the tiny hardware pointer).
  • The pointer is frozen with a 1px clip and moved by Wind from ballistics-cooked raw input, right after each view write, so it cannot drift from the view (no wobble). The freeze is hidden from the lock detector, tracking and edge mode pause, and the original clip is restored on close.

Rejected on the way (details in docs/SHELL-PANEL-CURSOR-FINDINGS.md): every window band; hook-thread writes (runtime ownership marshals every write onto the input thread: hitches).

Hidden knob panelPointer (default 1). Version 0.11.1.

Verification

  • build.bat test (all doctests), Playwright settings suite
  • Probes: pointer state per magnification channel (Desktop Duplication), wobble per write path (tools/mag_wobble_probe.ps1)
  • Owner field test on the signed UIAccess build: pointer big and on top of the picker, no wobble, no flicker, no zoom hitches, taskbar previews and jump lists clickable

🤖 Generated with Claude Code

https://claude.ai/code/session_01KPUNAWcwghXdHCApcKKjSG

Maxaubert and others added 5 commits September 29, 2026 15:40
…t panel is open (#283)

The emoji picker (and clipboard history, touch keyboard) is composed by the
shell above every window band, so the sprite went under it. While
TextInputHost's IME window is uncloaked, Wind shows the real pointer (the only
thing drawn above the panel), primes one public MagSetFullscreenTransform
write so DWM draws it magnified, and arms the hook write path so view and
pointer move together. Self-test at 8x, 900 px/s: pointer 0.2 px off-centre
with the picker open (43 px for tick-paced writes). Caret/focus tracking and
edge mode pause meanwhile. The hook thread now owns the runtime whenever
panelPointer=1 (default; restart).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KPUNAWcwghXdHCApcKKjSG
With the hook thread owning the runtime in every default session, a failed
MagSetInputTransform is retried once on the calling thread and the first
few failures are logged with both error codes. A field session saw every
publish stomped (shell dead zones); it did not reproduce after a restart,
and a stray magnifier client from probe runs is the suspect. Self-test:
0 publish failures across no-panel / panel / no-panel sessions.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KPUNAWcwghXdHCApcKKjSG
…hell panel is open (#283)

Hook-thread ownership marshalled every write onto the input thread (field:
hitches), so it is reverted. While the emoji picker is open the real pointer
is pinned by a 1px clip and moved by Wind from ballistics-cooked raw input,
right after the view write. The freeze is hidden from the lock detector (it
flapped LOCKED/free every ~20 ms: the flicker), the pointer is un-blanked
however it was hidden (invisible when zooming in with the picker open), and
the saved clip is restored on close.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KPUNAWcwghXdHCApcKKjSG
…otcha; version 0.11.1 (#283)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KPUNAWcwghXdHCApcKKjSG
- panel teardown runs on every session end (a quick-zoom snap-out left the
  pointer pinned to 1px) and releases the clip only while it is still ours
- the public prime flag resets with the runtime (tiny pointer on re-zoom)
- the mouselook gain learner ignores Wind-driven motion
- repaint nudge moves the 1px pin away and back (same-position was a no-op)
- a panel already open at startup is detected
- removed the leftover input-transform retry from the rejected hook design
- docs: pen/touch/remote limitation, review summary

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KPUNAWcwghXdHCApcKKjSG
@Maxaubert
Maxaubert merged commit 2584a86 into main Sep 29, 2026
1 check passed
@Maxaubert
Maxaubert deleted the fix/283-panel-pointer branch September 29, 2026 16:12
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.

Cursor goes under the emoji picker (and other shell input panels)

1 participant