Repository navigation
Conversation
|
@ralgar As announced, here it is. |
|
Yep, this is quite a lot. XD I'll build it and test behavior when I get a moment. Aside from that, I'll wait until I get the uniform UI plumbing finished (it's going well so it shouldn't be long), and then I can turn my full attention to this. I assume the fix you said I might want to cherry pick is that first commit? |
I told you... :-D But if you feel like it and if possible, we can break that down into smaller pieces maybe. The commit series is bisectable, so it should work by just picking one or two commits at a time (at least after the fixup commits are squashed).
Yes, it fixes Hogwarts Legecy which doesn't receive mouse clicks if vkShade is loaded, even if the GUI is not active:
|
|
One small design question before I continue:
I deliberately left this untouched for now. Refactoring it only inside the capture commit would make the shared abstraction look capture-specific. It might be cleaner to prepare a small, behavior-neutral Xlib geometry/pointer-snapshot helper on top of Would you prefer such a preparatory patch as a separate small PR, leave the duplication in this draft until the capture architecture is settled, or use a different ownership boundary? |
|
I've added a few fixups which insert comments into the code to make it easier to review. |
I figured as much, that seems to be your usual workflow. I think for now let's just leave it all together so the changes can be viewed as one unit. As I work through it I would probably break it down into smaller pieces, though. If you could squash those fixup commits that would be great btw, then I can step through them individually and still view the comments. Whenever you get a moment, no rush. |
64739af to
e12e06f
Compare
|
Updated the branch with explicit SDL2/SDL3 ABI-safe symbol resolution, synchronized SDL event-filter state, and native SDL3 relative-mouse inhibition. SDL3 window operations are dispatched asynchronously to its main thread, with generation tracking preventing stale work during rapid overlay state changes. I also autosquashed the existing fixups, reordered the commits semantically, rebased onto current main, and successfully smoke-tested the result with ETS2. |
|
Would you mind cherry-picking that first commit and rebasing on The GUI work will likely be completed by the end of this weekend, which will finally mark v0.1 and graduate the project to alpha status. So I'd like to get that fix merged as well. I still think the whole Xlib backend needs an overhaul, and I'm experimenting with some stuff there on the side, but no concrete action will be taken until after v0.1 is released and any initial bugs are worked out. |
Sure, will do.
Maybe it does. By researching the different sources of why mouse capture doesn't properly work in one or another game, finding that each may work different, I think vkShade might not only need a different Xlib backend per-se, but a generic input backend design with input inhibitors in mind. This PR does not exist as a request to merge as-is but rather as a research to find all the different aspects of mouse capture, and how it could be solved, discovering their input implementations. If time comes, we should treat this PR as an issue report and a reference with code examples rather than something I'd want to merge as-is. It's also rather big and not something intended to review as a whole. |
e1becd5 to
5072b6e
Compare
5072b6e to
70c1b27
Compare
|
The branch has been rebased onto current The main functional addition since the previous review is native Wayland mouse capture. It uses relative-pointer and pointer-constraints protocols on vkShade's isolated event queue and waits for confirmed release of an application-owned constraint before acquiring its own. The Xlib path also gained the XI2 physical-source fallback, SDL2/SDL3 ABI-safe inhibition, and stronger capture-state reconciliation. The final branch builds successfully and passes all 12 tests. The Xlib/XWayland path retains its existing multi-game runtime coverage. Native Wayland runtime testing is still pending, particularly the fractional-scaling scenario from #134. |
Wrap borrowed application Wayland displays with a vkShade-owned registry and event queue. Keep feature proxies on the isolated queue so input and future platform services can share the lifecycle without dispatching application events. Migrate the input backend to the shared context and release its seat, keyboard, and pointer proxies before tearing down the queue.
Separate capture requests, application inhibition, and native backend acquisition. Keep failed native acquisition retryable without replaying the inhibition transition, and represent asynchronous backend activation explicitly.
Centralize bounded cursor motion, application-warp rejection, and discontinuity handling for native input backends. Support root-relative, relative, and absolute event sources through one cursor state.
Allow independent application-input adapters to participate in one capture transition. Restore only adapters that acquired state, in reverse order, so SDL and Wine integration can remain isolated and optional.
Move application-side mouse suppression behind optional adapters. Resolve one SDL ABI through a version-specific anchor and bind every function to the same loaded object, because SDL2 and SDL3 export common event-filter symbols with different callback and return ABIs. Preserve and conditionally restore SDL state without overwriting a later event filter, and guard the predecessor and ownership state, since SDL may invoke the process-wide filter from any thread. Keep Wine clipping and Raw Input lifecycle independent of native window-system capture.
Use SDL3's window-specific relative-mode API and bool event-filter ABI. Dispatch window operations asynchronously to SDL's main thread, preserve restore state by window ID, and ignore stale work across rapid overlay state changes.
Connect GUI visibility to the capture controller while keeping backend setup and teardown explicit. Retry native acquisition during regular input updates without repeating application-side inhibition.
Let application input inhibitors report asynchronous readiness and confirmed pointer-constraint release. Require that handoff before native backends which replace an application-owned Wayland constraint can acquire capture.
Track the Vulkan Wayland surface and bind relative-pointer and pointer-constraints protocols on vkShade's isolated event queue. Drive the shared virtual cursor from relative motion while the overlay owns a persistent pointer lock. Handle same-display surface replacement, seat capability loss, cursor hiding, explicit request flushing, and protocol teardown without dispatching application events. Release the input backend when its surface or the last instance is destroyed, so its proxies are not destroyed after the application has disconnected from Wayland.
Decode packed XI2 valuator masks independently from Xlib event ownership so source-device fallback motion can be reviewed without native capture lifecycle changes.
Acquire pointer events through a private Xlib connection, suppress raw application input, and drive the shared virtual cursor while rejecting game warps. Reset the cursor and root-motion baseline to the absolute pointer position after acquisition and window re-entry, so the OS and overlay cursors keep no persistent offset. Reconcile focus in the frame path, retry failed acquisition through the controller, and safely restore an application grab across surface replacement.
Wine applications may retain a core pointer grab after overlay input is requested. This prevents a second Xlib connection from acquiring the pointer and suppresses master-device raw motion. Observe physical XI2 source devices while native capture is pending and drive the shared virtual cursor from their relative valuators. Filter master events to avoid duplicate motion, button, and wheel input. Initialize the virtual cursor from the real pointer when possible. Stop absolute polling as soon as capture is requested so application center warps cannot overwrite fallback motion.
70c1b27 to
a801d02
Compare
|
Updated and force-pushed. The branch is now ordered in layers (Wayland client context, backend-neutral foundation, application inhibition, reconciliation and handoff, Wayland capture, Xlib last), see the new section in the description.
The branch is rebased onto current |
Note
This remains a draft/RFC and a reference for the design, not something to merge as a whole. The Xlib/XWayland implementation has received broad runtime testing, while native Wayland capture is still untested at runtime. I keep this branch rebased and will split individual layers out as separate PRs when you are interested, and rebase this branch after each merge until nothing is left.
Feedback on state ownership, application-input inhibition, and backend boundaries would be especially useful before any of this is prepared for integration.
Summary
This series gives the vkShade overlay an independent mouse-capture path instead of relying on the application's absolute cursor position.
It:
How the series is organized
The commits are ordered in layers so that they can be picked apart. Each commit builds on its own.
refactor(platform): isolate Wayland client context): a private event queue and shared display state for the Wayland services.MouseCaptureController(capture state),VirtualMouseCursor, andMouseInputInhibitorGroup. None of these files mention Wayland, Xlib, or XCB.Motivation
Some Wine and Proton applications keep controlling, centering, clipping, or exclusively grabbing the pointer while the vkShade GUI is visible.
Cyberpunk 2077 can leave the overlay cursor near the center while mouse movement continues to affect the game. Other engines use different cursor-warp, Raw Input, SDL, or native window-system paths. Treating a successful pointer grab as the complete capture state therefore fails across games and display backends.
The overlay instead maintains its own virtual cursor, inhibits the application's input path where possible, and reconciles native capture independently.
Architecture
Capture controller
MouseCaptureControllerowns the overlay capture request and reconciles:Failed native acquisition remains retryable without repeating successful inhibition transitions.
Application inhibition
MouseInputInhibitorGroupcomposes optional SDL and Wine adapters. It restores only adapters that acquired state and does so in reverse order.SDL2 and SDL3 are resolved as separate runtime ABIs. SDL3 window operations use its asynchronous main-thread dispatcher, with generation tracking preventing stale work during rapid overlay close and reopen transitions.
Virtual cursor
VirtualMouseCursorcentralizes bounds handling, relative integration, known application-warp rejection, and resynchronization after unknown absolute discontinuities.The native backends provide observations while cursor policy remains backend-independent.
Xlib and XWayland
The Xlib backend owns private event connections and native grab state. When another X client retains the core pointer grab, vkShade observes physical XI2 source-device events for relative motion, buttons, and wheel input.
Events are filtered where
deviceid == sourceid, avoiding duplicate master and source events. Capture metadata is retained across surface replacement only while the application connection remains compatible.Native Wayland
The Wayland backend tracks the Vulkan surface and binds relative-pointer and pointer-constraints protocols on a vkShade-owned event queue.
Application inhibition must confirm that an existing game constraint has been released before vkShade requests its own constraint. This avoids the fatal Wayland
already_constrainedprotocol error.While capture is active, relative motion drives the shared virtual cursor and the native cursor is hidden. Surface replacement, seat capability loss, explicit request flushing, and protocol teardown remain isolated from the application's event queue.
The input backend is released when its Vulkan surface (or, as a fallback, the last instance) is destroyed, while the application still owns its Wayland connection. Before this, the backend's destructor ran at process exit and destroyed proxies of a display connection that the application had already closed, which crashed at exit.
Scope
This draft covers overlay mouse capture on Xlib/XWayland and native Wayland.
Keyboard isolation remains a separate concern: keyboard events can still reach the application while the overlay is open. An XCB native-acquisition backend and further query caching remain possible follow-ups.
Verification
Build:
I checked the state handling, inhibitor composition, SDL ABI isolation, virtual cursor, and XI2 decoding with unit tests. They are not part of this PR.
Manual Xlib/XWayland testing:
Native Wayland testing:
VK_KHR_wayland_surfacepath (vkcube with the Khronos validation layer; this found and fixed the exit-time crash mentioned above)Closes #39
Closes #134