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:
2026-06-18 23:21:20 +02:00
parent cf058aecfa
commit e370c8dcc5
19 changed files with 1038 additions and 11 deletions

View File

@@ -0,0 +1,34 @@
// Loads coop_hook.dll into a target process via the classic
// CreateRemoteThread(LoadLibraryW) technique.
#pragma once
#include <string>
namespace coop
{
enum class InjectStatus
{
Ok,
OpenProcessFailed, // insufficient rights (try running the host as admin)
BitnessMismatch, // 32-bit target; needs the x86 hook (later phase)
DllNotFound,
AllocFailed,
WriteFailed,
RemoteThreadFailed,
RemoteLoadFailed, // LoadLibraryW returned null inside the target
};
struct InjectResult
{
InjectStatus status = InjectStatus::OpenProcessFailed;
unsigned long os_error = 0; // GetLastError at the point of failure, if any
};
const char* to_string(InjectStatus status);
// Injects `dll_path` (absolute) into the process with `pid`. The host and DLL
// must match the target's bitness; 32-bit targets are rejected up front.
InjectResult inject_dll(unsigned long pid, const std::wstring& dll_path);
} // namespace coop