Upgrade mouse input from DirectInput 3 to DirectInput 8

- Use DirectInput8Create() instead of dynamic dinput.dll loading
- Switch to LPDIRECTINPUT8 / LPDIRECTINPUTDEVICE8 types and DI8 macros
- Replace custom MYDATA data format with c_dfDIMouse2 (8-button support)
- Use DIMOUSESTATE2 in GetDeviceState (correct size, 8 buttons)
- Add MOUSE5 button mapping via DIMOFS_BUTTON4
- Link against dinput8.lib; define required GUIDs inline to avoid dxguid.lib conflicts
- Fix .gitignore: remove Win32/ pattern that was shadowing code/win32/ source dir

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Sergei Shubin 2026-03-18 13:44:21 +08:00
parent f85c79bf5a
commit 111dce16ab
4 changed files with 49 additions and 105 deletions

1
.gitignore vendored
View file

@ -19,7 +19,6 @@ Debug/
Release/
Release_TA/
x64/
Win32/
*___Win32_*/
# Intermediate build files

View file

@ -155,7 +155,7 @@
<SuppressStartupBanner>true</SuppressStartupBanner>
</ClCompile>
<Link>
<AdditionalDependencies>winmm.lib;wsock32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>dinput8.lib;winmm.lib;wsock32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>.\Release_TA/quake3.exe</OutputFile>
<SuppressStartupBanner>true</SuppressStartupBanner>
<ProgramDatabaseFile>Release_TA/quake3.pdb</ProgramDatabaseFile>
@ -199,7 +199,7 @@
<DebugInformationFormat>EditAndContinue</DebugInformationFormat>
</ClCompile>
<Link>
<AdditionalDependencies>winmm.lib;wsock32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>dinput8.lib;winmm.lib;wsock32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>.\Debug/quake3.exe</OutputFile>
<SuppressStartupBanner>true</SuppressStartupBanner>
<GenerateDebugInformation>true</GenerateDebugInformation>
@ -246,7 +246,7 @@
<DebugInformationFormat>OldStyle</DebugInformationFormat>
</ClCompile>
<Link>
<AdditionalDependencies>winmm.lib;wsock32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>dinput8.lib;winmm.lib;wsock32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>.\quake3___Win32_Release_TA_DEMO/quake3.exe</OutputFile>
<SuppressStartupBanner>true</SuppressStartupBanner>
<GenerateDebugInformation>true</GenerateDebugInformation>
@ -287,7 +287,7 @@
<SuppressStartupBanner>true</SuppressStartupBanner>
</ClCompile>
<Link>
<AdditionalDependencies>winmm.lib;wsock32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>dinput8.lib;winmm.lib;wsock32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>.\Release/quake3.exe</OutputFile>
<SuppressStartupBanner>true</SuppressStartupBanner>
<GenerateDebugInformation>true</GenerateDebugInformation>
@ -328,7 +328,7 @@
<DebugInformationFormat>EditAndContinue</DebugInformationFormat>
</ClCompile>
<Link>
<AdditionalDependencies>winmm.lib;wsock32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>dinput8.lib;winmm.lib;wsock32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>.\quake3___Win32_Debug_TA_DEMO/quake3.exe</OutputFile>
<SuppressStartupBanner>true</SuppressStartupBanner>
<GenerateDebugInformation>true</GenerateDebugInformation>
@ -372,7 +372,7 @@
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
</ClCompile>
<Link>
<AdditionalDependencies>winmm.lib;wsock32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>dinput8.lib;winmm.lib;wsock32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>.\quake3___Win32_vector0/quake3.exe</OutputFile>
<SuppressStartupBanner>true</SuppressStartupBanner>
<GenerateDebugInformation>true</GenerateDebugInformation>
@ -413,7 +413,7 @@
<DebugInformationFormat>EditAndContinue</DebugInformationFormat>
</ClCompile>
<Link>
<AdditionalDependencies>winmm.lib;wsock32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>dinput8.lib;winmm.lib;wsock32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>.\Debug_TA/quake3.exe</OutputFile>
<SuppressStartupBanner>true</SuppressStartupBanner>
<GenerateDebugInformation>true</GenerateDebugInformation>

View file

