Phase 0: donor-launch spike foundation
Scaffold CoopAllTheThings: Remote Play Together for any XInput game via a mirror app under a donor appid (real game keeps its own appid, so DRM, achievements, and playtime stay intact). - Build: CMake skeleton, ImGui + SafetyHook submodules (no vcpkg) - common/: host<->hook IPC contract (seqlock pad state, shared-memory RAII) - host/: borderless D3D11 window + ImGui overlay listing visible XInput pads, behind an InputSource interface (Steam Input slots in later) - README documents the Phase 0 donor-launch validation procedure, anti-cheat limitation, and XInput/bitness constraints Phase 0 validates the riskiest assumption (Steam RPT streams an arbitrary window under a donor appid and routes guest input to it) before capture and injection are built. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
82
host/src/debug_overlay.cpp
Normal file
82
host/src/debug_overlay.cpp
Normal file
@@ -0,0 +1,82 @@
|
||||
#include "debug_overlay.hpp"
|
||||
|
||||
#include <imgui.h>
|
||||
|
||||
namespace coop
|
||||
{
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
struct ButtonBit
|
||||
{
|
||||
std::uint16_t mask;
|
||||
const char* label;
|
||||
};
|
||||
|
||||
// XINPUT_GAMEPAD_* bit values (kept local so this file needn't include Xinput.h).
|
||||
constexpr ButtonBit kButtons[] = {
|
||||
{0x0001, "Up"}, {0x0002, "Down"}, {0x0004, "Left"}, {0x0008, "Right"}, {0x0010, "Start"},
|
||||
{0x0020, "Back"}, {0x0040, "LS"}, {0x0080, "RS"}, {0x0100, "LB"}, {0x0200, "RB"},
|
||||
{0x1000, "A"}, {0x2000, "B"}, {0x4000, "X"}, {0x8000, "Y"},
|
||||
};
|
||||
|
||||
void draw_pad(int index, const PadInfo& pad)
|
||||
{
|
||||
ImGui::PushID(index);
|
||||
if (!pad.connected)
|
||||
{
|
||||
ImGui::TextDisabled("Slot %d: disconnected", index);
|
||||
ImGui::PopID();
|
||||
return;
|
||||
}
|
||||
|
||||
ImGui::Text("Slot %d [%s]", index, pad.source.c_str());
|
||||
ImGui::Text("LT %3u RT %3u", pad.state.left_trigger, pad.state.right_trigger);
|
||||
ImGui::Text("L (%6d, %6d) R (%6d, %6d)", pad.state.thumb_lx, pad.state.thumb_ly, pad.state.thumb_rx,
|
||||
pad.state.thumb_ry);
|
||||
|
||||
bool first = true;
|
||||
ImGui::TextUnformatted("Buttons: ");
|
||||
for (const ButtonBit& b : kButtons)
|
||||
{
|
||||
if ((pad.state.buttons & b.mask) != 0)
|
||||
{
|
||||
ImGui::SameLine();
|
||||
ImGui::TextColored(ImVec4(0.4f, 1.0f, 0.4f, 1.0f), "%s%s", first ? "" : ", ", b.label);
|
||||
first = false;
|
||||
}
|
||||
}
|
||||
if (first)
|
||||
{
|
||||
ImGui::SameLine();
|
||||
ImGui::TextDisabled("(none)");
|
||||
}
|
||||
ImGui::Separator();
|
||||
ImGui::PopID();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void draw_debug_overlay(const InputSource& input)
|
||||
{
|
||||
ImGui::SetNextWindowPos(ImVec2(24, 24), ImGuiCond_FirstUseEver);
|
||||
ImGui::SetNextWindowSize(ImVec2(420, 0), ImGuiCond_FirstUseEver);
|
||||
ImGui::Begin("CoopAllTheThings - Phase 0 spike");
|
||||
|
||||
ImGui::Text("Input backend: %s", input.name());
|
||||
ImGui::Text("%.1f FPS (%.2f ms)", ImGui::GetIO().Framerate, 1000.0f / ImGui::GetIO().Framerate);
|
||||
ImGui::TextDisabled("This window is what Remote Play Together captures.");
|
||||
ImGui::TextDisabled("Press Esc to quit.");
|
||||
ImGui::Separator();
|
||||
|
||||
const auto& pads = input.pads();
|
||||
for (int i = 0; i < static_cast<int>(pads.size()); ++i)
|
||||
{
|
||||
draw_pad(i, pads[i]);
|
||||
}
|
||||
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
} // namespace coop
|
||||
Reference in New Issue
Block a user