Skip to content

Commit 2154efb

Browse files
committed
Release v5.0: raw mouse pump WM_INPUT skip, cvar callback fix, logging
1 parent 70bd830 commit 2154efb

6 files changed

Lines changed: 94 additions & 24 deletions

File tree

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# Changelog
22

3+
## v5.0
4+
5+
- Raw mouse: message pump no longer removes `WM_INPUT` from the queue (avoids high-frequency peel cost on high-poll mice). Uses filtered `PeekMessage` bands around `WM_INPUT` when it blocks the head; otherwise `GetMessage` for strict FIFO. When both low-ID and high-ID candidates exist, orders by `MSG.time` with high-band tie-break for mouse/client messages. Raises per-pump cap to 10 dispatched messages; updates `sys_msg_time` and centralizes quit/dispatch in `DispatchOneMsg`.
6+
- Raw mouse: fix enabling `_sofbuddy_rawmouse` when the engine runs the cvar change callback before `Cvar_Get` returns — set `in_mouse_raw = cvar` at the start of `raw_mouse_on_change`; drop redundant second `raw_mouse_on_change` after registration (avoids false “not enabled” / “registration failed” pairs and duplicate “ENABLED” logs).
7+
- Raw mouse: optional dev logging when `raw_mouse_ensure_registered` is asked to log — “not enabled or API not supported”, “already registered for this window”; `raw_mouse_register_input` logs “Raw input registration succeeded” when registration completes.
8+
39
## v4.9
410

511
- Raw mouse: register raw input only with HWNDs owned by the game process (`GetWindowThreadProcessId` vs `GetCurrentProcessId`). Resolve the window via `GetGUIThreadInfo`, then `GetActiveWindow` / `GetForegroundWindow` only when they are local, plus `EnumThreadWindows` fallback—fixes `RegisterRawInputDevices` failing with error 87 (`ERROR_INVALID_PARAMETER`) when foreground belonged to another app or at startup. Cvar enable uses the same `raw_mouse_ensure_registered` path as the message pump; clearer log lines for invalid HWND and for error 87.

VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
4.9
1+
5.0

hdr/version.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,4 @@
77
Increment version using: ./increment_version.sh
88
*/
99

10-
#define SOFBUDDY_VERSION "4.9"
10+
#define SOFBUDDY_VERSION "5.0"

