[PATCH] xinput: XInputGetStateEx takes the same struct as XInputGetState

Andrew Eikum aeikum at codeweavers.com
Mon Jan 22 10:03:18 CST 2018


XINPUT_STATE_EX has four extra bytes for padding, but is otherwise
identical to XINPUT_STATE. It was introduced in a libSDL header in
2012, for use with the undocumented function at xinput ordinal 100,
which we call XInputGetStateEx.

In Wine tests, native XInputGetStateEx does not write to these padding
bytes. Some real win32 applications[1] do not allocate those bytes,
and they do not crash when using native XInputGetStateEx. So I believe
the evidence is that this struct doesn't exist in native xinput, and
both versions of this function use XINPUT_STATE.

[1] mGetState here is ordinal 100, note XINPUT_STATE is used:
  https://github.com/speps/XInputDotNet/blob/master/XInputInterface/GamePad.cpp#L73
This library is used in real games like THOTH, available on Steam.

Signed-off-by: Andrew Eikum <aeikum at codeweavers.com>
---
 dlls/xinput1_3/tests/xinput.c | 34 +++++++++++++++-------------------
 dlls/xinput1_3/xinput_main.c  | 14 ++++----------
 include/xinput.h              | 18 +-----------------
 3 files changed, 20 insertions(+), 46 deletions(-)

diff --git a/dlls/xinput1_3/tests/xinput.c b/dlls/xinput1_3/tests/xinput.c
index 87f9929782..f26fda90eb 100644
--- a/dlls/xinput1_3/tests/xinput.c
+++ b/dlls/xinput1_3/tests/xinput.c
@@ -24,7 +24,7 @@
 #include "wine/test.h"
 
 static DWORD (WINAPI *pXInputGetState)(DWORD, XINPUT_STATE*);
-static DWORD (WINAPI *pXInputGetStateEx)(DWORD, XINPUT_STATE_EX*);
+static DWORD (WINAPI *pXInputGetStateEx)(DWORD, XINPUT_STATE*);
 static DWORD (WINAPI *pXInputGetCapabilities)(DWORD,DWORD,XINPUT_CAPABILITIES*);
 static DWORD (WINAPI *pXInputSetState)(DWORD, XINPUT_VIBRATION*);
 static void  (WINAPI *pXInputEnable)(BOOL);
@@ -91,23 +91,19 @@ static void test_set_state(void)
 
 static void test_get_state(void)
 {
-    union
-    {
-        XINPUT_STATE state;
-        XINPUT_STATE_EX state_ex;
-    } xinput;
+    XINPUT_STATE state;
     DWORD controllerNum, i, result, good = XUSER_MAX_COUNT;
 
     for (i = 0; i < (pXInputGetStateEx ? 2 : 1); i++)
     {
         for (controllerNum = 0; controllerNum < XUSER_MAX_COUNT; controllerNum++)
         {
-            ZeroMemory(&xinput, sizeof(xinput));
+            ZeroMemory(&state, sizeof(state));
 
             if (i == 0)
-                result = pXInputGetState(controllerNum, &xinput.state);
+                result = pXInputGetState(controllerNum, &state);
             else
-                result = pXInputGetStateEx(controllerNum, &xinput.state_ex);
+                result = pXInputGetStateEx(controllerNum, &state);
             ok(result == ERROR_SUCCESS || result == ERROR_DEVICE_NOT_CONNECTED,
                "%s failed with (%d)\n", i == 0 ? "XInputGetState" : "XInputGetStateEx", result);
 
@@ -125,39 +121,39 @@ static void test_get_state(void)
             }
             else
                 trace("XInputGetStateEx: %d\n", result);
-            trace("State->dwPacketNumber: %d\n", xinput.state.dwPacketNumber);
-            dump_gamepad(&xinput.state.Gamepad);
+            trace("State->dwPacketNumber: %d\n", state.dwPacketNumber);
+            dump_gamepad(&state.Gamepad);
         }
     }
 
-    result = pXInputGetState(XUSER_MAX_COUNT, &xinput.state);
+    result = pXInputGetState(XUSER_MAX_COUNT, &state);
     ok(result == ERROR_BAD_ARGUMENTS, "XInputGetState returned (%d)\n", result);
 
