Fix input forwarding: default to XInput, make Steam Input opt-in

Making Steam Input the default backend silently broke input forwarding. Merely
initializing Steam Input activates Steam's in-process XInput interception, which
hides controllers from XInputGetState unless they're bound to our action set for
the running appid. With no such binding (the normal case for a donor appid) Steam
Input reports zero controllers AND XInput now sees nothing -> no input at all.

Reproduced with coop_steam_input_probe: without Steam, XInput slot 0 is seen;
with Steam Input initialized, 0 Steam controllers and the XInput fallback goes
empty.

Default to XInput (RPT delivers guest pads there and it works) and make Steam
Input an opt-in Controllers-panel toggle that switches the backend at runtime;
turning it off restores XInput. All 6 tests pass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-20 14:25:43 +02:00
parent 24d66020f6
commit 914dba4d25
4 changed files with 90 additions and 21 deletions

View File

@@ -21,11 +21,39 @@ public:
// reveals the raw axis values and the per-slot poll-rate table.
void draw(const InputSource& input, const HookStatusView& status, bool debug_details);
#ifdef COOP_WITH_STEAM
// Whether the operator has opted into Steam Input. It's off by default: simply
// initializing Steam Input activates Steam's in-process XInput interception,
// which hides controllers from XInput unless they're bound to our action set for
// this app -- so it can silently break the (working) XInput path. main reconciles
// this against the actual backend each frame.
[[nodiscard]] bool steam_input_requested() const
{
return steam_requested_;
}
void set_steam_active(bool active)
{
steam_active_ = active;
}
void on_steam_init_failed()
{
steam_requested_ = false;
steam_active_ = false;
steam_note_ = "Steam Input failed to start; using XInput.";
}
#endif
private:
// Sampled to turn the hook's cumulative per-slot counters into poll rates.
unsigned long long last_state_count_[kMaxPads] = {};
double state_rate_[kMaxPads] = {};
double last_sample_time_ = 0.0;
#ifdef COOP_WITH_STEAM
bool steam_requested_ = false; // operator opted into Steam Input (default off)
bool steam_active_ = false; // Steam Input actually initialized
const char* steam_note_ = "";
#endif
};
} // namespace coop