Skip to content

Commit 5db6df3

Browse files
committed
Release v5.3 (revised): raw mouse error-87 fallback, dispatch retry, changelog
Made-with: Cursor
1 parent 52dd192 commit 5db6df3

5 files changed

Lines changed: 17 additions & 50 deletions

File tree

CHANGELOG.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22

33
## v5.3
44

5-
- Raw mouse: if `RegisterRawInputDevices` returns `ERROR_INVALID_PARAMETER` (87) for focus-following registration (`hwndTarget=NULL`), retry once with an explicit top-level HWND resolved from the game window and foreground heuristics.
6-
- Raw mouse: call `RegisterRawInputDevices` only on the thread that owns `cl_hwnd`; other threads defer. `DispatchMessageA` retries registration while raw mouse is enabled and not yet registered so deferred work completes on the game message thread.
7-
- Raw mouse: when enable is deferred, the `_sofbuddy_rawmouse` cvar path logs that registration is pending instead of reporting a hard failure.
5+
- Raw mouse: if `RegisterRawInputDevices` returns `ERROR_INVALID_PARAMETER` (87) for focus-following registration (`hwndTarget=NULL`), retry once with an explicit same-process top-level HWND (resolved via `cl_hwnd`, window heuristics, or foreground when it belongs to the game process). Non-null `hwndTarget` must be owned by the calling process; comments in `raw_shared.cpp` document that Win32 rule.
6+
- Raw mouse: `DispatchMessageA` calls `raw_mouse_ensure_registered` while `_sofbuddy_rawmouse` is on and registration is not complete yet, so enable still settles if the first attempt runs before the pump has ticked.
7+
- Raw mouse: `RegisterRawInputDevices` may still be invoked from the cvar path or other threads (same as v5.2); raw input registration is per-process and must not be restricted to the window thread only.
88

99
## v5.2
1010

