Skip to content

Commit 5e72d6d

Browse files
committed
(DirectInput) code cleanups/improvements, including:
* Float division replaced with integer multiply (dinput_joypad_inl.h — * Rumble destroy loop deduplicated (dinput_joypad_inl.h) * Duplicated axis switch eliminated (dinput_joypad_inl.h) * Fixed: POV centered-sentinel not guarded (dinput_joypad_inl.h) * lZ never zeroed in poll (dinput_joypad_excl.h) * Rumble strong/weak index inverted (dinput_joypad_inl.h) * port_idx bounds-check after array dereference (dinput_joypad_inl.h * TCHAR* cast breaks Unicode builds (dinput_joypad_excl.h)
1 parent 76238c8 commit 5e72d6d

4 files changed

Lines changed: 218 additions & 269 deletions

File tree

input/drivers_joypad/dinput_joypad.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,11 @@
3737
#include "../../verbosity.h"
3838
#include "dinput_joypad.h"
3939

40-
/* TODO/FIXME - globals referenced outside */
40+
/* TODO/FIXME - globals referenced outside; candidate for context-struct refactor */
4141
struct dinput_joypad_data g_pads[MAX_USERS];
4242
unsigned g_joypad_cnt;
4343

44-
/* TODO/FIXME - forward declaration */
44+
/* Defined in dinput.c / dinput_input.c */
4545
extern LPDIRECTINPUT8 g_dinput_ctx;
4646

4747
#include "dinput_joypad_inl.h"

input/drivers_joypad/dinput_joypad.h

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -27,18 +27,22 @@
2727
/* For DIJOYSTATE2 struct, rgbButtons will always have 128 elements */
2828
#define ARRAY_SIZE_RGB_BUTTONS 128
2929

30+
/* DirectInput POV value indicating the hat is centred (no direction pressed).
31+
* rgdwPOV[] returns this sentinel when the hat is released. */
32+
#define DINPUT_POV_CENTERED 0xFFFFFFFFu
33+
3034
RETRO_BEGIN_DECLS
3135

3236
struct dinput_joypad_data
3337
{
3438
LPDIRECTINPUTDEVICE8 joypad;
35-
DIJOYSTATE2 joy_state;
36-
char* joy_name;
37-
char* joy_friendly_name;
38-
int32_t vid;
39-
int32_t pid;
40-
LPDIRECTINPUTEFFECT rumble_iface[2];
41-
DIEFFECT rumble_props;
39+
DIJOYSTATE2 joy_state;
40+
char *joy_name;
41+
char *joy_friendly_name;
42+
int32_t vid;
43+
int32_t pid;
44+
LPDIRECTINPUTEFFECT rumble_iface[2];
45+
DIEFFECT rumble_props;
4246
};
4347

4448
RETRO_END_DECLS

input/drivers_joypad/dinput_joypad_excl.h

Lines changed: 68 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -30,57 +30,22 @@ static void dinput_joypad_poll(void)
3030
int i;
3131
for (i = 0; i < MAX_USERS; i++)
3232
{
33-
int j;
3433
HRESULT ret;
35-
struct dinput_joypad_data *pad = &g_pads[i];
36-
if (!pad || !pad->joypad)
34+
struct dinput_joypad_data *pad = &g_pads[i];
35+
36+
if (!pad->joypad)
3737
continue;
3838

39-
pad->joy_state.lX = 0;
40-
pad->joy_state.lY = 0;
41-
pad->joy_state.lRx = 0;
42-
pad->joy_state.lRy = 0;
43-
pad->joy_state.lRz = 0;
44-
pad->joy_state.rglSlider[0] = 0;
45-
pad->joy_state.rglSlider[1] = 0;
46-
pad->joy_state.rgdwPOV[0] = 0;
47-
pad->joy_state.rgdwPOV[1] = 0;
48-
pad->joy_state.rgdwPOV[2] = 0;
49-
pad->joy_state.rgdwPOV[3] = 0;
50-
for (j = 0; j < 128; j++)
51-
pad->joy_state.rgbButtons[j] = 0;
52-
53-
pad->joy_state.lVX = 0;
54-
pad->joy_state.lVY = 0;
55-
pad->joy_state.lVZ = 0;
56-
pad->joy_state.lVRx = 0;
57-
pad->joy_state.lVRy = 0;
58-
pad->joy_state.lVRz = 0;
59-
pad->joy_state.rglVSlider[0] = 0;
60-
pad->joy_state.rglVSlider[1] = 0;
61-
pad->joy_state.lAX = 0;
62-
pad->joy_state.lAY = 0;
63-
pad->joy_state.lAZ = 0;
64-
pad->joy_state.lARx = 0;
65-
pad->joy_state.lARy = 0;
66-
pad->joy_state.lARz = 0;
67-
pad->joy_state.rglASlider[0] = 0;
68-
pad->joy_state.rglASlider[1] = 0;
69-
pad->joy_state.lFX = 0;
70-
pad->joy_state.lFY = 0;
71-
pad->joy_state.lFZ = 0;
72-
pad->joy_state.lFRx = 0;
73-
pad->joy_state.lFRy = 0;
74-
pad->joy_state.lFRz = 0;
75-
pad->joy_state.rglFSlider[0] = 0;
76-
pad->joy_state.rglFSlider[1] = 0;
77-
78-
/* If this fails, something *really* bad must have happened. */
39+
/* Zero the entire state structure before polling.
40+
* This also correctly zeroes lZ, which the previous
41+
* field-by-field implementation accidentally omitted. */
42+
ZeroMemory(&pad->joy_state, sizeof(pad->joy_state));
43+
44+
/* If Poll() fails, attempt to re-acquire and poll again.
45+
* If that also fails, skip this pad for this frame. */
7946
if (FAILED(IDirectInputDevice8_Poll(pad->joypad)))
80-
if (
81-
FAILED(IDirectInputDevice8_Acquire(pad->joypad))
82-
|| FAILED(IDirectInputDevice8_Poll(pad->joypad))
83-
)
47+
if ( FAILED(IDirectInputDevice8_Acquire(pad->joypad))
48+
|| FAILED(IDirectInputDevice8_Poll(pad->joypad)))
8449
continue;
8550

8651
ret = IDirectInputDevice8_GetDeviceState(pad->joypad,
@@ -91,9 +56,52 @@ static void dinput_joypad_poll(void)
9156
}
9257
}
9358

59+
/* ---------------------------------------------------------------------------
60+
* dinput_joypad_tchar_to_str
61+
*
62+
* Helper: safely converts a TCHAR string to a heap-allocated char* that
63+
* is valid in both ANSI and Unicode builds.
64+
*
65+
* Under ANSI builds (TCHAR == char) this is equivalent to strdup().
66+
* Under Unicode builds (TCHAR == wchar_t) the original code cast the
67+
* wide pointer directly to char*, silently producing garbage. We use
68+
* WideCharToMultiByte() instead.
69+
*
70+
* Returns NULL on allocation failure; the caller must free() the result.
71+
* --------------------------------------------------------------------------*/
72+
static char *dinput_joypad_tchar_to_str(const TCHAR *src)
73+
{
74+
#ifdef UNICODE
75+
int len;
76+
char *out;
77+
78+
if (!src)
79+
return NULL;
80+
81+
/* Query required buffer size (includes NUL terminator). */
82+
len = WideCharToMultiByte(CP_UTF8, 0, src, -1, NULL, 0, NULL, NULL);
83+
if (len <= 0)
84+
return NULL;
85+
86+
out = (char*)malloc((size_t)len);
87+
if (!out)
88+
return NULL;
89+
90+
WideCharToMultiByte(CP_UTF8, 0, src, -1, out, len, NULL, NULL);
91+
return out;
92+
#else
93+
if (!src)
94+
return NULL;
95+
return strdup(src);
96+
#endif
97+
}
98+
9499
static BOOL CALLBACK enum_joypad_cb(const DIDEVICEINSTANCE *inst, void *p)
95100
{
96101
LPDIRECTINPUTDEVICE8 *pad = NULL;
102+
103+
(void)p; /* unused */
104+
97105
if (g_joypad_cnt == MAX_USERS)
98106
return DIENUM_STOP;
99107

@@ -108,32 +116,19 @@ static BOOL CALLBACK enum_joypad_cb(const DIDEVICEINSTANCE *inst, void *p)
108116
#endif
109117
return DIENUM_CONTINUE;
110118

119+
/* Bug fixed: use the safe TCHAR helper instead of a raw cast that
120+
* would produce garbage under Unicode builds. */
111121
g_pads[g_joypad_cnt].joy_name =
112-
strdup((const char*)inst->tszProductName);
122+
dinput_joypad_tchar_to_str(inst->tszProductName);
113123
g_pads[g_joypad_cnt].joy_friendly_name =
114-
strdup((const char*)inst->tszInstanceName);
115-
116-
/* there may be more useful info in the GUID,
117-
* so leave this here for a while */
118-
#if 0
119-
printf("Guid = {%08lX-%04hX-%04hX-%02hhX%02hhX-%02hhX%02hhX%02hhX%02hhX%02hhX%02hhX}\n",
120-
inst->guidProduct.Data1,
121-
inst->guidProduct.Data2,
122-
inst->guidProduct.Data3,
123-
inst->guidProduct.Data4[0],
124-
inst->guidProduct.Data4[1],
125-
inst->guidProduct.Data4[2],
126-
inst->guidProduct.Data4[3],
127-
inst->guidProduct.Data4[4],
128-
inst->guidProduct.Data4[5],
129-
inst->guidProduct.Data4[6],
130-
inst->guidProduct.Data4[7]);
131-
#endif
124+
dinput_joypad_tchar_to_str(inst->tszInstanceName);
132125

133-
g_pads[g_joypad_cnt].vid = inst->guidProduct.Data1 % 0x10000;
134-
g_pads[g_joypad_cnt].pid = inst->guidProduct.Data1 / 0x10000;
126+
/* VID is in the low 16 bits of guidProduct.Data1,
127+
* PID is in the high 16 bits. */
128+
g_pads[g_joypad_cnt].vid = (int32_t)(inst->guidProduct.Data1 & 0xFFFFu);
129+
g_pads[g_joypad_cnt].pid = (int32_t)(inst->guidProduct.Data1 >> 16);
135130

136-
/* Set data format to simple joystick */
131+
/* Set data format to extended joystick state */
137132
IDirectInputDevice8_SetDataFormat(*pad, &c_dfDIJoystick2);
138133
IDirectInputDevice8_SetCooperativeLevel(*pad,
139134
(HWND)video_driver_window_get(),
@@ -159,21 +154,14 @@ static BOOL CALLBACK enum_joypad_cb(const DIDEVICEINSTANCE *inst, void *p)
159154

160155
static void *dinput_joypad_init(void *data)
161156
{
162-
int i;
163-
164157
if (!dinput_init_context())
165158
return NULL;
166-
167-
for (i = 0; i < MAX_USERS; ++i)
168-
{
169-
g_pads[i].joy_name = NULL;
170-
g_pads[i].joy_friendly_name = NULL;
171-
}
172-
159+
/* Zero the pad array; dinput_joypad_destroy() uses memset() on the same
160+
* region, so we stay consistent and avoid partial-initialisation bugs. */
161+
ZeroMemory(g_pads, sizeof(g_pads));
173162
IDirectInput8_EnumDevices(g_dinput_ctx, DI8DEVCLASS_GAMECTRL,
174163
enum_joypad_cb, NULL, DIEDFL_ATTACHEDONLY);
175-
176164
return (void*)-1;
177165
}
178166

179-
#endif
167+
#endif /* __DINPUT_JOYPAD_EXCL_INL_H */

0 commit comments

Comments
 (0)