-    result = pXInputGetState(XUSER_MAX_COUNT+1, &xinput.state);
+    result = pXInputGetState(XUSER_MAX_COUNT+1, &state);
     ok(result == ERROR_BAD_ARGUMENTS, "XInputGetState returned (%d)\n", result);
     if (pXInputGetStateEx)
     {
-        result = pXInputGetStateEx(XUSER_MAX_COUNT, &xinput.state_ex);
+        result = pXInputGetStateEx(XUSER_MAX_COUNT, &state);
         ok(result == ERROR_BAD_ARGUMENTS, "XInputGetState returned (%d)\n", result);
 
-        result = pXInputGetStateEx(XUSER_MAX_COUNT+1, &xinput.state_ex);
+        result = pXInputGetStateEx(XUSER_MAX_COUNT+1, &state);
         ok(result == ERROR_BAD_ARGUMENTS, "XInputGetState returned (%d)\n", result);
     }
 
     if (winetest_interactive && good < XUSER_MAX_COUNT)
     {
         DWORD now = GetTickCount(), packet = 0;
-        XINPUT_GAMEPAD *game = &xinput.state.Gamepad;
+        XINPUT_GAMEPAD *game = &state.Gamepad;
 
         trace("You have 20 seconds to test the joystick freely\n");
         do
         {
             Sleep(100);
-            pXInputGetState(good, &xinput.state);
-            if (xinput.state.dwPacketNumber == packet)
+            pXInputGetState(good, &state);
+            if (state.dwPacketNumber == packet)
                 continue;
 
-            packet = xinput.state.dwPacketNumber;
+            packet = state.dwPacketNumber;
             trace("Buttons 0x%04X Triggers %3d/%3d LT %6d/%6d RT %6d/%6d\n",
                   game->wButtons, game->bLeftTrigger, game->bRightTrigger,
                   game->sThumbLX, game->sThumbLY, game->sThumbRX, game->sThumbRY);
diff --git a/dlls/xinput1_3/xinput_main.c b/dlls/xinput1_3/xinput_main.c
index 402bd2f468..a0a0877cf4 100644
--- a/dlls/xinput1_3/xinput_main.c
+++ b/dlls/xinput1_3/xinput_main.c
@@ -73,34 +73,28 @@ DWORD WINAPI XInputSetState(DWORD index, XINPUT_VIBRATION* vibration)
 
 DWORD WINAPI DECLSPEC_HOTPATCH XInputGetState(DWORD index, XINPUT_STATE* state)
 {
-    union
-    {
-        XINPUT_STATE state;
-        XINPUT_STATE_EX state_ex;
-    } xinput;
     DWORD ret;
     static int warn_once;
 
     if (!warn_once++)
         FIXME("(index %u, state %p) Stub!\n", index, state);
 
-    ret = XInputGetStateEx(index, &xinput.state_ex);
+    ret = XInputGetStateEx(index, state);
     if (ret != ERROR_SUCCESS)
         return ret;
 
     /* The main difference between this and the Ex version is the media guide button */
-    xinput.state.Gamepad.wButtons &= ~XINPUT_GAMEPAD_GUIDE;
-    *state = xinput.state;
+    state->Gamepad.wButtons &= ~XINPUT_GAMEPAD_GUIDE;
 
     return ERROR_SUCCESS;
 }
 
-DWORD WINAPI DECLSPEC_HOTPATCH XInputGetStateEx(DWORD index, XINPUT_STATE_EX* state_ex)
+DWORD WINAPI DECLSPEC_HOTPATCH XInputGetStateEx(DWORD index, XINPUT_STATE* state)
 {
     static int warn_once;
 
     if (!warn_once++)
-        FIXME("(index %u, state %p) Stub!\n", index, state_ex);
+        FIXME("(index %u, state %p) Stub!\n", index, state);
 
     if (index >= XUSER_MAX_COUNT)
         return ERROR_BAD_ARGUMENTS;
diff --git a/include/xinput.h b/include/xinput.h
index ccdc023343..99ff0cc7cf 100644
--- a/include/xinput.h
+++ b/include/xinput.h
@@ -170,27 +170,11 @@ typedef struct _XINPUT_GAMEPAD {
     SHORT sThumbRY;
 } XINPUT_GAMEPAD, *PXINPUT_GAMEPAD;
 
-typedef struct _XINPUT_GAMEPAD_EX {
-    WORD wButtons;
-    BYTE bLeftTrigger;
-    BYTE bRightTrigger;
-    SHORT sThumbLX;
-    SHORT sThumbLY;
-    SHORT sThumbRX;
-    SHORT sThumbRY;
-    DWORD dwPaddingReserved;
-} XINPUT_GAMEPAD_EX, *PXINPUT_GAMEPAD_EX;
-
 typedef struct _XINPUT_STATE {
     DWORD dwPacketNumber;
     XINPUT_GAMEPAD Gamepad;
 } XINPUT_STATE, *PXINPUT_STATE;
 
-typedef struct _XINPUT_STATE_EX {
-    DWORD dwPacketNumber;
-    XINPUT_GAMEPAD_EX Gamepad;
-} XINPUT_STATE_EX, *PXINPUT_STATE_EX;
-
 /*
  * Defines the structure of how much vibration is set on both the
  * right and left motors in a joystick. If you're not using a 360
@@ -248,7 +232,7 @@ DWORD WINAPI XInputGetCapabilities(DWORD, DWORD, XINPUT_CAPABILITIES*);
 DWORD WINAPI XInputGetDSoundAudioDeviceGuids(DWORD, GUID*, GUID*);
 DWORD WINAPI XInputGetBatteryInformation(DWORD, BYTE, XINPUT_BATTERY_INFORMATION*);
 
-DWORD WINAPI XInputGetStateEx(DWORD, XINPUT_STATE_EX*);
+DWORD WINAPI XInputGetStateEx(DWORD, XINPUT_STATE*);
 
 #ifdef __cplusplus
 }
-- 
2.16.0




More information about the wine-devel mailing list