From 9b0bd3c03f76261820ab7619f36cd2c2ae761ebd Mon Sep 17 00:00:00 2001 From: serge_shubin Date: Sat, 21 Mar 2026 20:51:28 +0800 Subject: [PATCH] Input sticky buttons fixed --- code/win32/win_input.c | 70 +++++++++++++++--------------------------- 1 file changed, 25 insertions(+), 45 deletions(-) diff --git a/code/win32/win_input.c b/code/win32/win_input.c index d7990dd..93d1f1b 100644 --- a/code/win32/win_input.c +++ b/code/win32/win_input.c @@ -343,13 +343,20 @@ void IN_DIMouse( int *mx, int *my ) { DIMOUSESTATE2 state; DWORD dwElements; HRESULT hr; - int value; + int i, value; + static BYTE oldButtons[8]; + + static const int buttonKeys[5] = { + K_MOUSE1, K_MOUSE2, K_MOUSE3, K_MOUSE4, K_MOUSE5 + }; if ( !g_pMouse ) { return; } - // fetch new events + // flush the buffered data — we only use it for wheel events. + // buttons are handled via immediate state below to avoid + // stuck keys from buffer overflow. for (;;) { dwElements = 1; @@ -361,51 +368,11 @@ void IN_DIMouse( int *mx, int *my ) { return; } - /* Unable to read data or no data available */ - if ( FAILED(hr) ) { - break; - } - - if ( dwElements == 0 ) { + if ( FAILED(hr) || dwElements == 0 ) { break; } switch (od.dwOfs) { - case DIMOFS_BUTTON0: - if (od.dwData & 0x80) - Sys_QueEvent( od.dwTimeStamp, SE_KEY, K_MOUSE1, qtrue, 0, NULL ); - else - Sys_QueEvent( od.dwTimeStamp, SE_KEY, K_MOUSE1, qfalse, 0, NULL ); - break; - - case DIMOFS_BUTTON1: - if (od.dwData & 0x80) - Sys_QueEvent( od.dwTimeStamp, SE_KEY, K_MOUSE2, qtrue, 0, NULL ); - else - Sys_QueEvent( od.dwTimeStamp, SE_KEY, K_MOUSE2, qfalse, 0, NULL ); - break; - - case DIMOFS_BUTTON2: - if (od.dwData & 0x80) - Sys_QueEvent( od.dwTimeStamp, SE_KEY, K_MOUSE3, qtrue, 0, NULL ); - else - Sys_QueEvent( od.dwTimeStamp, SE_KEY, K_MOUSE3, qfalse, 0, NULL ); - break; - - case DIMOFS_BUTTON3: - if (od.dwData & 0x80) - Sys_QueEvent( od.dwTimeStamp, SE_KEY, K_MOUSE4, qtrue, 0, NULL ); - else - Sys_QueEvent( od.dwTimeStamp, SE_KEY, K_MOUSE4, qfalse, 0, NULL ); - break; - - case DIMOFS_BUTTON4: - if (od.dwData & 0x80) - Sys_QueEvent( od.dwTimeStamp, SE_KEY, K_MOUSE5, qtrue, 0, NULL ); - else - Sys_QueEvent( od.dwTimeStamp, SE_KEY, K_MOUSE5, qfalse, 0, NULL ); - break; - case DIMOFS_Z: value = od.dwData; if (value < 0) { @@ -419,16 +386,29 @@ void IN_DIMouse( int *mx, int *my ) { } } - // read the raw delta counter and ignore - // the individual sample time / values + // read immediate device state for axes and buttons hr = IDirectInputDevice8_GetDeviceState(g_pMouse, sizeof(DIMOUSESTATE2), &state); if ( FAILED(hr) ) { *mx = *my = 0; return; } + *mx = state.lX; *my = state.lY; + + // generate button press/release events from immediate state. + // comparing against previous state avoids stuck buttons entirely — + // if a press or release was missed in the buffer, the immediate + // state catches it next frame. + for ( i = 0; i < 5; i++ ) { + BYTE down = state.rgbButtons[i] & 0x80; + if ( down != oldButtons[i] ) { + Sys_QueEvent( g_wv.sysMsgTime, SE_KEY, buttonKeys[i], + down ? qtrue : qfalse, 0, NULL ); + oldButtons[i] = down; + } + } } /*