From 6592191624246ce2aa30569cf8abfa59b0c890be Mon Sep 17 00:00:00 2001 From: bicarus-dev <202771338+bicarus-dev@users.noreply.github.com> Date: Wed, 17 Sep 2025 03:55:02 -0700 Subject: [PATCH] pc: fix certain controller bindings not working (#368) ## Link to GitHub Issue, if one exists Fixes #364 ## Description of change The game attempts to hook raw input, but raw input API can only be used by one window per process. Hook `RegisterRawInputDevices` and prevent the game from registration for raw input notifications. ## Testing Tested that HID keyboard works with `Bind` option. --- src/spice2x/games/pc/pc.cpp | 25 +++++++++++++++++++++++++ src/spice2x/rawinput/rawinput.h | 3 ++- 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/src/spice2x/games/pc/pc.cpp b/src/spice2x/games/pc/pc.cpp index 28cc191..405bf2a 100644 --- a/src/spice2x/games/pc/pc.cpp +++ b/src/spice2x/games/pc/pc.cpp @@ -3,12 +3,15 @@ #include #include "bi2x_hook.h" +#include "util/detour.h" +#include "util/logging.h" #include "util/fileutils.h" #include "util/unity_player.h" #include "util/execexe.h" #include "acioemu/handle.h" #include "misc/wintouchemu.h" #include "hooks/graphics/graphics.h" +#include "rawinput/rawinput.h" namespace games::pc { std::string PC_INJECT_ARGS = ""; @@ -17,6 +20,24 @@ namespace games::pc { static acioemu::ACIOHandle *acioHandle = nullptr; static std::wstring portName = L"COM1"; + static decltype(RegisterRawInputDevices) *RegisterRawInputDevices_orig = nullptr; + + static BOOL WINAPI RegisterRawInputDevices_hook(PCRAWINPUTDEVICE pRawInputDevices, UINT uiNumDevices, UINT cbSize) { + + // if the caller is spice itself, then pass through. + if (pRawInputDevices && + (uiNumDevices > 0) && + (pRawInputDevices[0].hwndTarget == RI_MGR->input_hwnd)) { + + return RegisterRawInputDevices_orig(pRawInputDevices, uiNumDevices, cbSize); + } + + // otherwise, it must be the game; prevent the game from registering for raw input + // and hijacking WM_INPUT messages. + SetLastError(0xDEADBEEF); + return FALSE; + } + void PCGame::attach() { Game::attach(); @@ -39,6 +60,10 @@ namespace games::pc { } }); + const auto user32Dll = "user32.dll"; + detour::trampoline_try(user32Dll, "RegisterRawInputDevices", + RegisterRawInputDevices_hook, &RegisterRawInputDevices_orig); + if (GRAPHICS_SHOW_CURSOR) { unity_utils::force_show_cursor(true); diff --git a/src/spice2x/rawinput/rawinput.h b/src/spice2x/rawinput/rawinput.h index ff40c62..f50b09f 100644 --- a/src/spice2x/rawinput/rawinput.h +++ b/src/spice2x/rawinput/rawinput.h @@ -54,7 +54,6 @@ namespace rawinput { HotplugManager *hotplug; std::vector devices; - HWND input_hwnd = nullptr; WNDCLASSEX input_hwnd_class {}; std::thread *input_thread = nullptr; std::thread *flush_thread = nullptr; @@ -91,6 +90,8 @@ namespace rawinput { public: + HWND input_hwnd = nullptr; + RawInputManager(); ~RawInputManager();