src/features/raw_mouse/hooks/dispatchmessagea.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,8 @@ static bool msg_affects_cursor_clip(UINT msg) {
3434
LRESULT dispatchmessagea_override_callback(
3535
const MSG *msg, detour_DispatchMessageA::tDispatchMessageA original) {
3636
if (msg && raw_mouse_is_enabled() && raw_mouse_api_supported()) {
37-
/* Finish registration on the GUI thread after deferred attempts from
38-
* other threads (and before clip-only events). */
37+
/* Retry registration if enable ran before the pump ticked (cheap no-op once
38+
* registered). */
3939
if (!raw_mouse_registered) {
4040
raw_mouse_ensure_registered(msg->hwnd, false);
4141
}

src/features/raw_mouse/raw_cvars.cpp

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,6 @@ void raw_mouse_on_change(cvar_t *cvar)
2828
raw_mouse_ensure_registered(nullptr, true);
2929
if (raw_mouse_registered) {
3030
PrintOut(PRINT_DEV, "raw_mouse: Raw input is now ENABLED\n");
31-
} else if (raw_mouse_reg_deferred_to_gui_thread) {
32-
PrintOut(PRINT_LOG,
33-
"raw_mouse: Raw input enable pending (registration will "
34-
"complete on the game message thread)\n");
3531
} else {
3632
PrintOut(PRINT_BAD,
3733
"raw_mouse: Raw input was requested but registration failed\n");

src/features/raw_mouse/raw_shared.cpp

Lines changed: 12 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ int raw_mouse_delta_y = 0;
1313
POINT window_center = {0, 0};
1414
bool raw_mouse_center_valid = false;
1515
bool raw_mouse_registered = false;
16-
bool raw_mouse_reg_deferred_to_gui_thread = false;
1716
bool raw_mouse_cursor_clipped = false;
1817
HWND raw_mouse_hwnd_target = nullptr;
1918
static RECT raw_mouse_clip_rect = {0, 0, 0, 0};
@@ -427,20 +426,9 @@ static void RawMouseDropRegistration() {
427426
}
428427

429428
#if SOFBUDDY_RAWINPUT_API_AVAILABLE
430-
enum class RawMouseRegResult { Ok, Failed, Deferred };
431-
432-
/* RegisterRawInputDevices is only reliable from the thread that owns the game's
433-
* message queue. Other threads (e.g. GetCursorPos hook) must defer. */
434-
static bool RawMouseOnGameGuiThread() {
435-
HWND gw = RawMouseGameWindowHwnd();
436-
if (!gw || !IsWindow(gw)) {
437-
return true;
438-
}
439-
DWORD tid = 0;
440-
GetWindowThreadProcessId(gw, &tid);
441-
return GetCurrentThreadId() == tid;
442-
}
443-
429+
/* HWND used as rid.hwndTarget must belong to this process: RegisterRawInputDevices
430+
* rejects foreign HWNDs (error 87 is typical), by design so another process cannot
431+
* attach raw input to arbitrary third-party windows. */
444432
static HWND RawMouseFallbackRegistrationHwnd() {
445433
HWND w = RawMouseResolveLocalWindow(nullptr);
446434
if (w) {
@@ -453,16 +441,11 @@ static HWND RawMouseFallbackRegistrationHwnd() {
453441
return nullptr;
454442
}
455443

456-
static RawMouseRegResult RawMouseCommitRawInputRegistration(bool log_result) {
457-
if (!RawMouseOnGameGuiThread()) {
458-
if (log_result) {
459-
PrintOut(PRINT_DEV,
460-
"raw_mouse: Deferring raw input registration to the game GUI "
461-
"thread (RegisterRawInputDevices is not reliable off-thread)\n");
462-
}
463-
return RawMouseRegResult::Deferred;
464-
}
465-
444+
/* Prefer focus-following (hwndTarget=NULL). If that fails with ERROR_INVALID_PARAMETER,
445+
* retry with an explicit top-level HWND from RawMouseFallbackRegistrationHwnd (always
446+
* same-process via RawMouseNormalizeCandidateHwnd). Registration may be called from any
447+
* thread; the device list is per-process. */
448+
static bool RawMouseCommitRawInputRegistration(bool log_result) {
466449
RAWINPUTDEVICE rid = {};
467450
rid.usUsagePage = 0x01;
468451
rid.usUsage = 0x02;
@@ -489,7 +472,7 @@ static RawMouseRegResult RawMouseCommitRawInputRegistration(bool log_result) {
489472
PRINT_DEV);
490473
RawMouseLogRegisteredMouseDevice(PRINT_DEV);
491474
}
492-
return RawMouseRegResult::Ok;
475+
return true;
493476
}
494477
}
495478
}
@@ -512,7 +495,7 @@ static RawMouseRegResult RawMouseCommitRawInputRegistration(bool log_result) {
512495
}
513496
}
514497
RawMouseDropRegistration();
515-
return RawMouseRegResult::Failed;
498+
return false;
516499
}
517500

518501
raw_mouse_registered = true;
@@ -522,7 +505,7 @@ static RawMouseRegResult RawMouseCommitRawInputRegistration(bool log_result) {
522505
"(focus-following mode, hwndTarget=NULL)\n");
523506
RawMouseLogRegisteredMouseDevice(PRINT_DEV);
524507
}
525-
return RawMouseRegResult::Ok;
508+
return true;
526509
}
527510
#endif
528511

@@ -552,17 +535,7 @@ void raw_mouse_ensure_registered(HWND hwnd_hint, bool log_register_attempts) {
552535
return;
553536
}
554537
#if SOFBUDDY_RAWINPUT_API_AVAILABLE
555-
switch (RawMouseCommitRawInputRegistration(log_register_attempts)) {
556-
case RawMouseRegResult::Ok:
557-
raw_mouse_reg_deferred_to_gui_thread = false;
558-
break;
559-
case RawMouseRegResult::Deferred:
560-
raw_mouse_reg_deferred_to_gui_thread = true;
561-
return;
562-
case RawMouseRegResult::Failed:
563-
raw_mouse_reg_deferred_to_gui_thread = false;
564-
return;
565-
}
538+
if (!RawMouseCommitRawInputRegistration(log_register_attempts)) return;
566539
#endif
567540

568541
if (raw_mouse_hwnd_target) {

src/features/raw_mouse/shared.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,6 @@ extern int raw_mouse_delta_y;
3434
extern POINT window_center;
3535
extern bool raw_mouse_center_valid;
3636
extern bool raw_mouse_registered;
37-
/** True when RegisterRawInputDevices was skipped because we are not on the game GUI thread. */
38-
extern bool raw_mouse_reg_deferred_to_gui_thread;
3937
extern bool raw_mouse_cursor_clipped;
4038
extern HWND raw_mouse_hwnd_target;
4139

0 commit comments

Comments
 (0)