DetourModKit v3.6.1
Release Title: Gamepad Consume Leading-Edge Hardening
Version: 3.6.1
Changelog:
Patch release on top of v3.6.0. It closes a leading-edge race in the gamepad passthrough suppression shipped in v3.6.0: a consume chord can no longer leak a single trigger frame to the game when the modifier and trigger are pressed within one poll interval. The fix is internal and behavioral -- there are no public API changes, and a mod that does not set InputBinding::consume on a gamepad binding sees no difference. All v3.6.0 APIs compile and link unchanged.
Input: Close the Gamepad Consume Leading-Edge Window
The v3.6.0 consume feature hides a claimed gamepad button from the state the game reads, via the XInputGetState detour. The suppression mask was published reactively by the poll thread, so it trailed the physical controller by up to one poll cycle. A game that polls XInput faster than the mod's poll loop (the usual case) could read the trigger's leading edge in that gap, before the mask caught up -- a one-frame leak of an otherwise-suppressed press. Two changes close the window:
-
Pre-arm. The poll loop now claims a consume chord's digital gamepad trigger as soon as the chord's modifiers are held, before the trigger is physically pressed, so the published mask is already up when the trigger arrives. Masking a button that is not yet down is a no-op against the game's state, and the consume-until-release latch still trails the trigger, so the trailing edge and the modifier-released-before-trigger guarantee are unchanged.
-
Detour-side chord evaluation. A consume chord the detour can evaluate from
XINPUT_GAMEPAD.wButtonsalone (its modifiers and masked triggers are all digital gamepad buttons) is reduced to a compact rule and published to the detour behind a seqlock. The detour evaluates the rule against the exact button snapshot the game is about to read, so a modifier and trigger that arrive in the same sub-poll-interval snapshot are masked on the very frame the game reads them, not a cycle later. The rule path reproduces the poll loop's strict-match decision exactly -- a chord is rejected when a modifier belonging to a different chord is held -- so the reactive and detour paths never disagree. When any known modifier is not a digital gamepad button (a keyboard or analog modifier the detour cannot observe), no rules are published and the reactive pre-arm alone covers the chord.
Behavior and safety
- Detour-side rule masking shares the reactive mask's time-to-live and is gated to focused-and-connected poll cycles, so a stalled or backgrounded poll thread stops all masking and the game regains its input -- the same self-healing guarantee the reactive mask already had.
- The rule list is published by the binding-mutation path under the input bindings lock and read lock-free by the game's XInput threads. A torn or mid-update read masks nothing for that frame and resolves on the next game poll, microseconds later. Rules change only on a binding rebuild, so a torn read never coincides with steady gameplay input.
Backwards compatibility
- No public API changes. The fix lives entirely in the internal active-input layer; the
InputBinding::consume,InputManager::set_consume/InputPoller::set_consume, andConfig::register_consume_flagsurface from v3.6.0 is unchanged. - Because DetourModKit ships as a static library, rebuild against this release rather than reusing a prebuilt v3.6.0 archive.
Full Changelog: v3.6.0...v3.6.1
Artifacts:
This release includes packages for different build environments. Both packages ensure library names are prefixed with lib for consistency (e.g., libDetourModKit.a, libDetourModKit.lib).
DetourModKit_MinGW_v3.6.1.zip: Built with MinGW (g++). ContainslibDetourModKit.a,libsafetyhook.a, headers, CMake config files. (Zydis & Zycore are statically linked into libsafetyhook.a).DetourModKit_MSVC_v3.6.1.zip: Built with MSVC (Visual Studio 2022). ContainslibDetourModKit.lib,libsafetyhook.lib(orsafetyhook.libif SafetyHook doesn't get the prefix), headers, CMake config files. (Zydis & Zycore are statically linked into libsafetyhook.lib/safetyhook.lib).
These packages are ready to be used by other CMake projects via find_package(DetourModKit).
See README for detailed usage instructions.