// Controllers panel: the controller view of the pipeline. Shows what the host // receives from Remote Play Together (the guest pads, via the input backend) and // what the injected game actually reads back (per-slot XInput poll counts from the // hook). This is how we verify RPT routes a guest's gamepad in and the game polls // it out. The per-axis breakdown and per-slot poll table are debug-only. #pragma once #include #include "coop/protocol.hpp" #include "input/input_source.hpp" #include "ipc/ipc_server.hpp" namespace coop { class ControllersPanel { public: // `status` is the hook's back-channel (per-slot poll counters); `debug_details` // reveals the raw axis values, the per-slot poll-rate table, and the synthetic // test-input toggle. void draw(const InputSource& input, const HookStatusView& status, bool debug_details); // Whether the operator enabled "Forward synthetic test input" (a controller debug // aid). The host feeds this to InjectionPanel, which substitutes a synthetic pad. [[nodiscard]] bool test_input() const { return test_input_; } #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: bool test_input_ = false; // "Forward synthetic test input" (debug aid, default off) // 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