Move controller-poll info from Injection to Controllers panel

The per-slot XInput poll rates and the "game reading controller" summary
describe the controller, not the injection mechanism, so move them to the
Controllers panel (renamed from debug_overlay -> ControllersPanel, now a class
that owns the poll-rate sampling). The panel now shows both directions: the
guest pads the host receives from RPT, and what the injected game reads back.

The Injection panel keeps the hook attach state, focus spoof, focus-API
counts, and input-path diagnostics, and points to the Controllers panel for
poll rates.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-19 20:00:30 +02:00
parent 4e076420bf
commit 565934e8cf
8 changed files with 193 additions and 168 deletions

View File

@@ -148,21 +148,6 @@ void InjectionPanel::draw_hook_status(bool debug_details)
const HookStatusView status = server_.hook_status();
// Convert the cumulative per-slot counters into rates every half second.
const double now = ImGui::GetTime();
if (now - last_sample_time_ >= 0.5)
{
const double dt = now - last_sample_time_;
for (int i = 0; i < static_cast<int>(kMaxPads); ++i)
{
const unsigned long long delta =
status.get_state[i] >= last_state_count_[i] ? status.get_state[i] - last_state_count_[i] : 0;
state_rate_[i] = dt > 0.0 ? static_cast<double>(delta) / dt : 0.0;
last_state_count_[i] = status.get_state[i];
}
last_sample_time_ = now;
}
ImGui::SeparatorText("Hook status");
if (!status.attached)
{
@@ -173,57 +158,13 @@ void InjectionPanel::draw_hook_status(bool debug_details)
ImGui::TextColored(kGreen, "Attached (game pid %u)", status.game_pid);
ImGui::TextColored(status.focus_spoof ? kGreen : kGrey, "Focus spoof: %s",
status.focus_spoof ? "active" : "inactive");
// General summary: is the game actually polling our pad, and how fast.
double total_rate = 0.0;
for (int i = 0; i < static_cast<int>(kMaxPads); ++i)
{
total_rate += state_rate_[i];
}
if (total_rate > 0.0)
{
ImGui::TextColored(kGreen, "Game reading controller: %.0f polls/s", total_rate);
}
else
{
ImGui::TextColored(kGrey, "Game reading controller: idle");
}
ImGui::TextDisabled("Controller poll rates are in the Controllers panel.");
if (!debug_details)
{
return; // everything below is diagnostic detail
}
// Per-slot XInput polling: shows exactly which slots the game reads and how fast.
if (ImGui::BeginTable("slots", 4, ImGuiTableFlags_Borders | ImGuiTableFlags_SizingStretchProp))
{
ImGui::TableSetupColumn("Slot");
ImGui::TableSetupColumn("GetState/s");
ImGui::TableSetupColumn("GetState total");
ImGui::TableSetupColumn("GetCaps total");
ImGui::TableHeadersRow();
for (int i = 0; i < static_cast<int>(kMaxPads); ++i)
{
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::Text("%d", i);
ImGui::TableNextColumn();
if (state_rate_[i] > 0.0)
{
ImGui::TextColored(kGreen, "%.0f", state_rate_[i]);
}
else
{
ImGui::TextDisabled("0");
}
ImGui::TableNextColumn();
ImGui::Text("%llu", static_cast<unsigned long long>(status.get_state[i]));
ImGui::TableNextColumn();
ImGui::Text("%llu", static_cast<unsigned long long>(status.get_caps[i]));
}
ImGui::EndTable();
}
// Focus-API usage: tells us whether the game even consults these (which we
// spoof) when deciding it lost focus.
ImGui::Text("Focus API calls FG:%llu Active:%llu Focus:%llu",