Hook registry: list installed hooks + call counts in Injection panel
Add a process-wide hook registry (hook/src/hook_registry) that every hook module registers its hooks with and bumps a counter from each detour. The XInput, focus-spoof, and audio render-hooks now register their individual hooks (XInputGetState/Ex/Caps/SetState; GetForegroundWindow/GetActiveWindow/ GetFocus/WndProc guard; IMMDevice::Activate, IAudioClient::Initialize/ GetService, IAudioRenderClient::GetBuffer/ReleaseBuffer) and count calls. The worker publishes the table to the host each tick over a new HookStatus field (protocol v4 -> v5: HookEntry[] + count). The Injection panel shows it as a collapsible table grouped by subsystem with an installed flag and call count per hook; coop_audio_probe prints the same table headless. Verified against Phantom Brave: 13 hooks listed with live counts (focus APIs polled heavily, GetBuffer/ReleaseBuffer ticking with the audio render loop). All four tests pass. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -139,6 +139,67 @@ void InjectionPanel::publish(const std::array<PadInfo, kMaxPads>& pads)
|
||||
server_.publish(synthetic);
|
||||
}
|
||||
|
||||
void InjectionPanel::draw_hook_list(const HookStatusView& status)
|
||||
{
|
||||
static const char* kSubsysName[] = {"Input", "Focus", "Audio"};
|
||||
|
||||
const std::uint32_t n = status.hook_entry_count < kMaxHookEntries ? status.hook_entry_count : kMaxHookEntries;
|
||||
if (n == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ImGui::CollapsingHeader("Installed hooks", ImGuiTreeNodeFlags_DefaultOpen))
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (ImGui::BeginTable("hooks", 3, ImGuiTableFlags_Borders | ImGuiTableFlags_SizingStretchProp))
|
||||
{
|
||||
ImGui::TableSetupColumn("Hook");
|
||||
ImGui::TableSetupColumn("On", ImGuiTableColumnFlags_WidthFixed);
|
||||
ImGui::TableSetupColumn("Calls", ImGuiTableColumnFlags_WidthFixed);
|
||||
ImGui::TableHeadersRow();
|
||||
|
||||
// Group rows by subsystem so related hooks sit together.
|
||||
for (std::uint32_t sub = 0; sub < HookSubsys_Count; ++sub)
|
||||
{
|
||||
bool header_done = false;
|
||||
for (std::uint32_t i = 0; i < n; ++i)
|
||||
{
|
||||
const HookEntry& e = status.hook_entries[i];
|
||||
if (e.subsystem != sub)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (!header_done)
|
||||
{
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextDisabled("%s", kSubsysName[sub < 3 ? sub : 0]);
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TableNextColumn();
|
||||
header_done = true;
|
||||
}
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextUnformatted(e.name);
|
||||
ImGui::TableNextColumn();
|
||||
if (e.installed)
|
||||
{
|
||||
ImGui::TextColored(kGreen, "yes");
|
||||
}
|
||||
else
|
||||
{
|
||||
ImGui::TextDisabled("no");
|
||||
}
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("%llu", static_cast<unsigned long long>(e.calls));
|
||||
}
|
||||
}
|
||||
ImGui::EndTable();
|
||||
}
|
||||
}
|
||||
|
||||
void InjectionPanel::draw_hook_status(bool debug_details)
|
||||
{
|
||||
if (!server_.running())
|
||||
@@ -160,6 +221,8 @@ void InjectionPanel::draw_hook_status(bool debug_details)
|
||||
status.focus_spoof ? "active" : "inactive");
|
||||
ImGui::TextDisabled("Controller poll rates are in the Controllers panel.");
|
||||
|
||||
draw_hook_list(status);
|
||||
|
||||
if (!debug_details)
|
||||
{
|
||||
return; // everything below is diagnostic detail
|
||||
|
||||
Reference in New Issue
Block a user