From fb4cc70a6a193af4f76e61864e96a356f3c0db7b Mon Sep 17 00:00:00 2001 From: kozec Date: Fri, 30 Sep 2016 19:01:54 +0200 Subject: [PATCH 1/7] Initial import, xinput1_3 source from wine commmit 2035a8c7c84a5375144fdd70f951949ba7c5d818 --- xinput1_3/Makefile.in | 7 + xinput1_3/tests/Makefile.in | 5 + xinput1_3/tests/xinput.c | 288 ++++++++++++++++++++++++++++++++++++ xinput1_3/version.rc | 27 ++++ xinput1_3/xinput1_3.spec | 9 ++ xinput1_3/xinput1_3_main.c | 164 ++++++++++++++++++++ 6 files changed, 500 insertions(+) create mode 100644 xinput1_3/Makefile.in create mode 100644 xinput1_3/tests/Makefile.in create mode 100644 xinput1_3/tests/xinput.c create mode 100644 xinput1_3/version.rc create mode 100644 xinput1_3/xinput1_3.spec create mode 100644 xinput1_3/xinput1_3_main.c diff --git a/xinput1_3/Makefile.in b/xinput1_3/Makefile.in new file mode 100644 index 0000000..cf8f730 --- /dev/null +++ b/xinput1_3/Makefile.in @@ -0,0 +1,7 @@ +MODULE = xinput1_3.dll +IMPORTLIB = xinput + +C_SRCS = \ + xinput1_3_main.c + +RC_SRCS = version.rc diff --git a/xinput1_3/tests/Makefile.in b/xinput1_3/tests/Makefile.in new file mode 100644 index 0000000..718b47f --- /dev/null +++ b/xinput1_3/tests/Makefile.in @@ -0,0 +1,5 @@ +TESTDLL = xinput1_3.dll +IMPORTS = user32 + +C_SRCS = \ + xinput.c diff --git a/xinput1_3/tests/xinput.c b/xinput1_3/tests/xinput.c new file mode 100644 index 0000000..17884e1 --- /dev/null +++ b/xinput1_3/tests/xinput.c @@ -0,0 +1,288 @@ +/* + * The Wine project - Xinput Joystick Library + * Copyright 2008 Andrew Fenn + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include +#include + +#include "xinput.h" +#include "wine/test.h" + +static DWORD (WINAPI *pXInputGetState)(DWORD, XINPUT_STATE*); +static DWORD (WINAPI *pXInputGetStateEx)(DWORD, XINPUT_STATE_EX*); +static DWORD (WINAPI *pXInputGetCapabilities)(DWORD,DWORD,XINPUT_CAPABILITIES*); +static DWORD (WINAPI *pXInputSetState)(DWORD, XINPUT_VIBRATION*); +static void (WINAPI *pXInputEnable)(BOOL); +static DWORD (WINAPI *pXInputGetKeystroke)(DWORD, DWORD, PXINPUT_KEYSTROKE); +static DWORD (WINAPI *pXInputGetDSoundAudioDeviceGuids)(DWORD, GUID*, GUID*); +static DWORD (WINAPI *pXInputGetBatteryInformation)(DWORD, BYTE, XINPUT_BATTERY_INFORMATION*); + +static void test_set_state(void) +{ + XINPUT_VIBRATION vibrator; + DWORD controllerNum; + DWORD result; + + for(controllerNum=0; controllerNum < XUSER_MAX_COUNT; controllerNum++) + { + ZeroMemory(&vibrator, sizeof(XINPUT_VIBRATION)); + + vibrator.wLeftMotorSpeed = 0; + vibrator.wRightMotorSpeed = 0; + result = pXInputSetState(controllerNum, &vibrator); + ok(result == ERROR_SUCCESS || result == ERROR_DEVICE_NOT_CONNECTED, "XInputSetState failed with (%d)\n", result); + + if (pXInputEnable) pXInputEnable(0); + + vibrator.wLeftMotorSpeed = 65535; + vibrator.wRightMotorSpeed = 65535; + result = pXInputSetState(controllerNum, &vibrator); + ok(result == ERROR_SUCCESS || result == ERROR_DEVICE_NOT_CONNECTED, "XInputSetState failed with (%d)\n", result); + + if (pXInputEnable) pXInputEnable(1); + } + + result = pXInputSetState(XUSER_MAX_COUNT+1, &vibrator); + ok(result == ERROR_BAD_ARGUMENTS, "XInputSetState returned (%d)\n", result); +} + +static void test_get_state(void) +{ + union + { + XINPUT_STATE state; + XINPUT_STATE_EX state_ex; + } xinput; + DWORD controllerNum, i; + DWORD result; + + for (i = 0; i < (pXInputGetStateEx ? 2 : 1); i++) + { + for (controllerNum = 0; controllerNum < XUSER_MAX_COUNT; controllerNum++) + { + ZeroMemory(&xinput, sizeof(xinput)); + + if (i == 0) + result = pXInputGetState(controllerNum, &xinput.state); + else + result = pXInputGetStateEx(controllerNum, &xinput.state_ex); + ok(result == ERROR_SUCCESS || result == ERROR_DEVICE_NOT_CONNECTED, + "%s failed with (%d)\n", i == 0 ? "XInputGetState" : "XInputGetStateEx", result); + + if (ERROR_DEVICE_NOT_CONNECTED == result) + { + skip("Controller %d is not connected\n", controllerNum); + continue; + } + + trace("-- Results for controller %d --\n", controllerNum); + if (i == 0) + trace("XInputGetState: %d\n", result); + else + trace("XInputGetStateEx: %d\n", result); + trace("State->dwPacketNumber: %d\n", xinput.state.dwPacketNumber); + trace("Gamepad Variables --\n"); + trace("Gamepad.wButtons: %#x\n", xinput.state.Gamepad.wButtons); + trace("Gamepad.bLeftTrigger: 0x%08x\n", xinput.state.Gamepad.bLeftTrigger); + trace("Gamepad.bRightTrigger: 0x%08x\n", xinput.state.Gamepad.bRightTrigger); + trace("Gamepad.sThumbLX: %d\n", xinput.state.Gamepad.sThumbLX); + trace("Gamepad.sThumbLY: %d\n", xinput.state.Gamepad.sThumbLY); + trace("Gamepad.sThumbRX: %d\n", xinput.state.Gamepad.sThumbRX); + trace("Gamepad.sThumbRY: %d\n", xinput.state.Gamepad.sThumbRY); + } + } + + result = pXInputGetState(XUSER_MAX_COUNT, &xinput.state); + ok(result == ERROR_BAD_ARGUMENTS, "XInputGetState returned (%d)\n", result); + + result = pXInputGetState(XUSER_MAX_COUNT+1, &xinput.state); + ok(result == ERROR_BAD_ARGUMENTS, "XInputGetState returned (%d)\n", result); + if (pXInputGetStateEx) + { + result = pXInputGetStateEx(XUSER_MAX_COUNT, &xinput.state_ex); + ok(result == ERROR_BAD_ARGUMENTS, "XInputGetState returned (%d)\n", result); + + result = pXInputGetStateEx(XUSER_MAX_COUNT+1, &xinput.state_ex); + ok(result == ERROR_BAD_ARGUMENTS, "XInputGetState returned (%d)\n", result); + } +} + +static void test_get_keystroke(void) +{ + XINPUT_KEYSTROKE keystroke; + DWORD controllerNum; + DWORD result; + + for(controllerNum=0; controllerNum < XUSER_MAX_COUNT; controllerNum++) + { + ZeroMemory(&keystroke, sizeof(XINPUT_KEYSTROKE)); + + result = pXInputGetKeystroke(controllerNum, XINPUT_FLAG_GAMEPAD, &keystroke); + ok(result == ERROR_EMPTY || result == ERROR_SUCCESS || result == ERROR_DEVICE_NOT_CONNECTED, + "XInputGetKeystroke failed with (%d)\n", result); + + if (ERROR_DEVICE_NOT_CONNECTED == result) + { + skip("Controller %d is not connected\n", controllerNum); + } + } + + ZeroMemory(&keystroke, sizeof(XINPUT_KEYSTROKE)); + result = pXInputGetKeystroke(XUSER_MAX_COUNT+1, XINPUT_FLAG_GAMEPAD, &keystroke); + ok(result == ERROR_BAD_ARGUMENTS, "XInputGetKeystroke returned (%d)\n", result); +} + +static void test_get_capabilities(void) +{ + XINPUT_CAPABILITIES capabilities; + DWORD controllerNum; + DWORD result; + + for(controllerNum=0; controllerNum < XUSER_MAX_COUNT; controllerNum++) + { + ZeroMemory(&capabilities, sizeof(XINPUT_CAPABILITIES)); + + result = pXInputGetCapabilities(controllerNum, XINPUT_FLAG_GAMEPAD, &capabilities); + ok(result == ERROR_SUCCESS || result == ERROR_DEVICE_NOT_CONNECTED, "XInputGetCapabilities failed with (%d)\n", result); + + if (ERROR_DEVICE_NOT_CONNECTED == result) + { + skip("Controller %d is not connected\n", controllerNum); + } + } + + ZeroMemory(&capabilities, sizeof(XINPUT_CAPABILITIES)); + result = pXInputGetCapabilities(XUSER_MAX_COUNT+1, XINPUT_FLAG_GAMEPAD, &capabilities); + ok(result == ERROR_BAD_ARGUMENTS, "XInputGetCapabilities returned (%d)\n", result); +} + +static void test_get_dsoundaudiodevice(void) +{ + DWORD controllerNum; + DWORD result; + GUID soundRender; + GUID soundCapture; + + for(controllerNum=0; controllerNum < XUSER_MAX_COUNT; controllerNum++) + { + result = pXInputGetDSoundAudioDeviceGuids(controllerNum, &soundRender, &soundCapture); + ok(result == ERROR_SUCCESS || result == ERROR_DEVICE_NOT_CONNECTED, "XInputGetDSoundAudioDeviceGuids failed with (%d)\n", result); + + if (ERROR_DEVICE_NOT_CONNECTED == result) + { + skip("Controller %d is not connected\n", controllerNum); + } + } + + result = pXInputGetDSoundAudioDeviceGuids(XUSER_MAX_COUNT+1, &soundRender, &soundCapture); + ok(result == ERROR_BAD_ARGUMENTS, "XInputGetDSoundAudioDeviceGuids returned (%d)\n", result); +} + +static void test_get_batteryinformation(void) +{ + DWORD controllerNum; + DWORD result; + XINPUT_BATTERY_INFORMATION batteryInfo; + + for(controllerNum=0; controllerNum < XUSER_MAX_COUNT; controllerNum++) + { + ZeroMemory(&batteryInfo, sizeof(XINPUT_BATTERY_INFORMATION)); + + result = pXInputGetBatteryInformation(controllerNum, BATTERY_DEVTYPE_GAMEPAD, &batteryInfo); + ok(result == ERROR_SUCCESS || result == ERROR_DEVICE_NOT_CONNECTED, "XInputGetBatteryInformation failed with (%d)\n", result); + + if (ERROR_DEVICE_NOT_CONNECTED == result) + { + ok(batteryInfo.BatteryLevel == BATTERY_TYPE_DISCONNECTED, "Failed to report device as being disconnected.\n"); + skip("Controller %d is not connected\n", controllerNum); + } + } + + result = pXInputGetBatteryInformation(XUSER_MAX_COUNT+1, BATTERY_DEVTYPE_GAMEPAD, &batteryInfo); + ok(result == ERROR_BAD_ARGUMENTS, "XInputGetBatteryInformation returned (%d)\n", result); +} + +START_TEST(xinput) +{ + struct + { + const char *name; + int version; + } libs[] = { + { "xinput1_1.dll", 1 }, + { "xinput1_2.dll", 2 }, + { "xinput1_3.dll", 3 }, + { "xinput1_4.dll", 4 }, + { "xinput9_1_0.dll", 0 } /* legacy for XP/Vista */ + }; + HMODULE hXinput; + void *pXInputGetStateEx_Ordinal; + int i; + + for (i = 0; i < sizeof(libs) / sizeof(libs[0]); i++) + { + hXinput = LoadLibraryA( libs[i].name ); + + if (!hXinput) + { + win_skip("Could not load %s\n", libs[i].name); + continue; + } + trace("Testing %s\n", libs[i].name); + + pXInputEnable = (void*)GetProcAddress(hXinput, "XInputEnable"); + pXInputSetState = (void*)GetProcAddress(hXinput, "XInputSetState"); + pXInputGetState = (void*)GetProcAddress(hXinput, "XInputGetState"); + pXInputGetStateEx = (void*)GetProcAddress(hXinput, "XInputGetStateEx"); /* Win >= 8 */ + pXInputGetStateEx_Ordinal = (void*)GetProcAddress(hXinput, (LPCSTR) 100); + pXInputGetKeystroke = (void*)GetProcAddress(hXinput, "XInputGetKeystroke"); + pXInputGetCapabilities = (void*)GetProcAddress(hXinput, "XInputGetCapabilities"); + pXInputGetDSoundAudioDeviceGuids = (void*)GetProcAddress(hXinput, "XInputGetDSoundAudioDeviceGuids"); + pXInputGetBatteryInformation = (void*)GetProcAddress(hXinput, "XInputGetBatteryInformation"); + + /* XInputGetStateEx may not be present by name, use ordinal in this case */ + if (!pXInputGetStateEx) + pXInputGetStateEx = pXInputGetStateEx_Ordinal; + + test_set_state(); + test_get_state(); + test_get_capabilities(); + + if (libs[i].version != 4) + test_get_dsoundaudiodevice(); + else + ok(!pXInputGetDSoundAudioDeviceGuids, "XInputGetDSoundAudioDeviceGuids exists in %s\n", libs[i].name); + + if (libs[i].version > 2) + { + test_get_keystroke(); + test_get_batteryinformation(); + ok(pXInputGetStateEx != NULL, "XInputGetStateEx not found in %s\n", libs[i].name); + } + else + { + ok(!pXInputGetKeystroke, "XInputGetKeystroke exists in %s\n", libs[i].name); + ok(!pXInputGetStateEx, "XInputGetStateEx exists in %s\n", libs[i].name); + ok(!pXInputGetBatteryInformation, "XInputGetBatteryInformation exists in %s\n", libs[i].name); + if (libs[i].version == 0) + ok(!pXInputEnable, "XInputEnable exists in %s\n", libs[i].name); + } + + FreeLibrary(hXinput); + } +} diff --git a/xinput1_3/version.rc b/xinput1_3/version.rc new file mode 100644 index 0000000..191b142 --- /dev/null +++ b/xinput1_3/version.rc @@ -0,0 +1,27 @@ +/* + * The Wine project - Xinput Joystick Library + * Copyright 2008 Andrew Fenn + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#define WINE_FILEDESCRIPTION_STR "Wine Common Controller API" +#define WINE_FILENAME_STR "xinput1_3.dll" +#define WINE_FILEVERSION 9,15,779,0000 +#define WINE_FILEVERSION_STR "9.15.779.0000" +#define WINE_PRODUCTVERSION 9,15,779,0000 +#define WINE_PRODUCTVERSION_STR "9.15" + +#include "wine/wine_common_ver.rc" diff --git a/xinput1_3/xinput1_3.spec b/xinput1_3/xinput1_3.spec new file mode 100644 index 0000000..0023016 --- /dev/null +++ b/xinput1_3/xinput1_3.spec @@ -0,0 +1,9 @@ +1 stdcall -private DllMain(long long ptr) +2 stdcall XInputGetState(long ptr) +3 stdcall XInputSetState(long ptr) +4 stdcall XInputGetCapabilities(long long ptr) +5 stdcall XInputEnable(long) +6 stdcall XInputGetDSoundAudioDeviceGuids(long ptr ptr) +7 stdcall XInputGetBatteryInformation(long long ptr) +8 stdcall XInputGetKeystroke(long long ptr) +100 stdcall XInputGetStateEx(long ptr) diff --git a/xinput1_3/xinput1_3_main.c b/xinput1_3/xinput1_3_main.c new file mode 100644 index 0000000..04732eb --- /dev/null +++ b/xinput1_3/xinput1_3_main.c @@ -0,0 +1,164 @@ +/* + * The Wine project - Xinput Joystick Library + * Copyright 2008 Andrew Fenn + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "config.h" +#include +#include +#include + +#include "wine/debug.h" +#include "windef.h" +#include "winbase.h" +#include "winerror.h" + +#include "xinput.h" + +/* Not defined in the headers, used only by XInputGetStateEx */ +#define XINPUT_GAMEPAD_GUIDE 0x0400 + +WINE_DEFAULT_DEBUG_CHANNEL(xinput); + +struct +{ + BOOL connected; +} controllers[XUSER_MAX_COUNT]; + +BOOL WINAPI DllMain(HINSTANCE inst, DWORD reason, LPVOID reserved) +{ + switch(reason) + { + case DLL_WINE_PREATTACH: + return FALSE; /* prefer native version */ + case DLL_PROCESS_ATTACH: + DisableThreadLibraryCalls(inst); + break; + } + return TRUE; +} + +void WINAPI XInputEnable(BOOL enable) +{ + /* Setting to false will stop messages from XInputSetState being sent + to the controllers. Setting to true will send the last vibration + value (sent to XInputSetState) to the controller and allow messages to + be sent */ + FIXME("(enable %d) Stub!\n", enable); +} + +DWORD WINAPI XInputSetState(DWORD index, XINPUT_VIBRATION* vibration) +{ + FIXME("(index %u, vibration %p) Stub!\n", index, vibration); + + if (index >= XUSER_MAX_COUNT) + return ERROR_BAD_ARGUMENTS; + if (!controllers[index].connected) + return ERROR_DEVICE_NOT_CONNECTED; + + return ERROR_NOT_SUPPORTED; +} + +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); + 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; + + return ERROR_SUCCESS; +} + +DWORD WINAPI DECLSPEC_HOTPATCH XInputGetStateEx(DWORD index, XINPUT_STATE_EX* state_ex) +{ + static int warn_once; + + if (!warn_once++) + FIXME("(index %u, state %p) Stub!\n", index, state_ex); + + if (index >= XUSER_MAX_COUNT) + return ERROR_BAD_ARGUMENTS; + if (!controllers[index].connected) + return ERROR_DEVICE_NOT_CONNECTED; + + return ERROR_NOT_SUPPORTED; +} + +DWORD WINAPI XInputGetKeystroke(DWORD index, DWORD reserved, PXINPUT_KEYSTROKE keystroke) +{ + FIXME("(index %u, reserved %u, keystroke %p) Stub!\n", index, reserved, keystroke); + + if (index >= XUSER_MAX_COUNT) + return ERROR_BAD_ARGUMENTS; + if (!controllers[index].connected) + return ERROR_DEVICE_NOT_CONNECTED; + + return ERROR_NOT_SUPPORTED; +} + +DWORD WINAPI XInputGetCapabilities(DWORD index, DWORD flags, XINPUT_CAPABILITIES* capabilities) +{ + static int warn_once; + + if (!warn_once++) + FIXME("(index %u, flags 0x%x, capabilities %p) Stub!\n", index, flags, capabilities); + + if (index >= XUSER_MAX_COUNT) + return ERROR_BAD_ARGUMENTS; + if (!controllers[index].connected) + return ERROR_DEVICE_NOT_CONNECTED; + + return ERROR_NOT_SUPPORTED; +} + +DWORD WINAPI XInputGetDSoundAudioDeviceGuids(DWORD index, GUID* render_guid, GUID* capture_guid) +{ + FIXME("(index %u, render guid %p, capture guid %p) Stub!\n", index, render_guid, capture_guid); + + if (index >= XUSER_MAX_COUNT) + return ERROR_BAD_ARGUMENTS; + if (!controllers[index].connected) + return ERROR_DEVICE_NOT_CONNECTED; + + return ERROR_NOT_SUPPORTED; +} + +DWORD WINAPI XInputGetBatteryInformation(DWORD index, BYTE type, XINPUT_BATTERY_INFORMATION* battery) +{ + FIXME("(index %u, type %u, battery %p) Stub!\n", index, type, battery); + + if (index >= XUSER_MAX_COUNT) + return ERROR_BAD_ARGUMENTS; + if (!controllers[index].connected) + return ERROR_DEVICE_NOT_CONNECTED; + + return ERROR_NOT_SUPPORTED; +} From 40acca77bfa8fce3e367fc50f91e41eb1485a5cd Mon Sep 17 00:00:00 2001 From: kozec Date: Fri, 30 Sep 2016 19:02:58 +0200 Subject: [PATCH 2/7] Applied (by hand :( ) xinput_obiwan.patch from github.com/00cpxxx/wine-xinput --- xinput1_3/Makefile.in | 1 + xinput1_3/xinput1_3_main.c | 440 +++++++++++++++++++++++++++++++++++-- 2 files changed, 418 insertions(+), 23 deletions(-) diff --git a/xinput1_3/Makefile.in b/xinput1_3/Makefile.in index cf8f730..37621fa 100644 --- a/xinput1_3/Makefile.in +++ b/xinput1_3/Makefile.in @@ -1,5 +1,6 @@ MODULE = xinput1_3.dll IMPORTLIB = xinput +IMPORTS = uuid dxguid dinput dinput8 ole32 C_SRCS = \ xinput1_3_main.c diff --git a/xinput1_3/xinput1_3_main.c b/xinput1_3/xinput1_3_main.c index 04732eb..73b5d3f 100644 --- a/xinput1_3/xinput1_3_main.c +++ b/xinput1_3/xinput1_3_main.c @@ -1,6 +1,8 @@ /* * The Wine project - Xinput Joystick Library + * * Copyright 2008 Andrew Fenn + * Copyright 2016 Bruno Jesus * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -17,6 +19,7 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#define COBJMACROS #include "config.h" #include #include @@ -27,6 +30,7 @@ #include "winbase.h" #include "winerror.h" +#include "dinput.h" #include "xinput.h" /* Not defined in the headers, used only by XInputGetStateEx */ @@ -34,17 +38,340 @@ WINE_DEFAULT_DEBUG_CHANNEL(xinput); -struct +struct CapsFlags +{ + BOOL wireless, jedi, pov; + int axes, buttons; +}; + +static struct ControllerMap { - BOOL connected; + LPDIRECTINPUTDEVICE8A device; + BOOL connected, acquired; + struct CapsFlags caps; + XINPUT_STATE state; + XINPUT_VIBRATION vibration; + BOOL vibration_dirty; + + DIEFFECT effect_data; + LPDIRECTINPUTEFFECT effect_instance; } controllers[XUSER_MAX_COUNT]; +static struct +{ + LPDIRECTINPUT8A iface; + BOOL enabled; + int mapped; +} dinput; + +#define STARTUP_DINPUT if (!dinput.iface) dinput_start(); + +/* ========================= Internal functions ============================= */ + +static BOOL dinput_is_good(const LPDIRECTINPUTDEVICE8A device, struct CapsFlags *caps) +{ + HRESULT hr; + DIPROPDWORD property; + DIDEVCAPS dinput_caps; + static const unsigned long wireless_products[] = { + MAKELONG(0x045e, 0x0291) /* microsoft receiver */, + MAKELONG(0x045e, 0x0719) /* microsoft controller */, + MAKELONG(0x0738, 0x4556) /* mad catz */, + MAKELONG(0x0e6f, 0x0003) /* logitech */, + MAKELONG(0x0e6f, 0x0005) /* eclipse */, + MAKELONG(0x0e6f, 0x0006) /* edge */, + MAKELONG(0x102c, 0xff0c) /* joytech */ + }; + int i; + + dinput_caps.dwSize = sizeof(dinput_caps); + hr = IDirectInputDevice_GetCapabilities(device, &dinput_caps); + if (FAILED(hr)) + return FALSE; + + property.diph.dwSize = sizeof(property); + property.diph.dwHeaderSize = sizeof(property.diph); + property.diph.dwObj = 0; + property.diph.dwHow = DIPH_DEVICE; + + hr = IDirectInputDevice_GetProperty(device, DIPROP_VIDPID, &property.diph); + if (FAILED(hr)) + return FALSE; + + if (dinput_caps.dwAxes < 2 || dinput_caps.dwButtons < 8) + return FALSE; + + caps->axes = dinput_caps.dwAxes; + caps->buttons = dinput_caps.dwButtons; + caps->wireless = FALSE; + caps->jedi = !!(dinput_caps.dwFlags & DIDC_FORCEFEEDBACK); + caps->pov = !!dinput_caps.dwPOVs; + + for (i = 0; i < sizeof(wireless_products) / sizeof(wireless_products[0]); i++) + if (property.dwData == wireless_products[i]) + { + caps->wireless = TRUE; + break; + } + + if (dinput_caps.dwAxes == 6 && dinput_caps.dwButtons == 11 && dinput_caps.dwPOVs == 1) + TRACE("This controller has the same number of buttons/axes from xbox 360, should work...\n"); + else + FIXME("This is not a known xbox controller, using anyway. Expect problems!\n"); + + return TRUE; +} + +static BOOL dinput_set_range(const LPDIRECTINPUTDEVICE8A device) +{ + HRESULT hr; + DIPROPRANGE property; + + property.diph.dwSize = sizeof(property); + property.diph.dwHeaderSize = sizeof(property.diph); + property.diph.dwHow = DIPH_DEVICE; + property.diph.dwObj = 0; + property.lMin = -32767; + property.lMax = +32767; + + hr = IDirectInputDevice_SetProperty(device, DIPROP_RANGE, &property.diph); + if (FAILED(hr)) + { + WARN("Failed to set axis range (0x%x)\n", hr); + return FALSE; + } + return TRUE; +} + +static void dinput_joystate_to_xinput(DIJOYSTATE2 *js, XINPUT_GAMEPAD *gamepad, struct CapsFlags *caps) +{ + static const int xbox_buttons[] = { + XINPUT_GAMEPAD_A, + XINPUT_GAMEPAD_B, + XINPUT_GAMEPAD_X, + XINPUT_GAMEPAD_Y, + XINPUT_GAMEPAD_LEFT_SHOULDER, + XINPUT_GAMEPAD_RIGHT_SHOULDER, + XINPUT_GAMEPAD_BACK, + XINPUT_GAMEPAD_START, + 0, /* xbox key not used */ + XINPUT_GAMEPAD_LEFT_THUMB, + XINPUT_GAMEPAD_RIGHT_THUMB + }; + int i, buttons; + + gamepad->wButtons = 0x0000; + /* First the D-Pad which is recognized as a POV in dinput */ + if (caps->pov) + { + switch (js->rgdwPOV[0]) + { + case 0 : gamepad->wButtons |= XINPUT_GAMEPAD_DPAD_UP; break; + case 4500 : gamepad->wButtons |= XINPUT_GAMEPAD_DPAD_UP; /* fall through */ + case 9000 : gamepad->wButtons |= XINPUT_GAMEPAD_DPAD_RIGHT; break; + case 13500: gamepad->wButtons |= XINPUT_GAMEPAD_DPAD_RIGHT; /* fall through */ + case 18000: gamepad->wButtons |= XINPUT_GAMEPAD_DPAD_DOWN; break; + case 22500: gamepad->wButtons |= XINPUT_GAMEPAD_DPAD_DOWN; /* fall through */ + case 27000: gamepad->wButtons |= XINPUT_GAMEPAD_DPAD_LEFT; break; + case 31500: gamepad->wButtons |= XINPUT_GAMEPAD_DPAD_LEFT | XINPUT_GAMEPAD_DPAD_UP; + } + } + + /* Buttons */ + buttons = min(caps->buttons, sizeof(xbox_buttons) / sizeof(*xbox_buttons)); + for (i = 0; i < buttons; i++) + if (js->rgbButtons[i] & 0x80) + gamepad->wButtons |= xbox_buttons[i]; + + /* Axes */ + gamepad->sThumbLX = js->lX; + gamepad->sThumbLY = -js->lY; + if (caps->axes >= 4) + { + gamepad->sThumbRX = js->lRx; + gamepad->sThumbRY = -js->lRy; + } + else + gamepad->sThumbRX = gamepad->sThumbRY = 0; + + /* Both triggers */ + if (caps->axes >= 6) + { + gamepad->bLeftTrigger = (255 * (js->lZ + 32767)) / 32767; + gamepad->bRightTrigger = (255 * (js->lRz + 32767)) / 32767; + } + else + gamepad->bLeftTrigger = gamepad->bRightTrigger = 0; +} + +static void dinput_fill_effect(DIEFFECT *effect) +{ + static DWORD axes[2] = {DIJOFS_X, DIJOFS_Y}; + static LONG direction[2] = {0, 0}; + + effect->dwSize = sizeof(effect); + effect->dwFlags = DIEFF_CARTESIAN | DIEFF_OBJECTOFFSETS; + effect->dwDuration = INFINITE; + effect->dwGain = 0; + effect->dwTriggerButton = DIEB_NOTRIGGER; + effect->cAxes = sizeof(axes) / sizeof(axes[0]); + effect->rgdwAxes = axes; + effect->rglDirection = direction; +} + +static void dinput_send_effect(int index, int power) +{ + HRESULT hr; + DIPERIODIC periodic; + DIEFFECT *effect = &controllers[index].effect_data; + LPDIRECTINPUTEFFECT *instance = &controllers[index].effect_instance; + + if (!*instance) + dinput_fill_effect(effect); + + effect->cbTypeSpecificParams = sizeof(periodic); + effect->lpvTypeSpecificParams = &periodic; + + periodic.dwMagnitude = power; + periodic.dwPeriod = DI_SECONDS; /* 1 second */ + periodic.lOffset = 0; + periodic.dwPhase = 0; + + if (!*instance) + { + hr = IDirectInputDevice8_CreateEffect(controllers[index].device, &GUID_Square, + effect, instance, NULL); + if (FAILED(hr)) + { + WARN("Failed to create effect (0x%x)\n", hr); + return; + } + if (!*instance) + { + WARN("Effect not returned???\n"); + return; + } + + hr = IDirectInputEffect_SetParameters(*instance, effect, DIEP_AXES | DIEP_DIRECTION | DIEP_NODOWNLOAD); + if (FAILED(hr)) + { + IUnknown_Release(*instance); + *instance = NULL; + WARN("Failed to configure effect (0x%x)\n", hr); + return; + } + } + + hr = IDirectInputEffect_SetParameters(*instance, effect, DIEP_TYPESPECIFICPARAMS | DIEP_START); + if (FAILED(hr)) + { + WARN("Failed to play effect (0x%x)\n", hr); + return; + } +} + +static BOOL CALLBACK dinput_enum_callback(const DIDEVICEINSTANCEA *instance, void *context) +{ + LPDIRECTINPUTDEVICE8A device; + HRESULT hr; + + if (dinput.mapped == sizeof(controllers) / sizeof(*controllers)) + return DIENUM_STOP; + + hr = IDirectInput_CreateDevice(dinput.iface, &instance->guidInstance, &device, NULL); + if (FAILED(hr)) + return DIENUM_CONTINUE; + + if (!dinput_is_good(device, &controllers[dinput.mapped].caps)) + { + IDirectInput_Release(device); + return DIENUM_CONTINUE; + } + + if (!dinput_set_range(device)) + { + IDirectInput_Release(device); + return DIENUM_CONTINUE; + } + + controllers[dinput.mapped].connected = TRUE; + controllers[dinput.mapped].device = device; + dinput.mapped++; + + return DIENUM_CONTINUE; +} + +static void dinput_start(void) +{ + HRESULT hr; + + hr = DirectInput8Create(GetModuleHandleA(NULL), 0x0800, &IID_IDirectInput8A, + (void **)&dinput.iface, NULL); + if (FAILED(hr)) + { + ERR("Failed to create dinput8 interface, no xinput controller support (0x%x)\n", hr); + return; + } + + hr = IDirectInput8_EnumDevices(dinput.iface, DI8DEVCLASS_GAMECTRL, + dinput_enum_callback, NULL, DIEDFL_ATTACHEDONLY); + if (FAILED(hr)) + { + ERR("Failed to enumerate dinput8 devices, no xinput controller support (0x%x)\n", hr); + return; + } + + dinput.enabled = TRUE; +} + +static void dinput_update(int index) +{ + HRESULT hr; + DIJOYSTATE2 data; + XINPUT_GAMEPAD gamepad; + + if (dinput.enabled) + { + if (!controllers[index].acquired) + { + IDirectInputDevice8_SetDataFormat(controllers[index].device, &c_dfDIJoystick2); + hr = IDirectInputDevice8_Acquire(controllers[index].device); + if (FAILED(hr)) + { + WARN("Failed to acquire game controller (0x%x)\n", hr); + return; + } + controllers[index].acquired = TRUE; + } + + IDirectInputDevice8_Poll(controllers[index].device); + hr = IDirectInputDevice_GetDeviceState(controllers[index].device, sizeof(data), &data); + if (FAILED(hr)) + { + if (hr == DIERR_INPUTLOST) + controllers[index].acquired = FALSE; + WARN("Failed to get game controller state (0x%x)\n", hr); + return; + } + dinput_joystate_to_xinput(&data, &gamepad, &controllers[index].caps); + } + else + memset(&gamepad, 0, sizeof(gamepad)); + + if (memcmp(&controllers[index].state.Gamepad, &gamepad, sizeof(gamepad))) + { + controllers[index].state.Gamepad = gamepad; + controllers[index].state.dwPacketNumber++; + } +} + +/* ============================ Dll Functions =============================== */ + + BOOL WINAPI DllMain(HINSTANCE inst, DWORD reason, LPVOID reserved) { switch(reason) { - case DLL_WINE_PREATTACH: - return FALSE; /* prefer native version */ case DLL_PROCESS_ATTACH: DisableThreadLibraryCalls(inst); break; @@ -58,22 +385,57 @@ void WINAPI XInputEnable(BOOL enable) to the controllers. Setting to true will send the last vibration value (sent to XInputSetState) to the controller and allow messages to be sent */ - FIXME("(enable %d) Stub!\n", enable); + TRACE("(%d)\n", enable); + + STARTUP_DINPUT + + if((dinput.enabled = enable)) + { + int i; + /* Apply the last vibration status that was sent to the controller + * while xinput was disabled. */ + for (i = 0; i < sizeof(controllers) / sizeof(*controllers); i++) + { + if (controllers[i].connected && controllers[i].vibration_dirty) + XInputSetState(i, &controllers[i].vibration); + } + } } DWORD WINAPI XInputSetState(DWORD index, XINPUT_VIBRATION* vibration) { - FIXME("(index %u, vibration %p) Stub!\n", index, vibration); + TRACE("(%u %p)\n", index, vibration); + + STARTUP_DINPUT if (index >= XUSER_MAX_COUNT) return ERROR_BAD_ARGUMENTS; if (!controllers[index].connected) return ERROR_DEVICE_NOT_CONNECTED; - return ERROR_NOT_SUPPORTED; + /* Check if we really have to do all the process */ + if (!controllers[index].vibration_dirty && + !memcmp(&controllers[index].vibration, vibration, sizeof(*vibration))) + return ERROR_SUCCESS; + + controllers[index].vibration = *vibration; + controllers[index].vibration_dirty = !dinput.enabled; + + if (dinput.enabled && controllers[index].caps.jedi) + { + int power; + /* FIXME: we can't set the speed of each motor so do an average */ + power = DI_FFNOMINALMAX * (vibration->wLeftMotorSpeed + vibration->wRightMotorSpeed) / 2 / 0xFFFF; + + TRACE("Vibration left/right speed %d/%d translated to %d\n\n", + vibration->wLeftMotorSpeed, vibration->wRightMotorSpeed, power); + dinput_send_effect(index, power); + } + + return ERROR_SUCCESS; } -DWORD WINAPI DECLSPEC_HOTPATCH XInputGetState(DWORD index, XINPUT_STATE* state) +DWORD WINAPI XInputGetState(DWORD index, XINPUT_STATE* state) { union { @@ -81,23 +443,29 @@ DWORD WINAPI DECLSPEC_HOTPATCH XInputGetState(DWORD index, 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); + TRACE("(%u %p)\n", index, state); + STARTUP_DINPUT + + if (index >= XUSER_MAX_COUNT) + return ERROR_BAD_ARGUMENTS; + if (!controllers[index].connected) + return ERROR_DEVICE_NOT_CONNECTED; + - ret = XInputGetStateEx(index, &xinput.state_ex); - if (ret != ERROR_SUCCESS) - return ret; + dinput_update(index); + *state = controllers[index].state; /* The main difference between this and the Ex version is the media guide button */ - xinput.state.Gamepad.wButtons &= ~XINPUT_GAMEPAD_GUIDE; - *state = xinput.state; + /* TODO: Check on this. + * xinput.state.Gamepad.wButtons &= ~XINPUT_GAMEPAD_GUIDE; + * *state = xinput.state; + */ return ERROR_SUCCESS; } -DWORD WINAPI DECLSPEC_HOTPATCH XInputGetStateEx(DWORD index, XINPUT_STATE_EX* state_ex) +DWORD WINAPI XInputGetStateEx(DWORD index, XINPUT_STATE_EX* state_ex) { static int warn_once; @@ -124,19 +492,39 @@ DWORD WINAPI XInputGetKeystroke(DWORD index, DWORD reserved, PXINPUT_KEYSTROKE k return ERROR_NOT_SUPPORTED; } +/* Not defined anywhere ??? */ +#define XINPUT_CAPS_FFB_SUPPORTED 0x0001 +#define XINPUT_CAPS_WIRELESS 0x0002 +#define XINPUT_CAPS_NO_NAVIGATION 0x0010 + DWORD WINAPI XInputGetCapabilities(DWORD index, DWORD flags, XINPUT_CAPABILITIES* capabilities) { - static int warn_once; + TRACE("(%u %d %p)\n", index, flags, capabilities); - if (!warn_once++) - FIXME("(index %u, flags 0x%x, capabilities %p) Stub!\n", index, flags, capabilities); + STARTUP_DINPUT if (index >= XUSER_MAX_COUNT) return ERROR_BAD_ARGUMENTS; if (!controllers[index].connected) return ERROR_DEVICE_NOT_CONNECTED; - return ERROR_NOT_SUPPORTED; + capabilities->Type = XINPUT_DEVTYPE_GAMEPAD; + capabilities->SubType = XINPUT_DEVSUBTYPE_GAMEPAD; + + capabilities->Flags = 0; + if (controllers[index].caps.jedi) + capabilities->Flags |= XINPUT_CAPS_FFB_SUPPORTED; + if (controllers[index].caps.wireless) + capabilities->Flags |= XINPUT_CAPS_WIRELESS; + if (!controllers[index].caps.pov) + capabilities->Flags |= XINPUT_CAPS_NO_NAVIGATION; + + dinput_update(index); + + capabilities->Vibration = controllers[index].vibration; + capabilities->Gamepad = controllers[index].state.Gamepad; + + return ERROR_SUCCESS; } DWORD WINAPI XInputGetDSoundAudioDeviceGuids(DWORD index, GUID* render_guid, GUID* capture_guid) @@ -153,12 +541,18 @@ DWORD WINAPI XInputGetDSoundAudioDeviceGuids(DWORD index, GUID* render_guid, GUI DWORD WINAPI XInputGetBatteryInformation(DWORD index, BYTE type, XINPUT_BATTERY_INFORMATION* battery) { - FIXME("(index %u, type %u, battery %p) Stub!\n", index, type, battery); + TRACE("(%u %u %p) Stub!\n", index, type, battery); + + STARTUP_DINPUT if (index >= XUSER_MAX_COUNT) return ERROR_BAD_ARGUMENTS; if (!controllers[index].connected) return ERROR_DEVICE_NOT_CONNECTED; - return ERROR_NOT_SUPPORTED; + battery->BatteryType = BATTERY_TYPE_WIRED; + battery->BatteryLevel = BATTERY_LEVEL_FULL; + + + return ERROR_SUCCESS; } From 0b7d74ee4f8364d9499cc2cf81a4786e1a7f4e83 Mon Sep 17 00:00:00 2001 From: kozec Date: Fri, 30 Sep 2016 22:52:52 +0200 Subject: [PATCH 3/7] Added makefile and made entire thing buildable under mingw --- xinput1_3/Makefile | 14 +++++++++++++ xinput1_3/Makefile.in | 8 -------- xinput1_3/xinput1_3_main.c | 42 +++++++++++++++++++++++++++++++++++--- 3 files changed, 53 insertions(+), 11 deletions(-) create mode 100644 xinput1_3/Makefile delete mode 100644 xinput1_3/Makefile.in diff --git a/xinput1_3/Makefile b/xinput1_3/Makefile new file mode 100644 index 0000000..ba2c10f --- /dev/null +++ b/xinput1_3/Makefile @@ -0,0 +1,14 @@ +# mingw32-gcc +GCC = /usr/bin/i686-w64-mingw32-gcc -D _WXI_MINGW +INCLUDE_DIR = -I/usr/i686-w64-mingw32/include +CFLAGS = -Wl,--export-all-symbols +LIB_DIR = -L/usr/i686-w64-mingw32/lib/ +LIBS = -ldxguid -ldinput -ldinput8 + +xinput1_3.dll: xinput1_3_main.c + ${GCC} -shared ${CFLAGS} ${INCLUDE_DIR} ${LIB_DIR} $? ${LIBS} -o $@ + +clean: + rm -f *.o *.dll + +all: xinput1_3.dll diff --git a/xinput1_3/Makefile.in b/xinput1_3/Makefile.in deleted file mode 100644 index 37621fa..0000000 --- a/xinput1_3/Makefile.in +++ /dev/null @@ -1,8 +0,0 @@ -MODULE = xinput1_3.dll -IMPORTLIB = xinput -IMPORTS = uuid dxguid dinput dinput8 ole32 - -C_SRCS = \ - xinput1_3_main.c - -RC_SRCS = version.rc diff --git a/xinput1_3/xinput1_3_main.c b/xinput1_3/xinput1_3_main.c index 73b5d3f..c210b8a 100644 --- a/xinput1_3/xinput1_3_main.c +++ b/xinput1_3/xinput1_3_main.c @@ -20,23 +20,59 @@ */ #define COBJMACROS -#include "config.h" #include #include #include -#include "wine/debug.h" +#ifdef __WINEGCC__ + // Available only with winegcc + #include "wine/debug.h" + WINE_DEFAULT_DEBUG_CHANNEL(xinput); +#endif #include "windef.h" #include "winbase.h" #include "winerror.h" +#include "unknwn.h" #include "dinput.h" +#ifdef __MINGW32__ + // Mingw compiles weird mutation with no usable symbols without this + // TODO: I don't really know why this helps + #undef WINAPI + #define WINAPI +#endif #include "xinput.h" +#ifndef TRACE + // Unavailable outside wine + #define TRACE(...) do { } while(0) + #define FIXME(...) do { } while(0) + #define WARN(...) do { } while(0) + #define ERR(...) do { } while(0) +#endif + +#ifdef __MINGW32__ + // Stuff missing in mingw + typedef struct { + WORD wButtons; + BYTE bLeftTrigger; + BYTE bRightTrigger; + SHORT sThumbLX; + SHORT sThumbLY; + SHORT sThumbRX; + SHORT sThumbRY; + DWORD dwPaddingReserved; + } XINPUT_GAMEPAD_EX; + + typedef struct { + DWORD dwPacketNumber; + XINPUT_GAMEPAD_EX Gamepad; + } XINPUT_STATE_EX; +#endif + /* Not defined in the headers, used only by XInputGetStateEx */ #define XINPUT_GAMEPAD_GUIDE 0x0400 -WINE_DEFAULT_DEBUG_CHANNEL(xinput); struct CapsFlags { From ce367b68b8557154b5ef0b3d0e3921d5cc96ce96 Mon Sep 17 00:00:00 2001 From: kozec Date: Fri, 30 Sep 2016 22:53:34 +0200 Subject: [PATCH 4/7] Removed tests --- xinput1_3/tests/Makefile.in | 5 - xinput1_3/tests/xinput.c | 288 ------------------------------------ 2 files changed, 293 deletions(-) delete mode 100644 xinput1_3/tests/Makefile.in delete mode 100644 xinput1_3/tests/xinput.c diff --git a/xinput1_3/tests/Makefile.in b/xinput1_3/tests/Makefile.in deleted file mode 100644 index 718b47f..0000000 --- a/xinput1_3/tests/Makefile.in +++ /dev/null @@ -1,5 +0,0 @@ -TESTDLL = xinput1_3.dll -IMPORTS = user32 - -C_SRCS = \ - xinput.c diff --git a/xinput1_3/tests/xinput.c b/xinput1_3/tests/xinput.c deleted file mode 100644 index 17884e1..0000000 --- a/xinput1_3/tests/xinput.c +++ /dev/null @@ -1,288 +0,0 @@ -/* - * The Wine project - Xinput Joystick Library - * Copyright 2008 Andrew Fenn - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ - -#include -#include - -#include "xinput.h" -#include "wine/test.h" - -static DWORD (WINAPI *pXInputGetState)(DWORD, XINPUT_STATE*); -static DWORD (WINAPI *pXInputGetStateEx)(DWORD, XINPUT_STATE_EX*); -static DWORD (WINAPI *pXInputGetCapabilities)(DWORD,DWORD,XINPUT_CAPABILITIES*); -static DWORD (WINAPI *pXInputSetState)(DWORD, XINPUT_VIBRATION*); -static void (WINAPI *pXInputEnable)(BOOL); -static DWORD (WINAPI *pXInputGetKeystroke)(DWORD, DWORD, PXINPUT_KEYSTROKE); -static DWORD (WINAPI *pXInputGetDSoundAudioDeviceGuids)(DWORD, GUID*, GUID*); -static DWORD (WINAPI *pXInputGetBatteryInformation)(DWORD, BYTE, XINPUT_BATTERY_INFORMATION*); - -static void test_set_state(void) -{ - XINPUT_VIBRATION vibrator; - DWORD controllerNum; - DWORD result; - - for(controllerNum=0; controllerNum < XUSER_MAX_COUNT; controllerNum++) - { - ZeroMemory(&vibrator, sizeof(XINPUT_VIBRATION)); - - vibrator.wLeftMotorSpeed = 0; - vibrator.wRightMotorSpeed = 0; - result = pXInputSetState(controllerNum, &vibrator); - ok(result == ERROR_SUCCESS || result == ERROR_DEVICE_NOT_CONNECTED, "XInputSetState failed with (%d)\n", result); - - if (pXInputEnable) pXInputEnable(0); - - vibrator.wLeftMotorSpeed = 65535; - vibrator.wRightMotorSpeed = 65535; - result = pXInputSetState(controllerNum, &vibrator); - ok(result == ERROR_SUCCESS || result == ERROR_DEVICE_NOT_CONNECTED, "XInputSetState failed with (%d)\n", result); - - if (pXInputEnable) pXInputEnable(1); - } - - result = pXInputSetState(XUSER_MAX_COUNT+1, &vibrator); - ok(result == ERROR_BAD_ARGUMENTS, "XInputSetState returned (%d)\n", result); -} - -static void test_get_state(void) -{ - union - { - XINPUT_STATE state; - XINPUT_STATE_EX state_ex; - } xinput; - DWORD controllerNum, i; - DWORD result; - - for (i = 0; i < (pXInputGetStateEx ? 2 : 1); i++) - { - for (controllerNum = 0; controllerNum < XUSER_MAX_COUNT; controllerNum++) - { - ZeroMemory(&xinput, sizeof(xinput)); - - if (i == 0) - result = pXInputGetState(controllerNum, &xinput.state); - else - result = pXInputGetStateEx(controllerNum, &xinput.state_ex); - ok(result == ERROR_SUCCESS || result == ERROR_DEVICE_NOT_CONNECTED, - "%s failed with (%d)\n", i == 0 ? "XInputGetState" : "XInputGetStateEx", result); - - if (ERROR_DEVICE_NOT_CONNECTED == result) - { - skip("Controller %d is not connected\n", controllerNum); - continue; - } - - trace("-- Results for controller %d --\n", controllerNum); - if (i == 0) - trace("XInputGetState: %d\n", result); - else - trace("XInputGetStateEx: %d\n", result); - trace("State->dwPacketNumber: %d\n", xinput.state.dwPacketNumber); - trace("Gamepad Variables --\n"); - trace("Gamepad.wButtons: %#x\n", xinput.state.Gamepad.wButtons); - trace("Gamepad.bLeftTrigger: 0x%08x\n", xinput.state.Gamepad.bLeftTrigger); - trace("Gamepad.bRightTrigger: 0x%08x\n", xinput.state.Gamepad.bRightTrigger); - trace("Gamepad.sThumbLX: %d\n", xinput.state.Gamepad.sThumbLX); - trace("Gamepad.sThumbLY: %d\n", xinput.state.Gamepad.sThumbLY); - trace("Gamepad.sThumbRX: %d\n", xinput.state.Gamepad.sThumbRX); - trace("Gamepad.sThumbRY: %d\n", xinput.state.Gamepad.sThumbRY); - } - } - - result = pXInputGetState(XUSER_MAX_COUNT, &xinput.state); - ok(result == ERROR_BAD_ARGUMENTS, "XInputGetState returned (%d)\n", result); - - result = pXInputGetState(XUSER_MAX_COUNT+1, &xinput.state); - ok(result == ERROR_BAD_ARGUMENTS, "XInputGetState returned (%d)\n", result); - if (pXInputGetStateEx) - { - result = pXInputGetStateEx(XUSER_MAX_COUNT, &xinput.state_ex); - ok(result == ERROR_BAD_ARGUMENTS, "XInputGetState returned (%d)\n", result); - - result = pXInputGetStateEx(XUSER_MAX_COUNT+1, &xinput.state_ex); - ok(result == ERROR_BAD_ARGUMENTS, "XInputGetState returned (%d)\n", result); - } -} - -static void test_get_keystroke(void) -{ - XINPUT_KEYSTROKE keystroke; - DWORD controllerNum; - DWORD result; - - for(controllerNum=0; controllerNum < XUSER_MAX_COUNT; controllerNum++) - { - ZeroMemory(&keystroke, sizeof(XINPUT_KEYSTROKE)); - - result = pXInputGetKeystroke(controllerNum, XINPUT_FLAG_GAMEPAD, &keystroke); - ok(result == ERROR_EMPTY || result == ERROR_SUCCESS || result == ERROR_DEVICE_NOT_CONNECTED, - "XInputGetKeystroke failed with (%d)\n", result); - - if (ERROR_DEVICE_NOT_CONNECTED == result) - { - skip("Controller %d is not connected\n", controllerNum); - } - } - - ZeroMemory(&keystroke, sizeof(XINPUT_KEYSTROKE)); - result = pXInputGetKeystroke(XUSER_MAX_COUNT+1, XINPUT_FLAG_GAMEPAD, &keystroke); - ok(result == ERROR_BAD_ARGUMENTS, "XInputGetKeystroke returned (%d)\n", result); -} - -static void test_get_capabilities(void) -{ - XINPUT_CAPABILITIES capabilities; - DWORD controllerNum; - DWORD result; - - for(controllerNum=0; controllerNum < XUSER_MAX_COUNT; controllerNum++) - { - ZeroMemory(&capabilities, sizeof(XINPUT_CAPABILITIES)); - - result = pXInputGetCapabilities(controllerNum, XINPUT_FLAG_GAMEPAD, &capabilities); - ok(result == ERROR_SUCCESS || result == ERROR_DEVICE_NOT_CONNECTED, "XInputGetCapabilities failed with (%d)\n", result); - - if (ERROR_DEVICE_NOT_CONNECTED == result) - { - skip("Controller %d is not connected\n", controllerNum); - } - } - - ZeroMemory(&capabilities, sizeof(XINPUT_CAPABILITIES)); - result = pXInputGetCapabilities(XUSER_MAX_COUNT+1, XINPUT_FLAG_GAMEPAD, &capabilities); - ok(result == ERROR_BAD_ARGUMENTS, "XInputGetCapabilities returned (%d)\n", result); -} - -static void test_get_dsoundaudiodevice(void) -{ - DWORD controllerNum; - DWORD result; - GUID soundRender; - GUID soundCapture; - - for(controllerNum=0; controllerNum < XUSER_MAX_COUNT; controllerNum++) - { - result = pXInputGetDSoundAudioDeviceGuids(controllerNum, &soundRender, &soundCapture); - ok(result == ERROR_SUCCESS || result == ERROR_DEVICE_NOT_CONNECTED, "XInputGetDSoundAudioDeviceGuids failed with (%d)\n", result); - - if (ERROR_DEVICE_NOT_CONNECTED == result) - { - skip("Controller %d is not connected\n", controllerNum); - } - } - - result = pXInputGetDSoundAudioDeviceGuids(XUSER_MAX_COUNT+1, &soundRender, &soundCapture); - ok(result == ERROR_BAD_ARGUMENTS, "XInputGetDSoundAudioDeviceGuids returned (%d)\n", result); -} - -static void test_get_batteryinformation(void) -{ - DWORD controllerNum; - DWORD result; - XINPUT_BATTERY_INFORMATION batteryInfo; - - for(controllerNum=0; controllerNum < XUSER_MAX_COUNT; controllerNum++) - { - ZeroMemory(&batteryInfo, sizeof(XINPUT_BATTERY_INFORMATION)); - - result = pXInputGetBatteryInformation(controllerNum, BATTERY_DEVTYPE_GAMEPAD, &batteryInfo); - ok(result == ERROR_SUCCESS || result == ERROR_DEVICE_NOT_CONNECTED, "XInputGetBatteryInformation failed with (%d)\n", result); - - if (ERROR_DEVICE_NOT_CONNECTED == result) - { - ok(batteryInfo.BatteryLevel == BATTERY_TYPE_DISCONNECTED, "Failed to report device as being disconnected.\n"); - skip("Controller %d is not connected\n", controllerNum); - } - } - - result = pXInputGetBatteryInformation(XUSER_MAX_COUNT+1, BATTERY_DEVTYPE_GAMEPAD, &batteryInfo); - ok(result == ERROR_BAD_ARGUMENTS, "XInputGetBatteryInformation returned (%d)\n", result); -} - -START_TEST(xinput) -{ - struct - { - const char *name; - int version; - } libs[] = { - { "xinput1_1.dll", 1 }, - { "xinput1_2.dll", 2 }, - { "xinput1_3.dll", 3 }, - { "xinput1_4.dll", 4 }, - { "xinput9_1_0.dll", 0 } /* legacy for XP/Vista */ - }; - HMODULE hXinput; - void *pXInputGetStateEx_Ordinal; - int i; - - for (i = 0; i < sizeof(libs) / sizeof(libs[0]); i++) - { - hXinput = LoadLibraryA( libs[i].name ); - - if (!hXinput) - { - win_skip("Could not load %s\n", libs[i].name); - continue; - } - trace("Testing %s\n", libs[i].name); - - pXInputEnable = (void*)GetProcAddress(hXinput, "XInputEnable"); - pXInputSetState = (void*)GetProcAddress(hXinput, "XInputSetState"); - pXInputGetState = (void*)GetProcAddress(hXinput, "XInputGetState"); - pXInputGetStateEx = (void*)GetProcAddress(hXinput, "XInputGetStateEx"); /* Win >= 8 */ - pXInputGetStateEx_Ordinal = (void*)GetProcAddress(hXinput, (LPCSTR) 100); - pXInputGetKeystroke = (void*)GetProcAddress(hXinput, "XInputGetKeystroke"); - pXInputGetCapabilities = (void*)GetProcAddress(hXinput, "XInputGetCapabilities"); - pXInputGetDSoundAudioDeviceGuids = (void*)GetProcAddress(hXinput, "XInputGetDSoundAudioDeviceGuids"); - pXInputGetBatteryInformation = (void*)GetProcAddress(hXinput, "XInputGetBatteryInformation"); - - /* XInputGetStateEx may not be present by name, use ordinal in this case */ - if (!pXInputGetStateEx) - pXInputGetStateEx = pXInputGetStateEx_Ordinal; - - test_set_state(); - test_get_state(); - test_get_capabilities(); - - if (libs[i].version != 4) - test_get_dsoundaudiodevice(); - else - ok(!pXInputGetDSoundAudioDeviceGuids, "XInputGetDSoundAudioDeviceGuids exists in %s\n", libs[i].name); - - if (libs[i].version > 2) - { - test_get_keystroke(); - test_get_batteryinformation(); - ok(pXInputGetStateEx != NULL, "XInputGetStateEx not found in %s\n", libs[i].name); - } - else - { - ok(!pXInputGetKeystroke, "XInputGetKeystroke exists in %s\n", libs[i].name); - ok(!pXInputGetStateEx, "XInputGetStateEx exists in %s\n", libs[i].name); - ok(!pXInputGetBatteryInformation, "XInputGetBatteryInformation exists in %s\n", libs[i].name); - if (libs[i].version == 0) - ok(!pXInputEnable, "XInputEnable exists in %s\n", libs[i].name); - } - - FreeLibrary(hXinput); - } -} From 425fa264e1eccaeab2e25103cbd6ff51227cfae4 Mon Sep 17 00:00:00 2001 From: kozec Date: Fri, 30 Sep 2016 23:15:53 +0200 Subject: [PATCH 5/7] Cleaned redundant files --- xinput1_3/version.rc | 27 --------------------------- xinput1_3/xinput1_3.spec | 9 --------- 2 files changed, 36 deletions(-) delete mode 100644 xinput1_3/version.rc delete mode 100644 xinput1_3/xinput1_3.spec diff --git a/xinput1_3/version.rc b/xinput1_3/version.rc deleted file mode 100644 index 191b142..0000000 --- a/xinput1_3/version.rc +++ /dev/null @@ -1,27 +0,0 @@ -/* - * The Wine project - Xinput Joystick Library - * Copyright 2008 Andrew Fenn - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ - -#define WINE_FILEDESCRIPTION_STR "Wine Common Controller API" -#define WINE_FILENAME_STR "xinput1_3.dll" -#define WINE_FILEVERSION 9,15,779,0000 -#define WINE_FILEVERSION_STR "9.15.779.0000" -#define WINE_PRODUCTVERSION 9,15,779,0000 -#define WINE_PRODUCTVERSION_STR "9.15" - -#include "wine/wine_common_ver.rc" diff --git a/xinput1_3/xinput1_3.spec b/xinput1_3/xinput1_3.spec deleted file mode 100644 index 0023016..0000000 --- a/xinput1_3/xinput1_3.spec +++ /dev/null @@ -1,9 +0,0 @@ -1 stdcall -private DllMain(long long ptr) -2 stdcall XInputGetState(long ptr) -3 stdcall XInputSetState(long ptr) -4 stdcall XInputGetCapabilities(long long ptr) -5 stdcall XInputEnable(long) -6 stdcall XInputGetDSoundAudioDeviceGuids(long ptr ptr) -7 stdcall XInputGetBatteryInformation(long long ptr) -8 stdcall XInputGetKeystroke(long long ptr) -100 stdcall XInputGetStateEx(long ptr) From 7edcb37132ecfe8ef5754ca5ae0d00e229067e5a Mon Sep 17 00:00:00 2001 From: kozec Date: Fri, 30 Sep 2016 23:17:34 +0200 Subject: [PATCH 6/7] Moved Makefile --- xinput1_3/Makefile => Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename xinput1_3/Makefile => Makefile (88%) diff --git a/xinput1_3/Makefile b/Makefile similarity index 88% rename from xinput1_3/Makefile rename to Makefile index ba2c10f..37d5ec4 100644 --- a/xinput1_3/Makefile +++ b/Makefile @@ -5,7 +5,7 @@ CFLAGS = -Wl,--export-all-symbols LIB_DIR = -L/usr/i686-w64-mingw32/lib/ LIBS = -ldxguid -ldinput -ldinput8 -xinput1_3.dll: xinput1_3_main.c +xinput1_3.dll: xinput1_3/xinput1_3_main.c ${GCC} -shared ${CFLAGS} ${INCLUDE_DIR} ${LIB_DIR} $? ${LIBS} -o $@ clean: From 9f93e6527e455529ed12b14d0eea4403fabf4c41 Mon Sep 17 00:00:00 2001 From: kozec Date: Fri, 30 Sep 2016 23:33:55 +0200 Subject: [PATCH 7/7] Added 64bit build --- Makefile | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/Makefile b/Makefile index 37d5ec4..6301a7f 100644 --- a/Makefile +++ b/Makefile @@ -1,14 +1,28 @@ # mingw32-gcc -GCC = /usr/bin/i686-w64-mingw32-gcc -D _WXI_MINGW -INCLUDE_DIR = -I/usr/i686-w64-mingw32/include CFLAGS = -Wl,--export-all-symbols -LIB_DIR = -L/usr/i686-w64-mingw32/lib/ LIBS = -ldxguid -ldinput -ldinput8 -xinput1_3.dll: xinput1_3/xinput1_3_main.c - ${GCC} -shared ${CFLAGS} ${INCLUDE_DIR} ${LIB_DIR} $? ${LIBS} -o $@ +GCC32 = /usr/bin/i686-w64-mingw32-gcc -D _WXI_MINGW +INCLUDE_DIR32 = -I/usr/i686-w64-mingw32/include +LIB_DIR32 = -L/usr/i686-w64-mingw32/lib/ + +build/32/xinput1_3.dll: xinput1_3/xinput1_3_main.c + mkdir -p build/32/ + ${GCC32} -shared ${CFLAGS} ${INCLUDE_DIR32} ${LIB_DIR32} $? ${LIBS} -o $@ + +GCC64 = /usr/bin/x86_64-w64-mingw32-gcc -D _WXI_MINGW +INCLUDE_DIR64 = -I/usr/x86_64-w64-mingw32/include +LIB_DIR64 = -L/usr/x86_64-w64-mingw32/lib/ + +build/64/xinput1_3.dll: xinput1_3/xinput1_3_main.c + mkdir -p build/64/ + ${GCC64} -shared ${CFLAGS} ${INCLUDE_DIR64} ${LIB_DIR64} $? ${LIBS} -o $@ clean: rm -f *.o *.dll -all: xinput1_3.dll +32bit: build/32/xinput1_3.dll + +64bit: build/64/xinput1_3.dll + +all: build/32/xinput1_3.dll