Phase 1a: input forwarding via DLL injection + XInput hook
The host can now inject coop_hook.dll into a running game and forward controller state to it over shared memory, so the game reads the host's (eventually the guest's) input and nothing else. - hook/: coop_hook.dll. DllMain spawns a worker that opens the shared-memory channel (named by the game's pid) and installs SafetyHook inline hooks on XInputGetState/GetStateEx/GetCapabilities/SetState. Detours synthesize state from shared memory; unmanaged slots report disconnected, hiding physical pads. - host/: process picker (Toolhelp32), CreateRemoteThread(LoadLibraryW) injector with an IsWow64Process2 bitness guard, IPC server publishing pads each frame, and an ImGui Injection panel wiring it together. - tests/: hook_selftest exercises the IPC seqlock + hook detours in-process (no game/controller needed); passes. Build: SafetyHook wired in (COOP_BUILD_HOOK=ON), Zydis via FetchContent. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
54
host/src/ipc/ipc_server.cpp
Normal file
54
host/src/ipc/ipc_server.cpp
Normal file
@@ -0,0 +1,54 @@
|
||||
#include "ipc/ipc_server.hpp"
|
||||
|
||||
namespace coop
|
||||
{
|
||||
|
||||
bool IpcServer::start(unsigned long target_pid)
|
||||
{
|
||||
stop();
|
||||
|
||||
if (!shm_.create(shared_memory_name(target_pid), sizeof(SharedBlock)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
auto* block = shm_.as<SharedBlock>();
|
||||
// Fresh CreateFileMapping pages are zero-filled; set the header before the
|
||||
// hook (which validates magic/version) has a chance to read it.
|
||||
block->version = kProtocolVersion;
|
||||
block->pad_count = 0;
|
||||
block->sequence.store(0, std::memory_order_relaxed);
|
||||
block->magic = kProtocolMagic; // publish magic last so a racing reader bails
|
||||
|
||||
block_ = block;
|
||||
target_pid_ = target_pid;
|
||||
return true;
|
||||
}
|
||||
|
||||
void IpcServer::publish(const std::array<PadInfo, kMaxPads>& pads)
|
||||
{
|
||||
if (block_ == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
CoopPadState states[kMaxPads];
|
||||
for (std::size_t i = 0; i < pads.size(); ++i)
|
||||
{
|
||||
states[i] = pads[i].state;
|
||||
states[i].connected = pads[i].connected ? 1 : 0;
|
||||
}
|
||||
publish_pads(*block_, states, kMaxPads);
|
||||
}
|
||||
|
||||
void IpcServer::stop()
|
||||
{
|
||||
if (block_ != nullptr)
|
||||
{
|
||||
block_->magic = 0; // invalidate so a late hook read won't trust stale data
|
||||
block_ = nullptr;
|
||||
}
|
||||
shm_.reset();
|
||||
target_pid_ = 0;
|
||||
}
|
||||
|
||||
} // namespace coop
|
||||
Reference in New Issue
Block a user