@ -202,50 +202,12 @@ DEFINE_GUID(GUID_SysMouse, 0x6F1D2B60,0xD5A0,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0
DEFINE_GUID(GUID_XAxis, 0xA36D02E0,0xC9F3,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00);
DEFINE_GUID(GUID_YAxis, 0xA36D02E1,0xC9F3,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00);
DEFINE_GUID(GUID_ZAxis, 0xA36D02E2,0xC9F3,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00);
DEFINE_GUID(IID_IDirectInput8A, 0xBF798031,0x483A,0x4DA2,0xAA,0x99,0x5D,0x64,0xED,0x36,0x97,0x00);
#define DINPUT_BUFFERSIZE 16
#define iDirectInputCreate(a,b,c,d) pDirectInputCreate(a,b,c,d)
HRESULT (WINAPI *pDirectInputCreate)(HINSTANCE hinst, DWORD dwVersion,
LPDIRECTINPUT * lplpDirectInput, LPUNKNOWN punkOuter);
static HINSTANCE hInstDI;
typedef struct MYDATA {
LONG lX; // X axis goes here
LONG lY; // Y axis goes here
LONG lZ; // Z axis goes here
BYTE bButtonA; // One button goes here
BYTE bButtonB; // Another button goes here
BYTE bButtonC; // Another button goes here
BYTE bButtonD; // Another button goes here
} MYDATA;
static DIOBJECTDATAFORMAT rgodf[] = {
{ &GUID_XAxis, FIELD_OFFSET(MYDATA, lX), DIDFT_AXIS | DIDFT_ANYINSTANCE, 0,},
{ &GUID_YAxis, FIELD_OFFSET(MYDATA, lY), DIDFT_AXIS | DIDFT_ANYINSTANCE, 0,},
{ &GUID_ZAxis, FIELD_OFFSET(MYDATA, lZ), 0x80000000 | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0,},
{ 0, FIELD_OFFSET(MYDATA, bButtonA), DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0,},
{ 0, FIELD_OFFSET(MYDATA, bButtonB), DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0,},
{ 0, FIELD_OFFSET(MYDATA, bButtonC), 0x80000000 | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0,},
{ 0, FIELD_OFFSET(MYDATA, bButtonD), 0x80000000 | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0,},
};
#define NUM_OBJECTS (sizeof(rgodf) / sizeof(rgodf[0]))
// NOTE TTimo: would be easier using c_dfDIMouse or c_dfDIMouse2
static DIDATAFORMAT df = {
sizeof(DIDATAFORMAT), // this structure
sizeof(DIOBJECTDATAFORMAT), // size of object data format
DIDF_RELAXIS, // absolute axis coordinates
sizeof(MYDATA), // device data size
NUM_OBJECTS, // number of objects
rgodf, // and here they are
};
static LPDIRECTINPUT g_pdi;
static LPDIRECTINPUTDEVICE g_pMouse;
static LPDIRECTINPUT8 g_pdi;
static LPDIRECTINPUTDEVICE8 g_pMouse;
void IN_DIMouse( int *mx, int *my );
@ -267,45 +229,26 @@ qboolean IN_InitDIMouse( void ) {
DINPUT_BUFFERSIZE, // dwData
};
Com_Printf( "Initializing DirectInput...\n");
Com_Printf( "Initializing DirectInput 8...\n");
if (!hInstDI) {
hInstDI = LoadLibrary("dinput.dll");
if (hInstDI == NULL) {
Com_Printf ("Couldn't load dinput.dll\n");
return qfalse;
}
}
if (!pDirectInputCreate) {
pDirectInputCreate = (long (__stdcall *)(void *,unsigned long ,struct IDirectInputA ** ,struct IUnknown *))
GetProcAddress(hInstDI,"DirectInputCreateA");
if (!pDirectInputCreate) {
Com_Printf ("Couldn't get DI proc addr\n");
return qfalse;
}
}
// register with DirectInput and get an IDirectInput to play with.
hr = iDirectInputCreate( g_wv.hInstance, DIRECTINPUT_VERSION, &g_pdi, NULL);
// create the DirectInput 8 object
hr = DirectInput8Create( g_wv.hInstance, DIRECTINPUT_VERSION, &IID_IDirectInput8, (LPVOID*)&g_pdi, NULL );
if (FAILED(hr)) {
Com_Printf ("iDirectInputCreate failed\n");
Com_Printf ("DirectInput8Create failed\n");
return qfalse;
}
// obtain an interface to the system mouse device.
hr = IDirectInput_CreateDevice(g_pdi, &GUID_SysMouse, &g_pMouse, NULL);
hr = IDirectInput8_CreateDevice(g_pdi, &GUID_SysMouse, &g_pMouse, NULL);
if (FAILED(hr)) {
Com_Printf ("Couldn't open DI mouse device\n");
return qfalse;
}
// set the data format to "mouse format".
hr = IDirectInputDevice_SetDataFormat(g_pMouse, &df);
// set the data format to "mouse format 2" (supports 8 buttons).
hr = IDirectInputDevice8_SetDataFormat(g_pMouse, &c_dfDIMouse2);
if (FAILED(hr)) {
Com_Printf ("Couldn't set DI mouse format\n");
@ -313,19 +256,17 @@ qboolean IN_InitDIMouse( void ) {
}
// set the cooperativity level.
hr = IDirectInputDevice_SetCooperativeLevel(g_pMouse, g_wv.hWnd,
hr = IDirectInputDevice8_SetCooperativeLevel(g_pMouse, g_wv.hWnd,
DISCL_EXCLUSIVE | DISCL_FOREGROUND);
// https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=50
if (FAILED(hr)) {
Com_Printf ("Couldn't set DI coop level\n");
return qfalse;
}
// set the buffer size to DINPUT_BUFFERSIZE elements.
// the buffer size is a DWORD property associated with the device
hr = IDirectInputDevice_SetProperty(g_pMouse, DIPROP_BUFFERSIZE, &dipdw.diph);
hr = IDirectInputDevice8_SetProperty(g_pMouse, DIPROP_BUFFERSIZE, &dipdw.diph);
if (FAILED(hr)) {
Com_Printf ("Couldn't set DI buffersize\n");
@ -336,7 +277,7 @@ qboolean IN_InitDIMouse( void ) {
IN_DIMouse( &x, &y );
IN_DIMouse( &x, &y );
Com_Printf( "DirectInput initialized.\n");
Com_Printf( "DirectInput 8 initialized.\n");
return qtrue;
}
@ -347,12 +288,12 @@ IN_ShutdownDIMouse
*/
void IN_ShutdownDIMouse( void ) {
if (g_pMouse) {
IDirectInputDevice_Release(g_pMouse);
IDirectInputDevice8_Release(g_pMouse);
g_pMouse = NULL;
}
if (g_pdi) {
IDirectInput_Release(g_pdi);
IDirectInput8_Release(g_pdi);
g_pdi = NULL;
}
}
@ -370,7 +311,7 @@ void IN_ActivateDIMouse( void ) {
}
// we may fail to reacquire if the window has been recreated
hr = IDirectInputDevice_Acquire( g_pMouse );
hr = IDirectInputDevice8_Acquire( g_pMouse );
if (FAILED(hr)) {
if ( !IN_InitDIMouse() ) {
Com_Printf ("Falling back to Win32 mouse support...\n");
@ -388,7 +329,7 @@ void IN_DeactivateDIMouse( void ) {
if (!g_pMouse) {
return;
}
IDirectInputDevice_Unacquire( g_pMouse );
IDirectInputDevice8_Unacquire( g_pMouse );
}
@ -399,11 +340,10 @@ IN_DIMouse
*/
void IN_DIMouse( int *mx, int *my ) {
DIDEVICEOBJECTDATA od;
DIMOUSESTATE state;
DIMOUSESTATE2 state;
DWORD dwElements;
HRESULT hr;
int value;
static float oldSysTime;
if ( !g_pMouse ) {
return;
@ -414,10 +354,10 @@ void IN_DIMouse( int *mx, int *my ) {
{
dwElements = 1;
hr = IDirectInputDevice_GetDeviceData(g_pMouse,
hr = IDirectInputDevice8_GetDeviceData(g_pMouse,
sizeof(DIDEVICEOBJECTDATA), &od, &dwElements, 0);
if ((hr == DIERR_INPUTLOST) || (hr == DIERR_NOTACQUIRED)) {
IDirectInputDevice_Acquire(g_pMouse);
IDirectInputDevice8_Acquire(g_pMouse);
return;
}
@ -458,15 +398,20 @@ void IN_DIMouse( int *mx, int *my ) {
else
Sys_QueEvent( od.dwTimeStamp, SE_KEY, K_MOUSE4, qfalse, 0, NULL );
break;
// https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=50
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) {
} else if (value < 0) {
if (value < 0) {
Sys_QueEvent( od.dwTimeStamp, SE_KEY, K_MWHEELDOWN, qtrue, 0, NULL );
Sys_QueEvent( od.dwTimeStamp, SE_KEY, K_MWHEELDOWN, qfalse, 0, NULL );
} else {
} else if (value > 0) {
Sys_QueEvent( od.dwTimeStamp, SE_KEY, K_MWHEELUP, qtrue, 0, NULL );
Sys_QueEvent( od.dwTimeStamp, SE_KEY, K_MWHEELUP, qfalse, 0, NULL );
}
@ -476,8 +421,8 @@ void IN_DIMouse( int *mx, int *my ) {
// read the raw delta counter and ignore
// the individual sample time / values
hr = IDirectInputDevice_GetDeviceState(g_pMouse,
sizeof(DIDEVICEOBJECTDATA), &state);
hr = IDirectInputDevice8_GetDeviceState(g_pMouse,
sizeof(DIMOUSESTATE2), &state);
if ( FAILED(hr) ) {
*mx = *my = 0;
return;

View file

@ -31,7 +31,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#endif
#define DIRECTSOUND_VERSION 0x0300
#define DIRECTINPUT_VERSION 0x0300
#define DIRECTINPUT_VERSION 0x0800
#include <dinput.h>
#include <dsound.h>