mirror of
https://github.com/ddeverill/SteamlessController.git
synced 2026-10-21 14:12:16 -05:00
Game mode refused a shared handle outright whenever steam.exe was running, on the reasoning that the holder was probably Steam and that refusing would escalate to a device cycle that took the handle back. On machines where that cycle never wins the reopen race, it took nothing back and the app simply never worked: #79 counted 731 blocked claims in a single day against zero successes, and both of that reporter's successes across the whole log came through the shared path with Steam closed, never through an exclusive claim. No exclusive claim is obtainable against a live write handle, however polite its holder. Windows share arbitration runs in both directions: FILE_SHARE_READ asks the kernel to deny write access to everyone else, and it must refuse while such a handle exists. Measured on a puck receiver with Steam running, even GENERIC_READ with FILE_SHARE_READ returns ERROR_SHARING_VIOLATION, so it is our share mode being rejected rather than our access. "Steam only holds it shared" and "we can take it exclusively" were never compatible statements. Shared is now the last resort rather than a refusal. The claim still prefers exclusivity and a blocked claim still escalates to a device cycle exactly as before, so machines that win that race keep winning it. Only once cycling is over — the budget spent, or a cycle shown to have invalidated no handles — does the acquire path retry with sharing allowed, immediately before it would otherwise report failure. Two callers that rebuild an already-running game mode pass it too: a slot arriving late should join rather than be dropped, and a platform change should not cost the user their controller. Sharing is not free, which is why it is last. Steam keeps driving the same controller, and its stock desktop layout binds both the left stick and the D-pad to arrow keys. Measured with a dual-channel sampler: 16 D-pad presses produced 16 matching global UP/DOWN_ARROW keystrokes 1-2ms later, press and release both mirrored. Those are real SendInput keystrokes, so they reach processes Steam cannot inject into — the doubling was first reported in a Game Pass title. The tray reports the state rather than hiding it: a distinct icon and a "(sharing with Steam)" tooltip, so a user chasing doubled input knows where to look. Slots are probed quickly before they are probed properly. A receiver publishes an interface per slot and only one has a controller in it, but every empty slot cost the full 250ms state-report timeout before the live one was even reached — up to 750ms, spent before the first claim attempt. Steam reclaims the device about 180ms after it re-arrives, so that ordering handed it the race whenever re-enumeration put the live slot last. A 25ms pass now runs first, since a live slot streams continuously and answers within a few reports. Measured across a device cycle with the live slot arriving last: arrival to exclusive claim fell from 1697ms to 99ms. A quick probe that comes up short is not evidence of an empty slot, so it neither records the slot as silent nor logs it; otherwise a controller slow to resume streaming would be latched out of the full pass that follows. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
352 KiB
352 KiB