Phase 1a: per-slot poll viz + input-path diagnostics
Surfaced by a game (Life is Strange: Before the Storm) that ignores controller input when it lacks true OS focus even though it still polls XInput. To find the focus-gated detection path, instrument the hook. Protocol v3 status back-channel now reports: - per-slot XInputGetState and XInputGetCapabilities counters (replacing the single aggregate), so the overlay shows exactly which slots the game polls and how fast; - focus-API call counts (GetForegroundWindow/GetActiveWindow/GetFocus) to see whether the game consults the APIs we spoof; - input-path diagnostics: whether the process registered Raw Input for a gamepad usage and whether it set RIDEV_INPUTSINK (background delivery), and whether a DirectInput dll is loaded. Host overlay gains a per-slot poll table and an "Input path" section. The DLL refreshes input diagnostics each worker tick via GetRegisteredRawInputDevices. hook_selftest updated for per-slot counters; passes. This is diagnostic-only: once a real run shows which path LiS uses, the targeted focus fix (e.g. forcing RIDEV_INPUTSINK or DI background coop) follows. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -51,10 +51,21 @@ HookStatusView IpcServer::hook_status() const
|
||||
view.attached = s.attached != 0;
|
||||
view.focus_spoof = s.focus_spoof != 0;
|
||||
view.heartbeat = s.heartbeat.load(std::memory_order_relaxed);
|
||||
view.xinput_queries = s.xinput_queries.load(std::memory_order_relaxed);
|
||||
for (std::uint32_t i = 0; i < kMaxPads; ++i)
|
||||
{
|
||||
view.get_state[i] = s.get_state_calls[i].load(std::memory_order_relaxed);
|
||||
view.get_caps[i] = s.get_caps_calls[i].load(std::memory_order_relaxed);
|
||||
}
|
||||
for (std::uint32_t i = 0; i < FocusApi_Count; ++i)
|
||||
{
|
||||
view.focus_calls[i] = s.focus_query_calls[i].load(std::memory_order_relaxed);
|
||||
}
|
||||
view.game_pid = s.game_pid;
|
||||
view.game_hwnd = s.game_hwnd;
|
||||
view.last_user_index = s.last_user_index;
|
||||
view.raw_input_registered = s.raw_input_registered != 0;
|
||||
view.raw_input_gamepad = s.raw_input_gamepad != 0;
|
||||
view.raw_input_gamepad_sink = s.raw_input_gamepad_sink != 0;
|
||||
view.dinput_loaded = s.dinput_loaded != 0;
|
||||
return view;
|
||||
}
|
||||
|
||||
|
||||
@@ -18,10 +18,15 @@ struct HookStatusView
|
||||
bool attached = false; // XInput hooks installed in the game
|
||||
bool focus_spoof = false; // focus spoofing active
|
||||
std::uint32_t heartbeat = 0; // DLL liveness counter
|
||||
std::uint64_t xinput_queries = 0;
|
||||
std::uint64_t get_state[kMaxPads] = {};
|
||||
std::uint64_t get_caps[kMaxPads] = {};
|
||||
std::uint64_t focus_calls[FocusApi_Count] = {};
|
||||
std::uint32_t game_pid = 0;
|
||||
std::uint64_t game_hwnd = 0;
|
||||
std::uint32_t last_user_index = 0;
|
||||
bool raw_input_registered = false;
|
||||
bool raw_input_gamepad = false;
|
||||
bool raw_input_gamepad_sink = false;
|
||||
bool dinput_loaded = false;
|
||||
};
|
||||
|
||||
class IpcServer
|
||||
|
||||
Reference in New Issue
Block a user