src/features/raw_mouse/raw_cvars.cpp

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ cvar_t * in_mouse_raw = NULL;
1313
void raw_mouse_on_change(cvar_t *cvar)
1414
{
1515
if (!cvar) return;
16+
/* Cvar_Get may invoke this callback before returning; in_mouse_raw is not
17+
* assigned yet, so raw_mouse_is_enabled() would read a null pointer. */
18+
in_mouse_raw = cvar;
1619

1720
raw_mouse_reset_deltas();
1821
raw_mouse_center_valid = false;
@@ -38,11 +41,6 @@ void raw_mouse_on_change(cvar_t *cvar)
3841
void create_raw_mouse_cvars(void) {
3942
in_mouse_raw = orig_Cvar_Get("_sofbuddy_rawmouse", "0", CVAR_SOFBUDDY_ARCHIVE, &raw_mouse_on_change);
4043

41-
// Apply archived state immediately in case callback is not triggered on load.
42-
if (in_mouse_raw && in_mouse_raw->value != 0.0f) {
43-
raw_mouse_on_change(in_mouse_raw);
44-
}
45-
4644
PrintOut(PRINT_DEV, "raw_mouse: Registered _sofbuddy_rawmouse cvar with change callback\n");
4745
}
4846

src/features/raw_mouse/raw_message_pump.cpp

Lines changed: 68 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -13,30 +13,83 @@
1313
#ifndef WM_INPUT
1414
#define WM_INPUT 0x00FF
1515
#endif
16-
#ifndef WM_QUIT
17-
#define WM_QUIT 0x0012
18-
#endif
1916

20-
static const int MAX_MSG_PER_FRAME = 5;
17+
static const int MAX_MSG_PER_FRAME = 10;
2118

2219
static void QuitPath();
2320
static void SV_Shutdown(char*, int);
21+
static unsigned* SysMsgTimePtr();
22+
23+
24+
static void DispatchOneMsg(MSG* m, bool from_winmain) {
25+
if (m->message == WM_QUIT) {
26+
if (from_winmain) {
27+
SV_Shutdown(nullptr, 0);
28+
}
29+
QuitPath();
30+
}
31+
*SysMsgTimePtr() = static_cast<unsigned>(m->time);
32+
TranslateMessage(m);
33+
DispatchMessageA(m);
34+
}
2435

2536
void PumpWindowMessagesCapped(bool from_winmain) {
2637
MSG msg;
38+
MSG low_msg;
39+
MSG high_msg;
2740
int processed = 0;
41+
/* WM_INPUT is never removed (avoids high-frequency peel cost). When it sits at
42+
* the queue head, PeekMessage with ID bands skips it and removes the next matching
43+
* message. When the head is not WM_INPUT, GetMessage preserves strict FIFO.
44+
* If both bands have a candidate (WM_INPUT at head, or interleaved), msg.time
45+
* picks the earlier; tie-break prefers high band (mouse / client-area messages). */
2846
while (processed < MAX_MSG_PER_FRAME &&
29-
PeekMessageA(&msg, nullptr, 0, WM_INPUT - 1, PM_REMOVE)) {
30-
if (msg.message == WM_QUIT) { if (from_winmain) SV_Shutdown(nullptr, 0); QuitPath(); }
31-
TranslateMessage(&msg);
32-
DispatchMessageA(&msg);
33-
++processed;
34-
}
35-
while (processed < MAX_MSG_PER_FRAME &&
36-
PeekMessageA(&msg, nullptr, WM_INPUT + 1, 0xFFFFFFFF, PM_REMOVE)) {
37-
if (msg.message == WM_QUIT) { if (from_winmain) SV_Shutdown(nullptr, 0); QuitPath(); }
38-
TranslateMessage(&msg);
39-
DispatchMessageA(&msg);
47+
PeekMessageA(&msg, nullptr, 0, 0, PM_NOREMOVE)) {
48+
if (msg.message != WM_INPUT) {
49+
if (!GetMessageA(&msg, nullptr, 0, 0)) {
50+
if (from_winmain) {
51+
SV_Shutdown(nullptr, 0);
52+
}
53+
QuitPath();
54+
}
55+
DispatchOneMsg(&msg, from_winmain);
56+
++processed;
57+
continue;
58+
}
59+
60+
const BOOL has_low =
61+
PeekMessageA(&low_msg, nullptr, 0, WM_INPUT - 1, PM_NOREMOVE);
62+
const BOOL has_high = PeekMessageA(&high_msg, nullptr, WM_INPUT + 1, 0xFFFFFFFF,
63+
PM_NOREMOVE);
64+
if (!has_low && !has_high) {
65+
break;
66+
}
67+
if (has_low && !has_high) {
68+
if (!PeekMessageA(&msg, nullptr, 0, WM_INPUT - 1, PM_REMOVE)) {
69+
break;
70+
}
71+
} else if (!has_low && has_high) {
72+
if (!PeekMessageA(&msg, nullptr, WM_INPUT + 1, 0xFFFFFFFF, PM_REMOVE)) {
73+
break;
74+
}
75+
} else {
76+
const DWORD t_low = low_msg.time;
77+
const DWORD t_high = high_msg.time;
78+
if (t_low < t_high) {
79+
if (!PeekMessageA(&msg, nullptr, 0, WM_INPUT - 1, PM_REMOVE)) {
80+
break;
81+
}
82+
} else if (t_high < t_low) {
83+
if (!PeekMessageA(&msg, nullptr, WM_INPUT + 1, 0xFFFFFFFF, PM_REMOVE)) {
84+
break;
85+
}
86+
} else {
87+
if (!PeekMessageA(&msg, nullptr, WM_INPUT + 1, 0xFFFFFFFF, PM_REMOVE)) {
88+
break;
89+
}
90+
}
91+
}
92+
DispatchOneMsg(&msg, from_winmain);
4093
++processed;
4194
}
4295
}

src/features/raw_mouse/raw_shared.cpp

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -231,7 +231,12 @@ static HWND RawMouseGetRoot(HWND hwnd) {
231231
}
232232

233233
void raw_mouse_ensure_registered(HWND hwnd_hint, bool log_register_attempts) {
234-
if (!raw_mouse_is_enabled() || !raw_mouse_api_supported()) return;
234+
if (!raw_mouse_is_enabled() || !raw_mouse_api_supported()){
235+
if (log_register_attempts) {
236+
PrintOut(PRINT_BAD, "raw_mouse: Raw input is not enabled or API is not supported\n");
237+
}
238+
return;
239+
}
235240
if (raw_mouse_hwnd_target && !IsWindow(raw_mouse_hwnd_target)) {
236241
raw_mouse_registered = false;
237242
raw_mouse_hwnd_target = nullptr;
@@ -247,7 +252,12 @@ void raw_mouse_ensure_registered(HWND hwnd_hint, bool log_register_attempts) {
247252
return;
248253
}
249254
HWND root = RawMouseGetRoot(hwnd);
250-
if (raw_mouse_registered && raw_mouse_hwnd_target && IsWindow(raw_mouse_hwnd_target) && RawMouseGetRoot(raw_mouse_hwnd_target) == root) return;
255+
if (raw_mouse_registered && raw_mouse_hwnd_target && IsWindow(raw_mouse_hwnd_target) && RawMouseGetRoot(raw_mouse_hwnd_target) == root) {
256+
if (log_register_attempts) {
257+
PrintOut(PRINT_DEV, "raw_mouse: Raw input is already registered for this window\n");
258+
}
259+
return;
260+
}
251261
raw_mouse_register_input(root, log_register_attempts);
252262
}
253263

@@ -373,6 +383,9 @@ bool raw_mouse_register_input(HWND hwnd, bool log_result) {
373383
raw_mouse_registered = true;
374384
raw_mouse_hwnd_target = hwnd;
375385
raw_mouse_refresh_cursor_clip(hwnd);
386+
if (log_result) {
387+
PrintOut(PRINT_DEV, "raw_mouse: Raw input registration succeeded\n");
388+
}
376389
return true;
377390
#endif
378391
}

0 commit comments

Comments
 (0)