Cursor capture: hide the OS cursor and lock/confine the mouse to the window (Input.cursor_mode) #89
Labels
No labels
area:ci
area:docs
area:input
area:net
area:rendering
area:repo
area:stdlib
area:tooling
area:types
cleanup
dx
priority:high
priority:low
priority:medium
proposal
status:in-progress
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference: workshopsoft/ludic#89
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
A windowed action game aiming with the mouse needs to (a) hide the OS cursor while playing and draw its own reticle, and (b) keep the mouse from leaving the window (confine or lock+relative deltas), releasing both in pause/menus and on focus loss. The platform layer (runtime/native/cocoa.ll) has no cursor support at all — no NSCursor hide/unhide, no CGAssociateMouseAndMouseCursorPosition / CGWarpMouseCursorPosition — and there is no Input/Window builtin for it.
Proposal:
Input.cursor_mode(mode)with[NSCursor hide]while the window is key; unhide on focus loss / mode change.CGAssociateMouseAndMouseCursorPosition(false)+ warp to the window centre each frame, feedingInput.mouse_dx/dyas relative motion (and clampingmouse_x/yto the framebuffer) — the FPS/twin-stick capture mode.Auto-release: any mode returns to 0 while the window is not key (Cmd-Tab), and on
win_close. Headless: no-op. Windows/Linux backends implement the same contract (SetCursor/ClipCursor, XGrabPointer / SDL_SetRelativeMouseMode).Needs a new win_* intrinsic (emit_intrin2) + the cocoa.ll implementation +
Input.cursor_modein emit_call. Motivated by Emberdepths: the cursor wanders off the window mid-fight and the OS arrow sits over the game's own reticle.Shipped in
3eb5447(full suite 115/0, fixpoint intact).Input.cursor_mode(mode)with the four modes from the proposal:0normal — cursor visible and free (default)1hidden —[NSCursor hide]while the window is key; draw your own reticle2locked — hidden +CGAssociateMouseAndMouseCursorPosition(false); the mouse feeds relative motion throughInput.mouse_dx/dy(viaCGGetLastMouseDelta), andInput.mouse_x/yis a clamped virtual cursor — the FPS / twin-stick capture mode3confined — dissociated but visible; the mouse can't leave the windowAuto-release is handled every frame from
win_poll: while the window is not key (Cmd-Tab) the cursor is shown + reconnected, and it re-acquires on refocus — andwin_closerestores it, so a game never leaves the cursor hidden/locked. Headless / non-windowed it is a no-op (thewin_cursor_modecall is DCE'd behindis_windowed()).Implementation is all in the platform layer as the issue laid out: a new
win_cursor_modeintrinsic (emit_intrin2 + the emit_headdeclare) + thecocoa.llimplementation (NSCursor hide/unhide— ref-counted, so I track the applied state and toggle only on a change to keep the hide count balanced across focus changes;CGAssociateMouseAndMouseCursorPosition;CGGetLastMouseDelta) +Input.cursor_modein emit_call.This is windowed-only behaviour, so it's not in the headless golden suite;
examples/library/cursor_capture.ludicis wired as a compile smoke (it draws a reticle at the captured mouse position) and I verified a windowed build links cleanly against the new cocoa.ll. A Windows/Linux backend implements the samewin_cursor_modecontract (SetCursor/ClipCursor, XGrabPointer / SDL_SetRelativeMouseMode).One honest note on mode 3: it currently dissociates + clamps the virtual cursor (so the mouse can't leave), rather than warping the visible OS cursor back at the window edge each frame — a precise visible-confine warp needs the window/screen frame math and can be a follow-up if you want the visible arrow to slide along the edge.