From de6cd55961861c254bb4d96481a75bfb78553e5d Mon Sep 17 00:00:00 2001 From: Tk-Glitch Date: Thu, 12 Aug 2021 13:25:31 +0200 Subject: [PATCH] Update proton-sdl-joy patchset for 43f0c80 and move previous version to legacy --- wine-tkg-git/PKGBUILD | 2 +- .../legacy/proton-sdl-joy-43f0c80.patch | 10138 ++++++++++++++++ .../proton-tkg-specific/proton-sdl-joy.patch | 22 +- wine-tkg-git/wine-tkg-scripts/prepare.sh | 4 +- 4 files changed, 10153 insertions(+), 13 deletions(-) create mode 100644 wine-tkg-git/wine-tkg-patches/proton-tkg-specific/legacy/proton-sdl-joy-43f0c80.patch diff --git a/wine-tkg-git/PKGBUILD b/wine-tkg-git/PKGBUILD index ed149cf24..c83f6bb57 100644 --- a/wine-tkg-git/PKGBUILD +++ b/wine-tkg-git/PKGBUILD @@ -432,7 +432,7 @@ md5sums=('SKIP' '872bc9cc65ec8ce9603ac052b7468326' '3d5518c89320a59400774a86b9a1cf2f' '0310c86f736d1c9f35cdabdaedea9396' - '425d98f81fde60b67bcc51f9a1003513' + '2827ffa62eca46c32a96290a7099baea' 'aa3d7083feafc62f0c6427e0b98c42e2' '3ac0f9d110f954cda629ccda21b95ed8' 'b4a6fd86caa3b7a0c930f4d9b402e7cb' diff --git a/wine-tkg-git/wine-tkg-patches/proton-tkg-specific/legacy/proton-sdl-joy-43f0c80.patch b/wine-tkg-git/wine-tkg-patches/proton-tkg-specific/legacy/proton-sdl-joy-43f0c80.patch new file mode 100644 index 000000000..3555e4e3b --- /dev/null +++ b/wine-tkg-git/wine-tkg-patches/proton-tkg-specific/legacy/proton-sdl-joy-43f0c80.patch @@ -0,0 +1,10138 @@ +From 3d77c1ed4b63e5a8a359e8d5218d839e311609ba Mon Sep 17 00:00:00 2001 +From: Aric Stewart +Date: Thu, 28 Dec 2017 12:43:32 -0600 +Subject: [PATCH] dinput: Add SDL support + +v2: Include comments from Andrew including opening and closing devices more cleanly +Signed-off-by: Aric Stewart +--- + dlls/dinput/Makefile.in | 4 +- + dlls/dinput/dinput_main.c | 14 ++ + dlls/dinput/dinput_private.h | 1 + + dlls/dinput/joystick_sdl.c | 705 +++++++++++++++++++++++++++++++++++ + dlls/dinput8/Makefile.in | 5 +- + 5 files changed, 734 insertions(+), 2 deletions(-) + create mode 100644 dlls/dinput/joystick_sdl.c + +diff --git a/dlls/dinput/Makefile.in b/dlls/dinput/Makefile.in +index ae65fd4d93e..ee3ddc016e8 100644 +--- a/dlls/dinput/Makefile.in ++++ b/dlls/dinput/Makefile.in +@@ -2,7 +2,8 @@ MODULE = dinput.dll + IMPORTLIB = dinput + IMPORTS = dinput dxguid uuid comctl32 ole32 user32 advapi32 + EXTRADEFS = -DDIRECTINPUT_VERSION=0x0700 +-EXTRALIBS = $(IOKIT_LIBS) $(FORCEFEEDBACK_LIBS) ++EXTRALIBS = $(IOKIT_LIBS) $(FORCEFEEDBACK_LIBS) $(SDL2_LIBS) ++EXTRAINCL = $(SDL2_CFLAGS) + + C_SRCS = \ + config.c \ +@@ -14,6 +15,7 @@ C_SRCS = \ + joystick_linux.c \ + joystick_linuxinput.c \ + joystick_osx.c \ ++ joystick_sdl.c \ + keyboard.c \ + mouse.c + +diff --git a/dlls/dinput/dinput_main.c b/dlls/dinput/dinput_main.c +index 45023fc104a..ad72aaedff2 100644 +--- a/dlls/dinput/dinput_main.c ++++ b/dlls/dinput/dinput_main.c +@@ -90,6 +90,7 @@ static const struct dinput_device *dinput_devices[] = + { + &mouse_device, + &keyboard_device, ++ &joystick_sdl_device, + &joystick_linuxinput_device, + &joystick_linux_device, + &joystick_osx_device +@@ -524,6 +532,7 @@ static HRESULT WINAPI IDirectInputWImpl_EnumDevices( + unsigned int i; + int j; + HRESULT r; ++ BOOL found_device = FALSE; + + TRACE("(this=%p,0x%04x '%s',%p,%p,0x%04x)\n", + This, dwDevType, _dump_DIDEVTYPE_value(dwDevType, This->dwVersion), +@@ -545,9 +554,15 @@ static HRESULT WINAPI IDirectInputWImpl_EnumDevices( + TRACE(" - checking device %u ('%s')\n", i, dinput_devices[i]->name); + r = dinput_devices[i]->enum_deviceW(dwDevType, dwFlags, &devInstance, This->dwVersion, j); + if (r == S_OK) ++ { ++ found_device = TRUE; + if (enum_callback_wrapper(lpCallback, &devInstance, pvRef) == DIENUM_STOP) + return S_OK; ++ } + } ++ /* If we have found devices after SDL stop enumeration */ ++ if (dinput_devices[i] == &joystick_sdl_device && found_device) ++ return S_OK; + } + + return S_OK; +@@ -1247,6 +1262,9 @@ static HRESULT WINAPI IDirectInput8WImpl_EnumDevicesBySemantics( + didevis[device_count-1] = didevi; + } + } ++ /* If we have found devices after SDL stop enumeration */ ++ if (dinput_devices[i] == &joystick_sdl_device && device_count) ++ return S_OK; + } + + remain = device_count; +diff --git a/dlls/dinput/dinput_private.h b/dlls/dinput/dinput_private.h +index c0c88da9674..53bd7e39562 100644 +--- a/dlls/dinput/dinput_private.h ++++ b/dlls/dinput/dinput_private.h +@@ -68,6 +68,7 @@ extern const struct dinput_device keyboard_device DECLSPEC_HIDDEN; + extern const struct dinput_device joystick_linux_device DECLSPEC_HIDDEN; + extern const struct dinput_device joystick_linuxinput_device DECLSPEC_HIDDEN; + extern const struct dinput_device joystick_osx_device DECLSPEC_HIDDEN; ++extern const struct dinput_device joystick_sdl_device DECLSPEC_HIDDEN; + + extern void dinput_hooks_acquire_device(LPDIRECTINPUTDEVICE8W iface); + extern void dinput_hooks_unacquire_device(LPDIRECTINPUTDEVICE8W iface); +diff --git a/dlls/dinput/joystick_sdl.c b/dlls/dinput/joystick_sdl.c +new file mode 100644 +index 00000000000..a7619cc4cad +--- /dev/null ++++ b/dlls/dinput/joystick_sdl.c +@@ -0,0 +1,705 @@ ++/* DirectInput Joystick device from SDL ++ * ++ * Copyright 1998,2000 Marcus Meissner ++ * Copyright 1998,1999 Lionel Ulmer ++ * Copyright 2000-2001 TransGaming Technologies Inc. ++ * Copyright 2005 Daniel Remenak ++ * Copyright 2017 CodeWeavers, Aric Stewart ++ * ++ * 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 "wine/port.h" ++ ++#include ++#include ++#include ++#include ++#include ++#ifdef HAVE_UNISTD_H ++# include ++#endif ++#ifdef HAVE_SDL_H ++# include ++#endif ++#include ++ ++#include "wine/debug.h" ++#include "wine/unicode.h" ++#include "wine/list.h" ++#include "windef.h" ++#include "winbase.h" ++#include "winerror.h" ++#include "winreg.h" ++#include "dinput.h" ++ ++#include "dinput_private.h" ++#include "device_private.h" ++#include "joystick_private.h" ++ ++#ifdef HAVE_SDL_H ++ ++WINE_DEFAULT_DEBUG_CHANNEL(dinput); ++ ++typedef struct JoystickImpl JoystickImpl; ++static const IDirectInputDevice8AVtbl JoystickAvt; ++static const IDirectInputDevice8WVtbl JoystickWvt; ++ ++struct SDLDev { ++ int id; ++ WORD vendor_id; ++ WORD product_id; ++ CHAR *name; ++ ++ BOOL has_ff; ++}; ++ ++struct JoystickImpl ++{ ++ struct JoystickGenericImpl generic; ++ struct SDLDev *sdldev; ++ ++ SDL_Joystick *device; ++}; ++ ++static inline JoystickImpl *impl_from_IDirectInputDevice8A(IDirectInputDevice8A *iface) ++{ ++ return CONTAINING_RECORD(CONTAINING_RECORD(CONTAINING_RECORD(iface, IDirectInputDeviceImpl, IDirectInputDevice8A_iface), ++ JoystickGenericImpl, base), JoystickImpl, generic); ++} ++static inline JoystickImpl *impl_from_IDirectInputDevice8W(IDirectInputDevice8W *iface) ++{ ++ return CONTAINING_RECORD(CONTAINING_RECORD(CONTAINING_RECORD(iface, IDirectInputDeviceImpl, IDirectInputDevice8W_iface), ++ JoystickGenericImpl, base), JoystickImpl, generic); ++} ++ ++static inline IDirectInputDevice8W *IDirectInputDevice8W_from_impl(JoystickImpl *This) ++{ ++ return &This->generic.base.IDirectInputDevice8W_iface; ++} ++ ++static const GUID DInput_Wine_SDL_Joystick_GUID = { /* 001E36B7-5DBA-4C4F-A8C9-CFC8689DB403 */ ++ 0x001E36B7, 0x5DBA, 0x4C4F, {0xA8, 0xC9, 0xCF, 0xC8, 0x68, 0x9D, 0xB4, 0x03} ++}; ++ ++static int have_sdldevs = -1; ++static struct SDLDev *sdldevs = NULL; ++ ++static void find_sdldevs(void) ++{ ++ int i; ++ ++ if (InterlockedCompareExchange(&have_sdldevs, 0, -1) != -1) ++ /* Someone beat us to it */ ++ return; ++ ++ SDL_Init(SDL_INIT_JOYSTICK|SDL_INIT_HAPTIC); ++ SDL_JoystickEventState(SDL_ENABLE); ++ ++ for (i = 0; i < SDL_NumJoysticks(); i++) ++ { ++ struct SDLDev sdldev = {0}; ++ struct SDLDev *new_sdldevs; ++ SDL_Joystick *device; ++ const CHAR* name; ++ ++ sdldev.id = i; ++ device = SDL_JoystickOpen(i); ++ ++ name = SDL_JoystickName(device); ++ sdldev.name = HeapAlloc(GetProcessHeap(), 0, strlen(name) + 1); ++ strcpy(sdldev.name, name); ++ ++ if (device_disabled_registry(sdldev.name)) { ++ SDL_JoystickClose(device); ++ continue; ++ } ++ ++ TRACE("Found a joystick (%i) on %p: %s\n", have_sdldevs, device, sdldev.name); ++ ++ sdldev.vendor_id = SDL_JoystickGetVendor(device); ++ sdldev.product_id = SDL_JoystickGetProduct(device); ++ ++ if (!have_sdldevs) ++ new_sdldevs = HeapAlloc(GetProcessHeap(), 0, sizeof(struct SDLDev)); ++ else ++ new_sdldevs = HeapReAlloc(GetProcessHeap(), 0, sdldevs, (1 + have_sdldevs) * sizeof(struct SDLDev)); ++ ++ SDL_JoystickClose(device); ++ if (!new_sdldevs) ++ { ++ continue; ++ } ++ sdldevs = new_sdldevs; ++ sdldevs[have_sdldevs] = sdldev; ++ have_sdldevs++; ++ } ++} ++ ++static void fill_joystick_dideviceinstanceW(LPDIDEVICEINSTANCEW lpddi, DWORD version, int id) ++{ ++ DWORD dwSize = lpddi->dwSize; ++ ++ TRACE("%d %p\n", dwSize, lpddi); ++ memset(lpddi, 0, dwSize); ++ ++ lpddi->dwSize = dwSize; ++ lpddi->guidInstance = DInput_Wine_SDL_Joystick_GUID; ++ lpddi->guidInstance.Data3 = id; ++ lpddi->guidProduct = DInput_PIDVID_Product_GUID; ++ lpddi->guidProduct.Data1 = MAKELONG(sdldevs[id].vendor_id, sdldevs[id].product_id); ++ lpddi->guidFFDriver = GUID_NULL; ++ ++ if (version >= 0x0800) ++ lpddi->dwDevType = DI8DEVTYPE_JOYSTICK | (DI8DEVTYPEJOYSTICK_STANDARD << 8); ++ else ++ lpddi->dwDevType = DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_TRADITIONAL << 8); ++ ++ /* Assume the joystick as HID if it is attached to USB bus and has a valid VID/PID */ ++ if ( sdldevs[id].vendor_id && sdldevs[id].product_id) ++ { ++ lpddi->dwDevType |= DIDEVTYPE_HID; ++ lpddi->wUsagePage = 0x01; /* Desktop */ ++ if (lpddi->dwDevType == DI8DEVTYPE_JOYSTICK || lpddi->dwDevType == DIDEVTYPE_JOYSTICK) ++ lpddi->wUsage = 0x04; /* Joystick */ ++ else ++ lpddi->wUsage = 0x05; /* Game Pad */ ++ } ++ ++ MultiByteToWideChar(CP_ACP, 0, sdldevs[id].name, -1, lpddi->tszInstanceName, MAX_PATH); ++ MultiByteToWideChar(CP_ACP, 0, sdldevs[id].name, -1, lpddi->tszProductName, MAX_PATH); ++} ++ ++static void fill_joystick_dideviceinstanceA(LPDIDEVICEINSTANCEA lpddi, DWORD version, int id) ++{ ++ DIDEVICEINSTANCEW lpddiW; ++ DWORD dwSize = lpddi->dwSize; ++ ++ lpddiW.dwSize = sizeof(lpddiW); ++ fill_joystick_dideviceinstanceW(&lpddiW, version, id); ++ ++ TRACE("%d %p\n", dwSize, lpddi); ++ memset(lpddi, 0, dwSize); ++ ++ /* Convert W->A */ ++ lpddi->dwSize = dwSize; ++ lpddi->guidInstance = lpddiW.guidInstance; ++ lpddi->guidProduct = lpddiW.guidProduct; ++ lpddi->dwDevType = lpddiW.dwDevType; ++ strcpy(lpddi->tszInstanceName, sdldevs[id].name); ++ strcpy(lpddi->tszProductName, sdldevs[id].name); ++ lpddi->guidFFDriver = lpddiW.guidFFDriver; ++ lpddi->wUsagePage = lpddiW.wUsagePage; ++ lpddi->wUsage = lpddiW.wUsage; ++} ++ ++static HRESULT sdl_enum_deviceA(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEA lpddi, DWORD version, int id) ++{ ++ find_sdldevs(); ++ ++ if (id >= have_sdldevs) { ++ return E_FAIL; ++ } ++ ++ if (!((dwDevType == 0) || ++ ((dwDevType == DIDEVTYPE_JOYSTICK) && (version > 0x0300 && version < 0x0800)) || ++ (((dwDevType == DI8DEVCLASS_GAMECTRL) || (dwDevType == DI8DEVTYPE_JOYSTICK)) && (version >= 0x0800)))) ++ return S_FALSE; ++ ++ if (!(dwFlags & DIEDFL_FORCEFEEDBACK) || sdldevs[id].has_ff) { ++ fill_joystick_dideviceinstanceA(lpddi, version, id); ++ return S_OK; ++ } ++ return S_FALSE; ++} ++ ++static HRESULT sdl_enum_deviceW(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEW lpddi, DWORD version, int id) ++{ ++ find_sdldevs(); ++ ++ if (id >= have_sdldevs) { ++ return E_FAIL; ++ } ++ ++ if (!((dwDevType == 0) || ++ ((dwDevType == DIDEVTYPE_JOYSTICK) && (version > 0x0300 && version < 0x0800)) || ++ (((dwDevType == DI8DEVCLASS_GAMECTRL) || (dwDevType == DI8DEVTYPE_JOYSTICK)) && (version >= 0x0800)))) ++ return S_FALSE; ++ ++ if (!(dwFlags & DIEDFL_FORCEFEEDBACK) || sdldevs[id].has_ff) { ++ fill_joystick_dideviceinstanceW(lpddi, version, id); ++ return S_OK; ++ } ++ return S_FALSE; ++} ++ ++static void poll_sdl_device_state(LPDIRECTINPUTDEVICE8A iface) ++{ ++ JoystickImpl *This = impl_from_IDirectInputDevice8A(iface); ++ int i; ++ int inst_id = 0; ++ int newVal = 0; ++ ++ SDL_JoystickUpdate(); ++ ++ for (i = 0; i < SDL_JoystickNumButtons(This->device); i++) ++ { ++ int val = SDL_JoystickGetButton(This->device, i); ++ int oldVal = This->generic.js.rgbButtons[i]; ++ newVal = val ? 0x80 : 0x0; ++ This->generic.js.rgbButtons[i] = newVal; ++ if (oldVal != newVal) ++ { ++ TRACE("Button: %i val %d oldVal %d newVal %d\n", i, val, oldVal, newVal); ++ inst_id = DIDFT_MAKEINSTANCE(i) | DIDFT_PSHBUTTON; ++ queue_event(iface, inst_id, newVal, GetCurrentTime(), This->generic.base.dinput->evsequence++); ++ } ++ } ++ for (i = 0; i < SDL_JoystickNumAxes(This->device); i++) ++ { ++ int oldVal; ++ newVal = SDL_JoystickGetAxis(This->device, i); ++ newVal = joystick_map_axis(&This->generic.props[i], newVal); ++ switch (i) ++ { ++ case 0: oldVal = This->generic.js.lX; ++ This->generic.js.lX = newVal; break; ++ case 1: oldVal = This->generic.js.lY; ++ This->generic.js.lY = newVal; break; ++ case 2: oldVal = This->generic.js.lZ; ++ This->generic.js.lZ = newVal; break; ++ case 3: oldVal = This->generic.js.lRx; ++ This->generic.js.lRx = newVal; break; ++ case 4: oldVal = This->generic.js.lRy; ++ This->generic.js.lRy = newVal; break; ++ case 5: oldVal = This->generic.js.lRz; ++ This->generic.js.lRz = newVal; break; ++ case 6: oldVal = This->generic.js.rglSlider[0]; ++ This->generic.js.rglSlider[0] = newVal; break; ++ case 7: oldVal = This->generic.js.rglSlider[1]; ++ This->generic.js.rglSlider[1] = newVal; break; ++ } ++ if (oldVal != newVal) ++ { ++ TRACE("Axis: %i oldVal %d newVal %d\n", i, oldVal, newVal); ++ inst_id = DIDFT_MAKEINSTANCE(i) | DIDFT_ABSAXIS; ++ queue_event(iface, inst_id, newVal, GetCurrentTime(), This->generic.base.dinput->evsequence++); ++ } ++ } ++ for (i = 0; i < SDL_JoystickNumHats(This->device); i++) ++ { ++ int oldVal = This->generic.js.rgdwPOV[i]; ++ newVal = SDL_JoystickGetHat(This->device, i); ++ switch (newVal) ++ { ++ case SDL_HAT_CENTERED: newVal = -1; break; ++ case SDL_HAT_UP: newVal = 0; break; ++ case SDL_HAT_RIGHTUP:newVal = 4500; break; ++ case SDL_HAT_RIGHT: newVal = 9000; break; ++ case SDL_HAT_RIGHTDOWN: newVal = 13500; break; ++ case SDL_HAT_DOWN: newVal = 18000; break; ++ case SDL_HAT_LEFTDOWN: newVal = 22500; break; ++ case SDL_HAT_LEFT: newVal = 27000; break; ++ case SDL_HAT_LEFTUP: newVal = 31500; break; ++ } ++ if (oldVal != newVal) ++ { ++ TRACE("Hat : %i oldVal %d newVal %d\n", i, oldVal, newVal); ++ This->generic.js.rgdwPOV[i] = newVal; ++ inst_id = DIDFT_MAKEINSTANCE(i) | DIDFT_POV; ++ queue_event(iface, inst_id, newVal, GetCurrentTime(), This->generic.base.dinput->evsequence++); ++ } ++ } ++} ++ ++static JoystickImpl *alloc_device(REFGUID rguid, IDirectInputImpl *dinput, unsigned short index) ++{ ++ JoystickImpl* newDevice; ++ LPDIDATAFORMAT df = NULL; ++ DIDEVICEINSTANCEW ddi; ++ int i,idx = 0; ++ ++ newDevice = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(JoystickImpl)); ++ if (!newDevice) return NULL; ++ ++ newDevice->generic.guidInstance = DInput_Wine_SDL_Joystick_GUID; ++ newDevice->generic.guidInstance.Data3 = index; ++ newDevice->generic.guidProduct = DInput_PIDVID_Product_GUID; ++ newDevice->generic.guidProduct.Data1 = MAKELONG(sdldevs[index].vendor_id, sdldevs[index].product_id); ++ newDevice->generic.joy_polldev = poll_sdl_device_state; ++ ++ newDevice->generic.base.IDirectInputDevice8A_iface.lpVtbl = &JoystickAvt; ++ newDevice->generic.base.IDirectInputDevice8W_iface.lpVtbl = &JoystickWvt; ++ newDevice->generic.base.ref = 1; ++ newDevice->generic.base.guid = *rguid; ++ newDevice->generic.base.dinput = dinput; ++ newDevice->sdldev = &sdldevs[index]; ++ newDevice->generic.name = (char*)newDevice->sdldev->name; ++ ++ InitializeCriticalSection(&newDevice->generic.base.crit); ++ newDevice->generic.base.crit.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": JoystickImpl*->base.crit"); ++ ++ /* Open Device */ ++ newDevice->device = SDL_JoystickOpen(newDevice->sdldev->id); ++ ++ /* Count number of available axes - supported Axis & POVs */ ++ newDevice->generic.devcaps.dwAxes = SDL_JoystickNumAxes(newDevice->device); ++ ++ if (newDevice->generic.devcaps.dwAxes > 8 ) ++ { ++ WARN("Can't support %d axis. Clamping down to 8\n", newDevice->generic.devcaps.dwAxes); ++ newDevice->generic.devcaps.dwAxes = 8; ++ } ++ ++ for (i = 0; i < newDevice->generic.devcaps.dwAxes; i++) ++ { ++ newDevice->generic.props[i].lDevMin = -32768; ++ newDevice->generic.props[i].lDevMax = 32767; ++ newDevice->generic.props[i].lMin = 0; ++ newDevice->generic.props[i].lMax = 0xffff; ++ newDevice->generic.props[i].lDeadZone = 0; ++ newDevice->generic.props[i].lSaturation = 0; ++ } ++ ++ newDevice->generic.devcaps.dwPOVs = SDL_JoystickNumHats(newDevice->device); ++ if (newDevice->generic.devcaps.dwPOVs > 4) ++ { ++ WARN("Can't support %d POV. Clamping down to 4\n", newDevice->generic.devcaps.dwPOVs); ++ newDevice->generic.devcaps.dwPOVs = 4; ++ } ++ ++ newDevice->generic.devcaps.dwButtons = SDL_JoystickNumButtons(newDevice->device); ++ if (newDevice->generic.devcaps.dwButtons > 128) ++ { ++ WARN("Can't support %d buttons. Clamping down to 128\n", newDevice->generic.devcaps.dwButtons); ++ newDevice->generic.devcaps.dwButtons = 128; ++ } ++ ++ TRACE("axes %u povs %u buttons %u\n", newDevice->generic.devcaps.dwAxes, newDevice->generic.devcaps.dwPOVs, newDevice->generic.devcaps.dwButtons); ++ ++ /* Create copy of default data format */ ++ if (!(df = HeapAlloc(GetProcessHeap(), 0, c_dfDIJoystick2.dwSize))) goto failed; ++ memcpy(df, &c_dfDIJoystick2, c_dfDIJoystick2.dwSize); ++ ++ df->dwNumObjs = newDevice->generic.devcaps.dwAxes + newDevice->generic.devcaps.dwPOVs + newDevice->generic.devcaps.dwButtons; ++ if (!(df->rgodf = HeapAlloc(GetProcessHeap(), 0, df->dwNumObjs * df->dwObjSize))) goto failed; ++ ++ for (i = 0; i < newDevice->generic.devcaps.dwAxes; i++) ++ { ++ memcpy(&df->rgodf[idx], &c_dfDIJoystick2.rgodf[idx], df->dwObjSize); ++ df->rgodf[idx].dwType = DIDFT_MAKEINSTANCE(idx) | DIDFT_ABSAXIS; ++ ++idx; ++ } ++ ++ for (i = 0; i < newDevice->generic.devcaps.dwPOVs; i++) ++ { ++ memcpy(&df->rgodf[idx], &c_dfDIJoystick2.rgodf[i + 8], df->dwObjSize); ++ df->rgodf[idx++].dwType = DIDFT_MAKEINSTANCE(i) | DIDFT_POV; ++ } ++ ++ for (i = 0; i < newDevice->generic.devcaps.dwButtons; i++) ++ { ++ memcpy(&df->rgodf[idx], &c_dfDIJoystick2.rgodf[i + 12], df->dwObjSize); ++ df->rgodf[idx].pguid = &GUID_Button; ++ df->rgodf[idx++].dwType = DIDFT_MAKEINSTANCE(i) | DIDFT_PSHBUTTON; ++ } ++ newDevice->generic.base.data_format.wine_df = df; ++ ++ /* Fill the caps */ ++ newDevice->generic.devcaps.dwSize = sizeof(newDevice->generic.devcaps); ++ newDevice->generic.devcaps.dwFlags = DIDC_ATTACHED; ++ ++ ddi.dwSize = sizeof(ddi); ++ fill_joystick_dideviceinstanceW(&ddi, newDevice->generic.base.dinput->dwVersion, index); ++ newDevice->generic.devcaps.dwDevType = ddi.dwDevType; ++ ++ if (newDevice->sdldev->has_ff) ++ newDevice->generic.devcaps.dwFlags |= DIDC_FORCEFEEDBACK; ++ ++ IDirectInput_AddRef(&newDevice->generic.base.dinput->IDirectInput7A_iface); ++ ++ return newDevice; ++ ++failed: ++ if (df) HeapFree(GetProcessHeap(), 0, df->rgodf); ++ HeapFree(GetProcessHeap(), 0, df); ++ HeapFree(GetProcessHeap(), 0, newDevice); ++ return NULL; ++} ++ ++/****************************************************************************** ++ * get_joystick_index : Get the joystick index from a given GUID ++ */ ++static unsigned short get_joystick_index(REFGUID guid) ++{ ++ GUID wine_joystick = DInput_Wine_SDL_Joystick_GUID; ++ GUID dev_guid = *guid; ++ ++ wine_joystick.Data3 = 0; ++ dev_guid.Data3 = 0; ++ ++ /* for the standard joystick GUID use index 0 */ ++ if(IsEqualGUID(&GUID_Joystick,guid)) return 0; ++ ++ /* for the wine joystick GUIDs use the index stored in Data3 */ ++ if(IsEqualGUID(&wine_joystick, &dev_guid)) return guid->Data3; ++ ++ return 0xffff; ++} ++ ++static HRESULT sdl_create_device(IDirectInputImpl *dinput, REFGUID rguid, REFIID riid, LPVOID *pdev, int unicode) ++{ ++ unsigned short index; ++ ++ TRACE("%p %s %s %p %i\n", dinput, debugstr_guid(rguid), debugstr_guid(riid), pdev, unicode); ++ ++ find_sdldevs(); ++ *pdev = NULL; ++ ++ if ((index = get_joystick_index(rguid)) < 0xffff && ++ have_sdldevs && index < have_sdldevs) ++ { ++ JoystickImpl *This; ++ ++ if (riid == NULL) ++ ;/* nothing */ ++ else if (IsEqualGUID(&IID_IDirectInputDeviceA, riid) || ++ IsEqualGUID(&IID_IDirectInputDevice2A, riid) || ++ IsEqualGUID(&IID_IDirectInputDevice7A, riid) || ++ IsEqualGUID(&IID_IDirectInputDevice8A, riid)) ++ { ++ unicode = 0; ++ } ++ else if (IsEqualGUID(&IID_IDirectInputDeviceW, riid) || ++ IsEqualGUID(&IID_IDirectInputDevice2W, riid) || ++ IsEqualGUID(&IID_IDirectInputDevice7W, riid) || ++ IsEqualGUID(&IID_IDirectInputDevice8W, riid)) ++ { ++ unicode = 1; ++ } ++ else ++ { ++ WARN("no interface\n"); ++ return DIERR_NOINTERFACE; ++ } ++ ++ This = alloc_device(rguid, dinput, index); ++ TRACE("Created a Joystick device (%p)\n", This); ++ ++ if (!This) return DIERR_OUTOFMEMORY; ++ ++ if (unicode) ++ *pdev = &This->generic.base.IDirectInputDevice8W_iface; ++ else ++ *pdev = &This->generic.base.IDirectInputDevice8A_iface; ++ ++ return DI_OK; ++ } ++ ++ return DIERR_DEVICENOTREG; ++} ++ ++const struct dinput_device joystick_sdl_device = { ++ "Wine SDL joystick driver", ++ sdl_enum_deviceA, ++ sdl_enum_deviceW, ++ sdl_create_device ++}; ++ ++static ULONG WINAPI JoystickWImpl_Release(LPDIRECTINPUTDEVICE8W iface) ++{ ++ JoystickImpl *This = impl_from_IDirectInputDevice8W(iface); ++ TRACE("(this=%p)\n", iface); ++ if (This->generic.base.ref == 1 && This->device >= 0) ++ { ++ TRACE("Closing Joystick: %p\n",This); ++ SDL_JoystickClose(This->device); ++ This->device = NULL; ++ } ++ return IDirectInputDevice2WImpl_Release(iface); ++} ++ ++static ULONG WINAPI JoystickAImpl_Release(LPDIRECTINPUTDEVICE8A iface) ++{ ++ JoystickImpl *This = impl_from_IDirectInputDevice8A(iface); ++ return JoystickWImpl_Release(IDirectInputDevice8W_from_impl(This)); ++} ++ ++/****************************************************************************** ++ * GetProperty : get input device properties ++ */ ++static HRESULT WINAPI JoystickWImpl_GetProperty(LPDIRECTINPUTDEVICE8W iface, REFGUID rguid, LPDIPROPHEADER pdiph) ++{ ++ JoystickImpl *This = impl_from_IDirectInputDevice8W(iface); ++ ++ TRACE("(this=%p,%s,%p)\n", iface, debugstr_guid(rguid), pdiph); ++ _dump_DIPROPHEADER(pdiph); ++ ++ if (!IS_DIPROP(rguid)) return DI_OK; ++ ++ switch (LOWORD(rguid)) { ++ ++ case (DWORD_PTR) DIPROP_VIDPID: ++ { ++ LPDIPROPDWORD pd = (LPDIPROPDWORD)pdiph; ++ ++ if (!This->sdldev->product_id || !This->sdldev->vendor_id) ++ return DIERR_UNSUPPORTED; ++ pd->dwData = MAKELONG(This->sdldev->vendor_id, This->sdldev->product_id); ++ TRACE("DIPROP_VIDPID(%08x)\n", pd->dwData); ++ break; ++ } ++ case (DWORD_PTR) DIPROP_JOYSTICKID: ++ { ++ LPDIPROPDWORD pd = (LPDIPROPDWORD)pdiph; ++ ++ pd->dwData = This->sdldev->id; ++ TRACE("DIPROP_JOYSTICKID(%d)\n", pd->dwData); ++ break; ++ } ++ ++ default: ++ return JoystickWGenericImpl_GetProperty(iface, rguid, pdiph); ++ } ++ ++ return DI_OK; ++} ++ ++static HRESULT WINAPI JoystickAImpl_GetProperty(LPDIRECTINPUTDEVICE8A iface, REFGUID rguid, LPDIPROPHEADER pdiph) ++{ ++ JoystickImpl *This = impl_from_IDirectInputDevice8A(iface); ++ return JoystickWImpl_GetProperty(IDirectInputDevice8W_from_impl(This), rguid, pdiph); ++} ++ ++/****************************************************************************** ++ * GetDeviceInfo : get information about a device's identity ++ */ ++static HRESULT WINAPI JoystickAImpl_GetDeviceInfo(LPDIRECTINPUTDEVICE8A iface, ++ LPDIDEVICEINSTANCEA pdidi) ++{ ++ JoystickImpl *This = impl_from_IDirectInputDevice8A(iface); ++ ++ TRACE("(%p) %p\n", This, pdidi); ++ ++ if (pdidi == NULL) return E_POINTER; ++ if ((pdidi->dwSize != sizeof(DIDEVICEINSTANCE_DX3A)) && ++ (pdidi->dwSize != sizeof(DIDEVICEINSTANCEA))) ++ return DIERR_INVALIDPARAM; ++ ++ fill_joystick_dideviceinstanceA(pdidi, This->generic.base.dinput->dwVersion, ++ get_joystick_index(&This->generic.base.guid)); ++ return DI_OK; ++} ++ ++static HRESULT WINAPI JoystickWImpl_GetDeviceInfo(LPDIRECTINPUTDEVICE8W iface, ++ LPDIDEVICEINSTANCEW pdidi) ++{ ++ JoystickImpl *This = impl_from_IDirectInputDevice8W(iface); ++ ++ TRACE("(%p) %p\n", This, pdidi); ++ ++ if (pdidi == NULL) return E_POINTER; ++ if ((pdidi->dwSize != sizeof(DIDEVICEINSTANCE_DX3W)) && ++ (pdidi->dwSize != sizeof(DIDEVICEINSTANCEW))) ++ return DIERR_INVALIDPARAM; ++ ++ fill_joystick_dideviceinstanceW(pdidi, This->generic.base.dinput->dwVersion, ++ get_joystick_index(&This->generic.base.guid)); ++ return DI_OK; ++} ++ ++static const IDirectInputDevice8AVtbl JoystickAvt = ++{ ++ IDirectInputDevice2AImpl_QueryInterface, ++ IDirectInputDevice2AImpl_AddRef, ++ JoystickAImpl_Release, ++ JoystickAGenericImpl_GetCapabilities, ++ IDirectInputDevice2AImpl_EnumObjects, ++ JoystickAImpl_GetProperty, ++ JoystickAGenericImpl_SetProperty, ++ IDirectInputDevice2AImpl_Acquire, ++ IDirectInputDevice2AImpl_Unacquire, ++ JoystickAGenericImpl_GetDeviceState, ++ IDirectInputDevice2AImpl_GetDeviceData, ++ IDirectInputDevice2AImpl_SetDataFormat, ++ IDirectInputDevice2AImpl_SetEventNotification, ++ IDirectInputDevice2AImpl_SetCooperativeLevel, ++ JoystickAGenericImpl_GetObjectInfo, ++ JoystickAImpl_GetDeviceInfo, ++ IDirectInputDevice2AImpl_RunControlPanel, ++ IDirectInputDevice2AImpl_Initialize, ++ IDirectInputDevice2AImpl_CreateEffect, ++ IDirectInputDevice2AImpl_EnumEffects, ++ IDirectInputDevice2AImpl_GetEffectInfo, ++ IDirectInputDevice2AImpl_GetForceFeedbackState, ++ IDirectInputDevice2AImpl_SendForceFeedbackCommand, ++ IDirectInputDevice2AImpl_EnumCreatedEffectObjects, ++ IDirectInputDevice2AImpl_Escape, ++ JoystickAGenericImpl_Poll, ++ IDirectInputDevice2AImpl_SendDeviceData, ++ IDirectInputDevice7AImpl_EnumEffectsInFile, ++ IDirectInputDevice7AImpl_WriteEffectToFile, ++ JoystickAGenericImpl_BuildActionMap, ++ JoystickAGenericImpl_SetActionMap, ++ IDirectInputDevice8AImpl_GetImageInfo ++}; ++ ++static const IDirectInputDevice8WVtbl JoystickWvt = ++{ ++ IDirectInputDevice2WImpl_QueryInterface, ++ IDirectInputDevice2WImpl_AddRef, ++ JoystickWImpl_Release, ++ JoystickWGenericImpl_GetCapabilities, ++ IDirectInputDevice2WImpl_EnumObjects, ++ JoystickWImpl_GetProperty, ++ JoystickWGenericImpl_SetProperty, ++ IDirectInputDevice2WImpl_Acquire, ++ IDirectInputDevice2WImpl_Unacquire, ++ JoystickWGenericImpl_GetDeviceState, ++ IDirectInputDevice2WImpl_GetDeviceData, ++ IDirectInputDevice2WImpl_SetDataFormat, ++ IDirectInputDevice2WImpl_SetEventNotification, ++ IDirectInputDevice2WImpl_SetCooperativeLevel, ++ JoystickWGenericImpl_GetObjectInfo, ++ JoystickWImpl_GetDeviceInfo, ++ IDirectInputDevice2WImpl_RunControlPanel, ++ IDirectInputDevice2WImpl_Initialize, ++ IDirectInputDevice2WImpl_CreateEffect, ++ IDirectInputDevice2WImpl_EnumEffects, ++ IDirectInputDevice2WImpl_GetEffectInfo, ++ IDirectInputDevice2WImpl_GetForceFeedbackState, ++ IDirectInputDevice2WImpl_SendForceFeedbackCommand, ++ IDirectInputDevice2WImpl_EnumCreatedEffectObjects, ++ IDirectInputDevice2WImpl_Escape, ++ JoystickWGenericImpl_Poll, ++ IDirectInputDevice2WImpl_SendDeviceData, ++ IDirectInputDevice7WImpl_EnumEffectsInFile, ++ IDirectInputDevice7WImpl_WriteEffectToFile, ++ JoystickWGenericImpl_BuildActionMap, ++ JoystickWGenericImpl_SetActionMap, ++ IDirectInputDevice8WImpl_GetImageInfo ++}; ++ ++#else ++ ++const struct dinput_device joystick_sdl_device = { ++ "Wine SDL joystick driver", ++ NULL, ++ NULL, ++ NULL ++}; ++ ++#endif +diff --git a/dlls/dinput8/Makefile.in b/dlls/dinput8/Makefile.in +index 5f0dce97caa..0e6ef316a79 100644 +--- a/dlls/dinput8/Makefile.in ++++ b/dlls/dinput8/Makefile.in +@@ -2,7 +2,8 @@ MODULE = dinput8.dll + IMPORTLIB = dinput8 + IMPORTS = dinput8 dxguid uuid comctl32 ole32 user32 advapi32 + EXTRADEFS = -DDIRECTINPUT_VERSION=0x0800 +-EXTRALIBS = $(IOKIT_LIBS) $(FORCEFEEDBACK_LIBS) ++EXTRALIBS = $(IOKIT_LIBS) $(FORCEFEEDBACK_LIBS) $(SDL2_LIBS) ++EXTRAINCL = $(SDL2_CFLAGS) + PARENTSRC = ../dinput + + C_SRCS = \ +@@ -11,9 +12,11 @@ C_SRCS = \ + device.c \ + dinput_main.c \ + effect_linuxinput.c \ ++ effect_sdl.c \ + joystick.c \ + joystick_linux.c \ + joystick_linuxinput.c \ ++ joystick_sdl.c \ + joystick_osx.c \ + keyboard.c \ + mouse.c +From 3e2d859cde7522116eaf1c19d4e468416fec5f59 Mon Sep 17 00:00:00 2001 +From: Aric Stewart +Date: Thu, 28 Dec 2017 13:44:29 -0600 +Subject: [PATCH] dinput: Begin SDL haptic implemeting Get/SetProperty + +Signed-off-by: Aric Stewart +--- + dlls/dinput/joystick_sdl.c | 106 ++++++++++++++++++++++++++++++++++++- + 1 file changed, 104 insertions(+), 2 deletions(-) + +diff --git a/dlls/dinput/joystick_sdl.c b/dlls/dinput/joystick_sdl.c +index a7619cc4cad..74e2c950da7 100644 +--- a/dlls/dinput/joystick_sdl.c ++++ b/dlls/dinput/joystick_sdl.c +@@ -65,6 +65,8 @@ struct SDLDev { + CHAR *name; + + BOOL has_ff; ++ int autocenter; ++ int gain; + }; + + struct JoystickImpl +@@ -73,6 +75,7 @@ struct JoystickImpl + struct SDLDev *sdldev; + + SDL_Joystick *device; ++ SDL_Haptic *haptic; + }; + + static inline JoystickImpl *impl_from_IDirectInputDevice8A(IDirectInputDevice8A *iface) +@@ -130,6 +133,17 @@ static void find_sdldevs(void) + + TRACE("Found a joystick (%i) on %p: %s\n", have_sdldevs, device, sdldev.name); + ++ if (SDL_JoystickIsHaptic(device)) ++ { ++ SDL_Haptic *haptic = SDL_HapticOpenFromJoystick(device); ++ if (haptic) ++ { ++ TRACE(" ... with force feedback\n"); ++ sdldev.has_ff = TRUE; ++ SDL_HapticClose(haptic); ++ } ++ } ++ + sdldev.vendor_id = SDL_JoystickGetVendor(device); + sdldev.product_id = SDL_JoystickGetProduct(device); + +@@ -354,6 +368,7 @@ static JoystickImpl *alloc_device(REFGUID rguid, IDirectInputImpl *dinput, unsig + + /* Open Device */ + newDevice->device = SDL_JoystickOpen(newDevice->sdldev->id); ++ newDevice->haptic = SDL_HapticOpenFromJoystick(newDevice->device); + + /* Count number of available axes - supported Axis & POVs */ + newDevice->generic.devcaps.dwAxes = SDL_JoystickNumAxes(newDevice->device); +@@ -401,6 +416,8 @@ static JoystickImpl *alloc_device(REFGUID rguid, IDirectInputImpl *dinput, unsig + { + memcpy(&df->rgodf[idx], &c_dfDIJoystick2.rgodf[idx], df->dwObjSize); + df->rgodf[idx].dwType = DIDFT_MAKEINSTANCE(idx) | DIDFT_ABSAXIS; ++ if (newDevice->sdldev->has_ff && i < 2) ++ df->rgodf[idx].dwFlags |= DIDOI_FFACTUATOR; + ++idx; + } + +@@ -416,6 +433,10 @@ static JoystickImpl *alloc_device(REFGUID rguid, IDirectInputImpl *dinput, unsig + df->rgodf[idx].pguid = &GUID_Button; + df->rgodf[idx++].dwType = DIDFT_MAKEINSTANCE(i) | DIDFT_PSHBUTTON; + } ++ ++ if (newDevice->sdldev->has_ff) ++ newDevice->generic.devcaps.dwFlags |= DIDC_FORCEFEEDBACK; ++ + newDevice->generic.base.data_format.wine_df = df; + + /* Fill the caps */ +@@ -526,6 +547,8 @@ static ULONG WINAPI JoystickWImpl_Release(LPDIRECTINPUTDEVICE8W iface) + if (This->generic.base.ref == 1 && This->device >= 0) + { + TRACE("Closing Joystick: %p\n",This); ++ if (This->sdldev->has_ff) ++ SDL_HapticClose(This->haptic); + SDL_JoystickClose(This->device); + This->device = NULL; + } +@@ -551,7 +574,22 @@ static HRESULT WINAPI JoystickWImpl_GetProperty(LPDIRECTINPUTDEVICE8W iface, REF + if (!IS_DIPROP(rguid)) return DI_OK; + + switch (LOWORD(rguid)) { ++ case (DWORD_PTR) DIPROP_AUTOCENTER: ++ { ++ LPDIPROPDWORD pd = (LPDIPROPDWORD)pdiph; + ++ pd->dwData = This->sdldev->autocenter ? DIPROPAUTOCENTER_ON : DIPROPAUTOCENTER_OFF; ++ TRACE("autocenter(%d)\n", pd->dwData); ++ break; ++ } ++ case (DWORD_PTR) DIPROP_FFGAIN: ++ { ++ LPDIPROPDWORD pd = (LPDIPROPDWORD)pdiph; ++ ++ pd->dwData = This->sdldev->gain; ++ TRACE("DIPROP_FFGAIN(%d)\n", pd->dwData); ++ break; ++ } + case (DWORD_PTR) DIPROP_VIDPID: + { + LPDIPROPDWORD pd = (LPDIPROPDWORD)pdiph; +@@ -584,6 +622,70 @@ static HRESULT WINAPI JoystickAImpl_GetProperty(LPDIRECTINPUTDEVICE8A iface, REF + return JoystickWImpl_GetProperty(IDirectInputDevice8W_from_impl(This), rguid, pdiph); + } + ++static BOOL _SetProperty(JoystickImpl *This, const GUID *prop, const DIPROPHEADER *header) ++{ ++ int rc; ++ ++ switch(LOWORD(prop)) ++ { ++ case (DWORD_PTR)DIPROP_AUTOCENTER: ++ { ++ LPCDIPROPDWORD pd = (LPCDIPROPDWORD)header; ++ ++ This->sdldev->autocenter = pd->dwData == DIPROPAUTOCENTER_ON; ++ ++ rc = SDL_HapticSetAutocenter(This->haptic, This->sdldev->autocenter * 100); ++ if (rc != 0) ++ ERR("SDL_HapticSetAutocenter failed: %s\n", SDL_GetError()); ++ break; ++ } ++ case (DWORD_PTR)DIPROP_FFGAIN: ++ { ++ LPCDIPROPDWORD pd = (LPCDIPROPDWORD)header; ++ int sdl_gain = MulDiv(This->sdldev->gain, 100, 10000); ++ ++ TRACE("DIPROP_FFGAIN(%d)\n", pd->dwData); ++ ++ This->sdldev->gain = pd->dwData; ++ ++ rc = SDL_HapticSetGain(This->haptic, sdl_gain); ++ if (rc != 0) ++ ERR("SDL_HapticSetGain (%i -> %i) failed: %s\n", pd->dwData, sdl_gain, SDL_GetError()); ++ break; ++ } ++ default: ++ return FALSE; ++ } ++ ++ return TRUE; ++} ++ ++static HRESULT WINAPI JoystickWImpl_SetProperty(IDirectInputDevice8W *iface, ++ const GUID *prop, const DIPROPHEADER *header) ++{ ++ JoystickImpl *This = impl_from_IDirectInputDevice8W(iface); ++ ++ TRACE("%p %s %p\n", This, debugstr_guid(prop), header); ++ ++ if (_SetProperty(This, prop, header)) ++ return DI_OK; ++ else ++ return JoystickWGenericImpl_SetProperty(iface, prop, header); ++} ++ ++static HRESULT WINAPI JoystickAImpl_SetProperty(IDirectInputDevice8A *iface, ++ const GUID *prop, const DIPROPHEADER *header) ++{ ++ JoystickImpl *This = impl_from_IDirectInputDevice8A(iface); ++ ++ TRACE("%p %s %p\n", This, debugstr_guid(prop), header); ++ ++ if (_SetProperty(This, prop, header)) ++ return DI_OK; ++ else ++ return JoystickAGenericImpl_SetProperty(iface, prop, header); ++} ++ + /****************************************************************************** + * GetDeviceInfo : get information about a device's identity + */ +@@ -629,7 +731,7 @@ static const IDirectInputDevice8AVtbl JoystickAvt = + JoystickAGenericImpl_GetCapabilities, + IDirectInputDevice2AImpl_EnumObjects, + JoystickAImpl_GetProperty, +- JoystickAGenericImpl_SetProperty, ++ JoystickAImpl_SetProperty, + IDirectInputDevice2AImpl_Acquire, + IDirectInputDevice2AImpl_Unacquire, + JoystickAGenericImpl_GetDeviceState, +@@ -665,7 +767,7 @@ static const IDirectInputDevice8WVtbl JoystickWvt = + JoystickWGenericImpl_GetCapabilities, + IDirectInputDevice2WImpl_EnumObjects, + JoystickWImpl_GetProperty, +- JoystickWGenericImpl_SetProperty, ++ JoystickWImpl_SetProperty, + IDirectInputDevice2WImpl_Acquire, + IDirectInputDevice2WImpl_Unacquire, + JoystickWGenericImpl_GetDeviceState, +From 77255360d408ef50e16efa44b691a8fa39752a99 Mon Sep 17 00:00:00 2001 +From: Aric Stewart +Date: Wed, 3 Jan 2018 12:50:21 -0600 +Subject: [PATCH] dinput: Implement GetEffectInfo, SendForceFeedbackCommand and + EnumCreatedEffectObjects + +Signed-off-by: Aric Stewart +--- + dlls/dinput/joystick_sdl.c | 259 ++++++++++++++++++++++++++++++++++++- + 1 file changed, 253 insertions(+), 6 deletions(-) + +diff --git a/dlls/dinput/joystick_sdl.c b/dlls/dinput/joystick_sdl.c +index 74e2c950da7..f066640d56a 100644 +--- a/dlls/dinput/joystick_sdl.c ++++ b/dlls/dinput/joystick_sdl.c +@@ -67,6 +67,7 @@ struct SDLDev { + BOOL has_ff; + int autocenter; + int gain; ++ struct list effects; + }; + + struct JoystickImpl +@@ -362,6 +363,9 @@ static JoystickImpl *alloc_device(REFGUID rguid, IDirectInputImpl *dinput, unsig + newDevice->generic.base.dinput = dinput; + newDevice->sdldev = &sdldevs[index]; + newDevice->generic.name = (char*)newDevice->sdldev->name; ++ list_init(&newDevice->sdldev->effects); ++ newDevice->sdldev->autocenter = 1; ++ newDevice->sdldev->gain = 100; + + InitializeCriticalSection(&newDevice->generic.base.crit); + newDevice->generic.base.crit.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": JoystickImpl*->base.crit"); +@@ -723,6 +727,249 @@ static HRESULT WINAPI JoystickWImpl_GetDeviceInfo(LPDIRECTINPUTDEVICE8W iface, + return DI_OK; + } + ++static HRESULT WINAPI JoystickWImpl_EnumEffects(LPDIRECTINPUTDEVICE8W iface, ++ LPDIENUMEFFECTSCALLBACKW lpCallback, ++ LPVOID pvRef, ++ DWORD dwEffType) ++{ ++ DIEFFECTINFOW dei; ++ DWORD type = DIEFT_GETTYPE(dwEffType); ++ JoystickImpl* This = impl_from_IDirectInputDevice8W(iface); ++ unsigned int query; ++ ++ TRACE("(this=%p,%p,%d) type=%d\n", This, pvRef, dwEffType, type); ++ ++ dei.dwSize = sizeof(DIEFFECTINFOW); ++ query = SDL_HapticQuery(This->haptic); ++ TRACE("Effects 0x%x\n",query); ++ ++ if ((type == DIEFT_ALL || type == DIEFT_CONSTANTFORCE) ++ && (query & SDL_HAPTIC_CONSTANT)) ++ { ++ IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_ConstantForce); ++ (*lpCallback)(&dei, pvRef); ++ } ++ ++ if ((type == DIEFT_ALL || type == DIEFT_RAMPFORCE) && ++ (query & SDL_HAPTIC_RAMP)) ++ { ++ IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_RampForce); ++ (*lpCallback)(&dei, pvRef); ++ } ++ ++ if (type == DIEFT_ALL || type == DIEFT_PERIODIC) ++ { ++ if (query & SDL_HAPTIC_SINE) ++ { ++ IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Sine); ++ (*lpCallback)(&dei, pvRef); ++ } ++ if (query & SDL_HAPTIC_TRIANGLE) ++ { ++ IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Triangle); ++ (*lpCallback)(&dei, pvRef); ++ } ++ if (query & SDL_HAPTIC_SAWTOOTHUP) ++ { ++ IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_SawtoothUp); ++ (*lpCallback)(&dei, pvRef); ++ } ++ if (query & SDL_HAPTIC_SAWTOOTHDOWN) ++ { ++ IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_SawtoothDown); ++ (*lpCallback)(&dei, pvRef); ++ } ++ } ++ ++ if (type == DIEFT_ALL || type == DIEFT_CONDITION) ++ { ++ if (query & SDL_HAPTIC_SPRING) ++ { ++ IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Spring); ++ (*lpCallback)(&dei, pvRef); ++ } ++ if (query & SDL_HAPTIC_DAMPER) ++ { ++ IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Damper); ++ (*lpCallback)(&dei, pvRef); ++ } ++ if (query & SDL_HAPTIC_INERTIA) ++ { ++ IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Inertia); ++ (*lpCallback)(&dei, pvRef); ++ } ++ if (query & SDL_HAPTIC_FRICTION) ++ { ++ IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Friction); ++ (*lpCallback)(&dei, pvRef); ++ } ++ } ++ ++ return DI_OK; ++} ++ ++static HRESULT WINAPI JoystickAImpl_EnumEffects(LPDIRECTINPUTDEVICE8A iface, ++ LPDIENUMEFFECTSCALLBACKA lpCallback, ++ LPVOID pvRef, ++ DWORD dwEffType) ++{ ++ DIEFFECTINFOA dei; ++ DWORD type = DIEFT_GETTYPE(dwEffType); ++ JoystickImpl* This = impl_from_IDirectInputDevice8A(iface); ++ unsigned int query; ++ ++ TRACE("(this=%p,%p,%d) type=%d\n", This, pvRef, dwEffType, type); ++ ++ dei.dwSize = sizeof(DIEFFECTINFOA); ++ query = SDL_HapticQuery(This->haptic); ++ TRACE("Effects 0x%x\n",query); ++ ++ if ((type == DIEFT_ALL || type == DIEFT_CONSTANTFORCE) ++ && (query & SDL_HAPTIC_CONSTANT)) ++ { ++ IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_ConstantForce); ++ (*lpCallback)(&dei, pvRef); ++ } ++ ++ if ((type == DIEFT_ALL || type == DIEFT_RAMPFORCE) && ++ (query & SDL_HAPTIC_RAMP)) ++ { ++ IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_RampForce); ++ (*lpCallback)(&dei, pvRef); ++ } ++ ++ if (type == DIEFT_ALL || type == DIEFT_PERIODIC) ++ { ++ if (query & SDL_HAPTIC_SINE) ++ { ++ IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Sine); ++ (*lpCallback)(&dei, pvRef); ++ } ++ if (query & SDL_HAPTIC_TRIANGLE) ++ { ++ IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Triangle); ++ (*lpCallback)(&dei, pvRef); ++ } ++ if (query & SDL_HAPTIC_SAWTOOTHUP) ++ { ++ IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_SawtoothUp); ++ (*lpCallback)(&dei, pvRef); ++ } ++ if (query & SDL_HAPTIC_SAWTOOTHDOWN) ++ { ++ IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_SawtoothDown); ++ (*lpCallback)(&dei, pvRef); ++ } ++ } ++ ++ if (type == DIEFT_ALL || type == DIEFT_CONDITION) ++ { ++ if (query & SDL_HAPTIC_SPRING) ++ { ++ IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Spring); ++ (*lpCallback)(&dei, pvRef); ++ } ++ if (query & SDL_HAPTIC_DAMPER) ++ { ++ IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Damper); ++ (*lpCallback)(&dei, pvRef); ++ } ++ if (query & SDL_HAPTIC_INERTIA) ++ { ++ IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Inertia); ++ (*lpCallback)(&dei, pvRef); ++ } ++ if (query & SDL_HAPTIC_FRICTION) ++ { ++ IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Friction); ++ (*lpCallback)(&dei, pvRef); ++ } ++ } ++ ++ return DI_OK; ++} ++ ++static HRESULT WINAPI JoystickWImpl_SendForceFeedbackCommand(LPDIRECTINPUTDEVICE8W iface, DWORD dwFlags) ++{ ++ JoystickImpl* This = impl_from_IDirectInputDevice8W(iface); ++ TRACE("(this=%p,%d)\n", This, dwFlags); ++ ++ switch (dwFlags) ++ { ++ case DISFFC_STOPALL: ++ { ++ effect_list_item *itr; ++ ++ /* Stop all effects */ ++ LIST_FOR_EACH_ENTRY(itr, &This->sdldev->effects, effect_list_item, entry) ++ IDirectInputEffect_Stop(itr->ref); ++ break; ++ } ++ ++ case DISFFC_RESET: ++ { ++ effect_list_item *itr; ++ ++ /* Stop and unload all effects. It is not true that effects are released */ ++ LIST_FOR_EACH_ENTRY(itr, &This->sdldev->effects, effect_list_item, entry) ++ { ++ IDirectInputEffect_Stop(itr->ref); ++ IDirectInputEffect_Unload(itr->ref); ++ } ++ break; ++ } ++ case DISFFC_PAUSE: ++ case DISFFC_CONTINUE: ++ FIXME("No support for Pause or Continue in sdl\n"); ++ break; ++ ++ case DISFFC_SETACTUATORSOFF: ++ case DISFFC_SETACTUATORSON: ++ FIXME("No direct actuator control in sdl\n"); ++ break; ++ ++ default: ++ WARN("Unknown Force Feedback Command %u!\n", dwFlags); ++ return DIERR_INVALIDPARAM; ++ } ++ return DI_OK; ++} ++ ++static HRESULT WINAPI JoystickAImpl_SendForceFeedbackCommand(LPDIRECTINPUTDEVICE8A iface, DWORD dwFlags) ++{ ++ JoystickImpl *This = impl_from_IDirectInputDevice8A(iface); ++ return JoystickWImpl_SendForceFeedbackCommand(IDirectInputDevice8W_from_impl(This), dwFlags); ++} ++ ++static HRESULT WINAPI JoystickWImpl_EnumCreatedEffectObjects(LPDIRECTINPUTDEVICE8W iface, ++ LPDIENUMCREATEDEFFECTOBJECTSCALLBACK lpCallback, ++ LPVOID pvRef, DWORD dwFlags) ++{ ++ JoystickImpl* This = impl_from_IDirectInputDevice8W(iface); ++ effect_list_item *itr, *ptr; ++ ++ TRACE("(this=%p,%p,%p,%d)\n", This, lpCallback, pvRef, dwFlags); ++ ++ if (!lpCallback) ++ return DIERR_INVALIDPARAM; ++ ++ if (dwFlags != 0) ++ FIXME("Flags specified, but no flags exist yet (DX9)!\n"); ++ ++ LIST_FOR_EACH_ENTRY_SAFE(itr, ptr, &This->sdldev->effects, effect_list_item, entry) ++ (*lpCallback)(itr->ref, pvRef); ++ ++ return DI_OK; ++} ++ ++static HRESULT WINAPI JoystickAImpl_EnumCreatedEffectObjects(LPDIRECTINPUTDEVICE8A iface, ++ LPDIENUMCREATEDEFFECTOBJECTSCALLBACK lpCallback, ++ LPVOID pvRef, DWORD dwFlags) ++{ ++ JoystickImpl *This = impl_from_IDirectInputDevice8A(iface); ++ return JoystickWImpl_EnumCreatedEffectObjects(IDirectInputDevice8W_from_impl(This), lpCallback, pvRef, dwFlags); ++} ++ + static const IDirectInputDevice8AVtbl JoystickAvt = + { + IDirectInputDevice2AImpl_QueryInterface, +@@ -744,11 +991,11 @@ static const IDirectInputDevice8AVtbl JoystickAvt = + IDirectInputDevice2AImpl_RunControlPanel, + IDirectInputDevice2AImpl_Initialize, + IDirectInputDevice2AImpl_CreateEffect, +- IDirectInputDevice2AImpl_EnumEffects, ++ JoystickAImpl_EnumEffects, + IDirectInputDevice2AImpl_GetEffectInfo, + IDirectInputDevice2AImpl_GetForceFeedbackState, +- IDirectInputDevice2AImpl_SendForceFeedbackCommand, +- IDirectInputDevice2AImpl_EnumCreatedEffectObjects, ++ JoystickAImpl_SendForceFeedbackCommand, ++ JoystickAImpl_EnumCreatedEffectObjects, + IDirectInputDevice2AImpl_Escape, + JoystickAGenericImpl_Poll, + IDirectInputDevice2AImpl_SendDeviceData, +@@ -780,11 +1027,11 @@ static const IDirectInputDevice8WVtbl JoystickWvt = + IDirectInputDevice2WImpl_RunControlPanel, + IDirectInputDevice2WImpl_Initialize, + IDirectInputDevice2WImpl_CreateEffect, +- IDirectInputDevice2WImpl_EnumEffects, ++ JoystickWImpl_EnumEffects, + IDirectInputDevice2WImpl_GetEffectInfo, + IDirectInputDevice2WImpl_GetForceFeedbackState, +- IDirectInputDevice2WImpl_SendForceFeedbackCommand, +- IDirectInputDevice2WImpl_EnumCreatedEffectObjects, ++ JoystickWImpl_SendForceFeedbackCommand, ++ JoystickWImpl_EnumCreatedEffectObjects, + IDirectInputDevice2WImpl_Escape, + JoystickWGenericImpl_Poll, + IDirectInputDevice2WImpl_SendDeviceData, +From 1e47cfa0b703b43f825000bcd50f014a2370c937 Mon Sep 17 00:00:00 2001 +From: Aric Stewart +Date: Wed, 3 Jan 2018 13:26:27 -0600 +Subject: [PATCH] dinput: Implement FF effects for SDL joysticks + +Signed-off-by: Aric Stewart +--- + dlls/dinput/Makefile.in | 1 + + dlls/dinput/effect_sdl.c | 848 +++++++++++++++++++++++++++++++++++++ + dlls/dinput/joystick_sdl.c | 93 +++- + 3 files changed, 938 insertions(+), 4 deletions(-) + create mode 100644 dlls/dinput/effect_sdl.c + +diff --git a/dlls/dinput/Makefile.in b/dlls/dinput/Makefile.in +index ee3ddc016e8..8dfebb665fb 100644 +--- a/dlls/dinput/Makefile.in ++++ b/dlls/dinput/Makefile.in +@@ -11,6 +11,7 @@ C_SRCS = \ + device.c \ + dinput_main.c \ + effect_linuxinput.c \ ++ effect_sdl.c \ + joystick.c \ + joystick_linux.c \ + joystick_linuxinput.c \ +diff --git a/dlls/dinput/effect_sdl.c b/dlls/dinput/effect_sdl.c +new file mode 100644 +index 00000000000..ed2e78ae186 +--- /dev/null ++++ b/dlls/dinput/effect_sdl.c +@@ -0,0 +1,848 @@ ++/* DirectInput Joystick device from SDL ++ * ++ * Copyright 2017 CodeWeavers, Aric Stewart ++ * ++ * 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 "wine/port.h" ++ ++#include ++#include ++#include ++#include ++#include ++#ifdef HAVE_UNISTD_H ++# include ++#endif ++#ifdef HAVE_SDL_H ++# include ++#endif ++#include ++ ++#include "wine/debug.h" ++#include "wine/unicode.h" ++#include "wine/list.h" ++#include "windef.h" ++#include "winbase.h" ++#include "winerror.h" ++#include "winreg.h" ++#include "dinput.h" ++ ++#include "dinput_private.h" ++#include "device_private.h" ++#include "joystick_private.h" ++ ++#ifdef HAVE_SDL_H ++ ++WINE_DEFAULT_DEBUG_CHANNEL(dinput); ++ ++typedef struct _SDLInputEffectImpl { ++ IDirectInputEffect IDirectInputEffect_iface; ++ LONG ref; ++ ++ SDL_Haptic *haptic; ++ GUID guid; ++ ++ SDL_HapticEffect effect; ++ int effect_id; ++ BOOL first_axis_is_x; ++ ++ struct list *entry; ++} SDLInputEffectImpl; ++ ++static SDLInputEffectImpl *impl_from_IDirectInputEffect(IDirectInputEffect *iface) ++{ ++ return CONTAINING_RECORD(iface, SDLInputEffectImpl, IDirectInputEffect_iface); ++} ++ ++static const IDirectInputEffectVtbl EffectVtbl; ++ ++ ++static HRESULT WINAPI effect_QueryInterface(IDirectInputEffect *iface, ++ const GUID *guid, void **out) ++{ ++ SDLInputEffectImpl *This = impl_from_IDirectInputEffect(iface); ++ ++ TRACE("%p %s %p\n", This, debugstr_guid(guid), out); ++ ++ if(IsEqualIID(guid, &IID_IUnknown) || IsEqualIID(guid, &IID_IDirectInputEffect)){ ++ *out = iface; ++ IDirectInputEffect_AddRef(iface); ++ return DI_OK; ++ } ++ ++ return E_NOINTERFACE; ++} ++ ++static ULONG WINAPI effect_AddRef(IDirectInputEffect *iface) ++{ ++ SDLInputEffectImpl *This = impl_from_IDirectInputEffect(iface); ++ ULONG ref = InterlockedIncrement(&This->ref); ++ TRACE("%p, ref is now: %u\n", This, ref); ++ return ref; ++} ++ ++static ULONG WINAPI effect_Release(IDirectInputEffect *iface) ++{ ++ SDLInputEffectImpl *This = impl_from_IDirectInputEffect(iface); ++ ULONG ref = InterlockedDecrement(&This->ref); ++ TRACE("%p, ref is now: %u\n", This, ref); ++ ++ if (!ref) ++ { ++ list_remove(This->entry); ++ if (This->effect_id >= 0) ++ SDL_HapticDestroyEffect(This->haptic, This->effect_id); ++ HeapFree(GetProcessHeap(), 0, LIST_ENTRY(This->entry, effect_list_item, entry)); ++ HeapFree(GetProcessHeap(), 0, This); ++ } ++ ++ return ref; ++} ++ ++static HRESULT WINAPI effect_Initialize(IDirectInputEffect *iface, HINSTANCE hinst, ++ DWORD version, const GUID *guid) ++{ ++ SDLInputEffectImpl *This = impl_from_IDirectInputEffect(iface); ++ TRACE("%p %p 0x%x, %s\n", This, hinst, version, debugstr_guid(guid)); ++ return DI_OK; ++} ++ ++static HRESULT WINAPI effect_GetEffectGuid(IDirectInputEffect *iface, GUID *out) ++{ ++ SDLInputEffectImpl *This = impl_from_IDirectInputEffect(iface); ++ TRACE("%p %p\n", This, out); ++ *out = This->guid; ++ return DI_OK; ++} ++ ++ ++#define GET_BASE_EFFECT_FIELD(target, field, value) {\ ++ if (target.type == SDL_HAPTIC_SINE || \ ++ target.type == SDL_HAPTIC_TRIANGLE || \ ++ target.type == SDL_HAPTIC_SAWTOOTHUP || \ ++ target.type == SDL_HAPTIC_SAWTOOTHDOWN) \ ++ value = (target.periodic.field); \ ++ else if (target.type == SDL_HAPTIC_CONSTANT) \ ++ value = (target.constant.field); \ ++ else if (target.type == SDL_HAPTIC_RAMP) \ ++ value = (target.ramp.field); \ ++ else if (target.type == SDL_HAPTIC_SPRING || \ ++ target.type == SDL_HAPTIC_DAMPER || \ ++ target.type == SDL_HAPTIC_INERTIA || \ ++ target.type == SDL_HAPTIC_FRICTION) \ ++ value = (target.condition.field); \ ++ else if (target.type == SDL_HAPTIC_CUSTOM) \ ++ value = (target.custom.field); \ ++ } ++ ++#define GET_EXTENDED_EFFECT_FIELD(target, field, value) {\ ++ if (target.type == SDL_HAPTIC_SINE || \ ++ target.type == SDL_HAPTIC_TRIANGLE || \ ++ target.type == SDL_HAPTIC_SAWTOOTHUP || \ ++ target.type == SDL_HAPTIC_SAWTOOTHDOWN) \ ++ value = (target.periodic.field); \ ++ else if (target.type == SDL_HAPTIC_CONSTANT) \ ++ value = (target.constant.field); \ ++ else if (target.type == SDL_HAPTIC_RAMP) \ ++ value = (target.ramp.field); \ ++ else if (target.type == SDL_HAPTIC_SPRING || \ ++ target.type == SDL_HAPTIC_DAMPER || \ ++ target.type == SDL_HAPTIC_INERTIA || \ ++ target.type == SDL_HAPTIC_FRICTION); \ ++ /* Ignored because extended fields are not preset in these effects */ \ ++ else if (target.type == SDL_HAPTIC_CUSTOM) \ ++ value = (target.custom.field); \ ++ } ++ ++#define SCALE(type, target_range, target_min, value, source_range, source_min) \ ++ (type)((((target_range)*(value + source_min))/source_range)-target_min) ++ ++static HRESULT WINAPI effect_GetParameters(IDirectInputEffect *iface, ++ DIEFFECT *effect, DWORD flags) ++{ ++ HRESULT hr = DI_OK; ++ SDLInputEffectImpl *This = impl_from_IDirectInputEffect(iface); ++ TRACE("%p %p 0x%x\n", This, effect, flags); ++ ++ if (flags & DIEP_AXES) ++ { ++ if (effect->cAxes < 2) ++ hr = DIERR_MOREDATA; ++ effect->cAxes = 2; ++ if (hr) ++ return hr; ++ else ++ { ++ effect->rgdwAxes[0] = DIJOFS_X; ++ effect->rgdwAxes[1] = DIJOFS_Y; ++ } ++ } ++ ++ if (flags & DIEP_DIRECTION) ++ { ++ if (effect->cAxes < 2) ++ hr = DIERR_MOREDATA; ++ effect->cAxes = 2; ++ if (hr) ++ return hr; ++ else ++ { ++ if (effect->dwFlags & DIEFF_CARTESIAN) ++ { ++ GET_BASE_EFFECT_FIELD(This->effect, direction.dir[0], effect->rglDirection[0]); ++ GET_BASE_EFFECT_FIELD(This->effect, direction.dir[1], effect->rglDirection[1]); ++ } ++ else ++ { ++ /* Polar and spherical coordinates */ ++ GET_BASE_EFFECT_FIELD(This->effect, direction.dir[0], effect->rglDirection[0]); ++ } ++ } ++ } ++ ++ if (flags & DIEP_DURATION) ++ { ++ int sdl_length = 0; ++ GET_BASE_EFFECT_FIELD(This->effect, length, sdl_length); ++ if (sdl_length == SDL_HAPTIC_INFINITY) ++ effect->dwDuration = INFINITE; ++ else ++ effect->dwDuration = (DWORD)sdl_length * 1000; ++ } ++ ++ if (flags & DIEP_ENVELOPE) ++ { ++ int sdl_attack_length = 0; ++ int sdl_attack_level = 0; ++ int sdl_fade_length = 0; ++ int sdl_fade_level = 0; ++ ++ GET_EXTENDED_EFFECT_FIELD(This->effect, attack_length, sdl_attack_length); ++ GET_EXTENDED_EFFECT_FIELD(This->effect, attack_level, sdl_attack_level); ++ GET_EXTENDED_EFFECT_FIELD(This->effect, fade_length, sdl_fade_length); ++ GET_EXTENDED_EFFECT_FIELD(This->effect, fade_level, sdl_fade_level); ++ ++ if (sdl_attack_length == 0 && sdl_attack_level == 0 && sdl_fade_length == 0 && sdl_fade_level == 0) ++ { ++ effect->lpEnvelope = NULL; ++ } ++ else if (effect->lpEnvelope == NULL) ++ { ++ return DIERR_INVALIDPARAM; ++ } ++ else ++ { ++ effect->lpEnvelope->dwAttackLevel = sdl_attack_level; ++ effect->lpEnvelope->dwAttackTime = sdl_attack_length * 1000; ++ effect->lpEnvelope->dwFadeLevel = sdl_fade_level; ++ effect->lpEnvelope->dwFadeTime = sdl_fade_length * 1000; ++ } ++ } ++ ++ if (flags & DIEP_GAIN) ++ effect->dwGain = 0; ++ ++ if (flags & DIEP_SAMPLEPERIOD) ++ effect->dwSamplePeriod = 0; ++ ++ if (flags & DIEP_STARTDELAY && effect->dwSize > sizeof(DIEFFECT_DX5)) ++ { ++ GET_BASE_EFFECT_FIELD(This->effect, delay, effect->dwStartDelay); ++ effect->dwStartDelay *= 1000; ++ } ++ ++ if (flags & DIEP_TRIGGERBUTTON) ++ { ++ int trigger = 0; ++ GET_BASE_EFFECT_FIELD(This->effect, button, trigger); ++ effect->dwTriggerButton = DIJOFS_BUTTON(trigger); ++ } ++ ++ if (flags & DIEP_TRIGGERREPEATINTERVAL) ++ { ++ GET_BASE_EFFECT_FIELD(This->effect, interval, effect->dwTriggerRepeatInterval); ++ effect->dwTriggerRepeatInterval *= 1000; ++ } ++ ++ if (flags & DIEP_TYPESPECIFICPARAMS) ++ { ++ if (This->effect.type == SDL_HAPTIC_SINE || ++ This->effect.type == SDL_HAPTIC_TRIANGLE || ++ This->effect.type == SDL_HAPTIC_SAWTOOTHUP || ++ This->effect.type == SDL_HAPTIC_SAWTOOTHDOWN) ++ { ++ DIPERIODIC *tsp = effect->lpvTypeSpecificParams; ++ ++ tsp->dwMagnitude = MulDiv(This->effect.periodic.magnitude, 10000, 32767); ++ tsp->lOffset = This->effect.periodic.offset; ++ tsp->dwPhase = This->effect.periodic.phase; ++ tsp->dwPeriod = This->effect.periodic.period * 1000; ++ } ++ else if (This->effect.type == SDL_HAPTIC_CONSTANT) ++ { ++ LPDICONSTANTFORCE tsp = effect->lpvTypeSpecificParams; ++ tsp->lMagnitude = SCALE(LONG, 20000, -10000, This->effect.constant.level, 0xffff, -32767); ++ } ++ else if (This->effect.type == SDL_HAPTIC_RAMP) ++ { ++ DIRAMPFORCE *tsp = effect->lpvTypeSpecificParams; ++ ++ tsp->lStart = SCALE(Sint16, 20000, -10000, This->effect.ramp.start, 0xffff, -32767); ++ tsp->lEnd = SCALE(Sint16, 20000, -10000, This->effect.ramp.end, 0xffff, -32767); ++ } ++ else if (This->effect.type == SDL_HAPTIC_SPRING || ++ This->effect.type == SDL_HAPTIC_DAMPER || ++ This->effect.type == SDL_HAPTIC_INERTIA || ++ This->effect.type == SDL_HAPTIC_FRICTION) ++ { ++ int i; ++ DICONDITION *tsp = effect->lpvTypeSpecificParams; ++ for (i = 0; i < 2; i++) ++ { ++ tsp[i].lOffset = SCALE(LONG, 20000, -10000, This->effect.condition.center[i], 0xffff, -32767); ++ tsp[i].lPositiveCoefficient = SCALE(LONG, 20000, -10000, This->effect.condition.right_coeff[i], 0xffff, -32767); ++ tsp[i].lNegativeCoefficient = SCALE(LONG, 10000, -20000, This->effect.condition.left_coeff[i], 0xffff, -32767); ++ tsp[i].dwPositiveSaturation = SCALE(DWORD, 10000, 0, This->effect.condition.right_sat[i], 0xffff, 0); ++ tsp[i].dwNegativeSaturation = SCALE(DWORD, 10000, 0, This->effect.condition.left_sat[i], 0xffff, 0); ++ tsp[i].lDeadBand = SCALE(LONG, 20000, -10000, This->effect.condition.deadband[i], 0xffff, -32767); ++ } ++ } ++ else if (This->effect.type == SDL_HAPTIC_CUSTOM) ++ { ++ DICUSTOMFORCE *tsp = effect->lpvTypeSpecificParams; ++ ++ tsp->cChannels = This->effect.custom.channels; ++ tsp->dwSamplePeriod = This->effect.custom.period * 1000; ++ tsp->cSamples = This->effect.custom.samples; ++ tsp->rglForceData = (LONG*)This->effect.custom.data; ++ } ++ } ++ ++ return hr; ++} ++ ++static HRESULT WINAPI effect_Download(IDirectInputEffect *iface) ++{ ++ SDLInputEffectImpl *This = impl_from_IDirectInputEffect(iface); ++ TRACE("%p\n", This); ++ ++ if (This->effect_id < 0) ++ { ++ This->effect_id = SDL_HapticNewEffect(This->haptic, &This->effect); ++ if(This->effect_id < 0) ++ { ++ ERR("SDL_HapticNewEffect failed (Effect type %i): %s\n", This->effect.type, SDL_GetError()); ++ return E_FAIL; ++ } ++ } ++ ++ return DI_OK; ++} ++ ++static HRESULT WINAPI effect_Start(IDirectInputEffect *iface, DWORD iterations, ++ DWORD flags) ++{ ++ SDLInputEffectImpl *This = impl_from_IDirectInputEffect(iface); ++ ++ TRACE("%p 0x%x 0x%x\n", This, iterations, flags); ++ ++ if (!(flags & DIES_NODOWNLOAD)) ++ { ++ if (This->effect_id == -1) ++ { ++ HRESULT res = effect_Download(iface); ++ if (res != DI_OK) ++ return res; ++ } ++ } ++ ++ if (iterations == INFINITE) iterations = SDL_HAPTIC_INFINITY; ++ ++ if (SDL_HapticRunEffect(This->haptic, This->effect_id, iterations) < 0) ++ { ++ ERR("SDL_HapticRunEffect failed: %s\n", SDL_GetError()); ++ return E_FAIL; ++ } ++ return DI_OK; ++} ++ ++#define SET_BASE_EFFECT_FIELD(target, field, value) {\ ++ if (target.type == SDL_HAPTIC_SINE || \ ++ target.type == SDL_HAPTIC_TRIANGLE || \ ++ target.type == SDL_HAPTIC_SAWTOOTHUP || \ ++ target.type == SDL_HAPTIC_SAWTOOTHDOWN) \ ++ (target.periodic.field) = value; \ ++ else if (target.type == SDL_HAPTIC_CONSTANT) \ ++ (target.constant.field) = value; \ ++ else if (target.type == SDL_HAPTIC_RAMP) \ ++ (target.ramp.field) = value; \ ++ else if (target.type == SDL_HAPTIC_SPRING || \ ++ target.type == SDL_HAPTIC_DAMPER || \ ++ target.type == SDL_HAPTIC_INERTIA || \ ++ target.type == SDL_HAPTIC_FRICTION) \ ++ (target.condition.field) = value; \ ++ else if (target.type == SDL_HAPTIC_CUSTOM) \ ++ (target.custom.field) = value; \ ++ } ++ ++#define SET_EXTENDED_EFFECT_FIELD(target, field, value) {\ ++ if (target.type == SDL_HAPTIC_SINE || \ ++ target.type == SDL_HAPTIC_TRIANGLE || \ ++ target.type == SDL_HAPTIC_SAWTOOTHUP || \ ++ target.type == SDL_HAPTIC_SAWTOOTHDOWN) \ ++ (target.periodic.field) = value; \ ++ else if (target.type == SDL_HAPTIC_CONSTANT) \ ++ (target.constant.field) = value; \ ++ else if (target.type == SDL_HAPTIC_RAMP) \ ++ (target.ramp.field) = value; \ ++ else if (target.type == SDL_HAPTIC_SPRING || \ ++ target.type == SDL_HAPTIC_DAMPER || \ ++ target.type == SDL_HAPTIC_INERTIA || \ ++ target.type == SDL_HAPTIC_FRICTION); \ ++ /* Ignored because extended fields are not preset in these effects */ \ ++ else if (target.type == SDL_HAPTIC_CUSTOM) \ ++ (target.custom.field) = value; \ ++ } ++ ++static HRESULT WINAPI effect_SetParameters(IDirectInputEffect *iface, ++ const DIEFFECT *effect, DWORD flags) ++{ ++ SDLInputEffectImpl *This = impl_from_IDirectInputEffect(iface); ++ HRESULT retval = DI_OK; ++ ++ TRACE("%p %p 0x%x\n", This, effect, flags); ++ ++ dump_DIEFFECT(effect, &This->guid, flags); ++ ++ if (IsEqualGUID(&This->guid, &GUID_Sine)) ++ This->effect.type = SDL_HAPTIC_SINE; ++ else if (IsEqualGUID(&This->guid, &GUID_Triangle)) ++ This->effect.type = SDL_HAPTIC_TRIANGLE; ++ else if (IsEqualGUID(&This->guid, &GUID_SawtoothUp)) ++ This->effect.type = SDL_HAPTIC_SAWTOOTHUP; ++ else if (IsEqualGUID(&This->guid, &GUID_SawtoothDown)) ++ This->effect.type = SDL_HAPTIC_SAWTOOTHDOWN; ++ else if (IsEqualGUID(&This->guid, &GUID_ConstantForce)) ++ This->effect.type = SDL_HAPTIC_CONSTANT; ++ else if (IsEqualGUID(&This->guid, &GUID_RampForce)) ++ This->effect.type = SDL_HAPTIC_RAMP; ++ else if (IsEqualGUID(&This->guid, &GUID_Spring)) ++ This->effect.type = SDL_HAPTIC_SPRING; ++ else if (IsEqualGUID(&This->guid, &GUID_Damper)) ++ This->effect.type = SDL_HAPTIC_DAMPER; ++ else if (IsEqualGUID(&This->guid, &GUID_Inertia)) ++ This->effect.type = SDL_HAPTIC_INERTIA; ++ else if (IsEqualGUID(&This->guid, &GUID_Friction)) ++ This->effect.type = SDL_HAPTIC_FRICTION; ++ else if (IsEqualGUID(&This->guid, &GUID_CustomForce)) ++ This->effect.type = SDL_HAPTIC_CUSTOM; ++ ++ if ((flags & ~DIEP_NORESTART & ~DIEP_NODOWNLOAD & ~DIEP_START) == 0) ++ { ++ /* set everything */ ++ flags = DIEP_AXES | DIEP_DIRECTION | DIEP_DURATION | DIEP_ENVELOPE | ++ DIEP_GAIN | DIEP_SAMPLEPERIOD | DIEP_STARTDELAY | DIEP_TRIGGERBUTTON | ++ DIEP_TRIGGERREPEATINTERVAL | DIEP_TYPESPECIFICPARAMS; ++ } ++ ++ if (flags & DIEP_AXES) ++ { ++ if (effect->cAxes > 2) ++ return DIERR_INVALIDPARAM; ++ else if (effect->cAxes < 1) ++ return DIERR_INCOMPLETEEFFECT; ++ This->first_axis_is_x = effect->rgdwAxes[0] == DIJOFS_X; ++ } ++ ++ if (flags & DIEP_DIRECTION) ++ { ++ if (effect->cAxes == 1) ++ { ++ if (effect->dwFlags & DIEFF_CARTESIAN) ++ { ++ SET_BASE_EFFECT_FIELD(This->effect, direction.type, SDL_HAPTIC_CARTESIAN); ++ if (flags & DIEP_AXES) ++ { ++ SET_BASE_EFFECT_FIELD(This->effect, direction.dir[0], effect->rglDirection[0]); ++ SET_BASE_EFFECT_FIELD(This->effect, direction.dir[1], effect->rglDirection[1]); ++ } ++ } else { ++ /* one-axis effects must use cartesian coords */ ++ return DIERR_INVALIDPARAM; ++ } ++ } ++ /* two axes */ ++ else ++ { ++ if (effect->dwFlags & DIEFF_CARTESIAN) ++ { ++ LONG x, y; ++ ++ SET_BASE_EFFECT_FIELD(This->effect, direction.type, SDL_HAPTIC_CARTESIAN); ++ ++ if (This->first_axis_is_x) ++ { ++ x = effect->rglDirection[0]; ++ y = effect->rglDirection[1]; ++ } ++ else ++ { ++ x = effect->rglDirection[1]; ++ y = effect->rglDirection[0]; ++ } ++ SET_BASE_EFFECT_FIELD(This->effect, direction.dir[0], x); ++ SET_BASE_EFFECT_FIELD(This->effect, direction.dir[1], y); ++ } ++ else ++ { ++ if (effect->dwFlags & DIEFF_POLAR) ++ { ++ SET_BASE_EFFECT_FIELD(This->effect, direction.type, SDL_HAPTIC_POLAR); ++ } ++ if (effect->dwFlags & DIEFF_SPHERICAL) ++ { ++ SET_BASE_EFFECT_FIELD(This->effect, direction.type, SDL_HAPTIC_SPHERICAL); ++ } ++ SET_BASE_EFFECT_FIELD(This->effect, direction.dir[0], effect->rglDirection[0]); ++ } ++ } ++ } ++ ++ if (flags & DIEP_DURATION) ++ { ++ if (effect->dwDuration == INFINITE) ++ { ++ SET_BASE_EFFECT_FIELD(This->effect, length, SDL_HAPTIC_INFINITY); ++ } ++ else if(effect->dwDuration > 1000) ++ { ++ SET_BASE_EFFECT_FIELD(This->effect, length, effect->dwDuration / 1000); ++ } ++ else ++ { ++ SET_BASE_EFFECT_FIELD(This->effect, length, 1); ++ } ++ } ++ ++ if (flags & DIEP_STARTDELAY && effect->dwSize > sizeof(DIEFFECT_DX5)) ++ { ++ SET_BASE_EFFECT_FIELD(This->effect, delay, effect->dwStartDelay / 1000); ++ } ++ ++ if (flags & DIEP_TRIGGERBUTTON) ++ { ++ SET_BASE_EFFECT_FIELD(This->effect, button, effect->dwTriggerButton); ++ } ++ ++ if (flags & DIEP_TRIGGERREPEATINTERVAL) ++ { ++ SET_BASE_EFFECT_FIELD(This->effect, interval, effect->dwTriggerRepeatInterval / 1000); ++ } ++ ++ if (flags & DIEP_TYPESPECIFICPARAMS) ++ { ++ if (IsEqualGUID(&This->guid, &GUID_Sine) || ++ IsEqualGUID(&This->guid, &GUID_Triangle) || ++ IsEqualGUID(&This->guid, &GUID_SawtoothUp) || ++ IsEqualGUID(&This->guid, &GUID_SawtoothDown)) ++ { ++ DIPERIODIC *tsp; ++ if (effect->cbTypeSpecificParams != sizeof(DIPERIODIC)) ++ return DIERR_INVALIDPARAM; ++ tsp = effect->lpvTypeSpecificParams; ++ ++ This->effect.periodic.magnitude = MulDiv(tsp->dwMagnitude, 32767, 10000); ++ This->effect.periodic.offset = tsp->lOffset; ++ This->effect.periodic.phase = tsp->dwPhase; ++ if (tsp->dwPeriod <= 1000) ++ This->effect.periodic.period = 1; ++ else ++ This->effect.periodic.period = tsp->dwPeriod / 1000; ++ } ++ else if (IsEqualGUID(&This->guid, &GUID_ConstantForce)) ++ { ++ DICONSTANTFORCE *tsp = effect->lpvTypeSpecificParams; ++ ++ if (effect->cbTypeSpecificParams != sizeof(DICONSTANTFORCE)) ++ return DIERR_INVALIDPARAM; ++ tsp = effect->lpvTypeSpecificParams; ++ This->effect.constant.level = SCALE(Sint16, 0xffff, -32767, tsp->lMagnitude, 20000, -10000); ++ } ++ else if (IsEqualGUID(&This->guid, &GUID_RampForce)) ++ { ++ DIRAMPFORCE *tsp = effect->lpvTypeSpecificParams; ++ ++ if (effect->cbTypeSpecificParams != sizeof(DIRAMPFORCE)) ++ return DIERR_INVALIDPARAM; ++ tsp = effect->lpvTypeSpecificParams; ++ This->effect.ramp.start = SCALE(Sint16, 0xffff, -32767, tsp->lStart, 20000, -10000); ++ This->effect.ramp.end = SCALE(Sint16, 0xffff, -32767, tsp->lEnd, 20000, -10000); ++ } ++ else if (IsEqualGUID(&This->guid, &GUID_Spring) || ++ IsEqualGUID(&This->guid, &GUID_Damper) || ++ IsEqualGUID(&This->guid, &GUID_Inertia) || ++ IsEqualGUID(&This->guid, &GUID_Friction)) ++ { ++ int sources; ++ int i,j; ++ DICONDITION *tsp = effect->lpvTypeSpecificParams; ++ ++ if (effect->cbTypeSpecificParams == sizeof(DICONDITION)) ++ sources = 1; ++ else if (effect->cbTypeSpecificParams == 2 * sizeof(DICONDITION)) ++ sources = 2; ++ else if (effect->cbTypeSpecificParams == 3 * sizeof(DICONDITION)) ++ sources = 3; ++ else ++ return DIERR_INVALIDPARAM; ++ ++ for (i = j = 0; i < 3; ++i) ++ { ++ This->effect.condition.right_sat[i] = SCALE(Uint16, 0xffff, 0, tsp[j].dwPositiveSaturation, 10000, 0); ++ This->effect.condition.left_sat[i] = SCALE(Uint16, 0xffff, 0, tsp[j].dwNegativeSaturation, 10000, 0); ++ This->effect.condition.right_coeff[i] = SCALE(Sint16, 0xffff, -32767, tsp[j].lPositiveCoefficient, 20000, -10000); ++ This->effect.condition.left_coeff[i] = SCALE(Sint16, 0xffff, -32767, tsp[j].lNegativeCoefficient, 20000, -10000); ++ This->effect.condition.deadband[i] = SCALE(Uint16, 0xffff, 0, tsp[j].lDeadBand, 10000, 0); ++ This->effect.condition.center[i] = SCALE(Sint16, 0xffff, -32767, tsp[j].lOffset, 20000, -10000); ++ if (sources-1 > j) ++ j++; ++ } ++ } ++ else if (IsEqualGUID(&This->guid, &GUID_CustomForce)) ++ { ++ DICUSTOMFORCE *tsp = effect->lpvTypeSpecificParams; ++ ++ if (effect->cbTypeSpecificParams != sizeof(DICUSTOMFORCE)) ++ return DIERR_INVALIDPARAM; ++ ++ This->effect.custom.channels = tsp->cChannels; ++ This->effect.custom.period = tsp->dwSamplePeriod / 1000; ++ This->effect.custom.samples = tsp->cSamples; ++ This->effect.custom.data = (Uint16*)tsp->rglForceData; ++ } ++ else ++ { ++ FIXME("Specific effect params for type %s no implemented.\n", debugstr_guid(&This->guid)); ++ } ++ } ++ ++ if (flags & DIEP_ENVELOPE) ++ { ++ if (effect->lpEnvelope) ++ { ++ SET_EXTENDED_EFFECT_FIELD(This->effect, attack_length, effect->lpEnvelope->dwAttackTime / 1000); ++ SET_EXTENDED_EFFECT_FIELD(This->effect, attack_level, effect->lpEnvelope->dwAttackLevel); ++ SET_EXTENDED_EFFECT_FIELD(This->effect, fade_length, effect->lpEnvelope->dwFadeTime / 1000); ++ SET_EXTENDED_EFFECT_FIELD(This->effect, fade_level, effect->lpEnvelope->dwFadeLevel); ++ } ++ else ++ { ++ SET_EXTENDED_EFFECT_FIELD(This->effect, attack_length, 0); ++ SET_EXTENDED_EFFECT_FIELD(This->effect, attack_level, 0); ++ SET_EXTENDED_EFFECT_FIELD(This->effect, fade_length, 0); ++ SET_EXTENDED_EFFECT_FIELD(This->effect, fade_level, 0); ++ } ++ } ++ ++ if (flags & DIEP_GAIN) ++ TRACE("Effect gain requested but no effect gain functionality present.\n"); ++ ++ if (flags & DIEP_SAMPLEPERIOD) ++ TRACE("Sample period requested but no sample period functionality present.\n"); ++ ++ if (This->effect_id >= 0) ++ { ++ if (SDL_HapticUpdateEffect(This->haptic, This->effect_id, &This->effect) < 0) ++ { ++ ERR("SDL_HapticUpdateEffect failed: %s\n",SDL_GetError()); ++ return E_FAIL; ++ } ++ ++ } ++ ++ if (!(flags & DIEP_NODOWNLOAD)) ++ retval = effect_Download(iface); ++ if (retval != DI_OK) ++ return DI_DOWNLOADSKIPPED; ++ ++ if (flags & DIEP_START) ++ retval = effect_Start(iface, 1, 0); ++ ++ return DI_OK; ++} ++ ++static HRESULT WINAPI effect_Stop(IDirectInputEffect *iface) ++{ ++ SDLInputEffectImpl *This = impl_from_IDirectInputEffect(iface); ++ TRACE("%p\n", This); ++ if (SDL_HapticStopEffect(This->haptic, This->effect_id) < 0) ++ { ++ ERR("SDL_HapticStopEffect failed: %s\n", SDL_GetError()); ++ return E_FAIL; ++ } ++ return DI_OK; ++} ++ ++static HRESULT WINAPI effect_GetEffectStatus(IDirectInputEffect *iface, DWORD *flags) ++{ ++ int rc; ++ SDLInputEffectImpl *This = impl_from_IDirectInputEffect(iface); ++ TRACE("%p %p %p %i\n", This, flags, This->haptic, This->effect_id); ++ ++ if (!flags) ++ return E_POINTER; ++ ++ if (This->effect_id == -1) ++ return DIERR_NOTDOWNLOADED; ++ ++ rc = SDL_HapticGetEffectStatus(This->haptic, This->effect_id); ++ switch (rc) ++ { ++ case 0: *flags = 0; break; ++ case 1: *flags = DIEGES_PLAYING; break; ++ default: ++ ERR("SDL_HapticGetEffectStatus failed: %s\n", SDL_GetError()); ++ } ++ return DI_OK; ++} ++ ++static HRESULT WINAPI effect_Unload(IDirectInputEffect *iface) ++{ ++ SDLInputEffectImpl *This = impl_from_IDirectInputEffect(iface); ++ TRACE("%p\n", This); ++ if (This->effect_id >= 0) ++ SDL_HapticDestroyEffect(This->haptic, This->effect_id); ++ This->effect_id = -1; ++ return DI_OK; ++} ++ ++static HRESULT WINAPI effect_Escape(IDirectInputEffect *iface, DIEFFESCAPE *escape) ++{ ++ SDLInputEffectImpl *This = impl_from_IDirectInputEffect(iface); ++ TRACE("%p %p\n", This, escape); ++ return E_NOTIMPL; ++} ++ ++static const IDirectInputEffectVtbl EffectVtbl = { ++ effect_QueryInterface, ++ effect_AddRef, ++ effect_Release, ++ effect_Initialize, ++ effect_GetEffectGuid, ++ effect_GetParameters, ++ effect_SetParameters, ++ effect_Start, ++ effect_Stop, ++ effect_GetEffectStatus, ++ effect_Download, ++ effect_Unload, ++ effect_Escape ++}; ++ ++/****************************************************************************** ++ * SDLInputEffect ++ */ ++ ++DECLSPEC_HIDDEN HRESULT sdl_create_effect(SDL_Haptic *device, REFGUID rguid, struct list *parent_list_entry, LPDIRECTINPUTEFFECT* peff) ++{ ++ SDLInputEffectImpl *effect; ++ ++ effect = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(SDLInputEffectImpl)); ++ ++ effect->IDirectInputEffect_iface.lpVtbl = &EffectVtbl; ++ effect->ref = 1; ++ effect->guid = *rguid; ++ effect->haptic = device; ++ effect->effect_id = -1; ++ ++ effect->entry = parent_list_entry; ++ *peff = &effect->IDirectInputEffect_iface; ++ ++ return DI_OK; ++} ++ ++DECLSPEC_HIDDEN HRESULT sdl_input_get_info_A( ++ SDL_Joystick *dev, ++ REFGUID rguid, ++ LPDIEFFECTINFOA info) ++{ ++ DWORD type = typeFromGUID(rguid); ++ ++ TRACE("(%p, %s, %p) type=%d\n", dev, _dump_dinput_GUID(rguid), info, type); ++ ++ if (!info) return E_POINTER; ++ ++ if (info->dwSize != sizeof(DIEFFECTINFOA)) return DIERR_INVALIDPARAM; ++ ++ info->guid = *rguid; ++ ++ info->dwEffType = type; ++ /* the event device API does not support querying for all these things ++ * therefore we assume that we have support for them ++ * that's not as dangerous as it sounds, since drivers are allowed to ++ * ignore parameters they claim to support anyway */ ++ info->dwEffType |= DIEFT_DEADBAND | DIEFT_FFATTACK | DIEFT_FFFADE ++ | DIEFT_POSNEGCOEFFICIENTS | DIEFT_POSNEGSATURATION ++ | DIEFT_SATURATION | DIEFT_STARTDELAY; ++ ++ /* again, assume we have support for everything */ ++ info->dwStaticParams = DIEP_ALLPARAMS; ++ info->dwDynamicParams = info->dwStaticParams; ++ ++ /* yes, this is windows behavior (print the GUID_Name for name) */ ++ strcpy(info->tszName, _dump_dinput_GUID(rguid)); ++ ++ return DI_OK; ++} ++ ++DECLSPEC_HIDDEN HRESULT sdl_input_get_info_W( ++ SDL_Joystick *dev, ++ REFGUID rguid, ++ LPDIEFFECTINFOW info) ++{ ++ DWORD type = typeFromGUID(rguid); ++ ++ TRACE("(%p, %s, %p) type=%d\n", dev, _dump_dinput_GUID(rguid), info, type); ++ ++ if (!info) return E_POINTER; ++ ++ if (info->dwSize != sizeof(DIEFFECTINFOW)) return DIERR_INVALIDPARAM; ++ ++ info->guid = *rguid; ++ ++ info->dwEffType = type; ++ /* the event device API does not support querying for all these things ++ * therefore we assume that we have support for them ++ * that's not as dangerous as it sounds, since drivers are allowed to ++ * ignore parameters they claim to support anyway */ ++ info->dwEffType |= DIEFT_DEADBAND | DIEFT_FFATTACK | DIEFT_FFFADE ++ | DIEFT_POSNEGCOEFFICIENTS | DIEFT_POSNEGSATURATION ++ | DIEFT_SATURATION | DIEFT_STARTDELAY; ++ ++ /* again, assume we have support for everything */ ++ info->dwStaticParams = DIEP_ALLPARAMS; ++ info->dwDynamicParams = info->dwStaticParams; ++ ++ /* yes, this is windows behavior (print the GUID_Name for name) */ ++ MultiByteToWideChar(CP_ACP, 0, _dump_dinput_GUID(rguid), -1, ++ info->tszName, MAX_PATH); ++ ++ return DI_OK; ++} ++ ++#endif +diff --git a/dlls/dinput/joystick_sdl.c b/dlls/dinput/joystick_sdl.c +index f066640d56a..e9735ad4445 100644 +--- a/dlls/dinput/joystick_sdl.c ++++ b/dlls/dinput/joystick_sdl.c +@@ -58,6 +58,12 @@ typedef struct JoystickImpl JoystickImpl; + static const IDirectInputDevice8AVtbl JoystickAvt; + static const IDirectInputDevice8WVtbl JoystickWvt; + ++/* implemented in effect_sdl.c */ ++HRESULT sdl_create_effect(SDL_Haptic *haptic, REFGUID rguid, struct list *parent_list_entry, LPDIRECTINPUTEFFECT* peff); ++HRESULT sdl_input_get_info_A(SDL_Joystick *dev, REFGUID rguid, LPDIEFFECTINFOA info); ++HRESULT sdl_input_get_info_W(SDL_Joystick *dev, REFGUID rguid, LPDIEFFECTINFOW info); ++ ++ + struct SDLDev { + int id; + WORD vendor_id; +@@ -727,6 +733,67 @@ static HRESULT WINAPI JoystickWImpl_GetDeviceInfo(LPDIRECTINPUTDEVICE8W iface, + return DI_OK; + } + ++static HRESULT WINAPI JoystickWImpl_CreateEffect(IDirectInputDevice8W *iface, ++ const GUID *rguid, const DIEFFECT *lpeff, IDirectInputEffect **ppdef, ++ IUnknown *pUnkOuter) ++{ ++ JoystickImpl *This = impl_from_IDirectInputDevice8W(iface); ++ HRESULT retval = DI_OK; ++ effect_list_item* new_effect = NULL; ++ ++ TRACE("%p %s %p %p %p\n", iface, debugstr_guid(rguid), lpeff, ppdef, pUnkOuter); ++ if (lpeff) dump_DIEFFECT(lpeff, rguid, 0); ++ ++ if(!This->sdldev->has_ff){ ++ TRACE("No force feedback support\n"); ++ *ppdef = NULL; ++ return DIERR_UNSUPPORTED; ++ } ++ ++ if (pUnkOuter) ++ WARN("aggregation not implemented\n"); ++ ++ if (!(new_effect = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_effect)))) ++ return DIERR_OUTOFMEMORY; ++ ++ retval = sdl_create_effect(This->haptic, rguid, &new_effect->entry, &new_effect->ref); ++ if (retval != DI_OK) ++ { ++ HeapFree(GetProcessHeap(), 0, new_effect); ++ return retval; ++ } ++ ++ if (lpeff != NULL) ++ { ++ retval = IDirectInputEffect_SetParameters(new_effect->ref, lpeff, 0); ++ ++ if (retval != DI_OK && retval != DI_DOWNLOADSKIPPED) ++ { ++ HeapFree(GetProcessHeap(), 0, new_effect); ++ return retval; ++ } ++ } ++ ++ list_add_tail(&This->sdldev->effects, &new_effect->entry); ++ *ppdef = new_effect->ref; ++ ++ TRACE("allocated effect: %p\n", new_effect); ++ ++ return DI_OK; ++} ++ ++static HRESULT WINAPI JoystickAImpl_CreateEffect(IDirectInputDevice8A *iface, ++ const GUID *type, const DIEFFECT *params, IDirectInputEffect **out, ++ IUnknown *outer) ++{ ++ JoystickImpl *This = impl_from_IDirectInputDevice8A(iface); ++ ++ TRACE("%p %s %p %p %p\n", iface, debugstr_guid(type), params, out, outer); ++ ++ return JoystickWImpl_CreateEffect(&This->generic.base.IDirectInputDevice8W_iface, ++ type, params, out, outer); ++} ++ + static HRESULT WINAPI JoystickWImpl_EnumEffects(LPDIRECTINPUTDEVICE8W iface, + LPDIENUMEFFECTSCALLBACKW lpCallback, + LPVOID pvRef, +@@ -889,6 +956,24 @@ static HRESULT WINAPI JoystickAImpl_EnumEffects(LPDIRECTINPUTDEVICE8A iface, + return DI_OK; + } + ++static HRESULT WINAPI JoystickWImpl_GetEffectInfo(LPDIRECTINPUTDEVICE8W iface, ++ LPDIEFFECTINFOW pdei, ++ REFGUID guid) ++{ ++ JoystickImpl* This = impl_from_IDirectInputDevice8W(iface); ++ TRACE("(this=%p,%p,%s)\n", This, pdei, _dump_dinput_GUID(guid)); ++ return sdl_input_get_info_W(This->device, guid, pdei); ++} ++ ++static HRESULT WINAPI JoystickAImpl_GetEffectInfo(LPDIRECTINPUTDEVICE8A iface, ++ LPDIEFFECTINFOA pdei, ++ REFGUID guid) ++{ ++ JoystickImpl* This = impl_from_IDirectInputDevice8A(iface); ++ TRACE("(this=%p,%p,%s)\n", This, pdei, _dump_dinput_GUID(guid)); ++ return sdl_input_get_info_A(This->device, guid, pdei); ++} ++ + static HRESULT WINAPI JoystickWImpl_SendForceFeedbackCommand(LPDIRECTINPUTDEVICE8W iface, DWORD dwFlags) + { + JoystickImpl* This = impl_from_IDirectInputDevice8W(iface); +@@ -990,9 +1075,9 @@ static const IDirectInputDevice8AVtbl JoystickAvt = + JoystickAImpl_GetDeviceInfo, + IDirectInputDevice2AImpl_RunControlPanel, + IDirectInputDevice2AImpl_Initialize, +- IDirectInputDevice2AImpl_CreateEffect, ++ JoystickAImpl_CreateEffect, + JoystickAImpl_EnumEffects, +- IDirectInputDevice2AImpl_GetEffectInfo, ++ JoystickAImpl_GetEffectInfo, + IDirectInputDevice2AImpl_GetForceFeedbackState, + JoystickAImpl_SendForceFeedbackCommand, + JoystickAImpl_EnumCreatedEffectObjects, +@@ -1026,9 +1111,9 @@ static const IDirectInputDevice8WVtbl JoystickWvt = + JoystickWImpl_GetDeviceInfo, + IDirectInputDevice2WImpl_RunControlPanel, + IDirectInputDevice2WImpl_Initialize, +- IDirectInputDevice2WImpl_CreateEffect, ++ JoystickWImpl_CreateEffect, + JoystickWImpl_EnumEffects, +- IDirectInputDevice2WImpl_GetEffectInfo, ++ JoystickWImpl_GetEffectInfo, + IDirectInputDevice2WImpl_GetForceFeedbackState, + JoystickWImpl_SendForceFeedbackCommand, + JoystickWImpl_EnumCreatedEffectObjects, +From 1e6786a8f03c4760846d1562851cdf2b3ac96e0d Mon Sep 17 00:00:00 2001 +From: Aric Stewart +Date: Mon, 8 Jan 2018 07:48:06 -0600 +Subject: [PATCH] dinput: implement DISFFC_PAUSE/DISFFC_CONTINUE for SDL + +Signed-off-by: Aric Stewart +--- + dlls/dinput/joystick_sdl.c | 15 ++++++++++++++- + 1 file changed, 14 insertions(+), 1 deletion(-) + +diff --git a/dlls/dinput/joystick_sdl.c b/dlls/dinput/joystick_sdl.c +index e9735ad4445..12aba242834 100644 +--- a/dlls/dinput/joystick_sdl.c ++++ b/dlls/dinput/joystick_sdl.c +@@ -83,6 +83,7 @@ struct JoystickImpl + + SDL_Joystick *device; + SDL_Haptic *haptic; ++ BOOL ff_paused; + }; + + static inline JoystickImpl *impl_from_IDirectInputDevice8A(IDirectInputDevice8A *iface) +@@ -753,6 +754,12 @@ static HRESULT WINAPI JoystickWImpl_CreateEffect(IDirectInputDevice8W *iface, + if (pUnkOuter) + WARN("aggregation not implemented\n"); + ++ if (This->ff_paused) ++ { ++ FIXME("Cannot add new effects to a paused SDL device\n"); ++ return DIERR_GENERIC; ++ } ++ + if (!(new_effect = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_effect)))) + return DIERR_OUTOFMEMORY; + +@@ -1004,8 +1011,14 @@ static HRESULT WINAPI JoystickWImpl_SendForceFeedbackCommand(LPDIRECTINPUTDEVICE + break; + } + case DISFFC_PAUSE: ++ This->ff_paused = TRUE; ++ if (SDL_HapticPause(This->haptic) != 0) ++ ERR("SDL_HapticPause failed: %s\n",SDL_GetError()); ++ break; + case DISFFC_CONTINUE: +- FIXME("No support for Pause or Continue in sdl\n"); ++ This->ff_paused = FALSE; ++ if (SDL_HapticUnpause(This->haptic) != 0) ++ ERR("SDL_HapticUnpause failed: %s\n",SDL_GetError()); + break; + + case DISFFC_SETACTUATORSOFF: +From 75f613044ae7c46d810a6181ed0f1ad70bfa289b Mon Sep 17 00:00:00 2001 +From: Andrew Eikum +Date: Tue, 28 Aug 2018 10:35:08 -0500 +Subject: [PATCH] dinput: Don't fail to load on old SDL + +--- + dlls/dinput/joystick_sdl.c | 22 ++++++++++++++++++++-- + 1 file changed, 20 insertions(+), 2 deletions(-) + +diff --git a/dlls/dinput/joystick_sdl.c b/dlls/dinput/joystick_sdl.c +index 12aba242834..08e25efc6e6 100644 +--- a/dlls/dinput/joystick_sdl.c ++++ b/dlls/dinput/joystick_sdl.c +@@ -112,6 +112,9 @@ static struct SDLDev *sdldevs = NULL; + static void find_sdldevs(void) + { + int i; ++ Uint16 (*pSDL_JoystickGetProduct)(SDL_Joystick * joystick) = NULL; ++ Uint16 (*pSDL_JoystickGetVendor)(SDL_Joystick * joystick) = NULL; ++ void *sdl_handle = NULL; + + if (InterlockedCompareExchange(&have_sdldevs, 0, -1) != -1) + /* Someone beat us to it */ +@@ -120,6 +123,16 @@ static void find_sdldevs(void) + SDL_Init(SDL_INIT_JOYSTICK|SDL_INIT_HAPTIC); + SDL_JoystickEventState(SDL_ENABLE); + ++ sdl_handle = dlopen(SONAME_LIBSDL2, RTLD_NOW); ++ if (sdl_handle) { ++ pSDL_JoystickGetProduct = dlsym(sdl_handle, "SDL_JoystickGetProduct"); ++ pSDL_JoystickGetVendor = dlsym(sdl_handle, "SDL_JoystickGetVendor"); ++ } ++ ++ if(!pSDL_JoystickGetVendor){ ++ ERR("SDL installation is old! Please upgrade to >=2.0.6 to get accurate joystick information.\n"); ++ } ++ + for (i = 0; i < SDL_NumJoysticks(); i++) + { + struct SDLDev sdldev = {0}; +@@ -152,8 +165,13 @@ static void find_sdldevs(void) + } + } + +- sdldev.vendor_id = SDL_JoystickGetVendor(device); +- sdldev.product_id = SDL_JoystickGetProduct(device); ++ if(pSDL_JoystickGetVendor){ ++ sdldev.vendor_id = pSDL_JoystickGetVendor(device); ++ sdldev.product_id = pSDL_JoystickGetProduct(device); ++ }else{ ++ sdldev.vendor_id = 0x01; ++ sdldev.product_id = SDL_JoystickInstanceID(device) + 1; ++ } + + if (!have_sdldevs) + new_sdldevs = HeapAlloc(GetProcessHeap(), 0, sizeof(struct SDLDev)); +From f00c4108a99541ec6243869685fcf4fbcb730b07 Mon Sep 17 00:00:00 2001 +From: Andrew Eikum +Date: Wed, 8 May 2019 12:35:47 -0500 +Subject: [PATCH] dinput: Assign joystick/gamepad for SDL devices + +--- + dlls/dinput/joystick_sdl.c | 17 +++++++++++------ + 1 file changed, 11 insertions(+), 6 deletions(-) + +diff --git a/dlls/dinput/joystick_sdl.c b/dlls/dinput/joystick_sdl.c +index 08e25efc6e6..55dd1acb5e1 100644 +--- a/dlls/dinput/joystick_sdl.c ++++ b/dlls/dinput/joystick_sdl.c +@@ -70,7 +70,7 @@ struct SDLDev { + WORD product_id; + CHAR *name; + +- BOOL has_ff; ++ BOOL has_ff, is_joystick; + int autocenter; + int gain; + struct list effects; +@@ -173,6 +173,14 @@ static void find_sdldevs(void) + sdldev.product_id = SDL_JoystickInstanceID(device) + 1; + } + ++ { ++ SDL_JoystickType type = SDL_JoystickGetType(device); ++ sdldev.is_joystick = ++ type == SDL_JOYSTICK_TYPE_WHEEL || ++ type == SDL_JOYSTICK_TYPE_FLIGHT_STICK || ++ type == SDL_JOYSTICK_TYPE_THROTTLE; ++ } ++ + if (!have_sdldevs) + new_sdldevs = HeapAlloc(GetProcessHeap(), 0, sizeof(struct SDLDev)); + else +@@ -203,17 +211,14 @@ static void fill_joystick_dideviceinstanceW(LPDIDEVICEINSTANCEW lpddi, DWORD ver + lpddi->guidProduct.Data1 = MAKELONG(sdldevs[id].vendor_id, sdldevs[id].product_id); + lpddi->guidFFDriver = GUID_NULL; + +- if (version >= 0x0800) +- lpddi->dwDevType = DI8DEVTYPE_JOYSTICK | (DI8DEVTYPEJOYSTICK_STANDARD << 8); +- else +- lpddi->dwDevType = DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_TRADITIONAL << 8); ++ lpddi->dwDevType = get_device_type(version, sdldevs[id].is_joystick); + + /* Assume the joystick as HID if it is attached to USB bus and has a valid VID/PID */ + if ( sdldevs[id].vendor_id && sdldevs[id].product_id) + { + lpddi->dwDevType |= DIDEVTYPE_HID; + lpddi->wUsagePage = 0x01; /* Desktop */ +- if (lpddi->dwDevType == DI8DEVTYPE_JOYSTICK || lpddi->dwDevType == DIDEVTYPE_JOYSTICK) ++ if (sdldevs[id].is_joystick) + lpddi->wUsage = 0x04; /* Joystick */ + else + lpddi->wUsage = 0x05; /* Game Pad */ +From ebf4953f57dac705768edad562291a956d842541 Mon Sep 17 00:00:00 2001 +From: Andrew Eikum +Date: Fri, 10 May 2019 08:02:01 -0500 +Subject: [PATCH] dinput: For SDL, also allow enumeration of joysticks with + DirectX 3. + +--- + dlls/dinput/joystick_sdl.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/dlls/dinput/joystick_sdl.c b/dlls/dinput/joystick_sdl.c +index 55dd1acb5e1..f4beedc2d62 100644 +--- a/dlls/dinput/joystick_sdl.c ++++ b/dlls/dinput/joystick_sdl.c +@@ -260,7 +260,7 @@ static HRESULT sdl_enum_deviceA(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTAN + } + + if (!((dwDevType == 0) || +- ((dwDevType == DIDEVTYPE_JOYSTICK) && (version > 0x0300 && version < 0x0800)) || ++ ((dwDevType == DIDEVTYPE_JOYSTICK) && (version >= 0x0300 && version < 0x0800)) || + (((dwDevType == DI8DEVCLASS_GAMECTRL) || (dwDevType == DI8DEVTYPE_JOYSTICK)) && (version >= 0x0800)))) + return S_FALSE; + +@@ -280,7 +280,7 @@ static HRESULT sdl_enum_deviceW(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTAN + } + + if (!((dwDevType == 0) || +- ((dwDevType == DIDEVTYPE_JOYSTICK) && (version > 0x0300 && version < 0x0800)) || ++ ((dwDevType == DIDEVTYPE_JOYSTICK) && (version >= 0x0300 && version < 0x0800)) || + (((dwDevType == DI8DEVCLASS_GAMECTRL) || (dwDevType == DI8DEVTYPE_JOYSTICK)) && (version >= 0x0800)))) + return S_FALSE; + +From 4f9ba969084933980e7d8ff3094ee5d077ec2390 Mon Sep 17 00:00:00 2001 +From: Alexey Prokhin +Date: Wed, 15 May 2019 00:04:58 +0300 +Subject: [PATCH] dinput: return fake DIPROP_GUIDANDPATH property for SDL + devices + +Treaks some games such as AC Unity, AC Rouge, Far Cry 5 into exclusively using xinput for gamepads. +--- + dlls/dinput/joystick_sdl.c | 27 +++++++++++++++++++++++++++ + 1 file changed, 27 insertions(+) + +diff --git a/dlls/dinput/joystick_sdl.c b/dlls/dinput/joystick_sdl.c +index f4beedc2d62..ff45270a83b 100644 +--- a/dlls/dinput/joystick_sdl.c ++++ b/dlls/dinput/joystick_sdl.c +@@ -44,6 +44,7 @@ + #include "winbase.h" + #include "winerror.h" + #include "winreg.h" ++#include "devguid.h" + #include "dinput.h" + + #include "dinput_private.h" +@@ -69,6 +70,7 @@ struct SDLDev { + WORD vendor_id; + WORD product_id; + CHAR *name; ++ BOOL is_xbox_gamepad; + + BOOL has_ff, is_joystick; + int autocenter; +@@ -179,6 +181,11 @@ static void find_sdldevs(void) + type == SDL_JOYSTICK_TYPE_WHEEL || + type == SDL_JOYSTICK_TYPE_FLIGHT_STICK || + type == SDL_JOYSTICK_TYPE_THROTTLE; ++ ++ if (SDL_IsGameController(i)) ++ sdldev.is_xbox_gamepad = TRUE; ++ else ++ sdldev.is_xbox_gamepad = SDL_JoystickNumAxes(device) == 6 && SDL_JoystickNumButtons(device) >= 14; + } + + if (!have_sdldevs) +@@ -643,6 +650,26 @@ static HRESULT WINAPI JoystickWImpl_GetProperty(LPDIRECTINPUTDEVICE8W iface, REF + break; + } + ++ case (DWORD_PTR) DIPROP_GUIDANDPATH: ++ { ++ static const WCHAR formatW[] = {'\\','\\','?','\\','h','i','d','#','v','i','d','_','%','0','4','x','&', ++ 'p','i','d','_','%','0','4','x','&','%','s','_','%','i',0}; ++ static const WCHAR miW[] = {'m','i',0}; ++ static const WCHAR igW[] = {'i','g',0}; ++ ++ LPDIPROPGUIDANDPATH pd = (LPDIPROPGUIDANDPATH)pdiph; ++ ++ if (!This->sdldev->product_id || !This->sdldev->vendor_id) ++ return DIERR_UNSUPPORTED; ++ ++ pd->guidClass = GUID_DEVCLASS_HIDCLASS; ++ sprintfW(pd->wszPath, formatW, This->sdldev->vendor_id, This->sdldev->product_id, ++ This->sdldev->is_xbox_gamepad ? igW : miW, This->sdldev->id); ++ ++ TRACE("DIPROP_GUIDANDPATH(%s, %s): returning fake path\n", debugstr_guid(&pd->guidClass), debugstr_w(pd->wszPath)); ++ break; ++ } ++ + default: + return JoystickWGenericImpl_GetProperty(iface, rguid, pdiph); + } +From 101c921ae4f301390f80e3acb2a35470491bd199 Mon Sep 17 00:00:00 2001 +From: Andrew Eikum +Date: Tue, 16 Jul 2019 08:59:24 -0500 +Subject: [PATCH] dinput: Search setupapi to find xinput devices + +--- + dlls/dinput/Makefile.in | 2 +- + dlls/dinput/joystick.c | 73 ++++++++++++++++++++++++++------------ + dlls/dinput/joystick_sdl.c | 5 +-- + dlls/dinput8/Makefile.in | 2 +- + 4 files changed, 53 insertions(+), 29 deletions(-) + +diff --git a/dlls/dinput/Makefile.in b/dlls/dinput/Makefile.in +index 8dfebb665fb..b2e80668d1b 100644 +--- a/dlls/dinput/Makefile.in ++++ b/dlls/dinput/Makefile.in +@@ -1,6 +1,6 @@ + MODULE = dinput.dll + IMPORTLIB = dinput +-IMPORTS = dinput dxguid uuid comctl32 ole32 user32 advapi32 ++IMPORTS = dinput dxguid uuid comctl32 ole32 user32 advapi32 setupapi hid + EXTRADEFS = -DDIRECTINPUT_VERSION=0x0700 + EXTRALIBS = $(IOKIT_LIBS) $(FORCEFEEDBACK_LIBS) $(SDL2_LIBS) + EXTRAINCL = $(SDL2_CFLAGS) +diff --git a/dlls/dinput/joystick.c b/dlls/dinput/joystick.c +index 2eab4d3a33d..1c73f6351c8 100644 +--- a/dlls/dinput/joystick.c ++++ b/dlls/dinput/joystick.c +@@ -31,27 +31,11 @@ + #include "joystick_private.h" + #include "wine/debug.h" + #include "winreg.h" ++#include "setupapi.h" ++#include "ddk/hidsdi.h" + + WINE_DEFAULT_DEBUG_CHANNEL(dinput); + +-#define VID_MICROSOFT 0x045e +- +-static const WORD PID_XBOX_CONTROLLERS[] = { +- 0x0202, /* Xbox Controller */ +- 0x0285, /* Xbox Controller S */ +- 0x0289, /* Xbox Controller S */ +- 0x028e, /* Xbox360 Controller */ +- 0x028f, /* Xbox360 Wireless Controller */ +- 0x02d1, /* Xbox One Controller */ +- 0x02dd, /* Xbox One Controller (Covert Forces/Firmware 2015) */ +- 0x02e0, /* Xbox One X Controller */ +- 0x02e3, /* Xbox One Elite Controller */ +- 0x02e6, /* Wireless XBox Controller Dongle */ +- 0x02ea, /* Xbox One S Controller */ +- 0x02fd, /* Xbox One S Controller (Firmware 2017) */ +- 0x0719, /* Xbox 360 Wireless Adapter */ +-}; +- + /* Windows uses this GUID for guidProduct on non-keyboard/mouse devices. + * Data1 contains the device VID (low word) and PID (high word). + * Data4 ends with the ASCII bytes "PIDVID". +@@ -323,15 +307,58 @@ BOOL device_disabled_registry(const char* name) + + BOOL is_xinput_device(const DIDEVCAPS *devcaps, WORD vid, WORD pid) + { +- int i; ++ HDEVINFO device_info_set; ++ GUID hid_guid; ++ SP_DEVICE_INTERFACE_DATA interface_data; ++ SP_DEVICE_INTERFACE_DETAIL_DATA_W *data; ++ DWORD idx; ++ BOOL ret = FALSE; ++ char pathA[MAX_PATH]; ++ ++ HidD_GetHidGuid(&hid_guid); ++ hid_guid.Data4[7]++; /* HACK: look up the xinput-specific devices */ ++ ++ device_info_set = SetupDiGetClassDevsW(&hid_guid, NULL, NULL, DIGCF_DEVICEINTERFACE | DIGCF_PRESENT); + +- if (vid == VID_MICROSOFT) ++ data = HeapAlloc(GetProcessHeap(), 0 , sizeof(*data) + MAX_PATH * sizeof(WCHAR)); ++ data->cbSize = sizeof(*data); ++ ++ ZeroMemory(&interface_data, sizeof(interface_data)); ++ interface_data.cbSize = sizeof(interface_data); ++ ++ idx = 0; ++ while (!ret && SetupDiEnumDeviceInterfaces(device_info_set, NULL, &hid_guid, idx++, ++ &interface_data)) + { +- for (i = 0; i < ARRAY_SIZE(PID_XBOX_CONTROLLERS); i++) +- if (pid == PID_XBOX_CONTROLLERS[i]) return TRUE; ++ const char *vid_s, *pid_s; ++ DWORD di_vid = 0, di_pid = 0; ++ static const WCHAR ig[] = {'I','G','_',0}; ++ ++ if (!SetupDiGetDeviceInterfaceDetailW(device_info_set, ++ &interface_data, data, sizeof(*data) + MAX_PATH * sizeof(WCHAR), NULL, NULL)) ++ continue; ++ ++ if (!strstrW(data->DevicePath, ig)) ++ continue; ++ ++ WideCharToMultiByte(CP_ACP, 0, data->DevicePath, -1, ++ pathA, sizeof(pathA), NULL, NULL); ++ ++ vid_s = strstr(pathA, "VID_"); ++ if (vid_s) ++ sscanf(vid_s, "VID_%4X", &di_vid); ++ ++ pid_s = strstr(pathA, "PID_"); ++ if (pid_s) ++ sscanf(pid_s, "PID_%4X", &di_pid); ++ ++ ret = vid == di_vid && pid == di_pid; + } + +- return (devcaps->dwAxes == 6 && devcaps->dwButtons >= 14); ++ HeapFree(GetProcessHeap(), 0, data); ++ SetupDiDestroyDeviceInfoList(device_info_set); ++ ++ return ret; + } + + /****************************************************************************** +diff --git a/dlls/dinput/joystick_sdl.c b/dlls/dinput/joystick_sdl.c +index ff45270a83b..756c81f2938 100644 +--- a/dlls/dinput/joystick_sdl.c ++++ b/dlls/dinput/joystick_sdl.c +@@ -182,10 +182,7 @@ static void find_sdldevs(void) + type == SDL_JOYSTICK_TYPE_FLIGHT_STICK || + type == SDL_JOYSTICK_TYPE_THROTTLE; + +- if (SDL_IsGameController(i)) +- sdldev.is_xbox_gamepad = TRUE; +- else +- sdldev.is_xbox_gamepad = SDL_JoystickNumAxes(device) == 6 && SDL_JoystickNumButtons(device) >= 14; ++ sdldev.is_xbox_gamepad = is_xinput_device(NULL, sdldev.vendor_id, sdldev.product_id); + } + + if (!have_sdldevs) +diff --git a/dlls/dinput8/Makefile.in b/dlls/dinput8/Makefile.in +index 0e6ef316a79..79f309d3e60 100644 +--- a/dlls/dinput8/Makefile.in ++++ b/dlls/dinput8/Makefile.in +@@ -1,6 +1,6 @@ + MODULE = dinput8.dll + IMPORTLIB = dinput8 +-IMPORTS = dinput8 dxguid uuid comctl32 ole32 user32 advapi32 ++IMPORTS = dinput8 dxguid uuid comctl32 ole32 user32 advapi32 setupapi hid + EXTRADEFS = -DDIRECTINPUT_VERSION=0x0800 + EXTRALIBS = $(IOKIT_LIBS) $(FORCEFEEDBACK_LIBS) $(SDL2_LIBS) + EXTRAINCL = $(SDL2_CFLAGS) +From 0c320d00422253874c4a57ec84de0079c04fc68e Mon Sep 17 00:00:00 2001 +From: Andrew Eikum +Date: Tue, 6 Aug 2019 08:42:14 -0500 +Subject: [PATCH] dinput: Only enumerate SDL devices + +--- + dlls/dinput/dinput_main.c | 3 --- + 1 file changed, 3 deletions(-) + +diff --git a/dlls/dinput/dinput_main.c b/dlls/dinput/dinput_main.c +index ad72aaedff2..dc7e2959810 100644 +--- a/dlls/dinput/dinput_main.c ++++ b/dlls/dinput/dinput_main.c +@@ -91,9 +91,6 @@ static const struct dinput_device *dinput_devices[] = + &mouse_device, + &keyboard_device, + &joystick_sdl_device, +- &joystick_linuxinput_device, +- &joystick_linux_device, +- &joystick_osx_device + }; + + HINSTANCE DINPUT_instance; +From 6595088fd773578030b6c4072c4cae6fb910507e Mon Sep 17 00:00:00 2001 +From: Andrew Eikum +Date: Mon, 5 Aug 2019 10:55:26 -0500 +Subject: [PATCH] dinput: Add a mapping function for specific device types + +--- + dlls/dinput/joystick_sdl.c | 223 ++++++++++++++++++++++++++----------- + 1 file changed, 158 insertions(+), 65 deletions(-) + +diff --git a/dlls/dinput/joystick_sdl.c b/dlls/dinput/joystick_sdl.c +index 756c81f2938..38a7329bf54 100644 +--- a/dlls/dinput/joystick_sdl.c ++++ b/dlls/dinput/joystick_sdl.c +@@ -64,6 +64,17 @@ HRESULT sdl_create_effect(SDL_Haptic *haptic, REFGUID rguid, struct list *parent + HRESULT sdl_input_get_info_A(SDL_Joystick *dev, REFGUID rguid, LPDIEFFECTINFOA info); + HRESULT sdl_input_get_info_W(SDL_Joystick *dev, REFGUID rguid, LPDIEFFECTINFOW info); + ++#define ITEM_TYPE_BUTTON 1 ++#define ITEM_TYPE_AXIS 2 ++#define ITEM_TYPE_HAT 3 ++ ++struct device_state_item { ++ int type; ++ int idx; ++ int val; ++}; ++ ++typedef BOOL (*enum_device_state_function)(JoystickImpl*, struct device_state_item *, int); + + struct SDLDev { + int id; +@@ -72,6 +83,8 @@ struct SDLDev { + CHAR *name; + BOOL is_xbox_gamepad; + ++ int n_buttons, n_axes, n_hats; ++ + BOOL has_ff, is_joystick; + int autocenter; + int gain; +@@ -86,6 +99,8 @@ struct JoystickImpl + SDL_Joystick *device; + SDL_Haptic *haptic; + BOOL ff_paused; ++ ++ enum_device_state_function enum_device_state; + }; + + static inline JoystickImpl *impl_from_IDirectInputDevice8A(IDirectInputDevice8A *iface) +@@ -185,6 +200,10 @@ static void find_sdldevs(void) + sdldev.is_xbox_gamepad = is_xinput_device(NULL, sdldev.vendor_id, sdldev.product_id); + } + ++ sdldev.n_buttons = SDL_JoystickNumButtons(device); ++ sdldev.n_axes = SDL_JoystickNumAxes(device); ++ sdldev.n_hats = SDL_JoystickNumHats(device); ++ + if (!have_sdldevs) + new_sdldevs = HeapAlloc(GetProcessHeap(), 0, sizeof(struct SDLDev)); + else +@@ -295,91 +314,151 @@ static HRESULT sdl_enum_deviceW(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTAN + return S_FALSE; + } + ++/* straight 1:1 mapping of SDL items and dinput items */ ++static BOOL enum_device_state_standard(JoystickImpl *This, struct device_state_item *st, int idx) ++{ ++ DWORD n_buttons, n_axes, n_hats; ++ ++ n_buttons = This->generic.devcaps.dwButtons ? This->generic.devcaps.dwButtons : This->sdldev->n_buttons; ++ ++ if(idx < n_buttons) ++ { ++ st->type = ITEM_TYPE_BUTTON; ++ st->idx = idx; ++ st->val = SDL_JoystickGetButton(This->device, idx); ++ return TRUE; ++ } ++ ++ idx -= n_buttons; ++ ++ n_axes = This->generic.devcaps.dwAxes ? This->generic.devcaps.dwAxes : This->sdldev->n_axes; ++ ++ if(idx < n_axes) ++ { ++ st->type = ITEM_TYPE_AXIS; ++ st->idx = idx; ++ st->val = SDL_JoystickGetAxis(This->device, idx); ++ return TRUE; ++ } ++ ++ idx -= n_axes; ++ ++ n_hats = This->generic.devcaps.dwPOVs ? This->generic.devcaps.dwPOVs : This->sdldev->n_hats; ++ ++ if(idx < n_hats) ++ { ++ st->type = ITEM_TYPE_HAT; ++ st->idx = idx; ++ st->val = SDL_JoystickGetHat(This->device, idx); ++ return TRUE; ++ } ++ ++ return FALSE; ++} ++ + static void poll_sdl_device_state(LPDIRECTINPUTDEVICE8A iface) + { + JoystickImpl *This = impl_from_IDirectInputDevice8A(iface); +- int i; ++ int i = 0; + int inst_id = 0; + int newVal = 0; ++ struct device_state_item item; + + SDL_JoystickUpdate(); + +- for (i = 0; i < SDL_JoystickNumButtons(This->device); i++) ++ while(This->enum_device_state(This, &item, i++)) + { +- int val = SDL_JoystickGetButton(This->device, i); +- int oldVal = This->generic.js.rgbButtons[i]; +- newVal = val ? 0x80 : 0x0; +- This->generic.js.rgbButtons[i] = newVal; +- if (oldVal != newVal) ++ switch(item.type){ ++ case ITEM_TYPE_BUTTON: + { +- TRACE("Button: %i val %d oldVal %d newVal %d\n", i, val, oldVal, newVal); +- inst_id = DIDFT_MAKEINSTANCE(i) | DIDFT_PSHBUTTON; +- queue_event(iface, inst_id, newVal, GetCurrentTime(), This->generic.base.dinput->evsequence++); +- } +- } +- for (i = 0; i < SDL_JoystickNumAxes(This->device); i++) +- { +- int oldVal; +- newVal = SDL_JoystickGetAxis(This->device, i); +- newVal = joystick_map_axis(&This->generic.props[i], newVal); +- switch (i) +- { +- case 0: oldVal = This->generic.js.lX; +- This->generic.js.lX = newVal; break; +- case 1: oldVal = This->generic.js.lY; +- This->generic.js.lY = newVal; break; +- case 2: oldVal = This->generic.js.lZ; +- This->generic.js.lZ = newVal; break; +- case 3: oldVal = This->generic.js.lRx; +- This->generic.js.lRx = newVal; break; +- case 4: oldVal = This->generic.js.lRy; +- This->generic.js.lRy = newVal; break; +- case 5: oldVal = This->generic.js.lRz; +- This->generic.js.lRz = newVal; break; +- case 6: oldVal = This->generic.js.rglSlider[0]; +- This->generic.js.rglSlider[0] = newVal; break; +- case 7: oldVal = This->generic.js.rglSlider[1]; +- This->generic.js.rglSlider[1] = newVal; break; ++ int val = item.val; ++ int oldVal = This->generic.js.rgbButtons[item.idx]; ++ newVal = val ? 0x80 : 0x0; ++ This->generic.js.rgbButtons[item.idx] = newVal; ++ if (oldVal != newVal) ++ { ++ TRACE("Button: %i val %d oldVal %d newVal %d\n", item.idx, val, oldVal, newVal); ++ inst_id = DIDFT_MAKEINSTANCE(item.idx) | DIDFT_PSHBUTTON; ++ queue_event(iface, inst_id, newVal, GetCurrentTime(), This->generic.base.dinput->evsequence++); ++ } ++ break; + } +- if (oldVal != newVal) ++ ++ case ITEM_TYPE_AXIS: + { +- TRACE("Axis: %i oldVal %d newVal %d\n", i, oldVal, newVal); +- inst_id = DIDFT_MAKEINSTANCE(i) | DIDFT_ABSAXIS; +- queue_event(iface, inst_id, newVal, GetCurrentTime(), This->generic.base.dinput->evsequence++); ++ int oldVal; ++ newVal = item.val; ++ newVal = joystick_map_axis(&This->generic.props[item.idx], newVal); ++ switch (item.idx) ++ { ++ case 0: oldVal = This->generic.js.lX; ++ This->generic.js.lX = newVal; break; ++ case 1: oldVal = This->generic.js.lY; ++ This->generic.js.lY = newVal; break; ++ case 2: oldVal = This->generic.js.lZ; ++ This->generic.js.lZ = newVal; break; ++ case 3: oldVal = This->generic.js.lRx; ++ This->generic.js.lRx = newVal; break; ++ case 4: oldVal = This->generic.js.lRy; ++ This->generic.js.lRy = newVal; break; ++ case 5: oldVal = This->generic.js.lRz; ++ This->generic.js.lRz = newVal; break; ++ case 6: oldVal = This->generic.js.rglSlider[0]; ++ This->generic.js.rglSlider[0] = newVal; break; ++ case 7: oldVal = This->generic.js.rglSlider[1]; ++ This->generic.js.rglSlider[1] = newVal; break; ++ } ++ if (oldVal != newVal) ++ { ++ TRACE("Axis: %i oldVal %d newVal %d\n", item.idx, oldVal, newVal); ++ inst_id = DIDFT_MAKEINSTANCE(item.idx) | DIDFT_ABSAXIS; ++ queue_event(iface, inst_id, newVal, GetCurrentTime(), This->generic.base.dinput->evsequence++); ++ } ++ break; + } +- } +- for (i = 0; i < SDL_JoystickNumHats(This->device); i++) +- { +- int oldVal = This->generic.js.rgdwPOV[i]; +- newVal = SDL_JoystickGetHat(This->device, i); +- switch (newVal) ++ ++ case ITEM_TYPE_HAT: + { +- case SDL_HAT_CENTERED: newVal = -1; break; +- case SDL_HAT_UP: newVal = 0; break; +- case SDL_HAT_RIGHTUP:newVal = 4500; break; +- case SDL_HAT_RIGHT: newVal = 9000; break; +- case SDL_HAT_RIGHTDOWN: newVal = 13500; break; +- case SDL_HAT_DOWN: newVal = 18000; break; +- case SDL_HAT_LEFTDOWN: newVal = 22500; break; +- case SDL_HAT_LEFT: newVal = 27000; break; +- case SDL_HAT_LEFTUP: newVal = 31500; break; ++ int oldVal = This->generic.js.rgdwPOV[item.idx]; ++ newVal = item.val; ++ switch (newVal) ++ { ++ case SDL_HAT_CENTERED: newVal = -1; break; ++ case SDL_HAT_UP: newVal = 0; break; ++ case SDL_HAT_RIGHTUP:newVal = 4500; break; ++ case SDL_HAT_RIGHT: newVal = 9000; break; ++ case SDL_HAT_RIGHTDOWN: newVal = 13500; break; ++ case SDL_HAT_DOWN: newVal = 18000; break; ++ case SDL_HAT_LEFTDOWN: newVal = 22500; break; ++ case SDL_HAT_LEFT: newVal = 27000; break; ++ case SDL_HAT_LEFTUP: newVal = 31500; break; ++ } ++ if (oldVal != newVal) ++ { ++ TRACE("Hat : %i oldVal %d newVal %d\n", item.idx, oldVal, newVal); ++ This->generic.js.rgdwPOV[item.idx] = newVal; ++ inst_id = DIDFT_MAKEINSTANCE(item.idx) | DIDFT_POV; ++ queue_event(iface, inst_id, newVal, GetCurrentTime(), This->generic.base.dinput->evsequence++); ++ } ++ break; + } +- if (oldVal != newVal) +- { +- TRACE("Hat : %i oldVal %d newVal %d\n", i, oldVal, newVal); +- This->generic.js.rgdwPOV[i] = newVal; +- inst_id = DIDFT_MAKEINSTANCE(i) | DIDFT_POV; +- queue_event(iface, inst_id, newVal, GetCurrentTime(), This->generic.base.dinput->evsequence++); + } + } + } + ++static enum_device_state_function select_enum_function(struct SDLDev *sdldev) ++{ ++ TRACE("for %04x/%04x, using no maps\n", sdldev->vendor_id, sdldev->product_id); ++ return enum_device_state_standard; ++} ++ + static JoystickImpl *alloc_device(REFGUID rguid, IDirectInputImpl *dinput, unsigned short index) + { + JoystickImpl* newDevice; + LPDIDATAFORMAT df = NULL; + DIDEVICEINSTANCEW ddi; +- int i,idx = 0; ++ int i,idx = 0, axis_count = 0, button_count = 0, hat_count = 0; ++ struct device_state_item item; + + newDevice = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(JoystickImpl)); + if (!newDevice) return NULL; +@@ -389,6 +468,7 @@ static JoystickImpl *alloc_device(REFGUID rguid, IDirectInputImpl *dinput, unsig + newDevice->generic.guidProduct = DInput_PIDVID_Product_GUID; + newDevice->generic.guidProduct.Data1 = MAKELONG(sdldevs[index].vendor_id, sdldevs[index].product_id); + newDevice->generic.joy_polldev = poll_sdl_device_state; ++ newDevice->enum_device_state = select_enum_function(&sdldevs[index]); + + newDevice->generic.base.IDirectInputDevice8A_iface.lpVtbl = &JoystickAvt; + newDevice->generic.base.IDirectInputDevice8W_iface.lpVtbl = &JoystickWvt; +@@ -408,9 +488,22 @@ static JoystickImpl *alloc_device(REFGUID rguid, IDirectInputImpl *dinput, unsig + newDevice->device = SDL_JoystickOpen(newDevice->sdldev->id); + newDevice->haptic = SDL_HapticOpenFromJoystick(newDevice->device); + +- /* Count number of available axes - supported Axis & POVs */ +- newDevice->generic.devcaps.dwAxes = SDL_JoystickNumAxes(newDevice->device); ++ i = 0; ++ while(newDevice->enum_device_state(newDevice, &item, i++)){ ++ switch(item.type){ ++ case ITEM_TYPE_BUTTON: ++ ++button_count; ++ break; ++ case ITEM_TYPE_AXIS: ++ ++axis_count; ++ break; ++ case ITEM_TYPE_HAT: ++ ++hat_count; ++ break; ++ } ++ } + ++ newDevice->generic.devcaps.dwAxes = axis_count; + if (newDevice->generic.devcaps.dwAxes > 8 ) + { + WARN("Can't support %d axis. Clamping down to 8\n", newDevice->generic.devcaps.dwAxes); +@@ -427,14 +520,14 @@ static JoystickImpl *alloc_device(REFGUID rguid, IDirectInputImpl *dinput, unsig + newDevice->generic.props[i].lSaturation = 0; + } + +- newDevice->generic.devcaps.dwPOVs = SDL_JoystickNumHats(newDevice->device); ++ newDevice->generic.devcaps.dwPOVs = hat_count; + if (newDevice->generic.devcaps.dwPOVs > 4) + { + WARN("Can't support %d POV. Clamping down to 4\n", newDevice->generic.devcaps.dwPOVs); + newDevice->generic.devcaps.dwPOVs = 4; + } + +- newDevice->generic.devcaps.dwButtons = SDL_JoystickNumButtons(newDevice->device); ++ newDevice->generic.devcaps.dwButtons = button_count; + if (newDevice->generic.devcaps.dwButtons > 128) + { + WARN("Can't support %d buttons. Clamping down to 128\n", newDevice->generic.devcaps.dwButtons); +From d4da36ae6ed5cc3251a72888a128e03cf40cf56e Mon Sep 17 00:00:00 2001 +From: Andrew Eikum +Date: Mon, 5 Aug 2019 11:38:25 -0500 +Subject: [PATCH] dinput: Add mappings for dualshock 4 controllers + +--- + dlls/dinput/joystick_sdl.c | 321 +++++++++++++++++++++++++++++++------ + 1 file changed, 274 insertions(+), 47 deletions(-) + +diff --git a/dlls/dinput/joystick_sdl.c b/dlls/dinput/joystick_sdl.c +index 38a7329bf54..e16f5ef185a 100644 +--- a/dlls/dinput/joystick_sdl.c ++++ b/dlls/dinput/joystick_sdl.c +@@ -70,7 +70,7 @@ HRESULT sdl_input_get_info_W(SDL_Joystick *dev, REFGUID rguid, LPDIEFFECTINFOW i + + struct device_state_item { + int type; +- int idx; ++ int id; + int val; + }; + +@@ -314,6 +314,213 @@ static HRESULT sdl_enum_deviceW(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTAN + return S_FALSE; + } + ++static int buttons_to_sdl_hat(int u, int r, int d, int l) ++{ ++ if(u == d) ++ { ++ if(l == r) ++ return SDL_HAT_CENTERED; ++ if(l) ++ return SDL_HAT_LEFT; ++ return SDL_HAT_RIGHT; ++ } ++ if(u) ++ { ++ if(l == r) ++ return SDL_HAT_UP; ++ if(l) ++ return SDL_HAT_LEFTUP; ++ return SDL_HAT_RIGHTUP; ++ } ++ if(l == r) ++ return SDL_HAT_DOWN; ++ if(l) ++ return SDL_HAT_LEFTDOWN; ++ return SDL_HAT_RIGHTDOWN; ++} ++ ++/* playstation controllers */ ++#define VID_SONY 0x054c ++#define PID_SONY_DUALSHOCK_4 0x05c4 ++#define PID_SONY_DUALSHOCK_4_2 0x09cc ++#define PID_SONY_DUALSHOCK_4_DONGLE 0x0ba0 ++ ++static BOOL enum_device_state_ds4_16button(JoystickImpl *This, struct device_state_item *st, int idx) ++{ ++#define SPECIALCASE_HAT -1 ++#define SPECIALCASE_L2_BUTTON -2 ++#define SPECIALCASE_R2_BUTTON -3 ++ ++ static const struct { ++ int type; ++ int sdl_idx; ++ int dnp_id; ++ } map_ds4_16button[] = { ++ { ITEM_TYPE_AXIS, 3, 5 }, /* R2 */ ++ { ITEM_TYPE_AXIS, 2, 2 }, /* L2 */ ++ { ITEM_TYPE_AXIS, 1, 1 }, /* left vert */ ++ { ITEM_TYPE_AXIS, 0, 0 }, /* left horiz */ ++ ++ { ITEM_TYPE_HAT, SPECIALCASE_HAT, 0 }, /* d-pad */ ++ ++ { ITEM_TYPE_BUTTON, 2, 0}, /* square */ ++ { ITEM_TYPE_BUTTON, 0, 1}, /* cross */ ++ { ITEM_TYPE_BUTTON, 1, 2}, /* circle */ ++ { ITEM_TYPE_BUTTON, 3, 3}, /* triangle */ ++ ++ { ITEM_TYPE_BUTTON, 9, 4}, /* L1 */ ++ { ITEM_TYPE_BUTTON, 10, 5}, /* R1 */ ++ { ITEM_TYPE_BUTTON, SPECIALCASE_L2_BUTTON, 6}, /* L2 button */ ++ { ITEM_TYPE_BUTTON, SPECIALCASE_R2_BUTTON, 7}, /* R2 button */ ++ { ITEM_TYPE_BUTTON, 4, 8}, /* share */ ++ { ITEM_TYPE_BUTTON, 6, 9}, /* options */ ++ ++ { ITEM_TYPE_BUTTON, 7, 10}, /* guide */ ++ { ITEM_TYPE_BUTTON, 8, 11}, /* L3 */ ++ { ITEM_TYPE_BUTTON, 5, 12}, /* R3 */ ++ ++ { ITEM_TYPE_BUTTON, 15, 13}, /* touchpad button */ ++ ++ { ITEM_TYPE_AXIS, 5, 4 }, /* right vert */ ++ { ITEM_TYPE_AXIS, 4, 3 }, /* right horiz */ ++ }; ++ ++ if(idx >= ARRAY_SIZE(map_ds4_16button)) ++ return FALSE; ++ ++ st->type = map_ds4_16button[idx].type; ++ st->id = map_ds4_16button[idx].dnp_id; ++ ++ if(map_ds4_16button[idx].sdl_idx >= 0) ++ { ++ /* simple reads */ ++ switch(map_ds4_16button[idx].type) ++ { ++ case ITEM_TYPE_BUTTON: ++ st->val = SDL_JoystickGetButton(This->device, map_ds4_16button[idx].sdl_idx); ++ return TRUE; ++ ++ case ITEM_TYPE_AXIS: ++ st->val = SDL_JoystickGetAxis(This->device, map_ds4_16button[idx].sdl_idx); ++ return TRUE; ++ ++ case ITEM_TYPE_HAT: ++ st->val = SDL_JoystickGetHat(This->device, map_ds4_16button[idx].sdl_idx); ++ return TRUE; ++ } ++ } ++ ++ switch(map_ds4_16button[idx].sdl_idx){ ++ case SPECIALCASE_HAT: ++ { ++ /* d-pad */ ++ static const int SDL_DPAD_UP_BUTTON = 11; ++ static const int SDL_DPAD_DOWN_BUTTON = 12; ++ static const int SDL_DPAD_LEFT_BUTTON = 13; ++ static const int SDL_DPAD_RIGHT_BUTTON = 14; ++ st->val = buttons_to_sdl_hat( ++ SDL_JoystickGetButton(This->device, SDL_DPAD_UP_BUTTON), ++ SDL_JoystickGetButton(This->device, SDL_DPAD_RIGHT_BUTTON), ++ SDL_JoystickGetButton(This->device, SDL_DPAD_DOWN_BUTTON), ++ SDL_JoystickGetButton(This->device, SDL_DPAD_LEFT_BUTTON)); ++ return TRUE; ++ } ++ ++ case SPECIALCASE_L2_BUTTON : ++ { ++ /* L2 button */ ++ /* turn button on at about 1/8 of the trigger travel */ ++ static const int SDL_L2_AXIS = 4; ++ st->val = SDL_JoystickGetAxis(This->device, SDL_L2_AXIS) > 3 * SDL_JOYSTICK_AXIS_MIN / 4; ++ return TRUE; ++ } ++ ++ case SPECIALCASE_R2_BUTTON: ++ { ++ /* R2 button */ ++ /* turn button on at about 1/8 of the trigger travel */ ++ static const int SDL_R2_AXIS = 5; ++ st->val = SDL_JoystickGetAxis(This->device, SDL_R2_AXIS) > 3 * SDL_JOYSTICK_AXIS_MIN / 4; ++ return TRUE; ++ } ++ } ++ ++ ERR("???\n"); /* error in static data above */ ++ return FALSE; ++ ++#undef SPECIALCASE_HAT ++#undef SPECIALCASE_L2_BUTTON ++#undef SPECIALCASE_R2_BUTTON ++} ++ ++static BOOL enum_device_state_ds4_13button(JoystickImpl *This, struct device_state_item *st, int idx) ++{ ++ static const struct { ++ int type; ++ int sdl_idx; ++ int dnp_id; ++ } map_ds4_13button[] = { ++ { ITEM_TYPE_AXIS, 4, 5 }, /* R2 */ ++ { ITEM_TYPE_AXIS, 3, 2 }, /* L2 */ ++ { ITEM_TYPE_AXIS, 1, 1 }, /* left vert */ ++ { ITEM_TYPE_AXIS, 0, 0 }, /* left horiz */ ++ ++ { ITEM_TYPE_HAT, 0, 0 }, /* d-pad */ ++ ++ { ITEM_TYPE_BUTTON, 3, 0}, /* square */ ++ { ITEM_TYPE_BUTTON, 0, 1}, /* cross */ ++ { ITEM_TYPE_BUTTON, 1, 2}, /* circle */ ++ { ITEM_TYPE_BUTTON, 2, 3}, /* triangle */ ++ ++ { ITEM_TYPE_BUTTON, 4, 4}, /* L1 */ ++ { ITEM_TYPE_BUTTON, 5, 5}, /* R1 */ ++ { ITEM_TYPE_BUTTON, 6, 6}, /* L2 button */ ++ { ITEM_TYPE_BUTTON, 7, 7}, /* R2 button */ ++ { ITEM_TYPE_BUTTON, 8, 8}, /* share */ ++ { ITEM_TYPE_BUTTON, 9, 9}, /* options */ ++ ++ { ITEM_TYPE_BUTTON, 11, 10}, /* guide */ ++ { ITEM_TYPE_BUTTON, 12, 11}, /* L3 */ ++ { ITEM_TYPE_BUTTON, 10, 12}, /* R3 */ ++ ++ /* ps4 controller through linux event API does not support touchpad button */ ++ { ITEM_TYPE_BUTTON, -1, 13}, /* touchpad button */ ++ ++ { ITEM_TYPE_AXIS, 5, 4 }, /* right vert */ ++ { ITEM_TYPE_AXIS, 2, 3 }, /* right horiz */ ++ }; ++ ++ if(idx >= ARRAY_SIZE(map_ds4_13button)) ++ return FALSE; ++ ++ st->type = map_ds4_13button[idx].type; ++ st->id = map_ds4_13button[idx].dnp_id; ++ ++ if(map_ds4_13button[idx].sdl_idx < 0) ++ { ++ st->val = 0; ++ return TRUE; ++ } ++ ++ switch(map_ds4_13button[idx].type) ++ { ++ case ITEM_TYPE_BUTTON: ++ st->val = SDL_JoystickGetButton(This->device, map_ds4_13button[idx].sdl_idx); ++ return TRUE; ++ ++ case ITEM_TYPE_AXIS: ++ st->val = SDL_JoystickGetAxis(This->device, map_ds4_13button[idx].sdl_idx); ++ return TRUE; ++ ++ case ITEM_TYPE_HAT: ++ st->val = SDL_JoystickGetHat(This->device, map_ds4_13button[idx].sdl_idx); ++ return TRUE; ++ } ++ ++ ERR("???\n"); /* error in static data above */ ++ return FALSE; ++} ++ + /* straight 1:1 mapping of SDL items and dinput items */ + static BOOL enum_device_state_standard(JoystickImpl *This, struct device_state_item *st, int idx) + { +@@ -324,7 +531,7 @@ static BOOL enum_device_state_standard(JoystickImpl *This, struct device_state_i + if(idx < n_buttons) + { + st->type = ITEM_TYPE_BUTTON; +- st->idx = idx; ++ st->id = idx; + st->val = SDL_JoystickGetButton(This->device, idx); + return TRUE; + } +@@ -336,7 +543,7 @@ static BOOL enum_device_state_standard(JoystickImpl *This, struct device_state_i + if(idx < n_axes) + { + st->type = ITEM_TYPE_AXIS; +- st->idx = idx; ++ st->id = idx; + st->val = SDL_JoystickGetAxis(This->device, idx); + return TRUE; + } +@@ -348,7 +555,7 @@ static BOOL enum_device_state_standard(JoystickImpl *This, struct device_state_i + if(idx < n_hats) + { + st->type = ITEM_TYPE_HAT; +- st->idx = idx; ++ st->id = idx; + st->val = SDL_JoystickGetHat(This->device, idx); + return TRUE; + } +@@ -372,13 +579,13 @@ static void poll_sdl_device_state(LPDIRECTINPUTDEVICE8A iface) + case ITEM_TYPE_BUTTON: + { + int val = item.val; +- int oldVal = This->generic.js.rgbButtons[item.idx]; ++ int oldVal = This->generic.js.rgbButtons[item.id]; + newVal = val ? 0x80 : 0x0; +- This->generic.js.rgbButtons[item.idx] = newVal; ++ This->generic.js.rgbButtons[item.id] = newVal; + if (oldVal != newVal) + { +- TRACE("Button: %i val %d oldVal %d newVal %d\n", item.idx, val, oldVal, newVal); +- inst_id = DIDFT_MAKEINSTANCE(item.idx) | DIDFT_PSHBUTTON; ++ TRACE("Button: %i val %d oldVal %d newVal %d\n", item.id, val, oldVal, newVal); ++ inst_id = DIDFT_MAKEINSTANCE(item.id) | DIDFT_PSHBUTTON; + queue_event(iface, inst_id, newVal, GetCurrentTime(), This->generic.base.dinput->evsequence++); + } + break; +@@ -386,10 +593,13 @@ static void poll_sdl_device_state(LPDIRECTINPUTDEVICE8A iface) + + case ITEM_TYPE_AXIS: + { +- int oldVal; ++ int oldVal, obj; ++ ++ obj = id_to_object(This->generic.base.data_format.wine_df, DIDFT_MAKEINSTANCE(item.id) | DIDFT_ABSAXIS); + newVal = item.val; +- newVal = joystick_map_axis(&This->generic.props[item.idx], newVal); +- switch (item.idx) ++ newVal = joystick_map_axis(&This->generic.props[obj], newVal); ++ ++ switch (item.id) + { + case 0: oldVal = This->generic.js.lX; + This->generic.js.lX = newVal; break; +@@ -410,8 +620,8 @@ static void poll_sdl_device_state(LPDIRECTINPUTDEVICE8A iface) + } + if (oldVal != newVal) + { +- TRACE("Axis: %i oldVal %d newVal %d\n", item.idx, oldVal, newVal); +- inst_id = DIDFT_MAKEINSTANCE(item.idx) | DIDFT_ABSAXIS; ++ TRACE("Axis: %i oldVal %d newVal %d\n", item.id, oldVal, newVal); ++ inst_id = DIDFT_MAKEINSTANCE(item.id) | DIDFT_ABSAXIS; + queue_event(iface, inst_id, newVal, GetCurrentTime(), This->generic.base.dinput->evsequence++); + } + break; +@@ -419,7 +629,7 @@ static void poll_sdl_device_state(LPDIRECTINPUTDEVICE8A iface) + + case ITEM_TYPE_HAT: + { +- int oldVal = This->generic.js.rgdwPOV[item.idx]; ++ int oldVal = This->generic.js.rgdwPOV[item.id]; + newVal = item.val; + switch (newVal) + { +@@ -435,9 +645,9 @@ static void poll_sdl_device_state(LPDIRECTINPUTDEVICE8A iface) + } + if (oldVal != newVal) + { +- TRACE("Hat : %i oldVal %d newVal %d\n", item.idx, oldVal, newVal); +- This->generic.js.rgdwPOV[item.idx] = newVal; +- inst_id = DIDFT_MAKEINSTANCE(item.idx) | DIDFT_POV; ++ TRACE("Hat : %i oldVal %d newVal %d\n", item.id, oldVal, newVal); ++ This->generic.js.rgdwPOV[item.id] = newVal; ++ inst_id = DIDFT_MAKEINSTANCE(item.id) | DIDFT_POV; + queue_event(iface, inst_id, newVal, GetCurrentTime(), This->generic.base.dinput->evsequence++); + } + break; +@@ -448,6 +658,23 @@ static void poll_sdl_device_state(LPDIRECTINPUTDEVICE8A iface) + + static enum_device_state_function select_enum_function(struct SDLDev *sdldev) + { ++ switch(sdldev->vendor_id){ ++ case VID_SONY: ++ switch(sdldev->product_id){ ++ case PID_SONY_DUALSHOCK_4: ++ case PID_SONY_DUALSHOCK_4_2: ++ case PID_SONY_DUALSHOCK_4_DONGLE: ++ TRACE("for %04x/%04x, polling ds4 controller\n", sdldev->vendor_id, sdldev->product_id); ++ if(sdldev->n_buttons >= 16) ++ return enum_device_state_ds4_16button; ++ ++ TRACE("SDL only reports %u buttons for this PS4 controller. Please upgrade SDL to > 2.0.10 and/or give your user hidraw access.\n", ++ sdldev->n_buttons); ++ return enum_device_state_ds4_13button; ++ } ++ break; ++ } ++ + TRACE("for %04x/%04x, using no maps\n", sdldev->vendor_id, sdldev->product_id); + return enum_device_state_standard; + } +@@ -510,16 +737,6 @@ static JoystickImpl *alloc_device(REFGUID rguid, IDirectInputImpl *dinput, unsig + newDevice->generic.devcaps.dwAxes = 8; + } + +- for (i = 0; i < newDevice->generic.devcaps.dwAxes; i++) +- { +- newDevice->generic.props[i].lDevMin = -32768; +- newDevice->generic.props[i].lDevMax = 32767; +- newDevice->generic.props[i].lMin = 0; +- newDevice->generic.props[i].lMax = 0xffff; +- newDevice->generic.props[i].lDeadZone = 0; +- newDevice->generic.props[i].lSaturation = 0; +- } +- + newDevice->generic.devcaps.dwPOVs = hat_count; + if (newDevice->generic.devcaps.dwPOVs > 4) + { +@@ -543,26 +760,36 @@ static JoystickImpl *alloc_device(REFGUID rguid, IDirectInputImpl *dinput, unsig + df->dwNumObjs = newDevice->generic.devcaps.dwAxes + newDevice->generic.devcaps.dwPOVs + newDevice->generic.devcaps.dwButtons; + if (!(df->rgodf = HeapAlloc(GetProcessHeap(), 0, df->dwNumObjs * df->dwObjSize))) goto failed; + +- for (i = 0; i < newDevice->generic.devcaps.dwAxes; i++) +- { +- memcpy(&df->rgodf[idx], &c_dfDIJoystick2.rgodf[idx], df->dwObjSize); +- df->rgodf[idx].dwType = DIDFT_MAKEINSTANCE(idx) | DIDFT_ABSAXIS; +- if (newDevice->sdldev->has_ff && i < 2) +- df->rgodf[idx].dwFlags |= DIDOI_FFACTUATOR; +- ++idx; +- } +- +- for (i = 0; i < newDevice->generic.devcaps.dwPOVs; i++) +- { +- memcpy(&df->rgodf[idx], &c_dfDIJoystick2.rgodf[i + 8], df->dwObjSize); +- df->rgodf[idx++].dwType = DIDFT_MAKEINSTANCE(i) | DIDFT_POV; +- } +- +- for (i = 0; i < newDevice->generic.devcaps.dwButtons; i++) +- { +- memcpy(&df->rgodf[idx], &c_dfDIJoystick2.rgodf[i + 12], df->dwObjSize); +- df->rgodf[idx].pguid = &GUID_Button; +- df->rgodf[idx++].dwType = DIDFT_MAKEINSTANCE(i) | DIDFT_PSHBUTTON; ++ i = 0; ++ while(newDevice->enum_device_state(newDevice, &item, i++)){ ++ switch(item.type){ ++ case ITEM_TYPE_BUTTON: ++ memcpy(&df->rgodf[idx], &c_dfDIJoystick2.rgodf[item.id + 12], df->dwObjSize); ++ df->rgodf[idx].pguid = &GUID_Button; ++ df->rgodf[idx].dwType = DIDFT_MAKEINSTANCE(item.id) | DIDFT_PSHBUTTON; ++ ++idx; ++ break; ++ case ITEM_TYPE_AXIS: ++ memcpy(&df->rgodf[idx], &c_dfDIJoystick2.rgodf[item.id], df->dwObjSize); ++ df->rgodf[idx].dwType = DIDFT_MAKEINSTANCE(item.id) | DIDFT_ABSAXIS; ++ if (newDevice->sdldev->has_ff && item.id < 2) ++ df->rgodf[idx].dwFlags |= DIDOI_FFACTUATOR; ++ ++ newDevice->generic.props[idx].lDevMin = -32768; ++ newDevice->generic.props[idx].lDevMax = 32767; ++ newDevice->generic.props[idx].lMin = 0; ++ newDevice->generic.props[idx].lMax = 0xffff; ++ newDevice->generic.props[idx].lDeadZone = 0; ++ newDevice->generic.props[idx].lSaturation = 0; ++ ++ ++idx; ++ break; ++ case ITEM_TYPE_HAT: ++ memcpy(&df->rgodf[idx], &c_dfDIJoystick2.rgodf[item.id + 8], df->dwObjSize); ++ df->rgodf[idx].dwType = DIDFT_MAKEINSTANCE(item.id) | DIDFT_POV; ++ ++idx; ++ break; ++ } + } + + if (newDevice->sdldev->has_ff) +From 350e9b7907ee73ce439f2f4837e92c247f9848ca Mon Sep 17 00:00:00 2001 +From: Andrew Eikum +Date: Wed, 21 Aug 2019 10:28:44 -0500 +Subject: [PATCH] dinput: Implement SDL GetDeviceInfoW on top of GetDeviceInfoA + +--- + dlls/dinput/joystick_sdl.c | 32 ++++++++++++++++---------------- + 1 file changed, 16 insertions(+), 16 deletions(-) + +diff --git a/dlls/dinput/joystick_sdl.c b/dlls/dinput/joystick_sdl.c +index e16f5ef185a..ec1fc655975 100644 +--- a/dlls/dinput/joystick_sdl.c ++++ b/dlls/dinput/joystick_sdl.c +@@ -220,7 +220,7 @@ static void find_sdldevs(void) + } + } + +-static void fill_joystick_dideviceinstanceW(LPDIDEVICEINSTANCEW lpddi, DWORD version, int id) ++static void fill_joystick_dideviceinstanceA(LPDIDEVICEINSTANCEA lpddi, DWORD version, int id) + { + DWORD dwSize = lpddi->dwSize; + +@@ -247,31 +247,31 @@ static void fill_joystick_dideviceinstanceW(LPDIDEVICEINSTANCEW lpddi, DWORD ver + lpddi->wUsage = 0x05; /* Game Pad */ + } + +- MultiByteToWideChar(CP_ACP, 0, sdldevs[id].name, -1, lpddi->tszInstanceName, MAX_PATH); +- MultiByteToWideChar(CP_ACP, 0, sdldevs[id].name, -1, lpddi->tszProductName, MAX_PATH); ++ strcpy(lpddi->tszInstanceName, sdldevs[id].name); ++ strcpy(lpddi->tszProductName, sdldevs[id].name); + } + +-static void fill_joystick_dideviceinstanceA(LPDIDEVICEINSTANCEA lpddi, DWORD version, int id) ++static void fill_joystick_dideviceinstanceW(LPDIDEVICEINSTANCEW lpddi, DWORD version, int id) + { +- DIDEVICEINSTANCEW lpddiW; ++ DIDEVICEINSTANCEA lpddiA; + DWORD dwSize = lpddi->dwSize; + +- lpddiW.dwSize = sizeof(lpddiW); +- fill_joystick_dideviceinstanceW(&lpddiW, version, id); ++ lpddiA.dwSize = sizeof(lpddiA); ++ fill_joystick_dideviceinstanceA(&lpddiA, version, id); + + TRACE("%d %p\n", dwSize, lpddi); + memset(lpddi, 0, dwSize); + +- /* Convert W->A */ ++ /* Convert A->W */ + lpddi->dwSize = dwSize; +- lpddi->guidInstance = lpddiW.guidInstance; +- lpddi->guidProduct = lpddiW.guidProduct; +- lpddi->dwDevType = lpddiW.dwDevType; +- strcpy(lpddi->tszInstanceName, sdldevs[id].name); +- strcpy(lpddi->tszProductName, sdldevs[id].name); +- lpddi->guidFFDriver = lpddiW.guidFFDriver; +- lpddi->wUsagePage = lpddiW.wUsagePage; +- lpddi->wUsage = lpddiW.wUsage; ++ lpddi->guidInstance = lpddiA.guidInstance; ++ lpddi->guidProduct = lpddiA.guidProduct; ++ lpddi->dwDevType = lpddiA.dwDevType; ++ MultiByteToWideChar(CP_ACP, 0, lpddiA.tszInstanceName, -1, lpddi->tszInstanceName, MAX_PATH); ++ MultiByteToWideChar(CP_ACP, 0, lpddiA.tszProductName, -1, lpddi->tszProductName, MAX_PATH); ++ lpddi->guidFFDriver = lpddiA.guidFFDriver; ++ lpddi->wUsagePage = lpddiA.wUsagePage; ++ lpddi->wUsage = lpddiA.wUsage; + } + + static HRESULT sdl_enum_deviceA(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEA lpddi, DWORD version, int id) +From 3eda4cad14a22fb8b0ae874d63f32fee641cf310 Mon Sep 17 00:00:00 2001 +From: Andrew Eikum +Date: Wed, 21 Aug 2019 10:25:12 -0500 +Subject: [PATCH] dinput: Add device info overrides for dualshock 4 + +--- + dlls/dinput/joystick_sdl.c | 60 +++++++++++++++++++++++++++++++++----- + 1 file changed, 52 insertions(+), 8 deletions(-) + +diff --git a/dlls/dinput/joystick_sdl.c b/dlls/dinput/joystick_sdl.c +index ec1fc655975..8193752dc37 100644 +--- a/dlls/dinput/joystick_sdl.c ++++ b/dlls/dinput/joystick_sdl.c +@@ -55,6 +55,11 @@ + + WINE_DEFAULT_DEBUG_CHANNEL(dinput); + ++#define VID_SONY 0x054c ++#define PID_SONY_DUALSHOCK_4 0x05c4 ++#define PID_SONY_DUALSHOCK_4_2 0x09cc ++#define PID_SONY_DUALSHOCK_4_DONGLE 0x0ba0 ++ + typedef struct JoystickImpl JoystickImpl; + static const IDirectInputDevice8AVtbl JoystickAvt; + static const IDirectInputDevice8WVtbl JoystickWvt; +@@ -220,9 +225,30 @@ static void find_sdldevs(void) + } + } + ++static struct device_info_override { ++ WORD vid; ++ WORD pid; ++ const char *instance_name; ++ const char *product_name; ++ DWORD dev_type; ++ DWORD dev_type8; ++} device_info_overrides[] = { ++ { VID_SONY, PID_SONY_DUALSHOCK_4, "Wireless Controller", "Wireless Controller", ++ DIDEVTYPE_HID | DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_GAMEPAD << 8), ++ DIDEVTYPE_HID | DI8DEVTYPE_1STPERSON | (DI8DEVTYPE1STPERSON_SIXDOF << 8) }, ++ ++ { VID_SONY, PID_SONY_DUALSHOCK_4_2, "Wireless Controller", "Wireless Controller", ++ DIDEVTYPE_HID | DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_GAMEPAD << 8), ++ DIDEVTYPE_HID | DI8DEVTYPE_1STPERSON | (DI8DEVTYPE1STPERSON_SIXDOF << 8) }, ++ ++ { VID_SONY, PID_SONY_DUALSHOCK_4_DONGLE, "Wireless Controller", "Wireless Controller", ++ DIDEVTYPE_HID | DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_GAMEPAD << 8), ++ DIDEVTYPE_HID | DI8DEVTYPE_1STPERSON | (DI8DEVTYPE1STPERSON_SIXDOF << 8) }, ++}; ++ + static void fill_joystick_dideviceinstanceA(LPDIDEVICEINSTANCEA lpddi, DWORD version, int id) + { +- DWORD dwSize = lpddi->dwSize; ++ DWORD dwSize = lpddi->dwSize, i; + + TRACE("%d %p\n", dwSize, lpddi); + memset(lpddi, 0, dwSize); +@@ -247,8 +273,31 @@ static void fill_joystick_dideviceinstanceA(LPDIDEVICEINSTANCEA lpddi, DWORD ver + lpddi->wUsage = 0x05; /* Game Pad */ + } + +- strcpy(lpddi->tszInstanceName, sdldevs[id].name); +- strcpy(lpddi->tszProductName, sdldevs[id].name); ++ for(i = 0; i < ARRAY_SIZE(device_info_overrides); ++i) ++ { ++ const struct device_info_override *override = &device_info_overrides[i]; ++ if(sdldevs[id].vendor_id == override->vid && ++ sdldevs[id].product_id == override->pid) ++ { ++ TRACE("found devinfo override for %04hx/%04hx\n", ++ override->vid, override->pid); ++ if(version >= 0x800) ++ lpddi->dwDevType = override->dev_type8; ++ else ++ lpddi->dwDevType = override->dev_type; ++ ++ strcpy(lpddi->tszInstanceName, override->instance_name); ++ strcpy(lpddi->tszProductName, override->product_name); ++ ++ break; ++ } ++ } ++ ++ if(i >= ARRAY_SIZE(device_info_overrides)) ++ { ++ strcpy(lpddi->tszInstanceName, sdldevs[id].name); ++ strcpy(lpddi->tszProductName, sdldevs[id].name); ++ } + } + + static void fill_joystick_dideviceinstanceW(LPDIDEVICEINSTANCEW lpddi, DWORD version, int id) +@@ -340,11 +389,6 @@ static int buttons_to_sdl_hat(int u, int r, int d, int l) + } + + /* playstation controllers */ +-#define VID_SONY 0x054c +-#define PID_SONY_DUALSHOCK_4 0x05c4 +-#define PID_SONY_DUALSHOCK_4_2 0x09cc +-#define PID_SONY_DUALSHOCK_4_DONGLE 0x0ba0 +- + static BOOL enum_device_state_ds4_16button(JoystickImpl *This, struct device_state_item *st, int idx) + { + #define SPECIALCASE_HAT -1 +From aa97f95819e7e437895e4cf075d3e494457ccb84 Mon Sep 17 00:00:00 2001 +From: Alexey Prokhin +Date: Tue, 27 Aug 2019 20:42:07 +0300 +Subject: [PATCH] dinput: Remove is_xbox_gamepad flag from SDL joysticks + +--- + dlls/dinput/joystick_sdl.c | 7 +++---- + 1 file changed, 3 insertions(+), 4 deletions(-) + +diff --git a/dlls/dinput/joystick_sdl.c b/dlls/dinput/joystick_sdl.c +index 8193752dc37..2d1f585d8ab 100644 +--- a/dlls/dinput/joystick_sdl.c ++++ b/dlls/dinput/joystick_sdl.c +@@ -86,7 +86,6 @@ struct SDLDev { + WORD vendor_id; + WORD product_id; + CHAR *name; +- BOOL is_xbox_gamepad; + + int n_buttons, n_axes, n_hats; + +@@ -201,8 +200,6 @@ static void find_sdldevs(void) + type == SDL_JOYSTICK_TYPE_WHEEL || + type == SDL_JOYSTICK_TYPE_FLIGHT_STICK || + type == SDL_JOYSTICK_TYPE_THROTTLE; +- +- sdldev.is_xbox_gamepad = is_xinput_device(NULL, sdldev.vendor_id, sdldev.product_id); + } + + sdldev.n_buttons = SDL_JoystickNumButtons(device); +@@ -1018,14 +1015,16 @@ static HRESULT WINAPI JoystickWImpl_GetProperty(LPDIRECTINPUTDEVICE8W iface, REF + static const WCHAR miW[] = {'m','i',0}; + static const WCHAR igW[] = {'i','g',0}; + ++ BOOL is_gamepad; + LPDIPROPGUIDANDPATH pd = (LPDIPROPGUIDANDPATH)pdiph; + + if (!This->sdldev->product_id || !This->sdldev->vendor_id) + return DIERR_UNSUPPORTED; + ++ is_gamepad = is_xinput_device(&This->generic.devcaps, This->sdldev->vendor_id, This->sdldev->product_id); + pd->guidClass = GUID_DEVCLASS_HIDCLASS; + sprintfW(pd->wszPath, formatW, This->sdldev->vendor_id, This->sdldev->product_id, +- This->sdldev->is_xbox_gamepad ? igW : miW, This->sdldev->id); ++ is_gamepad ? igW : miW, This->sdldev->id); + + TRACE("DIPROP_GUIDANDPATH(%s, %s): returning fake path\n", debugstr_guid(&pd->guidClass), debugstr_w(pd->wszPath)); + break; +From 437f265ac88f30935148909a65ead31c96841db6 Mon Sep 17 00:00:00 2001 +From: Andrew Eikum +Date: Fri, 30 Aug 2019 09:20:46 -0500 +Subject: [PATCH] dinput: Don't enumerate joysticks that are blacklisted + +SDL only respects these variables for game controllers. All joysticks +are allowed through. But we don't want to present these at all, so we'll +check the variables manually. +--- + dlls/dinput/joystick_sdl.c | 37 +++++++++++++++++++++++++++++++++++++ + 1 file changed, 37 insertions(+) + +diff --git a/dlls/dinput/joystick_sdl.c b/dlls/dinput/joystick_sdl.c +index 2d1f585d8ab..0f84ea9f214 100644 +--- a/dlls/dinput/joystick_sdl.c ++++ b/dlls/dinput/joystick_sdl.c +@@ -130,6 +130,35 @@ static const GUID DInput_Wine_SDL_Joystick_GUID = { /* 001E36B7-5DBA-4C4F-A8C9-C + static int have_sdldevs = -1; + static struct SDLDev *sdldevs = NULL; + ++/* logic from SDL2's SDL_ShouldIgnoreGameController */ ++static BOOL is_in_sdl_blacklist(DWORD vid, DWORD pid) ++{ ++ char needle[16]; ++ const char *blacklist = getenv("SDL_GAMECONTROLLER_IGNORE_DEVICES"); ++ const char *whitelist = getenv("SDL_GAMECONTROLLER_IGNORE_DEVICES_EXCEPT"); ++ const char *allow_virtual = getenv("SDL_GAMECONTROLLER_ALLOW_STEAM_VIRTUAL_GAMEPAD"); ++ ++ if (!blacklist && !whitelist) ++ return FALSE; ++ ++ if (allow_virtual && *allow_virtual != '0') ++ { ++ if(vid == 0x28DE && pid == 0x11FF) ++ return FALSE; ++ } ++ ++ if (whitelist) ++ { ++ sprintf(needle, "0x%04x/0x%04x", vid, pid); ++ ++ return strcasestr(whitelist, needle) == NULL; ++ } ++ ++ sprintf(needle, "0x%04x/0x%04x", vid, pid); ++ ++ return strcasestr(blacklist, needle) != NULL; ++} ++ + static void find_sdldevs(void) + { + int i; +@@ -170,6 +199,7 @@ static void find_sdldevs(void) + + if (device_disabled_registry(sdldev.name)) { + SDL_JoystickClose(device); ++ HeapFree(GetProcessHeap(), 0, sdldev.name); + continue; + } + +@@ -194,6 +224,13 @@ static void find_sdldevs(void) + sdldev.product_id = SDL_JoystickInstanceID(device) + 1; + } + ++ if(is_in_sdl_blacklist(sdldev.vendor_id, sdldev.product_id)) ++ { ++ TRACE("joystick %04x/%04x is in SDL blacklist, ignoring\n", sdldev.vendor_id, sdldev.product_id); ++ SDL_JoystickClose(device); ++ continue; ++ } ++ + { + SDL_JoystickType type = SDL_JoystickGetType(device); + sdldev.is_joystick = +From d9d3c45318a5f43f1f8945bd5c60c0c9cfc65ab0 Mon Sep 17 00:00:00 2001 +From: Andrew Eikum +Date: Fri, 30 Aug 2019 10:58:16 -0500 +Subject: [PATCH] dinput: Override Steam virtual controller name + +--- + dlls/dinput/joystick_sdl.c | 53 +++++++++++++++++++++++++++++++++++++- + 1 file changed, 52 insertions(+), 1 deletion(-) + +diff --git a/dlls/dinput/joystick_sdl.c b/dlls/dinput/joystick_sdl.c +index 0f84ea9f214..150a5176404 100644 +--- a/dlls/dinput/joystick_sdl.c ++++ b/dlls/dinput/joystick_sdl.c +@@ -60,6 +60,19 @@ WINE_DEFAULT_DEBUG_CHANNEL(dinput); + #define PID_SONY_DUALSHOCK_4_2 0x09cc + #define PID_SONY_DUALSHOCK_4_DONGLE 0x0ba0 + ++#define VID_VALVE 0x28de ++#define PID_VALVE_VIRTUAL_CONTROLLER 0x11ff ++ ++#define VID_MICROSOFT 0x045e ++#define PID_MICROSOFT_XBOX_360 0x028e ++#define PID_MICROSOFT_XBOX_360_WIRELESS 0x028f ++#define PID_MICROSOFT_XBOX_360_ADAPTER 0x0719 ++#define PID_MICROSOFT_XBOX_ONE 0x02d1 ++#define PID_MICROSOFT_XBOX_ONE_CF 0x02dd ++#define PID_MICROSOFT_XBOX_ONE_ELITE 0x02e3 ++#define PID_MICROSOFT_XBOX_ONE_S 0x02ea ++#define PID_MICROSOFT_XBOX_ONE_S_2 0x02fd ++ + typedef struct JoystickImpl JoystickImpl; + static const IDirectInputDevice8AVtbl JoystickAvt; + static const IDirectInputDevice8WVtbl JoystickWvt; +@@ -143,7 +156,7 @@ static BOOL is_in_sdl_blacklist(DWORD vid, DWORD pid) + + if (allow_virtual && *allow_virtual != '0') + { +- if(vid == 0x28DE && pid == 0x11FF) ++ if(vid == VID_VALVE && pid == PID_VALVE_VIRTUAL_CONTROLLER) + return FALSE; + } + +@@ -231,6 +244,12 @@ static void find_sdldevs(void) + continue; + } + ++ if(sdldev.vendor_id == VID_VALVE && sdldev.product_id == PID_VALVE_VIRTUAL_CONTROLLER) ++ { ++ sdldev.vendor_id = VID_MICROSOFT; ++ sdldev.product_id = PID_MICROSOFT_XBOX_360; ++ } ++ + { + SDL_JoystickType type = SDL_JoystickGetType(device); + sdldev.is_joystick = +@@ -278,6 +297,38 @@ static struct device_info_override { + { VID_SONY, PID_SONY_DUALSHOCK_4_DONGLE, "Wireless Controller", "Wireless Controller", + DIDEVTYPE_HID | DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_GAMEPAD << 8), + DIDEVTYPE_HID | DI8DEVTYPE_1STPERSON | (DI8DEVTYPE1STPERSON_SIXDOF << 8) }, ++ ++ { VID_MICROSOFT, PID_MICROSOFT_XBOX_360, "Controller (XBOX 360 For Windows)", "Controller (XBOX 360 For Windows)", ++ DIDEVTYPE_HID | DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_GAMEPAD << 8), ++ DIDEVTYPE_HID | DI8DEVTYPE_GAMEPAD | (DI8DEVTYPEGAMEPAD_STANDARD << 8) }, ++ ++ { VID_MICROSOFT, PID_MICROSOFT_XBOX_360_WIRELESS, "Controller (XBOX 360 For Windows)", "Controller (XBOX 360 For Windows)", ++ DIDEVTYPE_HID | DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_GAMEPAD << 8), ++ DIDEVTYPE_HID | DI8DEVTYPE_GAMEPAD | (DI8DEVTYPEGAMEPAD_STANDARD << 8) }, ++ ++ { VID_MICROSOFT, PID_MICROSOFT_XBOX_360_ADAPTER, "Controller (XBOX 360 For Windows)", "Controller (XBOX 360 For Windows)", ++ DIDEVTYPE_HID | DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_GAMEPAD << 8), ++ DIDEVTYPE_HID | DI8DEVTYPE_GAMEPAD | (DI8DEVTYPEGAMEPAD_STANDARD << 8) }, ++ ++ { VID_MICROSOFT, PID_MICROSOFT_XBOX_ONE, "Controller (XBOX One For Windows)", "Controller (XBOX One For Windows)", ++ DIDEVTYPE_HID | DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_GAMEPAD << 8), ++ DIDEVTYPE_HID | DI8DEVTYPE_GAMEPAD | (DI8DEVTYPEGAMEPAD_STANDARD << 8) }, ++ ++ { VID_MICROSOFT, PID_MICROSOFT_XBOX_ONE_CF, "Controller (XBOX One For Windows)", "Controller (XBOX One For Windows)", ++ DIDEVTYPE_HID | DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_GAMEPAD << 8), ++ DIDEVTYPE_HID | DI8DEVTYPE_GAMEPAD | (DI8DEVTYPEGAMEPAD_STANDARD << 8) }, ++ ++ { VID_MICROSOFT, PID_MICROSOFT_XBOX_ONE_ELITE, "Controller (XBOX One For Windows)", "Controller (XBOX One For Windows)", ++ DIDEVTYPE_HID | DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_GAMEPAD << 8), ++ DIDEVTYPE_HID | DI8DEVTYPE_GAMEPAD | (DI8DEVTYPEGAMEPAD_STANDARD << 8) }, ++ ++ { VID_MICROSOFT, PID_MICROSOFT_XBOX_ONE_S, "Controller (XBOX One For Windows)", "Controller (XBOX One For Windows)", ++ DIDEVTYPE_HID | DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_GAMEPAD << 8), ++ DIDEVTYPE_HID | DI8DEVTYPE_GAMEPAD | (DI8DEVTYPEGAMEPAD_STANDARD << 8) }, ++ ++ { VID_MICROSOFT, PID_MICROSOFT_XBOX_ONE_S_2, "Controller (XBOX One For Windows)", "Controller (XBOX One For Windows)", ++ DIDEVTYPE_HID | DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_GAMEPAD << 8), ++ DIDEVTYPE_HID | DI8DEVTYPE_GAMEPAD | (DI8DEVTYPEGAMEPAD_STANDARD << 8) }, + }; + + static void fill_joystick_dideviceinstanceA(LPDIDEVICEINSTANCEA lpddi, DWORD version, int id) +From 1e7e5768c4a9014686a75fb992fe0072905d34be Mon Sep 17 00:00:00 2001 +From: Andrew Eikum +Date: Tue, 3 Sep 2019 10:49:53 -0500 +Subject: [PATCH] dinput: Return real rawinput path for dinput device + +--- + dlls/dinput/joystick_sdl.c | 72 ++++++++++++++++++++++++++++++++------ + 1 file changed, 61 insertions(+), 11 deletions(-) + +diff --git a/dlls/dinput/joystick_sdl.c b/dlls/dinput/joystick_sdl.c +index 150a5176404..a5f7562e340 100644 +--- a/dlls/dinput/joystick_sdl.c ++++ b/dlls/dinput/joystick_sdl.c +@@ -24,6 +24,7 @@ + #include "config.h" + #include "wine/port.h" + ++#define NONAMELESSUNION + #include + #include + #include +@@ -1098,23 +1099,72 @@ static HRESULT WINAPI JoystickWImpl_GetProperty(LPDIRECTINPUTDEVICE8W iface, REF + + case (DWORD_PTR) DIPROP_GUIDANDPATH: + { +- static const WCHAR formatW[] = {'\\','\\','?','\\','h','i','d','#','v','i','d','_','%','0','4','x','&', +- 'p','i','d','_','%','0','4','x','&','%','s','_','%','i',0}; +- static const WCHAR miW[] = {'m','i',0}; +- static const WCHAR igW[] = {'i','g',0}; +- +- BOOL is_gamepad; ++ RAWINPUTDEVICELIST *list; ++ RID_DEVICE_INFO info; ++ UINT ndevs, i, ur, size; + LPDIPROPGUIDANDPATH pd = (LPDIPROPGUIDANDPATH)pdiph; + ++ memset(pd, 0, sizeof(*pd)); ++ + if (!This->sdldev->product_id || !This->sdldev->vendor_id) + return DIERR_UNSUPPORTED; + +- is_gamepad = is_xinput_device(&This->generic.devcaps, This->sdldev->vendor_id, This->sdldev->product_id); +- pd->guidClass = GUID_DEVCLASS_HIDCLASS; +- sprintfW(pd->wszPath, formatW, This->sdldev->vendor_id, This->sdldev->product_id, +- is_gamepad ? igW : miW, This->sdldev->id); ++ ur = GetRawInputDeviceList(NULL, &ndevs, sizeof(RAWINPUTDEVICELIST)); ++ if (ur == (UINT)-1) ++ return DIERR_GENERIC; ++ ++ list = HeapAlloc(GetProcessHeap(), 0, ndevs * sizeof(*list)); ++ if (!list) ++ return DIERR_OUTOFMEMORY; ++ ++ ndevs = GetRawInputDeviceList(list, &ndevs, sizeof(RAWINPUTDEVICELIST)); ++ if (ndevs == (UINT)-1) ++ { ++ HeapFree(GetProcessHeap(), 0, list); ++ return DIERR_GENERIC; ++ } ++ ++ for (i = 0; i < ndevs; ++i) ++ { ++ if (list[i].dwType != RIM_TYPEHID) ++ continue; ++ ++ memset(&info, 0, sizeof(info)); ++ size = info.cbSize = sizeof(info); ++ ++ ur = GetRawInputDeviceInfoW(list[i].hDevice, RIDI_DEVICEINFO, &info, &size); ++ TRACE("got hid: %04x/%04x\n", info.u.hid.dwVendorId, ++ info.u.hid.dwProductId); ++ if (ur == (UINT)-1 || ++ (info.u.hid.dwVendorId != This->sdldev->vendor_id || ++ info.u.hid.dwProductId != This->sdldev->product_id)) ++ continue; ++ ++ /* found device with same vid/pid, return this path. won't work ++ * for multiple identical controllers... */ ++ ++ size = ARRAY_SIZE(pd->wszPath); ++ ur = GetRawInputDeviceInfoW(list[i].hDevice, RIDI_DEVICENAME, pd->wszPath, &size); ++ if (ur == (UINT)-1) ++ { ++ HeapFree(GetProcessHeap(), 0, list); ++ return DIERR_GENERIC; ++ } ++ ++ pd->guidClass = GUID_DEVCLASS_HIDCLASS; ++ ++ TRACE("DIPROP_GUIDANDPATH(%s, %s): returning path\n", debugstr_guid(&pd->guidClass), debugstr_w(pd->wszPath)); ++ break; ++ } ++ ++ HeapFree(GetProcessHeap(), 0, list); ++ ++ if (i >= ndevs) ++ { ++ TRACE("couldn't find matching rawinput device\n"); ++ return DIERR_GENERIC; ++ } + +- TRACE("DIPROP_GUIDANDPATH(%s, %s): returning fake path\n", debugstr_guid(&pd->guidClass), debugstr_w(pd->wszPath)); + break; + } + +From 62896d51ea4311e15245b7bda5f2686a632761b8 Mon Sep 17 00:00:00 2001 +From: Andrew Eikum +Date: Thu, 5 Sep 2019 10:31:35 -0500 +Subject: [PATCH] dinput: Use axis ID to look up properties, not data offset + +--- + dlls/dinput/joystick.c | 36 ++++++++++++++++++------------------ + 1 file changed, 18 insertions(+), 18 deletions(-) + +diff --git a/dlls/dinput/joystick.c b/dlls/dinput/joystick.c +index 1c73f6351c8..9c7f2ef4193 100644 +--- a/dlls/dinput/joystick.c ++++ b/dlls/dinput/joystick.c +@@ -367,15 +367,15 @@ static void remap_apply(JoystickGenericImpl *This, int obj, ObjProps *remap_prop + /* Many games poll the joystick immediately after setting the range + * for calibration purposes, so the old values need to be remapped + * to the new range before it does so */ +- switch (This->base.data_format.wine_df->rgodf[obj].dwOfs){ +- case DIJOFS_X : This->js.lX = joystick_map_axis(remap_props, This->js.lX); break; +- case DIJOFS_Y : This->js.lY = joystick_map_axis(remap_props, This->js.lY); break; +- case DIJOFS_Z : This->js.lZ = joystick_map_axis(remap_props, This->js.lZ); break; +- case DIJOFS_RX : This->js.lRx = joystick_map_axis(remap_props, This->js.lRx); break; +- case DIJOFS_RY : This->js.lRy = joystick_map_axis(remap_props, This->js.lRy); break; +- case DIJOFS_RZ : This->js.lRz = joystick_map_axis(remap_props, This->js.lRz); break; +- case DIJOFS_SLIDER(0): This->js.rglSlider[0] = joystick_map_axis(remap_props, This->js.rglSlider[0]); break; +- case DIJOFS_SLIDER(1): This->js.rglSlider[1] = joystick_map_axis(remap_props, This->js.rglSlider[1]); break; ++ switch (DIDFT_GETINSTANCE(This->base.data_format.wine_df->rgodf[obj].dwType)) { ++ case 0: This->js.lX = joystick_map_axis(&remap_props, This->js.lX); break; ++ case 1: This->js.lY = joystick_map_axis(&remap_props, This->js.lY); break; ++ case 2: This->js.lZ = joystick_map_axis(&remap_props, This->js.lZ); break; ++ case 3: This->js.lRx = joystick_map_axis(&remap_props, This->js.lRx); break; ++ case 4: This->js.lRy = joystick_map_axis(&remap_props, This->js.lRy); break; ++ case 5: This->js.lRz = joystick_map_axis(&remap_props, This->js.lRz); break; ++ case 6: This->js.rglSlider[0] = joystick_map_axis(&remap_props, This->js.rglSlider[0]); break; ++ case 7: This->js.rglSlider[1] = joystick_map_axis(&remap_props, This->js.rglSlider[1]); break; + default: break; + } + } +From ecf58e5b0b0bda00bbeecd239dea636d25d35c37 Mon Sep 17 00:00:00 2001 +From: Andrew Eikum +Date: Wed, 21 Aug 2019 14:12:27 -0500 +Subject: [PATCH] dinput: Check for device loss in joystick Poll + +--- + dlls/dinput/joystick.c | 16 +++++++++------- + dlls/dinput/joystick_linux.c | 16 +++++++++------- + dlls/dinput/joystick_linuxinput.c | 12 +++++++----- + dlls/dinput/joystick_osx.c | 20 +++++++++++--------- + dlls/dinput/joystick_private.h | 2 +- + dlls/dinput/joystick_sdl.c | 7 ++++++- + 6 files changed, 43 insertions(+), 30 deletions(-) + +diff --git a/dlls/dinput/joystick.c b/dlls/dinput/joystick.c +index 9c7f2ef4193..fc4040757f8 100644 +--- a/dlls/dinput/joystick.c ++++ b/dlls/dinput/joystick.c +@@ -815,8 +815,7 @@ HRESULT WINAPI JoystickWGenericImpl_Poll(LPDIRECTINPUTDEVICE8W iface) + return DIERR_NOTACQUIRED; + } + +- This->joy_polldev( iface ); +- return DI_OK; ++ return This->joy_polldev( iface ); + } + + HRESULT WINAPI JoystickAGenericImpl_Poll(LPDIRECTINPUTDEVICE8A iface) +@@ -831,6 +830,7 @@ HRESULT WINAPI JoystickAGenericImpl_Poll(LPDIRECTINPUTDEVICE8A iface) + */ + HRESULT WINAPI JoystickWGenericImpl_GetDeviceState(LPDIRECTINPUTDEVICE8W iface, DWORD len, LPVOID ptr) + { ++ HRESULT hr; + JoystickGenericImpl *This = impl_from_IDirectInputDevice8W(iface); + + TRACE("(%p,0x%08x,%p)\n", This, len, ptr); +@@ -841,12 +841,14 @@ HRESULT WINAPI JoystickWGenericImpl_GetDeviceState(LPDIRECTINPUTDEVICE8W iface, + } + + /* update joystick state */ +- This->joy_polldev( iface ); +- +- /* convert and copy data to user supplied buffer */ +- fill_DataFormat(ptr, len, &This->js, &This->base.data_format); ++ hr = This->joy_polldev( iface ); ++ if (SUCCEEDED(hr)) ++ { ++ /* convert and copy data to user supplied buffer */ ++ fill_DataFormat(ptr, len, &This->js, &This->base.data_format); ++ } + +- return DI_OK; ++ return hr; + } + + HRESULT WINAPI JoystickAGenericImpl_GetDeviceState(LPDIRECTINPUTDEVICE8A iface, DWORD len, LPVOID ptr) +diff --git a/dlls/dinput/joystick_linux.c b/dlls/dinput/joystick_linux.c +index 2b26eb806d3..4229f3ee642 100644 +--- a/dlls/dinput/joystick_linux.c ++++ b/dlls/dinput/joystick_linux.c +@@ -130,7 +130,7 @@ static const GUID DInput_Wine_Joystick_GUID = { /* 9e573ed9-7734-11d2-8d4a-23903 + static INT joystick_devices_count = -1; + static struct JoyDev *joystick_devices; + +-static void joy_polldev( IDirectInputDevice8W *iface ); ++static HRESULT joy_polldev( IDirectInputDevice8W *iface ); + + #define SYS_PATH_FORMAT "/sys/class/input/js%d/device/id/%s" + static BOOL read_sys_id_variable(int index, const char *property, WORD *value) +@@ -840,7 +840,7 @@ static HRESULT WINAPI JoystickLinuxAImpl_Unacquire(LPDIRECTINPUTDEVICE8A iface) + return JoystickLinuxWImpl_Unacquire(IDirectInputDevice8W_from_impl(This)); + } + +-static void joy_polldev( IDirectInputDevice8W *iface ) ++static HRESULT joy_polldev( IDirectInputDevice8W *iface ) + { + struct pollfd plfd; + struct js_event jse; +@@ -850,7 +850,7 @@ static void joy_polldev(LPDIRECTINPUTDEVICE8A iface) + + if (This->joyfd==-1) { + WARN("no device\n"); +- return; ++ return DIERR_INPUTLOST; + } + while (1) + { +@@ -860,17 +860,17 @@ static void joy_polldev(LPDIRECTINPUTDEVICE8A iface) + plfd.fd = This->joyfd; + plfd.events = POLLIN; + if (poll(&plfd,1,0) != 1) +- return; ++ return DI_OK; + /* we have one event, so we can read */ + if (sizeof(jse)!=read(This->joyfd,&jse,sizeof(jse))) { +- return; ++ return DIERR_INPUTLOST; + } + TRACE("js_event: type 0x%x, number %d, value %d\n", + jse.type,jse.number,jse.value); + if (jse.type & JS_EVENT_BUTTON) + { + int button; +- if (jse.number >= This->generic.devcaps.dwButtons) return; ++ if (jse.number >= This->generic.devcaps.dwButtons) continue; + + button = This->generic.button_map[jse.number]; + +@@ -878,7 +878,7 @@ static void joy_polldev(LPDIRECTINPUTDEVICE8A iface) + { + int number = This->generic.axis_map[jse.number]; /* wine format object index */ + +- if (number < 0) return; ++ if (number < 0) continue; + inst_id = number < 8 ? DIDFT_MAKEINSTANCE(number) | DIDFT_ABSAXIS : + DIDFT_MAKEINSTANCE(number - 8) | DIDFT_POV; + value = joystick_map_axis(&This->generic.props[id_to_object(This->generic.base.data_format.wine_df, inst_id)], jse.value); +@@ -913,6 +913,8 @@ static void joy_polldev(LPDIRECTINPUTDEVICE8A iface) + if (inst_id >= 0) + queue_event(iface, inst_id, value, GetCurrentTime(), This->generic.base.dinput->evsequence++); + } ++ ++ return DI_OK; + } + + static const IDirectInputDevice8AVtbl JoystickAvt = +diff --git a/dlls/dinput/joystick_linuxinput.c b/dlls/dinput/joystick_linuxinput.c +index 102de8269b9..66fc9b7f9b1 100644 +--- a/dlls/dinput/joystick_linuxinput.c ++++ b/dlls/dinput/joystick_linuxinput.c +@@ -155,7 +155,7 @@ static inline IDirectInputDevice8W *IDirectInputDevice8W_from_impl(JoystickImpl + + static void fake_current_js_state(JoystickImpl *ji); + static void find_joydevs(void); +-static void joy_polldev( IDirectInputDevice8W *iface ); ++static HRESULT joy_polldev( IDirectInputDevice8W *iface ); + + /* This GUID is slightly different from the linux joystick one. Take note. */ + static const GUID DInput_Wine_Joystick_Base_GUID = { /* 9e573eda-7734-11d2-8d4a-23903fb6bdf7 */ +@@ -731,7 +731,7 @@ static void fake_current_js_state(JoystickImpl *ji) + #undef CENTER_AXIS + + /* convert wine format offset to user format object index */ +-static void joy_polldev( IDirectInputDevice8W *iface ) ++static HRESULT joy_polldev( IDirectInputDevice8W *iface ) + { + struct pollfd plfd; + struct input_event ie; +@@ -794,7 +794,7 @@ static void joy_polldev( IDirectInputDevice8W *iface ) + This->joyfd = -1; + This->joyfd_state = WINE_FD_STATE_DISCONNECTED; + } +- return; ++ return DI_OK; + } + + /* we have one event, so we can read */ +@@ -808,7 +808,7 @@ static void joy_polldev( IDirectInputDevice8W *iface ) + This->joyfd = -1; + This->joyfd_state = WINE_FD_STATE_DISCONNECTED; + } +- return; ++ return DIERR_INPUTLOST; + } + + TRACE("input_event: type %d, code %d, value %d\n",ie.type,ie.code,ie.value); +@@ -910,6 +910,8 @@ static void joy_polldev(LPDIRECTINPUTDEVICE8A iface) + queue_event(iface, inst_id, + value, GetCurrentTime(), This->generic.base.dinput->evsequence++); + } ++ ++ return DI_OK; + } + + /****************************************************************************** +diff --git a/dlls/dinput/joystick_osx.c b/dlls/dinput/joystick_osx.c +index 805b75639fe..0dd77842a20 100644 +--- a/dlls/dinput/joystick_osx.c ++++ b/dlls/dinput/joystick_osx.c +@@ -797,7 +797,7 @@ static void get_osx_device_elements_props(JoystickImpl *device) + } + } + +-static void poll_osx_device_state( IDirectInputDevice8W *iface ) ++static HRESULT poll_osx_device_state( IDirectInputDevice8W *iface ) + { + JoystickImpl *device = impl_from_IDirectInputDevice8W( iface ); + IOHIDElementRef device_main_element; +@@ -806,13 +806,13 @@ static void poll_osx_device_state(LPDIRECTINPUTDEVICE8A iface) + TRACE("device %p device->id %i\n", device, device->id); + + if (!device_main_elements || device->id >= CFArrayGetCount(device_main_elements)) +- return; ++ return DIERR_INPUTLOST; + + device_main_element = (IOHIDElementRef) CFArrayGetValueAtIndex(device_main_elements, device->id); + hid_device = IOHIDElementGetDevice(device_main_element); + TRACE("main element %s hid_device %s\n", debugstr_element(device_main_element), debugstr_device(hid_device)); + if (!hid_device) +- return; ++ return DIERR_INPUTLOST; + + if (device->elements) + { +@@ -839,9 +839,9 @@ static void poll_osx_device_state(LPDIRECTINPUTDEVICE8A iface) + { + valueRef = NULL; + if (IOHIDDeviceGetValue(hid_device, element, &valueRef) != kIOReturnSuccess) +- return; ++ continue; + if (valueRef == NULL) +- return; ++ continue; + val = IOHIDValueGetIntegerValue(valueRef); + newVal = val ? 0x80 : 0x0; + oldVal = device->generic.js.rgbButtons[button_idx]; +@@ -866,9 +866,9 @@ static void poll_osx_device_state(LPDIRECTINPUTDEVICE8A iface) + TRACE("kIOHIDElementTypeInput_Misc / kHIDUsage_GD_Hatswitch\n"); + valueRef = NULL; + if (IOHIDDeviceGetValue(hid_device, element, &valueRef) != kIOReturnSuccess) +- return; ++ continue; + if (valueRef == NULL) +- return; ++ continue; + val = IOHIDValueGetIntegerValue(valueRef); + oldVal = device->generic.js.rgdwPOV[pov_idx]; + if ((val > device->generic.props[idx].lDevMax) || (val < device->generic.props[idx].lDevMin)) +@@ -899,9 +899,9 @@ static void poll_osx_device_state(LPDIRECTINPUTDEVICE8A iface) + + valueRef = NULL; + if (IOHIDDeviceGetValue(hid_device, element, &valueRef) != kIOReturnSuccess) +- return; ++ continue; + if (valueRef == NULL) +- return; ++ continue; + val = IOHIDValueGetIntegerValue(valueRef); + newVal = joystick_map_axis(&device->generic.props[idx], val); + switch (MAKEUINT64(usage_page, usage)) +@@ -972,6 +972,8 @@ static void poll_osx_device_state(LPDIRECTINPUTDEVICE8A iface) + } + } + } ++ ++ return DI_OK; + } + + static INT find_joystick_devices(void) +diff --git a/dlls/dinput/joystick_private.h b/dlls/dinput/joystick_private.h +index b786c84decb..2af4a294303 100644 +--- a/dlls/dinput/joystick_private.h ++++ b/dlls/dinput/joystick_private.h +@@ -33,7 +33,7 @@ + #define MAX_PROPS 164 + struct JoystickGenericImpl; + +-typedef void joy_polldev_handler( IDirectInputDevice8W *iface ); ++typedef HRESULT joy_polldev_handler( IDirectInputDevice8W *iface ); + + typedef struct JoystickGenericImpl + { +diff --git a/dlls/dinput/joystick_sdl.c b/dlls/dinput/joystick_sdl.c +index a5f7562e340..1b39977add5 100644 +--- a/dlls/dinput/joystick_sdl.c ++++ b/dlls/dinput/joystick_sdl.c +@@ -693,7 +693,7 @@ static BOOL enum_device_state_standard(JoystickImpl *This, struct device_state_i + return FALSE; + } + +-static void poll_sdl_device_state(LPDIRECTINPUTDEVICE8A iface) ++static HRESULT poll_sdl_device_state( IDirectInputDevice8W *iface ) + { +- JoystickImpl *This = impl_from_IDirectInputDevice8A(iface); ++ JoystickImpl *This = impl_from_IDirectInputDevice8W( iface ); + int i = 0; +@@ -701,6 +701,9 @@ static void poll_sdl_device_state(LPDIRECTINPUTDEVICE8A iface) + int newVal = 0; + struct device_state_item item; + ++ if(!SDL_JoystickGetAttached(This->device)) ++ return DIERR_INPUTLOST; ++ + SDL_JoystickUpdate(); + + while(This->enum_device_state(This, &item, i++)) +@@ -784,6 +787,8 @@ static void poll_sdl_device_state(LPDIRECTINPUTDEVICE8A iface) + } + } + } ++ ++ return DI_OK; + } + + static enum_device_state_function select_enum_function(struct SDLDev *sdldev) +From b784af044fbd90ee74ba43f36aad8c314803ff4c Mon Sep 17 00:00:00 2001 +From: Andrew Eikum +Date: Thu, 12 Sep 2019 12:35:08 -0500 +Subject: [PATCH] dinput: Keep track of joysticks even after disconnected + +--- + dlls/dinput/joystick_sdl.c | 107 +++++++++++++++++++++---------------- + 1 file changed, 61 insertions(+), 46 deletions(-) + +diff --git a/dlls/dinput/joystick_sdl.c b/dlls/dinput/joystick_sdl.c +index 1b39977add5..2e0423b78ab 100644 +--- a/dlls/dinput/joystick_sdl.c ++++ b/dlls/dinput/joystick_sdl.c +@@ -96,7 +96,9 @@ struct device_state_item { + typedef BOOL (*enum_device_state_function)(JoystickImpl*, struct device_state_item *, int); + + struct SDLDev { +- int id; ++ BOOL valid; ++ ++ int instance_id; + WORD vendor_id; + WORD product_id; + CHAR *name; +@@ -141,8 +143,16 @@ static const GUID DInput_Wine_SDL_Joystick_GUID = { /* 001E36B7-5DBA-4C4F-A8C9-C + 0x001E36B7, 0x5DBA, 0x4C4F, {0xA8, 0xC9, 0xCF, 0xC8, 0x68, 0x9D, 0xB4, 0x03} + }; + +-static int have_sdldevs = -1; +-static struct SDLDev *sdldevs = NULL; ++static CRITICAL_SECTION sdldevs_lock; ++static CRITICAL_SECTION_DEBUG sdldevs_lock_debug = ++{ ++ 0, 0, &sdldevs_lock, ++ { &sdldevs_lock_debug.ProcessLocksList, &sdldevs_lock_debug.ProcessLocksList }, ++ 0, 0, { (DWORD_PTR)(__FILE__ ": sdldevs_lock") } ++}; ++static CRITICAL_SECTION sdldevs_lock = { &sdldevs_lock_debug, -1, 0, 0, 0, 0 }; ++ ++static struct SDLDev sdldevs[64]; + + /* logic from SDL2's SDL_ShouldIgnoreGameController */ + static BOOL is_in_sdl_blacklist(DWORD vid, DWORD pid) +@@ -179,6 +189,7 @@ static void find_sdldevs(void) + Uint16 (*pSDL_JoystickGetProduct)(SDL_Joystick * joystick) = NULL; + Uint16 (*pSDL_JoystickGetVendor)(SDL_Joystick * joystick) = NULL; + void *sdl_handle = NULL; ++ static int have_sdldevs = -1; + + if (InterlockedCompareExchange(&have_sdldevs, 0, -1) != -1) + /* Someone beat us to it */ +@@ -199,25 +210,24 @@ static void find_sdldevs(void) + + for (i = 0; i < SDL_NumJoysticks(); i++) + { +- struct SDLDev sdldev = {0}; +- struct SDLDev *new_sdldevs; ++ struct SDLDev *sdldev = &sdldevs[have_sdldevs]; + SDL_Joystick *device; + const CHAR* name; + +- sdldev.id = i; + device = SDL_JoystickOpen(i); ++ sdldev->instance_id = SDL_JoystickInstanceID(device); + + name = SDL_JoystickName(device); +- sdldev.name = HeapAlloc(GetProcessHeap(), 0, strlen(name) + 1); +- strcpy(sdldev.name, name); ++ sdldev->name = HeapAlloc(GetProcessHeap(), 0, strlen(name) + 1); ++ strcpy(sdldev->name, name); + +- if (device_disabled_registry(sdldev.name)) { ++ if (device_disabled_registry(sdldev->name)) { + SDL_JoystickClose(device); +- HeapFree(GetProcessHeap(), 0, sdldev.name); ++ HeapFree(GetProcessHeap(), 0, sdldev->name); + continue; + } + +- TRACE("Found a joystick (%i) on %p: %s\n", have_sdldevs, device, sdldev.name); ++ TRACE("Found a joystick (%i) on %p: %s\n", have_sdldevs, device, sdldev->name); + + if (SDL_JoystickIsHaptic(device)) + { +@@ -225,56 +235,48 @@ static void find_sdldevs(void) + if (haptic) + { + TRACE(" ... with force feedback\n"); +- sdldev.has_ff = TRUE; ++ sdldev->has_ff = TRUE; + SDL_HapticClose(haptic); + } + } + + if(pSDL_JoystickGetVendor){ +- sdldev.vendor_id = pSDL_JoystickGetVendor(device); +- sdldev.product_id = pSDL_JoystickGetProduct(device); ++ sdldev->vendor_id = pSDL_JoystickGetVendor(device); ++ sdldev->product_id = pSDL_JoystickGetProduct(device); + }else{ +- sdldev.vendor_id = 0x01; +- sdldev.product_id = SDL_JoystickInstanceID(device) + 1; ++ sdldev->vendor_id = 0x01; ++ sdldev->product_id = SDL_JoystickInstanceID(device) + 1; + } + +- if(is_in_sdl_blacklist(sdldev.vendor_id, sdldev.product_id)) ++ if(is_in_sdl_blacklist(sdldev->vendor_id, sdldev->product_id)) + { +- TRACE("joystick %04x/%04x is in SDL blacklist, ignoring\n", sdldev.vendor_id, sdldev.product_id); ++ TRACE("joystick %04x/%04x is in SDL blacklist, ignoring\n", sdldev->vendor_id, sdldev->product_id); + SDL_JoystickClose(device); + continue; + } + +- if(sdldev.vendor_id == VID_VALVE && sdldev.product_id == PID_VALVE_VIRTUAL_CONTROLLER) ++ if(sdldev->vendor_id == VID_VALVE && sdldev->product_id == PID_VALVE_VIRTUAL_CONTROLLER) + { +- sdldev.vendor_id = VID_MICROSOFT; +- sdldev.product_id = PID_MICROSOFT_XBOX_360; ++ sdldev->vendor_id = VID_MICROSOFT; ++ sdldev->product_id = PID_MICROSOFT_XBOX_360; + } + + { + SDL_JoystickType type = SDL_JoystickGetType(device); +- sdldev.is_joystick = ++ sdldev->is_joystick = + type == SDL_JOYSTICK_TYPE_WHEEL || + type == SDL_JOYSTICK_TYPE_FLIGHT_STICK || + type == SDL_JOYSTICK_TYPE_THROTTLE; + } + +- sdldev.n_buttons = SDL_JoystickNumButtons(device); +- sdldev.n_axes = SDL_JoystickNumAxes(device); +- sdldev.n_hats = SDL_JoystickNumHats(device); ++ sdldev->n_buttons = SDL_JoystickNumButtons(device); ++ sdldev->n_axes = SDL_JoystickNumAxes(device); ++ sdldev->n_hats = SDL_JoystickNumHats(device); + +- if (!have_sdldevs) +- new_sdldevs = HeapAlloc(GetProcessHeap(), 0, sizeof(struct SDLDev)); +- else +- new_sdldevs = HeapReAlloc(GetProcessHeap(), 0, sdldevs, (1 + have_sdldevs) * sizeof(struct SDLDev)); ++ sdldev->valid = TRUE; + + SDL_JoystickClose(device); +- if (!new_sdldevs) +- { +- continue; +- } +- sdldevs = new_sdldevs; +- sdldevs[have_sdldevs] = sdldev; ++ + have_sdldevs++; + } + } +@@ -413,9 +415,8 @@ static HRESULT sdl_enum_deviceA(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTAN + { + find_sdldevs(); + +- if (id >= have_sdldevs) { +- return E_FAIL; +- } ++ if (id >= ARRAY_SIZE(sdldevs) || !sdldevs[id].valid) ++ return E_FAIL; + + if (!((dwDevType == 0) || + ((dwDevType == DIDEVTYPE_JOYSTICK) && (version >= 0x0300 && version < 0x0800)) || +@@ -431,11 +432,13 @@ static HRESULT sdl_enum_deviceA(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTAN + + static HRESULT sdl_enum_deviceW(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEW lpddi, DWORD version, int id) + { +- find_sdldevs(); ++ find_sdldevs(); + +- if (id >= have_sdldevs) { +- return E_FAIL; +- } ++ if (id >= ARRAY_SIZE(sdldevs) || !sdldevs[id].valid) ++ return E_FAIL; ++ ++ if (!sdldevs[id].valid) ++ return E_FAIL; + + if (!((dwDevType == 0) || + ((dwDevType == DIDEVTYPE_JOYSTICK) && (version >= 0x0300 && version < 0x0800)) || +@@ -821,6 +824,17 @@ static JoystickImpl *alloc_device(REFGUID rguid, IDirectInputImpl *dinput, unsig + DIDEVICEINSTANCEW ddi; + int i,idx = 0, axis_count = 0, button_count = 0, hat_count = 0; + struct device_state_item item; ++ SDL_Joystick *sdl_js; ++ ++ sdl_js = SDL_JoystickFromInstanceID(sdldevs[index].instance_id); ++ if (!sdl_js) ++ return NULL; ++ ++ if (!SDL_JoystickGetAttached(sdl_js)) ++ { ++ SDL_JoystickClose(sdl_js); ++ return NULL; ++ } + + newDevice = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(JoystickImpl)); + if (!newDevice) return NULL; +@@ -847,7 +861,7 @@ static JoystickImpl *alloc_device(REFGUID rguid, IDirectInputImpl *dinput, unsig + newDevice->generic.base.crit.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": JoystickImpl*->base.crit"); + + /* Open Device */ +- newDevice->device = SDL_JoystickOpen(newDevice->sdldev->id); ++ newDevice->device = sdl_js; + newDevice->haptic = SDL_HapticOpenFromJoystick(newDevice->device); + + i = 0; +@@ -983,8 +997,7 @@ static HRESULT sdl_create_device(IDirectInputImpl *dinput, REFGUID rguid, REFIID + find_sdldevs(); + *pdev = NULL; + +- if ((index = get_joystick_index(rguid)) < 0xffff && +- have_sdldevs && index < have_sdldevs) ++ if ((index = get_joystick_index(rguid)) < 0xffff && sdldevs[index].valid) + { + JoystickImpl *This; + +@@ -1011,6 +1024,8 @@ static HRESULT sdl_create_device(IDirectInputImpl *dinput, REFGUID rguid, REFIID + } + + This = alloc_device(rguid, dinput, index); ++ if (!This) ++ return DIERR_INPUTLOST; + TRACE("Created a Joystick device (%p)\n", This); + + if (!This) return DIERR_OUTOFMEMORY; +@@ -1097,7 +1112,7 @@ static HRESULT WINAPI JoystickWImpl_GetProperty(LPDIRECTINPUTDEVICE8W iface, REF + { + LPDIPROPDWORD pd = (LPDIPROPDWORD)pdiph; + +- pd->dwData = This->sdldev->id; ++ pd->dwData = This->sdldev - sdldevs; + TRACE("DIPROP_JOYSTICKID(%d)\n", pd->dwData); + break; + } +From fdef0593bbf6e83829abf7fae3c41bd09505b31c Mon Sep 17 00:00:00 2001 +From: Andrew Eikum +Date: Thu, 12 Sep 2019 14:21:08 -0500 +Subject: [PATCH] dinput: Poll for new SDL devices when requested + +--- + dlls/dinput/joystick_sdl.c | 136 ++++++++++++++++++++++++------------- + 1 file changed, 90 insertions(+), 46 deletions(-) + +diff --git a/dlls/dinput/joystick_sdl.c b/dlls/dinput/joystick_sdl.c +index 2e0423b78ab..ee0af983909 100644 +--- a/dlls/dinput/joystick_sdl.c ++++ b/dlls/dinput/joystick_sdl.c +@@ -108,6 +108,9 @@ struct SDLDev { + BOOL has_ff, is_joystick; + int autocenter; + int gain; ++ ++ SDL_Joystick *sdl_js; ++ + struct list effects; + }; + +@@ -183,20 +186,12 @@ static BOOL is_in_sdl_blacklist(DWORD vid, DWORD pid) + return strcasestr(blacklist, needle) != NULL; + } + +-static void find_sdldevs(void) ++static Uint16 (*pSDL_JoystickGetProduct)(SDL_Joystick *); ++static Uint16 (*pSDL_JoystickGetVendor)(SDL_Joystick *); ++ ++static BOOL WINAPI sdldrv_init(INIT_ONCE *once, void *param, void **context) + { +- int i; +- Uint16 (*pSDL_JoystickGetProduct)(SDL_Joystick * joystick) = NULL; +- Uint16 (*pSDL_JoystickGetVendor)(SDL_Joystick * joystick) = NULL; + void *sdl_handle = NULL; +- static int have_sdldevs = -1; +- +- if (InterlockedCompareExchange(&have_sdldevs, 0, -1) != -1) +- /* Someone beat us to it */ +- return; +- +- SDL_Init(SDL_INIT_JOYSTICK|SDL_INIT_HAPTIC); +- SDL_JoystickEventState(SDL_ENABLE); + + sdl_handle = dlopen(SONAME_LIBSDL2, RTLD_NOW); + if (sdl_handle) { +@@ -208,12 +203,59 @@ static void find_sdldevs(void) + ERR("SDL installation is old! Please upgrade to >=2.0.6 to get accurate joystick information.\n"); + } + ++ SDL_Init(SDL_INIT_JOYSTICK|SDL_INIT_HAPTIC); ++ SDL_JoystickEventState(SDL_ENABLE); ++ ++ return TRUE; ++} ++ ++static void find_sdldevs(void) ++{ ++ static INIT_ONCE init_once = INIT_ONCE_STATIC_INIT; ++ static ULONGLONG last_check = 0; ++ ULONGLONG now; ++ int i; ++ ++ InitOnceExecuteOnce(&init_once, sdldrv_init, NULL, NULL); ++ ++ SDL_PumpEvents(); ++ ++ now = GetTickCount64(); ++ ++ if(last_check > 0 && last_check + 1000 > now) ++ return; ++ ++ last_check = now; ++ ++ EnterCriticalSection(&sdldevs_lock); ++ + for (i = 0; i < SDL_NumJoysticks(); i++) + { +- struct SDLDev *sdldev = &sdldevs[have_sdldevs]; ++ struct SDLDev *sdldev = &sdldevs[0]; + SDL_Joystick *device; + const CHAR* name; + ++ while(sdldev < &sdldevs[ARRAY_SIZE(sdldevs)] && ++ sdldev->valid) ++ { ++ if(sdldev->instance_id == SDL_JoystickGetDeviceInstanceID(i)) ++ break; ++ sdldev++; ++ } ++ ++ if(sdldev >= &sdldevs[ARRAY_SIZE(sdldevs)]) ++ { ++ ERR("ran out of joystick slots!!\n"); ++ LeaveCriticalSection(&sdldevs_lock); ++ return; ++ } ++ ++ if(sdldev->valid) ++ { ++ /* this joystic is already discovered */ ++ continue; ++ } ++ + device = SDL_JoystickOpen(i); + sdldev->instance_id = SDL_JoystickInstanceID(device); + +@@ -227,7 +269,7 @@ static void find_sdldevs(void) + continue; + } + +- TRACE("Found a joystick (%i) on %p: %s\n", have_sdldevs, device, sdldev->name); ++ TRACE("Found a joystick on %p: %s\n", device, sdldev->name); + + if (SDL_JoystickIsHaptic(device)) + { +@@ -252,6 +294,7 @@ static void find_sdldevs(void) + { + TRACE("joystick %04x/%04x is in SDL blacklist, ignoring\n", sdldev->vendor_id, sdldev->product_id); + SDL_JoystickClose(device); ++ HeapFree(GetProcessHeap(), 0, sdldev->name); + continue; + } + +@@ -273,12 +316,13 @@ static void find_sdldevs(void) + sdldev->n_axes = SDL_JoystickNumAxes(device); + sdldev->n_hats = SDL_JoystickNumHats(device); + +- sdldev->valid = TRUE; +- +- SDL_JoystickClose(device); ++ sdldev->sdl_js = device; + +- have_sdldevs++; ++ /* must be last member to be set */ ++ sdldev->valid = TRUE; + } ++ ++ LeaveCriticalSection(&sdldevs_lock); + } + + static struct device_info_override { +@@ -413,21 +457,27 @@ static void fill_joystick_dideviceinstanceW(LPDIDEVICEINSTANCEW lpddi, DWORD ver + + static HRESULT sdl_enum_deviceA(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEA lpddi, DWORD version, int id) + { +- find_sdldevs(); ++ find_sdldevs(); + + if (id >= ARRAY_SIZE(sdldevs) || !sdldevs[id].valid) + return E_FAIL; + +- if (!((dwDevType == 0) || +- ((dwDevType == DIDEVTYPE_JOYSTICK) && (version >= 0x0300 && version < 0x0800)) || +- (((dwDevType == DI8DEVCLASS_GAMECTRL) || (dwDevType == DI8DEVTYPE_JOYSTICK)) && (version >= 0x0800)))) +- return S_FALSE; ++ if (!((dwDevType == 0) || ++ ((dwDevType == DIDEVTYPE_JOYSTICK) && (version >= 0x0300 && version < 0x0800)) || ++ (((dwDevType == DI8DEVCLASS_GAMECTRL) || (dwDevType == DI8DEVTYPE_JOYSTICK)) && (version >= 0x0800)))) ++ return S_FALSE; ++ ++ if ((dwFlags & DIEDFL_FORCEFEEDBACK) && !sdldevs[id].has_ff) ++ return S_FALSE; ++ ++ if (dwFlags & DIEDFL_ATTACHEDONLY) ++ { ++ if (!SDL_JoystickGetAttached(sdldevs[id].sdl_js)) ++ return S_FALSE; ++ } + +- if (!(dwFlags & DIEDFL_FORCEFEEDBACK) || sdldevs[id].has_ff) { + fill_joystick_dideviceinstanceA(lpddi, version, id); + return S_OK; +- } +- return S_FALSE; + } + + static HRESULT sdl_enum_deviceW(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEW lpddi, DWORD version, int id) +@@ -437,19 +487,22 @@ static HRESULT sdl_enum_deviceW(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTAN + if (id >= ARRAY_SIZE(sdldevs) || !sdldevs[id].valid) + return E_FAIL; + +- if (!sdldevs[id].valid) +- return E_FAIL; ++ if (!((dwDevType == 0) || ++ ((dwDevType == DIDEVTYPE_JOYSTICK) && (version >= 0x0300 && version < 0x0800)) || ++ (((dwDevType == DI8DEVCLASS_GAMECTRL) || (dwDevType == DI8DEVTYPE_JOYSTICK)) && (version >= 0x0800)))) ++ return S_FALSE; ++ ++ if ((dwFlags & DIEDFL_FORCEFEEDBACK) && !sdldevs[id].has_ff) ++ return S_FALSE; + +- if (!((dwDevType == 0) || +- ((dwDevType == DIDEVTYPE_JOYSTICK) && (version >= 0x0300 && version < 0x0800)) || +- (((dwDevType == DI8DEVCLASS_GAMECTRL) || (dwDevType == DI8DEVTYPE_JOYSTICK)) && (version >= 0x0800)))) +- return S_FALSE; ++ if (dwFlags & DIEDFL_ATTACHEDONLY) ++ { ++ if (!SDL_JoystickGetAttached(sdldevs[id].sdl_js)) ++ return S_FALSE; ++ } + +- if (!(dwFlags & DIEDFL_FORCEFEEDBACK) || sdldevs[id].has_ff) { + fill_joystick_dideviceinstanceW(lpddi, version, id); + return S_OK; +- } +- return S_FALSE; + } + + static int buttons_to_sdl_hat(int u, int r, int d, int l) +@@ -824,18 +877,10 @@ static JoystickImpl *alloc_device(REFGUID rguid, IDirectInputImpl *dinput, unsig + DIDEVICEINSTANCEW ddi; + int i,idx = 0, axis_count = 0, button_count = 0, hat_count = 0; + struct device_state_item item; +- SDL_Joystick *sdl_js; + +- sdl_js = SDL_JoystickFromInstanceID(sdldevs[index].instance_id); +- if (!sdl_js) ++ if (!SDL_JoystickGetAttached(sdldevs[index].sdl_js)) + return NULL; + +- if (!SDL_JoystickGetAttached(sdl_js)) +- { +- SDL_JoystickClose(sdl_js); +- return NULL; +- } +- + newDevice = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(JoystickImpl)); + if (!newDevice) return NULL; + +@@ -861,7 +906,7 @@ static JoystickImpl *alloc_device(REFGUID rguid, IDirectInputImpl *dinput, unsig + newDevice->generic.base.crit.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": JoystickImpl*->base.crit"); + + /* Open Device */ +- newDevice->device = sdl_js; ++ newDevice->device = sdldevs[index].sdl_js; + newDevice->haptic = SDL_HapticOpenFromJoystick(newDevice->device); + + i = 0; +@@ -1057,7 +1102,6 @@ static ULONG WINAPI JoystickWImpl_Release(LPDIRECTINPUTDEVICE8W iface) + TRACE("Closing Joystick: %p\n",This); + if (This->sdldev->has_ff) + SDL_HapticClose(This->haptic); +- SDL_JoystickClose(This->device); + This->device = NULL; + } + return IDirectInputDevice2WImpl_Release(iface); +From 1a701c311a5cf6ad7dc31f089c8f9fd5bb05ddb0 Mon Sep 17 00:00:00 2001 +From: Andrew Eikum +Date: Mon, 16 Sep 2019 12:31:37 -0500 +Subject: [PATCH] dinput: Access SDL_Joystick member once per operation + +In case it changes out from under us. +--- + dlls/dinput/joystick_sdl.c | 103 +++++++++++++++++-------------------- + 1 file changed, 48 insertions(+), 55 deletions(-) + +diff --git a/dlls/dinput/joystick_sdl.c b/dlls/dinput/joystick_sdl.c +index ee0af983909..3b2c1954863 100644 +--- a/dlls/dinput/joystick_sdl.c ++++ b/dlls/dinput/joystick_sdl.c +@@ -93,7 +93,7 @@ struct device_state_item { + int val; + }; + +-typedef BOOL (*enum_device_state_function)(JoystickImpl*, struct device_state_item *, int); ++typedef BOOL (*enum_device_state_function)(SDL_Joystick *, JoystickImpl *, struct device_state_item *, int); + + struct SDLDev { + BOOL valid; +@@ -105,11 +105,12 @@ struct SDLDev { + + int n_buttons, n_axes, n_hats; + +- BOOL has_ff, is_joystick; ++ BOOL is_joystick; + int autocenter; + int gain; + + SDL_Joystick *sdl_js; ++ SDL_Haptic *sdl_haptic; + + struct list effects; + }; +@@ -119,8 +120,6 @@ struct JoystickImpl + struct JoystickGenericImpl generic; + struct SDLDev *sdldev; + +- SDL_Joystick *device; +- SDL_Haptic *haptic; + BOOL ff_paused; + + enum_device_state_function enum_device_state; +@@ -233,6 +232,7 @@ static void find_sdldevs(void) + { + struct SDLDev *sdldev = &sdldevs[0]; + SDL_Joystick *device; ++ SDL_Haptic *haptic = NULL; + const CHAR* name; + + while(sdldev < &sdldevs[ARRAY_SIZE(sdldevs)] && +@@ -273,12 +273,10 @@ static void find_sdldevs(void) + + if (SDL_JoystickIsHaptic(device)) + { +- SDL_Haptic *haptic = SDL_HapticOpenFromJoystick(device); ++ haptic = SDL_HapticOpenFromJoystick(device); + if (haptic) + { + TRACE(" ... with force feedback\n"); +- sdldev->has_ff = TRUE; +- SDL_HapticClose(haptic); + } + } + +@@ -317,6 +315,7 @@ static void find_sdldevs(void) + sdldev->n_hats = SDL_JoystickNumHats(device); + + sdldev->sdl_js = device; ++ sdldev->sdl_haptic = haptic; + + /* must be last member to be set */ + sdldev->valid = TRUE; +@@ -467,7 +466,7 @@ static HRESULT sdl_enum_deviceA(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTAN + (((dwDevType == DI8DEVCLASS_GAMECTRL) || (dwDevType == DI8DEVTYPE_JOYSTICK)) && (version >= 0x0800)))) + return S_FALSE; + +- if ((dwFlags & DIEDFL_FORCEFEEDBACK) && !sdldevs[id].has_ff) ++ if ((dwFlags & DIEDFL_FORCEFEEDBACK) && !sdldevs[id].sdl_haptic) + return S_FALSE; + + if (dwFlags & DIEDFL_ATTACHEDONLY) +@@ -492,7 +491,7 @@ static HRESULT sdl_enum_deviceW(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTAN + (((dwDevType == DI8DEVCLASS_GAMECTRL) || (dwDevType == DI8DEVTYPE_JOYSTICK)) && (version >= 0x0800)))) + return S_FALSE; + +- if ((dwFlags & DIEDFL_FORCEFEEDBACK) && !sdldevs[id].has_ff) ++ if ((dwFlags & DIEDFL_FORCEFEEDBACK) && !sdldevs[id].sdl_haptic) + return S_FALSE; + + if (dwFlags & DIEDFL_ATTACHEDONLY) +@@ -531,7 +530,7 @@ static int buttons_to_sdl_hat(int u, int r, int d, int l) + } + + /* playstation controllers */ +-static BOOL enum_device_state_ds4_16button(JoystickImpl *This, struct device_state_item *st, int idx) ++static BOOL enum_device_state_ds4_16button(SDL_Joystick *js, JoystickImpl *This, struct device_state_item *st, int idx) + { + #define SPECIALCASE_HAT -1 + #define SPECIALCASE_L2_BUTTON -2 +@@ -583,15 +582,15 @@ static BOOL enum_device_state_ds4_16button(JoystickImpl *This, struct device_sta + switch(map_ds4_16button[idx].type) + { + case ITEM_TYPE_BUTTON: +- st->val = SDL_JoystickGetButton(This->device, map_ds4_16button[idx].sdl_idx); ++ st->val = SDL_JoystickGetButton(js, map_ds4_16button[idx].sdl_idx); + return TRUE; + + case ITEM_TYPE_AXIS: +- st->val = SDL_JoystickGetAxis(This->device, map_ds4_16button[idx].sdl_idx); ++ st->val = SDL_JoystickGetAxis(js, map_ds4_16button[idx].sdl_idx); + return TRUE; + + case ITEM_TYPE_HAT: +- st->val = SDL_JoystickGetHat(This->device, map_ds4_16button[idx].sdl_idx); ++ st->val = SDL_JoystickGetHat(js, map_ds4_16button[idx].sdl_idx); + return TRUE; + } + } +@@ -605,10 +604,10 @@ static BOOL enum_device_state_ds4_16button(JoystickImpl *This, struct device_sta + static const int SDL_DPAD_LEFT_BUTTON = 13; + static const int SDL_DPAD_RIGHT_BUTTON = 14; + st->val = buttons_to_sdl_hat( +- SDL_JoystickGetButton(This->device, SDL_DPAD_UP_BUTTON), +- SDL_JoystickGetButton(This->device, SDL_DPAD_RIGHT_BUTTON), +- SDL_JoystickGetButton(This->device, SDL_DPAD_DOWN_BUTTON), +- SDL_JoystickGetButton(This->device, SDL_DPAD_LEFT_BUTTON)); ++ SDL_JoystickGetButton(js, SDL_DPAD_UP_BUTTON), ++ SDL_JoystickGetButton(js, SDL_DPAD_RIGHT_BUTTON), ++ SDL_JoystickGetButton(js, SDL_DPAD_DOWN_BUTTON), ++ SDL_JoystickGetButton(js, SDL_DPAD_LEFT_BUTTON)); + return TRUE; + } + +@@ -617,7 +616,7 @@ static BOOL enum_device_state_ds4_16button(JoystickImpl *This, struct device_sta + /* L2 button */ + /* turn button on at about 1/8 of the trigger travel */ + static const int SDL_L2_AXIS = 4; +- st->val = SDL_JoystickGetAxis(This->device, SDL_L2_AXIS) > 3 * SDL_JOYSTICK_AXIS_MIN / 4; ++ st->val = SDL_JoystickGetAxis(js, SDL_L2_AXIS) > 3 * SDL_JOYSTICK_AXIS_MIN / 4; + return TRUE; + } + +@@ -626,7 +625,7 @@ static BOOL enum_device_state_ds4_16button(JoystickImpl *This, struct device_sta + /* R2 button */ + /* turn button on at about 1/8 of the trigger travel */ + static const int SDL_R2_AXIS = 5; +- st->val = SDL_JoystickGetAxis(This->device, SDL_R2_AXIS) > 3 * SDL_JOYSTICK_AXIS_MIN / 4; ++ st->val = SDL_JoystickGetAxis(js, SDL_R2_AXIS) > 3 * SDL_JOYSTICK_AXIS_MIN / 4; + return TRUE; + } + } +@@ -639,7 +638,7 @@ static BOOL enum_device_state_ds4_16button(JoystickImpl *This, struct device_sta + #undef SPECIALCASE_R2_BUTTON + } + +-static BOOL enum_device_state_ds4_13button(JoystickImpl *This, struct device_state_item *st, int idx) ++static BOOL enum_device_state_ds4_13button(SDL_Joystick *js, JoystickImpl *This, struct device_state_item *st, int idx) + { + static const struct { + int type; +@@ -691,15 +690,15 @@ static BOOL enum_device_state_ds4_13button(JoystickImpl *This, struct device_sta + switch(map_ds4_13button[idx].type) + { + case ITEM_TYPE_BUTTON: +- st->val = SDL_JoystickGetButton(This->device, map_ds4_13button[idx].sdl_idx); ++ st->val = SDL_JoystickGetButton(js, map_ds4_13button[idx].sdl_idx); + return TRUE; + + case ITEM_TYPE_AXIS: +- st->val = SDL_JoystickGetAxis(This->device, map_ds4_13button[idx].sdl_idx); ++ st->val = SDL_JoystickGetAxis(js, map_ds4_13button[idx].sdl_idx); + return TRUE; + + case ITEM_TYPE_HAT: +- st->val = SDL_JoystickGetHat(This->device, map_ds4_13button[idx].sdl_idx); ++ st->val = SDL_JoystickGetHat(js, map_ds4_13button[idx].sdl_idx); + return TRUE; + } + +@@ -708,7 +707,7 @@ static BOOL enum_device_state_ds4_13button(JoystickImpl *This, struct device_sta + } + + /* straight 1:1 mapping of SDL items and dinput items */ +-static BOOL enum_device_state_standard(JoystickImpl *This, struct device_state_item *st, int idx) ++static BOOL enum_device_state_standard(SDL_Joystick *js, JoystickImpl *This, struct device_state_item *st, int idx) + { + DWORD n_buttons, n_axes, n_hats; + +@@ -718,7 +717,7 @@ static BOOL enum_device_state_standard(JoystickImpl *This, struct device_state_i + { + st->type = ITEM_TYPE_BUTTON; + st->id = idx; +- st->val = SDL_JoystickGetButton(This->device, idx); ++ st->val = SDL_JoystickGetButton(js, idx); + return TRUE; + } + +@@ -730,7 +729,7 @@ static BOOL enum_device_state_standard(JoystickImpl *This, struct device_state_i + { + st->type = ITEM_TYPE_AXIS; + st->id = idx; +- st->val = SDL_JoystickGetAxis(This->device, idx); ++ st->val = SDL_JoystickGetAxis(js, idx); + return TRUE; + } + +@@ -742,7 +741,7 @@ static BOOL enum_device_state_standard(JoystickImpl *This, struct device_state_i + { + st->type = ITEM_TYPE_HAT; + st->id = idx; +- st->val = SDL_JoystickGetHat(This->device, idx); ++ st->val = SDL_JoystickGetHat(js, idx); + return TRUE; + } + +@@ -756,13 +755,14 @@ static HRESULT poll_sdl_device_state(LPDIRECTINPUTDEVICE8A iface) + int inst_id = 0; + int newVal = 0; + struct device_state_item item; ++ SDL_Joystick *js = This->sdldev->sdl_js; + +- if(!SDL_JoystickGetAttached(This->device)) ++ if(!SDL_JoystickGetAttached(js)) + return DIERR_INPUTLOST; + + SDL_JoystickUpdate(); + +- while(This->enum_device_state(This, &item, i++)) ++ while(This->enum_device_state(js, This, &item, i++)) + { + switch(item.type){ + case ITEM_TYPE_BUTTON: +@@ -877,8 +877,11 @@ static JoystickImpl *alloc_device(REFGUID rguid, IDirectInputImpl *dinput, unsig + DIDEVICEINSTANCEW ddi; + int i,idx = 0, axis_count = 0, button_count = 0, hat_count = 0; + struct device_state_item item; ++ SDL_Joystick *js; + +- if (!SDL_JoystickGetAttached(sdldevs[index].sdl_js)) ++ js = sdldevs[index].sdl_js; ++ ++ if (!SDL_JoystickGetAttached(js)) + return NULL; + + newDevice = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(JoystickImpl)); +@@ -906,11 +909,9 @@ static JoystickImpl *alloc_device(REFGUID rguid, IDirectInputImpl *dinput, unsig + newDevice->generic.base.crit.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": JoystickImpl*->base.crit"); + + /* Open Device */ +- newDevice->device = sdldevs[index].sdl_js; +- newDevice->haptic = SDL_HapticOpenFromJoystick(newDevice->device); + + i = 0; +- while(newDevice->enum_device_state(newDevice, &item, i++)){ ++ while(newDevice->enum_device_state(js, newDevice, &item, i++)){ + switch(item.type){ + case ITEM_TYPE_BUTTON: + ++button_count; +@@ -955,7 +956,7 @@ static JoystickImpl *alloc_device(REFGUID rguid, IDirectInputImpl *dinput, unsig + if (!(df->rgodf = HeapAlloc(GetProcessHeap(), 0, df->dwNumObjs * df->dwObjSize))) goto failed; + + i = 0; +- while(newDevice->enum_device_state(newDevice, &item, i++)){ ++ while(newDevice->enum_device_state(js, newDevice, &item, i++)){ + switch(item.type){ + case ITEM_TYPE_BUTTON: + memcpy(&df->rgodf[idx], &c_dfDIJoystick2.rgodf[item.id + 12], df->dwObjSize); +@@ -966,7 +967,7 @@ static JoystickImpl *alloc_device(REFGUID rguid, IDirectInputImpl *dinput, unsig + case ITEM_TYPE_AXIS: + memcpy(&df->rgodf[idx], &c_dfDIJoystick2.rgodf[item.id], df->dwObjSize); + df->rgodf[idx].dwType = DIDFT_MAKEINSTANCE(item.id) | DIDFT_ABSAXIS; +- if (newDevice->sdldev->has_ff && item.id < 2) ++ if (newDevice->sdldev->sdl_haptic && item.id < 2) + df->rgodf[idx].dwFlags |= DIDOI_FFACTUATOR; + + newDevice->generic.props[idx].lDevMin = -32768; +@@ -986,7 +987,7 @@ static JoystickImpl *alloc_device(REFGUID rguid, IDirectInputImpl *dinput, unsig + } + } + +- if (newDevice->sdldev->has_ff) ++ if (newDevice->sdldev->sdl_haptic) + newDevice->generic.devcaps.dwFlags |= DIDC_FORCEFEEDBACK; + + newDevice->generic.base.data_format.wine_df = df; +@@ -999,7 +1000,7 @@ static JoystickImpl *alloc_device(REFGUID rguid, IDirectInputImpl *dinput, unsig + fill_joystick_dideviceinstanceW(&ddi, newDevice->generic.base.dinput->dwVersion, index); + newDevice->generic.devcaps.dwDevType = ddi.dwDevType; + +- if (newDevice->sdldev->has_ff) ++ if (newDevice->sdldev->sdl_haptic) + newDevice->generic.devcaps.dwFlags |= DIDC_FORCEFEEDBACK; + + IDirectInput_AddRef(&newDevice->generic.base.dinput->IDirectInput7A_iface); +@@ -1095,15 +1096,7 @@ const struct dinput_device joystick_sdl_device = { + + static ULONG WINAPI JoystickWImpl_Release(LPDIRECTINPUTDEVICE8W iface) + { +- JoystickImpl *This = impl_from_IDirectInputDevice8W(iface); + TRACE("(this=%p)\n", iface); +- if (This->generic.base.ref == 1 && This->device >= 0) +- { +- TRACE("Closing Joystick: %p\n",This); +- if (This->sdldev->has_ff) +- SDL_HapticClose(This->haptic); +- This->device = NULL; +- } + return IDirectInputDevice2WImpl_Release(iface); + } + +@@ -1257,7 +1250,7 @@ static BOOL _SetProperty(JoystickImpl *This, const GUID *prop, const DIPROPHEADE + + This->sdldev->autocenter = pd->dwData == DIPROPAUTOCENTER_ON; + +- rc = SDL_HapticSetAutocenter(This->haptic, This->sdldev->autocenter * 100); ++ rc = SDL_HapticSetAutocenter(This->sdldev->sdl_haptic, This->sdldev->autocenter * 100); + if (rc != 0) + ERR("SDL_HapticSetAutocenter failed: %s\n", SDL_GetError()); + break; +@@ -1271,7 +1264,7 @@ static BOOL _SetProperty(JoystickImpl *This, const GUID *prop, const DIPROPHEADE + + This->sdldev->gain = pd->dwData; + +- rc = SDL_HapticSetGain(This->haptic, sdl_gain); ++ rc = SDL_HapticSetGain(This->sdldev->sdl_haptic, sdl_gain); + if (rc != 0) + ERR("SDL_HapticSetGain (%i -> %i) failed: %s\n", pd->dwData, sdl_gain, SDL_GetError()); + break; +@@ -1357,7 +1350,7 @@ static HRESULT WINAPI JoystickWImpl_CreateEffect(IDirectInputDevice8W *iface, + TRACE("%p %s %p %p %p\n", iface, debugstr_guid(rguid), lpeff, ppdef, pUnkOuter); + if (lpeff) dump_DIEFFECT(lpeff, rguid, 0); + +- if(!This->sdldev->has_ff){ ++ if(!This->sdldev->sdl_haptic){ + TRACE("No force feedback support\n"); + *ppdef = NULL; + return DIERR_UNSUPPORTED; +@@ -1375,7 +1368,7 @@ static HRESULT WINAPI JoystickWImpl_CreateEffect(IDirectInputDevice8W *iface, + if (!(new_effect = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_effect)))) + return DIERR_OUTOFMEMORY; + +- retval = sdl_create_effect(This->haptic, rguid, &new_effect->entry, &new_effect->ref); ++ retval = sdl_create_effect(This->sdldev->sdl_haptic, rguid, &new_effect->entry, &new_effect->ref); + if (retval != DI_OK) + { + HeapFree(GetProcessHeap(), 0, new_effect); +@@ -1426,7 +1419,7 @@ static HRESULT WINAPI JoystickWImpl_EnumEffects(LPDIRECTINPUTDEVICE8W iface, + TRACE("(this=%p,%p,%d) type=%d\n", This, pvRef, dwEffType, type); + + dei.dwSize = sizeof(DIEFFECTINFOW); +- query = SDL_HapticQuery(This->haptic); ++ query = SDL_HapticQuery(This->sdldev->sdl_haptic); + TRACE("Effects 0x%x\n",query); + + if ((type == DIEFT_ALL || type == DIEFT_CONSTANTFORCE) +@@ -1507,7 +1500,7 @@ static HRESULT WINAPI JoystickAImpl_EnumEffects(LPDIRECTINPUTDEVICE8A iface, + TRACE("(this=%p,%p,%d) type=%d\n", This, pvRef, dwEffType, type); + + dei.dwSize = sizeof(DIEFFECTINFOA); +- query = SDL_HapticQuery(This->haptic); ++ query = SDL_HapticQuery(This->sdldev->sdl_haptic); + TRACE("Effects 0x%x\n",query); + + if ((type == DIEFT_ALL || type == DIEFT_CONSTANTFORCE) +@@ -1581,7 +1574,7 @@ static HRESULT WINAPI JoystickWImpl_GetEffectInfo(LPDIRECTINPUTDEVICE8W iface, + { + JoystickImpl* This = impl_from_IDirectInputDevice8W(iface); + TRACE("(this=%p,%p,%s)\n", This, pdei, _dump_dinput_GUID(guid)); +- return sdl_input_get_info_W(This->device, guid, pdei); ++ return sdl_input_get_info_W(This->sdldev->sdl_js, guid, pdei); + } + + static HRESULT WINAPI JoystickAImpl_GetEffectInfo(LPDIRECTINPUTDEVICE8A iface, +@@ -1590,7 +1583,7 @@ static HRESULT WINAPI JoystickAImpl_GetEffectInfo(LPDIRECTINPUTDEVICE8A iface, + { + JoystickImpl* This = impl_from_IDirectInputDevice8A(iface); + TRACE("(this=%p,%p,%s)\n", This, pdei, _dump_dinput_GUID(guid)); +- return sdl_input_get_info_A(This->device, guid, pdei); ++ return sdl_input_get_info_A(This->sdldev->sdl_js, guid, pdei); + } + + static HRESULT WINAPI JoystickWImpl_SendForceFeedbackCommand(LPDIRECTINPUTDEVICE8W iface, DWORD dwFlags) +@@ -1624,12 +1617,12 @@ static HRESULT WINAPI JoystickWImpl_SendForceFeedbackCommand(LPDIRECTINPUTDEVICE + } + case DISFFC_PAUSE: + This->ff_paused = TRUE; +- if (SDL_HapticPause(This->haptic) != 0) ++ if (SDL_HapticPause(This->sdldev->sdl_haptic) != 0) + ERR("SDL_HapticPause failed: %s\n",SDL_GetError()); + break; + case DISFFC_CONTINUE: + This->ff_paused = FALSE; +- if (SDL_HapticUnpause(This->haptic) != 0) ++ if (SDL_HapticUnpause(This->sdldev->sdl_haptic) != 0) + ERR("SDL_HapticUnpause failed: %s\n",SDL_GetError()); + break; + +From 15586bdc02108e9e0a2c38ef02f8156cbc417076 Mon Sep 17 00:00:00 2001 +From: Andrew Eikum +Date: Mon, 16 Sep 2019 13:49:06 -0500 +Subject: [PATCH] dinput: Check for new devices on every access + +--- + dlls/dinput/joystick_sdl.c | 36 +++++++++++++++++++++++++++++++++--- + 1 file changed, 33 insertions(+), 3 deletions(-) + +diff --git a/dlls/dinput/joystick_sdl.c b/dlls/dinput/joystick_sdl.c +index 3b2c1954863..d63289ecebe 100644 +--- a/dlls/dinput/joystick_sdl.c ++++ b/dlls/dinput/joystick_sdl.c +@@ -101,6 +101,7 @@ struct SDLDev { + int instance_id; + WORD vendor_id; + WORD product_id; ++ SDL_JoystickGUID sdl_guid; + CHAR *name; + + int n_buttons, n_axes, n_hats; +@@ -238,8 +239,15 @@ static void find_sdldevs(void) + while(sdldev < &sdldevs[ARRAY_SIZE(sdldevs)] && + sdldev->valid) + { ++ SDL_JoystickGUID sdl_guid; + if(sdldev->instance_id == SDL_JoystickGetDeviceInstanceID(i)) + break; ++ sdl_guid = SDL_JoystickGetDeviceGUID(i); ++ if(!memcmp(&sdldev->sdl_guid, &sdl_guid, sizeof(SDL_JoystickGUID))){ ++ if(!SDL_JoystickGetAttached(sdldev->sdl_js)) ++ /* same GUID but detached; reconnected, so assign to this slot */ ++ break; ++ } + sdldev++; + } + +@@ -252,12 +260,26 @@ static void find_sdldevs(void) + + if(sdldev->valid) + { +- /* this joystic is already discovered */ ++ if(SDL_JoystickGetAttached(sdldev->sdl_js)) ++ { ++ /* this joystic is already discovered */ ++ continue; ++ } ++ ++ /* reconnected, update sdldev */ ++ TRACE("reconnected \"%s\"\n", sdldev->name); ++ device = SDL_JoystickOpen(i); ++ sdldev->instance_id = SDL_JoystickInstanceID(device); ++ if (SDL_JoystickIsHaptic(device)) ++ sdldev->sdl_haptic = SDL_HapticOpenFromJoystick(device); ++ ++ InterlockedExchangePointer((void**)&sdldev->sdl_js, device); + continue; + } + + device = SDL_JoystickOpen(i); + sdldev->instance_id = SDL_JoystickInstanceID(device); ++ sdldev->sdl_guid = SDL_JoystickGetGUID(device); + + name = SDL_JoystickName(device); + sdldev->name = HeapAlloc(GetProcessHeap(), 0, strlen(name) + 1); +@@ -757,10 +779,16 @@ static HRESULT poll_sdl_device_state(LPDIRECTINPUTDEVICE8A iface) + struct device_state_item item; + SDL_Joystick *js = This->sdldev->sdl_js; + ++ SDL_JoystickUpdate(); ++ + if(!SDL_JoystickGetAttached(js)) +- return DIERR_INPUTLOST; ++ { ++ find_sdldevs(); + +- SDL_JoystickUpdate(); ++ js = This->sdldev->sdl_js; ++ if(!SDL_JoystickGetAttached(js)) ++ return DIERR_INPUTLOST; ++ } + + while(This->enum_device_state(js, This, &item, i++)) + { +@@ -1574,6 +1602,7 @@ static HRESULT WINAPI JoystickWImpl_GetEffectInfo(LPDIRECTINPUTDEVICE8W iface, + { + JoystickImpl* This = impl_from_IDirectInputDevice8W(iface); + TRACE("(this=%p,%p,%s)\n", This, pdei, _dump_dinput_GUID(guid)); ++ find_sdldevs(); + return sdl_input_get_info_W(This->sdldev->sdl_js, guid, pdei); + } + +@@ -1583,6 +1612,7 @@ static HRESULT WINAPI JoystickAImpl_GetEffectInfo(LPDIRECTINPUTDEVICE8A iface, + { + JoystickImpl* This = impl_from_IDirectInputDevice8A(iface); + TRACE("(this=%p,%p,%s)\n", This, pdei, _dump_dinput_GUID(guid)); ++ find_sdldevs(); + return sdl_input_get_info_A(This->sdldev->sdl_js, guid, pdei); + } + +From 74629b1609f0f74cfbc0b64ccdd445c5c860e81d Mon Sep 17 00:00:00 2001 +From: Bernat Arlandis +Date: Tue, 3 Dec 2019 00:16:43 +0100 +Subject: [PATCH] dinput: Scale periodic effect offset correctly + +--- + dlls/dinput/effect_sdl.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/dlls/dinput/effect_sdl.c b/dlls/dinput/effect_sdl.c +index ed2e78ae186..3c95db117bc 100644 +--- a/dlls/dinput/effect_sdl.c ++++ b/dlls/dinput/effect_sdl.c +@@ -289,7 +289,7 @@ static HRESULT WINAPI effect_GetParameters(IDirectInputEffect *iface, + DIPERIODIC *tsp = effect->lpvTypeSpecificParams; + + tsp->dwMagnitude = MulDiv(This->effect.periodic.magnitude, 10000, 32767); +- tsp->lOffset = This->effect.periodic.offset; ++ tsp->lOffset = SCALE(LONG, 20000, -10000, This->effect.periodic.offset, 0xffff, -32767); + tsp->dwPhase = This->effect.periodic.phase; + tsp->dwPeriod = This->effect.periodic.period * 1000; + } +@@ -567,7 +567,7 @@ static HRESULT WINAPI effect_SetParameters(IDirectInputEffect *iface, + tsp = effect->lpvTypeSpecificParams; + + This->effect.periodic.magnitude = MulDiv(tsp->dwMagnitude, 32767, 10000); +- This->effect.periodic.offset = tsp->lOffset; ++ This->effect.periodic.offset = SCALE(Sint16, 0xffff, -32767, tsp->lOffset, 20000, -10000); + This->effect.periodic.phase = tsp->dwPhase; + if (tsp->dwPeriod <= 1000) + This->effect.periodic.period = 1; +From 741cfdd9c8b2a9d269aaee42bb6b0d8c704e37c9 Mon Sep 17 00:00:00 2001 +From: Bernat Arlandis +Date: Tue, 3 Dec 2019 00:16:43 +0100 +Subject: [PATCH] dinput: Log effect directions, and use effective flags + +--- + dlls/dinput/effect_sdl.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/dlls/dinput/effect_sdl.c b/dlls/dinput/effect_sdl.c +index 3c95db117bc..a15b713f9aa 100644 +--- a/dlls/dinput/effect_sdl.c ++++ b/dlls/dinput/effect_sdl.c +@@ -427,8 +427,6 @@ static HRESULT WINAPI effect_SetParameters(IDirectInputEffect *iface, + + TRACE("%p %p 0x%x\n", This, effect, flags); + +- dump_DIEFFECT(effect, &This->guid, flags); +- + if (IsEqualGUID(&This->guid, &GUID_Sine)) + This->effect.type = SDL_HAPTIC_SINE; + else if (IsEqualGUID(&This->guid, &GUID_Triangle)) +@@ -469,6 +467,8 @@ static HRESULT WINAPI effect_SetParameters(IDirectInputEffect *iface, + This->first_axis_is_x = effect->rgdwAxes[0] == DIJOFS_X; + } + ++ dump_DIEFFECT(effect, &This->guid, flags); ++ + if (flags & DIEP_DIRECTION) + { + if (effect->cAxes == 1) +From d7f95268f324edcbbb47220d381e4fb5e5d93fb0 Mon Sep 17 00:00:00 2001 +From: Bernat Arlandis +Date: Tue, 3 Dec 2019 00:16:43 +0100 +Subject: [PATCH] dinput: Don't set unused effect direction value + +--- + dlls/dinput/effect_sdl.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/dlls/dinput/effect_sdl.c b/dlls/dinput/effect_sdl.c +index a15b713f9aa..734da182a65 100644 +--- a/dlls/dinput/effect_sdl.c ++++ b/dlls/dinput/effect_sdl.c +@@ -479,7 +479,6 @@ static HRESULT WINAPI effect_SetParameters(IDirectInputEffect *iface, + if (flags & DIEP_AXES) + { + SET_BASE_EFFECT_FIELD(This->effect, direction.dir[0], effect->rglDirection[0]); +- SET_BASE_EFFECT_FIELD(This->effect, direction.dir[1], effect->rglDirection[1]); + } + } else { + /* one-axis effects must use cartesian coords */ +From 77f4b7cc141a8c92d0b5c9e243c36e9f61c26daf Mon Sep 17 00:00:00 2001 +From: Bernat Arlandis +Date: Tue, 3 Dec 2019 00:16:43 +0100 +Subject: [PATCH] dinput: Set SDL gain correctly + +--- + dlls/dinput/joystick_sdl.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/dlls/dinput/joystick_sdl.c b/dlls/dinput/joystick_sdl.c +index d63289ecebe..3ff46c8cfbe 100644 +--- a/dlls/dinput/joystick_sdl.c ++++ b/dlls/dinput/joystick_sdl.c +@@ -1286,12 +1286,14 @@ static BOOL _SetProperty(JoystickImpl *This, const GUID *prop, const DIPROPHEADE + case (DWORD_PTR)DIPROP_FFGAIN: + { + LPCDIPROPDWORD pd = (LPCDIPROPDWORD)header; +- int sdl_gain = MulDiv(This->sdldev->gain, 100, 10000); ++ int sdl_gain; + + TRACE("DIPROP_FFGAIN(%d)\n", pd->dwData); + + This->sdldev->gain = pd->dwData; + ++ sdl_gain = MulDiv(This->sdldev->gain, 100, 10000); ++ + rc = SDL_HapticSetGain(This->sdldev->sdl_haptic, sdl_gain); + if (rc != 0) + ERR("SDL_HapticSetGain (%i -> %i) failed: %s\n", pd->dwData, sdl_gain, SDL_GetError()); +From c65dec00b68c69005d5fc5d3e442990257f7fdf4 Mon Sep 17 00:00:00 2001 +From: Andrew Eikum +Date: Tue, 3 Dec 2019 14:44:57 -0600 +Subject: [PATCH] dinput: Fix converting effect values to and from SDL + +With assistance from Bernat Arlandis. +--- + dlls/dinput/effect_sdl.c | 61 ++++++++++++++++++++++++---------------- + 1 file changed, 37 insertions(+), 24 deletions(-) + +diff --git a/dlls/dinput/effect_sdl.c b/dlls/dinput/effect_sdl.c +index 734da182a65..47ab59e2f66 100644 +--- a/dlls/dinput/effect_sdl.c ++++ b/dlls/dinput/effect_sdl.c +@@ -169,8 +169,21 @@ static HRESULT WINAPI effect_GetEffectGuid(IDirectInputEffect *iface, GUID *out) + value = (target.custom.field); \ + } + +-#define SCALE(type, target_range, target_min, value, source_range, source_min) \ +- (type)((((target_range)*(value + source_min))/source_range)-target_min) ++/* map [-32768, 0, 32767] -> [-10000, 0, 10000] */ ++#define CENTERED_SDL_TO_DI(val) \ ++ ((20000 * (val - 0x8000)) / 0xffff + 10000) ++ ++/* map [-10000, 0, 10000] -> [-32768, 0, 32767] */ ++#define CENTERED_DI_TO_SDL(val) \ ++ ((0xffff * (val - 10000)) / 20000 + 0x7fff) ++ ++/* map [0, sdl_max] -> [0, 10000] */ ++#define ZEROED_SDL_TO_DI(val, sdl_max) \ ++ ((10000 * val) / sdl_max) ++ ++/* map [0, 10000] -> [0, sdl_max] */ ++#define ZEROED_DI_TO_SDL(val, sdl_max) \ ++ ((sdl_max * val) / 10000) + + static HRESULT WINAPI effect_GetParameters(IDirectInputEffect *iface, + DIEFFECT *effect, DWORD flags) +@@ -288,22 +301,22 @@ static HRESULT WINAPI effect_GetParameters(IDirectInputEffect *iface, + { + DIPERIODIC *tsp = effect->lpvTypeSpecificParams; + +- tsp->dwMagnitude = MulDiv(This->effect.periodic.magnitude, 10000, 32767); +- tsp->lOffset = SCALE(LONG, 20000, -10000, This->effect.periodic.offset, 0xffff, -32767); ++ tsp->dwMagnitude = ZEROED_SDL_TO_DI(This->effect.periodic.magnitude, SDL_MAX_SINT16); ++ tsp->lOffset = CENTERED_SDL_TO_DI(This->effect.periodic.offset); + tsp->dwPhase = This->effect.periodic.phase; + tsp->dwPeriod = This->effect.periodic.period * 1000; + } + else if (This->effect.type == SDL_HAPTIC_CONSTANT) + { + LPDICONSTANTFORCE tsp = effect->lpvTypeSpecificParams; +- tsp->lMagnitude = SCALE(LONG, 20000, -10000, This->effect.constant.level, 0xffff, -32767); ++ tsp->lMagnitude = CENTERED_SDL_TO_DI(This->effect.constant.level); + } + else if (This->effect.type == SDL_HAPTIC_RAMP) + { + DIRAMPFORCE *tsp = effect->lpvTypeSpecificParams; + +- tsp->lStart = SCALE(Sint16, 20000, -10000, This->effect.ramp.start, 0xffff, -32767); +- tsp->lEnd = SCALE(Sint16, 20000, -10000, This->effect.ramp.end, 0xffff, -32767); ++ tsp->lStart = CENTERED_SDL_TO_DI(This->effect.ramp.start); ++ tsp->lEnd = CENTERED_SDL_TO_DI(This->effect.ramp.end); + } + else if (This->effect.type == SDL_HAPTIC_SPRING || + This->effect.type == SDL_HAPTIC_DAMPER || +@@ -314,12 +327,12 @@ static HRESULT WINAPI effect_GetParameters(IDirectInputEffect *iface, + DICONDITION *tsp = effect->lpvTypeSpecificParams; + for (i = 0; i < 2; i++) + { +- tsp[i].lOffset = SCALE(LONG, 20000, -10000, This->effect.condition.center[i], 0xffff, -32767); +- tsp[i].lPositiveCoefficient = SCALE(LONG, 20000, -10000, This->effect.condition.right_coeff[i], 0xffff, -32767); +- tsp[i].lNegativeCoefficient = SCALE(LONG, 10000, -20000, This->effect.condition.left_coeff[i], 0xffff, -32767); +- tsp[i].dwPositiveSaturation = SCALE(DWORD, 10000, 0, This->effect.condition.right_sat[i], 0xffff, 0); +- tsp[i].dwNegativeSaturation = SCALE(DWORD, 10000, 0, This->effect.condition.left_sat[i], 0xffff, 0); +- tsp[i].lDeadBand = SCALE(LONG, 20000, -10000, This->effect.condition.deadband[i], 0xffff, -32767); ++ tsp[i].lOffset = CENTERED_SDL_TO_DI(This->effect.condition.center[i]); ++ tsp[i].lPositiveCoefficient = CENTERED_SDL_TO_DI(This->effect.condition.right_coeff[i]); ++ tsp[i].lNegativeCoefficient = CENTERED_SDL_TO_DI(This->effect.condition.left_coeff[i]); ++ tsp[i].dwPositiveSaturation = ZEROED_SDL_TO_DI(This->effect.condition.right_sat[i], SDL_MAX_UINT16); ++ tsp[i].dwNegativeSaturation = ZEROED_SDL_TO_DI(This->effect.condition.left_sat[i], SDL_MAX_UINT16); ++ tsp[i].lDeadBand = This->effect.condition.deadband[i] * 10000 / SDL_MAX_UINT16; + } + } + else if (This->effect.type == SDL_HAPTIC_CUSTOM) +@@ -565,8 +578,8 @@ static HRESULT WINAPI effect_SetParameters(IDirectInputEffect *iface, + return DIERR_INVALIDPARAM; + tsp = effect->lpvTypeSpecificParams; + +- This->effect.periodic.magnitude = MulDiv(tsp->dwMagnitude, 32767, 10000); +- This->effect.periodic.offset = SCALE(Sint16, 0xffff, -32767, tsp->lOffset, 20000, -10000); ++ This->effect.periodic.magnitude = ZEROED_DI_TO_SDL(tsp->dwMagnitude, SDL_MAX_SINT16); ++ This->effect.periodic.offset = CENTERED_DI_TO_SDL(tsp->lOffset); + This->effect.periodic.phase = tsp->dwPhase; + if (tsp->dwPeriod <= 1000) + This->effect.periodic.period = 1; +@@ -580,7 +593,7 @@ static HRESULT WINAPI effect_SetParameters(IDirectInputEffect *iface, + if (effect->cbTypeSpecificParams != sizeof(DICONSTANTFORCE)) + return DIERR_INVALIDPARAM; + tsp = effect->lpvTypeSpecificParams; +- This->effect.constant.level = SCALE(Sint16, 0xffff, -32767, tsp->lMagnitude, 20000, -10000); ++ This->effect.constant.level = CENTERED_DI_TO_SDL(tsp->lMagnitude); + } + else if (IsEqualGUID(&This->guid, &GUID_RampForce)) + { +@@ -589,8 +602,8 @@ static HRESULT WINAPI effect_SetParameters(IDirectInputEffect *iface, + if (effect->cbTypeSpecificParams != sizeof(DIRAMPFORCE)) + return DIERR_INVALIDPARAM; + tsp = effect->lpvTypeSpecificParams; +- This->effect.ramp.start = SCALE(Sint16, 0xffff, -32767, tsp->lStart, 20000, -10000); +- This->effect.ramp.end = SCALE(Sint16, 0xffff, -32767, tsp->lEnd, 20000, -10000); ++ This->effect.ramp.start = CENTERED_DI_TO_SDL(tsp->lStart); ++ This->effect.ramp.end = CENTERED_DI_TO_SDL(tsp->lEnd); + } + else if (IsEqualGUID(&This->guid, &GUID_Spring) || + IsEqualGUID(&This->guid, &GUID_Damper) || +@@ -612,12 +625,12 @@ static HRESULT WINAPI effect_SetParameters(IDirectInputEffect *iface, + + for (i = j = 0; i < 3; ++i) + { +- This->effect.condition.right_sat[i] = SCALE(Uint16, 0xffff, 0, tsp[j].dwPositiveSaturation, 10000, 0); +- This->effect.condition.left_sat[i] = SCALE(Uint16, 0xffff, 0, tsp[j].dwNegativeSaturation, 10000, 0); +- This->effect.condition.right_coeff[i] = SCALE(Sint16, 0xffff, -32767, tsp[j].lPositiveCoefficient, 20000, -10000); +- This->effect.condition.left_coeff[i] = SCALE(Sint16, 0xffff, -32767, tsp[j].lNegativeCoefficient, 20000, -10000); +- This->effect.condition.deadband[i] = SCALE(Uint16, 0xffff, 0, tsp[j].lDeadBand, 10000, 0); +- This->effect.condition.center[i] = SCALE(Sint16, 0xffff, -32767, tsp[j].lOffset, 20000, -10000); ++ This->effect.condition.right_sat[i] = ZEROED_DI_TO_SDL(tsp[j].dwPositiveSaturation, SDL_MAX_UINT16); ++ This->effect.condition.left_sat[i] = ZEROED_DI_TO_SDL(tsp[j].dwNegativeSaturation, SDL_MAX_UINT16); ++ This->effect.condition.right_coeff[i] = CENTERED_DI_TO_SDL(tsp[j].lPositiveCoefficient); ++ This->effect.condition.left_coeff[i] = CENTERED_DI_TO_SDL(tsp[j].lNegativeCoefficient); ++ This->effect.condition.deadband[i] = tsp[j].lDeadBand * SDL_MAX_UINT16 / 10000; ++ This->effect.condition.center[i] = CENTERED_DI_TO_SDL(tsp[j].lOffset); + if (sources-1 > j) + j++; + } +From 414ca725a5a7d0376a02b078e7e79e16e977ec16 Mon Sep 17 00:00:00 2001 +From: Andrew Eikum +Date: Tue, 3 Dec 2019 13:38:28 -0600 +Subject: [PATCH] dinput: Add mapping for xbox controllers + +--- + dlls/dinput/joystick_sdl.c | 92 ++++++++++++++++++++++++++++++++++++++ + 1 file changed, 92 insertions(+) + +diff --git a/dlls/dinput/joystick_sdl.c b/dlls/dinput/joystick_sdl.c +index 3ff46c8cfbe..ecca97d832a 100644 +--- a/dlls/dinput/joystick_sdl.c ++++ b/dlls/dinput/joystick_sdl.c +@@ -728,6 +728,83 @@ static BOOL enum_device_state_ds4_13button(SDL_Joystick *js, JoystickImpl *This, + return FALSE; + } + ++static BOOL enum_device_state_ms_xb360(SDL_Joystick *js, JoystickImpl *This, struct device_state_item *st, int idx) ++{ ++#define SPECIALCASE_TRIGGERS -1 ++ ++ static const struct { ++ int type; ++ int sdl_idx; ++ int dnp_id; ++ } map_ms_xb360[] = { ++ { ITEM_TYPE_AXIS, 1, 1 }, /* left vert */ ++ { ITEM_TYPE_AXIS, 0, 0 }, /* left horiz */ ++ { ITEM_TYPE_AXIS, 4, 4 }, /* right vert */ ++ { ITEM_TYPE_AXIS, 3, 3 }, /* right horiz */ ++ { ITEM_TYPE_AXIS, SPECIALCASE_TRIGGERS, 2 }, /* combined triggers */ ++ ++ { ITEM_TYPE_BUTTON, 0, 0}, /* A */ ++ { ITEM_TYPE_BUTTON, 1, 1}, /* B */ ++ { ITEM_TYPE_BUTTON, 2, 2}, /* X */ ++ { ITEM_TYPE_BUTTON, 3, 3}, /* Y */ ++ { ITEM_TYPE_BUTTON, 4, 4}, /* LB */ ++ { ITEM_TYPE_BUTTON, 5, 5}, /* RB */ ++ { ITEM_TYPE_BUTTON, 6, 6}, /* Back */ ++ { ITEM_TYPE_BUTTON, 7, 7}, /* Start */ ++ /* guide button (#8) is not reported by dinput */ ++ { ITEM_TYPE_BUTTON, 9, 8}, /* LS */ ++ { ITEM_TYPE_BUTTON, 10, 9}, /* RS */ ++ ++ { ITEM_TYPE_HAT, 0, 0 }, /* d-pad */ ++ }; ++ ++ if(idx >= ARRAY_SIZE(map_ms_xb360)) ++ return FALSE; ++ ++ st->type = map_ms_xb360[idx].type; ++ st->id = map_ms_xb360[idx].dnp_id; ++ ++ if(map_ms_xb360[idx].sdl_idx >= 0) ++ { ++ /* simple reads */ ++ switch(map_ms_xb360[idx].type) ++ { ++ case ITEM_TYPE_BUTTON: ++ st->val = SDL_JoystickGetButton(js, map_ms_xb360[idx].sdl_idx); ++ return TRUE; ++ ++ case ITEM_TYPE_AXIS: ++ st->val = SDL_JoystickGetAxis(js, map_ms_xb360[idx].sdl_idx); ++ return TRUE; ++ ++ case ITEM_TYPE_HAT: ++ st->val = SDL_JoystickGetHat(js, map_ms_xb360[idx].sdl_idx); ++ return TRUE; ++ } ++ } ++ ++ switch(map_ms_xb360[idx].sdl_idx){ ++ case SPECIALCASE_TRIGGERS: ++ { ++ /* combined triggers axis */ ++ static const int SDL_LTRIGGER = 2; ++ static const int SDL_RTRIGGER = 5; ++ ++ int ltrigger = SDL_JoystickGetAxis(js, SDL_LTRIGGER); ++ int rtrigger = SDL_JoystickGetAxis(js, SDL_RTRIGGER); ++ ++ /* yes, they are combined into one value and cannot be detangled */ ++ st->val = (ltrigger - rtrigger) / 2; ++ return TRUE; ++ } ++ } ++ ++ ERR("???\n"); /* error in static data above */ ++ return FALSE; ++ ++#undef SPECIALCASE_TRIGGERS ++} ++ + /* straight 1:1 mapping of SDL items and dinput items */ + static BOOL enum_device_state_standard(SDL_Joystick *js, JoystickImpl *This, struct device_state_item *st, int idx) + { +@@ -892,6 +969,21 @@ static enum_device_state_function select_enum_function(struct SDLDev *sdldev) + return enum_device_state_ds4_13button; + } + break; ++ ++ case VID_MICROSOFT: ++ switch(sdldev->product_id){ ++ case PID_MICROSOFT_XBOX_360: ++ case PID_MICROSOFT_XBOX_360_WIRELESS: ++ case PID_MICROSOFT_XBOX_360_ADAPTER: ++ case PID_MICROSOFT_XBOX_ONE: ++ case PID_MICROSOFT_XBOX_ONE_CF: ++ case PID_MICROSOFT_XBOX_ONE_ELITE: ++ case PID_MICROSOFT_XBOX_ONE_S: ++ case PID_MICROSOFT_XBOX_ONE_S_2: ++ TRACE("for %04x/%04x, polling xbox 360/one controller\n", sdldev->vendor_id, sdldev->product_id); ++ return enum_device_state_ms_xb360; ++ } ++ break; + } + + TRACE("for %04x/%04x, using no maps\n", sdldev->vendor_id, sdldev->product_id); +From f3e99504b3dee3d87d06ef6d5e40b1d13ce71073 Mon Sep 17 00:00:00 2001 +From: Andrew Eikum +Date: Tue, 31 Mar 2020 08:25:38 -0500 +Subject: [PATCH] winebus, dinput: Ignore some joysticks that SDL reports + +SDL has a blacklist, but it isn't complete. Ignore some more devices +while we fix upstream. +--- + dlls/dinput/joystick_sdl.c | 24 ++++++++++++++++++++++++ + dlls/winebus.sys/bus_sdl.c | 24 +++++++++++++++++++++++- + include/wine/js_blacklist.h | 3 +++ + 3 files changed, 50 insertions(+), 1 deletion(-) + create mode 100644 include/wine/js_blacklist.h + +diff --git a/dlls/dinput/joystick_sdl.c b/dlls/dinput/joystick_sdl.c +index ecca97d832a..ca42fd89686 100644 +--- a/dlls/dinput/joystick_sdl.c ++++ b/dlls/dinput/joystick_sdl.c +@@ -52,6 +52,8 @@ + #include "device_private.h" + #include "joystick_private.h" + ++#include "wine/js_blacklist.h" /* for wine_js_blacklist */ ++ + #ifdef HAVE_SDL_H + + WINE_DEFAULT_DEBUG_CHANNEL(dinput); +@@ -186,6 +188,20 @@ static BOOL is_in_sdl_blacklist(DWORD vid, DWORD pid) + return strcasestr(blacklist, needle) != NULL; + } + ++static BOOL is_in_wine_blacklist(const DWORD vid, const DWORD pid) ++{ ++ int i; ++ for(i = 0; i < ARRAY_SIZE(wine_js_blacklist); ++i) ++ { ++ if(vid == wine_js_blacklist[i].vid && ++ (wine_js_blacklist[i].pid == 0 || ++ wine_js_blacklist[i].pid == pid)) ++ return TRUE; ++ } ++ ++ return FALSE; ++} ++ + static Uint16 (*pSDL_JoystickGetProduct)(SDL_Joystick *); + static Uint16 (*pSDL_JoystickGetVendor)(SDL_Joystick *); + +@@ -318,6 +334,14 @@ static void find_sdldevs(void) + continue; + } + ++ if(is_in_wine_blacklist(sdldev->vendor_id, sdldev->product_id)) ++ { ++ TRACE("joystick %04x/%04x is in Wine blacklist, ignoring\n", sdldev->vendor_id, sdldev->product_id); ++ SDL_JoystickClose(device); ++ HeapFree(GetProcessHeap(), 0, sdldev->name); ++ continue; ++ } ++ + if(sdldev->vendor_id == VID_VALVE && sdldev->product_id == PID_VALVE_VIRTUAL_CONTROLLER) + { + sdldev->vendor_id = VID_MICROSOFT; +diff --git a/dlls/winebus.sys/bus_sdl.c b/dlls/winebus.sys/bus_sdl.c +index b1b70c20294..efe4a8c6b46 100644 +--- a/dlls/winebus.sys/bus_sdl.c ++++ b/dlls/winebus.sys/bus_sdl.c +@@ -47,6 +47,8 @@ + #include "hidusage.h" + #include "controller.h" + ++#include "wine/js_blacklist.h" /* for wine_js_blacklist */ ++ + #ifdef WORDS_BIGENDIAN + # define LE_WORD(x) RtlUshortByteSwap(x) + #else +diff --git a/include/wine/js_blacklist.h b/include/wine/js_blacklist.h +new file mode 100644 +index 00000000000..b8f2ec7dd28 +--- /dev/null ++++ b/include/wine/js_blacklist.h +@@ -0,0 +1,3 @@ ++static const struct { short vid; short pid; } wine_js_blacklist[] = { ++ {0x056a, 0x0000}, /* all Wacom devices */ ++}; +From 890e0c7af5fa8af3fa63e7694390969bbcd517e7 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?R=C3=A9mi=20Bernon?= +Date: Thu, 19 Mar 2020 14:54:52 +0100 +Subject: [PATCH] dinput: Ignore force feedback on gamepads. + +DmC Devil May Cry crashes if gamepads report ffb support. +--- + dlls/dinput/joystick_sdl.c | 26 +++++++++++++------------- + 1 file changed, 13 insertions(+), 13 deletions(-) + +diff --git a/dlls/dinput/joystick_sdl.c b/dlls/dinput/joystick_sdl.c +index ca42fd89686..91d570ddf48 100644 +--- a/dlls/dinput/joystick_sdl.c ++++ b/dlls/dinput/joystick_sdl.c +@@ -286,7 +286,7 @@ static void find_sdldevs(void) + TRACE("reconnected \"%s\"\n", sdldev->name); + device = SDL_JoystickOpen(i); + sdldev->instance_id = SDL_JoystickInstanceID(device); +- if (SDL_JoystickIsHaptic(device)) ++ if (sdldev->is_joystick && SDL_JoystickIsHaptic(device)) + sdldev->sdl_haptic = SDL_HapticOpenFromJoystick(device); + + InterlockedExchangePointer((void**)&sdldev->sdl_js, device); +@@ -309,13 +309,21 @@ static void find_sdldevs(void) + + TRACE("Found a joystick on %p: %s\n", device, sdldev->name); + ++ { ++ SDL_JoystickType type = SDL_JoystickGetType(device); ++ sdldev->is_joystick = ++ type == SDL_JOYSTICK_TYPE_UNKNOWN || ++ type == SDL_JOYSTICK_TYPE_WHEEL || ++ type == SDL_JOYSTICK_TYPE_FLIGHT_STICK || ++ type == SDL_JOYSTICK_TYPE_THROTTLE; ++ } ++ + if (SDL_JoystickIsHaptic(device)) + { +- haptic = SDL_HapticOpenFromJoystick(device); +- if (haptic) +- { ++ if (!sdldev->is_joystick) ++ WARN("Ignoring force feedback support for \"%s\"\n", sdldev->name); ++ else if ((haptic = SDL_HapticOpenFromJoystick(device))) + TRACE(" ... with force feedback\n"); +- } + } + + if(pSDL_JoystickGetVendor){ +@@ -348,14 +356,6 @@ static void find_sdldevs(void) + sdldev->product_id = PID_MICROSOFT_XBOX_360; + } + +- { +- SDL_JoystickType type = SDL_JoystickGetType(device); +- sdldev->is_joystick = +- type == SDL_JOYSTICK_TYPE_WHEEL || +- type == SDL_JOYSTICK_TYPE_FLIGHT_STICK || +- type == SDL_JOYSTICK_TYPE_THROTTLE; +- } +- + sdldev->n_buttons = SDL_JoystickNumButtons(device); + sdldev->n_axes = SDL_JoystickNumAxes(device); + sdldev->n_hats = SDL_JoystickNumHats(device); +From dd87a09a7b87006ef665df0c303f66ab02802bc2 Mon Sep 17 00:00:00 2001 +From: Brendan Shanks +Date: Thu, 23 Apr 2020 17:12:48 -0700 +Subject: [PATCH] dinput/sdl: Fix IDirectInputEffect::SetParameters() behavior + with NULL effect parameters. + +Equivalent of upstream f66517b5a27057243912f3a7c4a41a291ab2bfb8 for +effect_sdl. +--- + dlls/dinput/effect_sdl.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/dlls/dinput/effect_sdl.c b/dlls/dinput/effect_sdl.c +index 47ab59e2f66..0062e1f5aed 100644 +--- a/dlls/dinput/effect_sdl.c ++++ b/dlls/dinput/effect_sdl.c +@@ -473,6 +473,9 @@ static HRESULT WINAPI effect_SetParameters(IDirectInputEffect *iface, + + if (flags & DIEP_AXES) + { ++ if (!effect->rgdwAxes) ++ return DIERR_INVALIDPARAM; ++ + if (effect->cAxes > 2) + return DIERR_INVALIDPARAM; + else if (effect->cAxes < 1) +@@ -484,6 +487,9 @@ static HRESULT WINAPI effect_SetParameters(IDirectInputEffect *iface, + + if (flags & DIEP_DIRECTION) + { ++ if (!effect->rglDirection) ++ return DIERR_INVALIDPARAM; ++ + if (effect->cAxes == 1) + { + if (effect->dwFlags & DIEFF_CARTESIAN) +@@ -568,6 +574,9 @@ static HRESULT WINAPI effect_SetParameters(IDirectInputEffect *iface, + + if (flags & DIEP_TYPESPECIFICPARAMS) + { ++ if (!effect->lpvTypeSpecificParams) ++ return DIERR_INVALIDPARAM; ++ + if (IsEqualGUID(&This->guid, &GUID_Sine) || + IsEqualGUID(&This->guid, &GUID_Triangle) || + IsEqualGUID(&This->guid, &GUID_SawtoothUp) || +From bdb531f6b18c0c033e272a82910867c7448fc963 Mon Sep 17 00:00:00 2001 +From: Brendan Shanks +Date: Thu, 23 Apr 2020 17:22:03 -0700 +Subject: [PATCH] dinput/sdl: Fix IDirectInputEffect::SetParameters() when + called with flags=0. + +Equivalent of upstream 1832dc3df32f0133e695457401f6961d8d40532d for +effect/joystick_sdl. +--- + dlls/dinput/effect_sdl.c | 13 ++++--------- + dlls/dinput/joystick_sdl.c | 5 ++++- + 2 files changed, 8 insertions(+), 10 deletions(-) + +diff --git a/dlls/dinput/effect_sdl.c b/dlls/dinput/effect_sdl.c +index 0062e1f5aed..a2b00f89082 100644 +--- a/dlls/dinput/effect_sdl.c ++++ b/dlls/dinput/effect_sdl.c +@@ -463,13 +463,10 @@ static HRESULT WINAPI effect_SetParameters(IDirectInputEffect *iface, + else if (IsEqualGUID(&This->guid, &GUID_CustomForce)) + This->effect.type = SDL_HAPTIC_CUSTOM; + +- if ((flags & ~DIEP_NORESTART & ~DIEP_NODOWNLOAD & ~DIEP_START) == 0) +- { +- /* set everything */ +- flags = DIEP_AXES | DIEP_DIRECTION | DIEP_DURATION | DIEP_ENVELOPE | +- DIEP_GAIN | DIEP_SAMPLEPERIOD | DIEP_STARTDELAY | DIEP_TRIGGERBUTTON | +- DIEP_TRIGGERREPEATINTERVAL | DIEP_TYPESPECIFICPARAMS; +- } ++ dump_DIEFFECT(effect, &This->guid, flags); ++ ++ if (!flags) ++ return DI_NOEFFECT; + + if (flags & DIEP_AXES) + { +@@ -483,8 +480,6 @@ static HRESULT WINAPI effect_SetParameters(IDirectInputEffect *iface, + This->first_axis_is_x = effect->rgdwAxes[0] == DIJOFS_X; + } + +- dump_DIEFFECT(effect, &This->guid, flags); +- + if (flags & DIEP_DIRECTION) + { + if (!effect->rglDirection) +diff --git a/dlls/dinput/joystick_sdl.c b/dlls/dinput/joystick_sdl.c +index 91d570ddf48..5eeb40f8de5 100644 +--- a/dlls/dinput/joystick_sdl.c ++++ b/dlls/dinput/joystick_sdl.c +@@ -1523,7 +1523,10 @@ static HRESULT WINAPI JoystickWImpl_CreateEffect(IDirectInputDevice8W *iface, + + if (lpeff != NULL) + { +- retval = IDirectInputEffect_SetParameters(new_effect->ref, lpeff, 0); ++ retval = IDirectInputEffect_SetParameters(new_effect->ref, lpeff, ++ DIEP_AXES | DIEP_DIRECTION | DIEP_DURATION | DIEP_ENVELOPE | ++ DIEP_GAIN | DIEP_SAMPLEPERIOD | DIEP_STARTDELAY | DIEP_TRIGGERBUTTON | ++ DIEP_TRIGGERREPEATINTERVAL | DIEP_TYPESPECIFICPARAMS); + + if (retval != DI_OK && retval != DI_DOWNLOADSKIPPED) + { +From d8b0d68b1ac41248095e5af0d7afd831a3252021 Mon Sep 17 00:00:00 2001 +From: Brendan Shanks +Date: Mon, 27 Apr 2020 10:35:45 -0700 +Subject: [PATCH] dinput: Set dwDevType specifically for steering wheels. + +Fixes wheel detection for WRC 7 +--- + dlls/dinput/joystick_sdl.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/dlls/dinput/joystick_sdl.c b/dlls/dinput/joystick_sdl.c +index 5eeb40f8de5..ae47132e89c 100644 +--- a/dlls/dinput/joystick_sdl.c ++++ b/dlls/dinput/joystick_sdl.c +@@ -108,6 +108,7 @@ struct SDLDev { + + int n_buttons, n_axes, n_hats; + ++ SDL_JoystickType type; + BOOL is_joystick; + int autocenter; + int gain; +@@ -311,6 +312,7 @@ static void find_sdldevs(void) + + { + SDL_JoystickType type = SDL_JoystickGetType(device); ++ sdldev->type = type; + sdldev->is_joystick = + type == SDL_JOYSTICK_TYPE_UNKNOWN || + type == SDL_JOYSTICK_TYPE_WHEEL || +@@ -439,6 +441,13 @@ static void fill_joystick_dideviceinstanceA(LPDIDEVICEINSTANCEA lpddi, DWORD ver + + lpddi->dwDevType = get_device_type(version, sdldevs[id].is_joystick); + ++ /* DirectInput 8 has more-specific device types which some games look for */ ++ if (version >= 0x800) ++ { ++ if (sdldevs[id].type == SDL_JOYSTICK_TYPE_WHEEL) ++ lpddi->dwDevType = DI8DEVTYPE_DRIVING | (DI8DEVTYPEDRIVING_DUALPEDALS << 8); ++ } ++ + /* Assume the joystick as HID if it is attached to USB bus and has a valid VID/PID */ + if ( sdldevs[id].vendor_id && sdldevs[id].product_id) + { +From 894728b29485d76920e018898b2b364ed09b9032 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?R=C3=A9mi=20Bernon?= +Date: Sat, 9 Jan 2021 20:11:52 +0100 +Subject: [PATCH] HACK: steam: dinput: Check Steam overlay presence and ignore + updates when enabled. + +--- + dlls/dinput/joystick_sdl.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/dlls/dinput/joystick_sdl.c b/dlls/dinput/joystick_sdl.c +index ae47132e89c..2d574b15547 100644 +--- a/dlls/dinput/joystick_sdl.c ++++ b/dlls/dinput/joystick_sdl.c +@@ -159,6 +159,7 @@ static CRITICAL_SECTION_DEBUG sdldevs_lock_debug = + static CRITICAL_SECTION sdldevs_lock = { &sdldevs_lock_debug, -1, 0, 0, 0, 0 }; + + static struct SDLDev sdldevs[64]; ++static HANDLE steam_overlay_event; + + /* logic from SDL2's SDL_ShouldIgnoreGameController */ + static BOOL is_in_sdl_blacklist(DWORD vid, DWORD pid) +@@ -223,6 +224,8 @@ static BOOL WINAPI sdldrv_init(INIT_ONCE *once, void *param, void **context) + SDL_Init(SDL_INIT_JOYSTICK|SDL_INIT_HAPTIC); + SDL_JoystickEventState(SDL_ENABLE); + ++ steam_overlay_event = CreateEventA(NULL, TRUE, FALSE, "__wine_steamclient_GameOverlayActivated"); ++ + return TRUE; + } + +@@ -889,6 +892,9 @@ static HRESULT poll_sdl_device_state(LPDIRECTINPUTDEVICE8A iface) + struct device_state_item item; + SDL_Joystick *js = This->sdldev->sdl_js; + ++ if (WaitForSingleObject(steam_overlay_event, 0) == WAIT_OBJECT_0) ++ return DI_OK; /* steam overlay is enabled */ ++ + SDL_JoystickUpdate(); + + if(!SDL_JoystickGetAttached(js)) +From ba5532e2c077323dc92a9847e240f9f8ddd445fb Mon Sep 17 00:00:00 2001 +From: Arkadiusz Hiler +Date: Mon, 14 Dec 2020 12:17:48 +0200 +Subject: [PATCH] dinput: Return lowercase path for devices + +For Yakuza: Like A Dragon Xbox controller support. + +Yakuza: Like A Dragon uses dinput to do controller discovery. It also tells +xinput controllers apart the other kinds using the dinput device path. + +The game is looking for vid_ and ig_ in the path, both lowercase and the +comparison is case sensitive. + +Patch c34e297b76f9 ("dinput: Return real rawinput path for dinput device") +started using raw input paths for dinput devices, which looks like what +Windows is doing but with the small omission of lowercasing the whole string. +--- + dlls/dinput/joystick_sdl.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/dlls/dinput/joystick_sdl.c b/dlls/dinput/joystick_sdl.c +index 2d574b15547..04dda48421d 100644 +--- a/dlls/dinput/joystick_sdl.c ++++ b/dlls/dinput/joystick_sdl.c +@@ -1367,6 +1367,8 @@ static HRESULT WINAPI JoystickWImpl_GetProperty(LPDIRECTINPUTDEVICE8W iface, REF + return DIERR_GENERIC; + } + ++ strlwrW(pd->wszPath); ++ + pd->guidClass = GUID_DEVCLASS_HIDCLASS; + + TRACE("DIPROP_GUIDANDPATH(%s, %s): returning path\n", debugstr_guid(&pd->guidClass), debugstr_w(pd->wszPath)); +From 5ff989fd2d1cbf5911833cebd70e160bae644276 Mon Sep 17 00:00:00 2001 +From: Arkadiusz Hiler +Date: Mon, 1 Mar 2021 17:23:34 +0200 +Subject: [PATCH] dinput: Add DualSense controller mapping. + +Also known as the PS5 controller. +--- + dlls/dinput/joystick_sdl.c | 146 +++++++++++++++++++++++++------------ + 1 file changed, 100 insertions(+), 46 deletions(-) + +diff --git a/dlls/dinput/joystick_sdl.c b/dlls/dinput/joystick_sdl.c +index 04dda48421d..ae3c9852eb7 100644 +--- a/dlls/dinput/joystick_sdl.c ++++ b/dlls/dinput/joystick_sdl.c +@@ -62,6 +62,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(dinput); + #define PID_SONY_DUALSHOCK_4 0x05c4 + #define PID_SONY_DUALSHOCK_4_2 0x09cc + #define PID_SONY_DUALSHOCK_4_DONGLE 0x0ba0 ++#define PID_SONY_DUALSENSE 0x0ce6 + + #define VID_VALVE 0x28de + #define PID_VALVE_VIRTUAL_CONTROLLER 0x11ff +@@ -395,6 +396,10 @@ static struct device_info_override { + DIDEVTYPE_HID | DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_GAMEPAD << 8), + DIDEVTYPE_HID | DI8DEVTYPE_1STPERSON | (DI8DEVTYPE1STPERSON_SIXDOF << 8) }, + ++ { VID_SONY, PID_SONY_DUALSENSE, "Wireless Controller", "Wireless Controller", ++ DIDEVTYPE_HID | DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_GAMEPAD << 8), ++ DIDEVTYPE_HID | DI8DEVTYPE_1STPERSON | (DI8DEVTYPE1STPERSON_SIXDOF << 8) }, ++ + { VID_MICROSOFT, PID_MICROSOFT_XBOX_360, "Controller (XBOX 360 For Windows)", "Controller (XBOX 360 For Windows)", + DIDEVTYPE_HID | DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_GAMEPAD << 8), + DIDEVTYPE_HID | DI8DEVTYPE_GAMEPAD | (DI8DEVTYPEGAMEPAD_STANDARD << 8) }, +@@ -587,73 +592,45 @@ static int buttons_to_sdl_hat(int u, int r, int d, int l) + return SDL_HAT_RIGHTDOWN; + } + +-/* playstation controllers */ +-static BOOL enum_device_state_ds4_16button(SDL_Joystick *js, JoystickImpl *This, struct device_state_item *st, int idx) +-{ + #define SPECIALCASE_HAT -1 + #define SPECIALCASE_L2_BUTTON -2 + #define SPECIALCASE_R2_BUTTON -3 + +- static const struct { +- int type; +- int sdl_idx; +- int dnp_id; +- } map_ds4_16button[] = { +- { ITEM_TYPE_AXIS, 3, 5 }, /* R2 */ +- { ITEM_TYPE_AXIS, 2, 2 }, /* L2 */ +- { ITEM_TYPE_AXIS, 1, 1 }, /* left vert */ +- { ITEM_TYPE_AXIS, 0, 0 }, /* left horiz */ +- +- { ITEM_TYPE_HAT, SPECIALCASE_HAT, 0 }, /* d-pad */ +- +- { ITEM_TYPE_BUTTON, 2, 0}, /* square */ +- { ITEM_TYPE_BUTTON, 0, 1}, /* cross */ +- { ITEM_TYPE_BUTTON, 1, 2}, /* circle */ +- { ITEM_TYPE_BUTTON, 3, 3}, /* triangle */ +- +- { ITEM_TYPE_BUTTON, 9, 4}, /* L1 */ +- { ITEM_TYPE_BUTTON, 10, 5}, /* R1 */ +- { ITEM_TYPE_BUTTON, SPECIALCASE_L2_BUTTON, 6}, /* L2 button */ +- { ITEM_TYPE_BUTTON, SPECIALCASE_R2_BUTTON, 7}, /* R2 button */ +- { ITEM_TYPE_BUTTON, 4, 8}, /* share */ +- { ITEM_TYPE_BUTTON, 6, 9}, /* options */ +- +- { ITEM_TYPE_BUTTON, 7, 10}, /* guide */ +- { ITEM_TYPE_BUTTON, 8, 11}, /* L3 */ +- { ITEM_TYPE_BUTTON, 5, 12}, /* R3 */ +- +- { ITEM_TYPE_BUTTON, 15, 13}, /* touchpad button */ +- +- { ITEM_TYPE_AXIS, 5, 4 }, /* right vert */ +- { ITEM_TYPE_AXIS, 4, 3 }, /* right horiz */ +- }; ++struct enum_map ++{ ++ int type; ++ int sdl_idx; ++ int dnp_id; ++}; + +- if(idx >= ARRAY_SIZE(map_ds4_16button)) ++static BOOL enum_device_state_sony(const struct enum_map *enum_map, int map_size, SDL_Joystick *js, JoystickImpl *This, struct device_state_item *st, int idx) ++{ ++ if(idx >= map_size) + return FALSE; + +- st->type = map_ds4_16button[idx].type; +- st->id = map_ds4_16button[idx].dnp_id; ++ st->type = enum_map[idx].type; ++ st->id = enum_map[idx].dnp_id; + +- if(map_ds4_16button[idx].sdl_idx >= 0) ++ if(enum_map[idx].sdl_idx >= 0) + { + /* simple reads */ +- switch(map_ds4_16button[idx].type) ++ switch(enum_map[idx].type) + { + case ITEM_TYPE_BUTTON: +- st->val = SDL_JoystickGetButton(js, map_ds4_16button[idx].sdl_idx); ++ st->val = SDL_JoystickGetButton(js, enum_map[idx].sdl_idx); + return TRUE; + + case ITEM_TYPE_AXIS: +- st->val = SDL_JoystickGetAxis(js, map_ds4_16button[idx].sdl_idx); ++ st->val = SDL_JoystickGetAxis(js, enum_map[idx].sdl_idx); + return TRUE; + + case ITEM_TYPE_HAT: +- st->val = SDL_JoystickGetHat(js, map_ds4_16button[idx].sdl_idx); ++ st->val = SDL_JoystickGetHat(js, enum_map[idx].sdl_idx); + return TRUE; + } + } + +- switch(map_ds4_16button[idx].sdl_idx){ ++ switch(enum_map[idx].sdl_idx){ + case SPECIALCASE_HAT: + { + /* d-pad */ +@@ -691,10 +668,85 @@ static BOOL enum_device_state_ds4_16button(SDL_Joystick *js, JoystickImpl *This, + ERR("???\n"); /* error in static data above */ + return FALSE; + ++} ++ ++/* playstation controllers */ ++static BOOL enum_device_state_ds4_16button(SDL_Joystick *js, JoystickImpl *This, struct device_state_item *st, int idx) ++{ ++ ++ static const struct enum_map map_ds4_16button[] = { ++ { ITEM_TYPE_AXIS, 3, 5 }, /* R2 */ ++ { ITEM_TYPE_AXIS, 2, 2 }, /* L2 */ ++ { ITEM_TYPE_AXIS, 1, 1 }, /* left vert */ ++ { ITEM_TYPE_AXIS, 0, 0 }, /* left horiz */ ++ ++ { ITEM_TYPE_HAT, SPECIALCASE_HAT, 0 }, /* d-pad */ ++ ++ { ITEM_TYPE_BUTTON, 2, 0}, /* square */ ++ { ITEM_TYPE_BUTTON, 0, 1}, /* cross */ ++ { ITEM_TYPE_BUTTON, 1, 2}, /* circle */ ++ { ITEM_TYPE_BUTTON, 3, 3}, /* triangle */ ++ ++ { ITEM_TYPE_BUTTON, 9, 4}, /* L1 */ ++ { ITEM_TYPE_BUTTON, 10, 5}, /* R1 */ ++ { ITEM_TYPE_BUTTON, SPECIALCASE_L2_BUTTON, 6}, /* L2 button */ ++ { ITEM_TYPE_BUTTON, SPECIALCASE_R2_BUTTON, 7}, /* R2 button */ ++ { ITEM_TYPE_BUTTON, 4, 8}, /* share */ ++ { ITEM_TYPE_BUTTON, 6, 9}, /* options */ ++ ++ { ITEM_TYPE_BUTTON, 7, 10}, /* guide */ ++ { ITEM_TYPE_BUTTON, 8, 11}, /* L3 */ ++ { ITEM_TYPE_BUTTON, 5, 12}, /* R3 */ ++ ++ { ITEM_TYPE_BUTTON, 15, 13}, /* touchpad button */ ++ ++ { ITEM_TYPE_AXIS, 5, 4 }, /* right vert */ ++ { ITEM_TYPE_AXIS, 4, 3 }, /* right horiz */ ++ }; ++ ++ return enum_device_state_sony(map_ds4_16button, ARRAY_SIZE(map_ds4_16button), js, This, st, idx); ++} ++ ++static BOOL enum_device_state_dualsense(SDL_Joystick *js, JoystickImpl *This, struct device_state_item *st, int idx) ++{ ++ ++ static const struct enum_map map_dualsense[] = { ++ { ITEM_TYPE_AXIS, 3, 5 }, /* R2 */ ++ { ITEM_TYPE_AXIS, 2, 2 }, /* L2 */ ++ { ITEM_TYPE_AXIS, 1, 1 }, /* left vert */ ++ { ITEM_TYPE_AXIS, 0, 0 }, /* left horiz */ ++ ++ { ITEM_TYPE_HAT, SPECIALCASE_HAT, 0 }, /* d-pad */ ++ ++ { ITEM_TYPE_BUTTON, 2, 0}, /* square */ ++ { ITEM_TYPE_BUTTON, 0, 1}, /* cross */ ++ { ITEM_TYPE_BUTTON, 1, 2}, /* circle */ ++ { ITEM_TYPE_BUTTON, 3, 3}, /* triangle */ ++ ++ { ITEM_TYPE_BUTTON, 9, 4}, /* L1 */ ++ { ITEM_TYPE_BUTTON, 10, 5}, /* R1 */ ++ { ITEM_TYPE_BUTTON, SPECIALCASE_L2_BUTTON, 6}, /* L2 button */ ++ { ITEM_TYPE_BUTTON, SPECIALCASE_R2_BUTTON, 7}, /* R2 button */ ++ { ITEM_TYPE_BUTTON, 4, 8}, /* share */ ++ { ITEM_TYPE_BUTTON, 6, 9}, /* options */ ++ ++ { ITEM_TYPE_BUTTON, 7, 10}, /* guide */ ++ { ITEM_TYPE_BUTTON, 8, 11}, /* L3 */ ++ { ITEM_TYPE_BUTTON, 5, 12}, /* R3 */ ++ ++ { ITEM_TYPE_BUTTON, 16, 13}, /* touchpad button */ ++ { ITEM_TYPE_BUTTON, 15, 14}, /* mic mute button */ ++ ++ { ITEM_TYPE_AXIS, 5, 4 }, /* right vert */ ++ { ITEM_TYPE_AXIS, 4, 3 }, /* right horiz */ ++ }; ++ ++ return enum_device_state_sony(map_dualsense, ARRAY_SIZE(map_dualsense), js, This, st, idx); ++} ++ + #undef SPECIALCASE_HAT + #undef SPECIALCASE_L2_BUTTON + #undef SPECIALCASE_R2_BUTTON +-} + + static BOOL enum_device_state_ds4_13button(SDL_Joystick *js, JoystickImpl *This, struct device_state_item *st, int idx) + { +@@ -1007,6 +1059,8 @@ static enum_device_state_function select_enum_function(struct SDLDev *sdldev) + sdldev->n_buttons); + return enum_device_state_ds4_13button; + } ++ case PID_SONY_DUALSENSE: ++ return enum_device_state_dualsense; + break; + + case VID_MICROSOFT: +From 5801f2615a0dca106915a4b1a745dd0cc2c392a5 Mon Sep 17 00:00:00 2001 +From: Andrew Eikum +Date: Fri, 19 Feb 2021 07:08:02 -0600 +Subject: [PATCH] dinput: Instance GUID should be deterministic + +According to MSDN, the instance GUID will be stable across app launches. +Assetto Corsa Competizione stores the instance GUID and expects it to +refer to the same object across launches. +--- + dlls/dinput/joystick_sdl.c | 73 ++++++++++++++++++++++++++++++++------ + 1 file changed, 62 insertions(+), 11 deletions(-) + +diff --git a/dlls/dinput/joystick_sdl.c b/dlls/dinput/joystick_sdl.c +index ae3c9852eb7..e8e47b15140 100644 +--- a/dlls/dinput/joystick_sdl.c ++++ b/dlls/dinput/joystick_sdl.c +@@ -104,6 +104,7 @@ struct SDLDev { + int instance_id; + WORD vendor_id; + WORD product_id; ++ int nth_instance; /* zero-indexed nth instance of this vid/pid */ + SDL_JoystickGUID sdl_guid; + CHAR *name; + +@@ -146,8 +147,24 @@ static inline IDirectInputDevice8W *IDirectInputDevice8W_from_impl(JoystickImpl + return &This->generic.base.IDirectInputDevice8W_iface; + } + +-static const GUID DInput_Wine_SDL_Joystick_GUID = { /* 001E36B7-5DBA-4C4F-A8C9-CFC8689DB403 */ +- 0x001E36B7, 0x5DBA, 0x4C4F, {0xA8, 0xC9, 0xCF, 0xC8, 0x68, 0x9D, 0xB4, 0x03} ++#define PUT_JS_GUID_VID(guid, vid) \ ++ (guid)->Data4[2] = (vid >> 8) & 0xFF; \ ++ (guid)->Data4[3] = vid & 0xFF ++#define PUT_JS_GUID_PID(guid, pid) \ ++ (guid)->Data4[4] = (pid >> 8) & 0xFF; \ ++ (guid)->Data4[5] = pid & 0xFF ++#define PUT_JS_GUID_INSTANCE(guid, instance) \ ++ (guid)->Data4[7] = instance & 0xFF ++ ++#define GET_JS_GUID_VID(guid) \ ++ ((guid)->Data4[2] << 8) | (guid)->Data4[3] ++#define GET_JS_GUID_PID(guid) \ ++ ((guid)->Data4[4] << 8) | (guid)->Data4[5] ++#define GET_JS_GUID_INSTANCE(guid) \ ++ (guid)->Data4[7] ++ ++static const GUID DInput_Wine_SDL_Joystick_GUID = { /* 001E36B7-5DBA-4C4F-A8C9-000000000000 */ ++ 0x001E36B7, 0x5DBA, 0x4C4F, {0xA8, 0xC9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} + }; + + static CRITICAL_SECTION sdldevs_lock; +@@ -230,6 +247,21 @@ static BOOL WINAPI sdldrv_init(INIT_ONCE *once, void *param, void **context) + return TRUE; + } + ++static int get_num_vidpids(WORD vid, WORD pid) ++{ ++ int i, ret = 0; ++ ++ for(i = 0; i < ARRAY_SIZE(sdldevs); ++i){ ++ if(!sdldevs[i].valid) ++ break; ++ if(sdldevs[i].vendor_id == vid && ++ sdldevs[i].product_id == pid) ++ ++ret; ++ } ++ ++ return ret; ++} ++ + static void find_sdldevs(void) + { + static INIT_ONCE init_once = INIT_ONCE_STATIC_INIT; +@@ -362,6 +394,8 @@ static void find_sdldevs(void) + sdldev->product_id = PID_MICROSOFT_XBOX_360; + } + ++ sdldev->nth_instance = get_num_vidpids(sdldev->vendor_id, sdldev->product_id); ++ + sdldev->n_buttons = SDL_JoystickNumButtons(device); + sdldev->n_axes = SDL_JoystickNumAxes(device); + sdldev->n_hats = SDL_JoystickNumHats(device); +@@ -442,7 +476,9 @@ static void fill_joystick_dideviceinstanceA(LPDIDEVICEINSTANCEA lpddi, DWORD ver + + lpddi->dwSize = dwSize; + lpddi->guidInstance = DInput_Wine_SDL_Joystick_GUID; +- lpddi->guidInstance.Data3 = id; ++ PUT_JS_GUID_VID(&lpddi->guidInstance, sdldevs[id].vendor_id); ++ PUT_JS_GUID_PID(&lpddi->guidInstance, sdldevs[id].product_id); ++ PUT_JS_GUID_INSTANCE(&lpddi->guidInstance, sdldevs[id].nth_instance); + lpddi->guidProduct = DInput_PIDVID_Product_GUID; + lpddi->guidProduct.Data1 = MAKELONG(sdldevs[id].vendor_id, sdldevs[id].product_id); + lpddi->guidFFDriver = GUID_NULL; +@@ -1101,7 +1137,9 @@ static JoystickImpl *alloc_device(REFGUID rguid, IDirectInputImpl *dinput, unsig + if (!newDevice) return NULL; + + newDevice->generic.guidInstance = DInput_Wine_SDL_Joystick_GUID; +- newDevice->generic.guidInstance.Data3 = index; ++ PUT_JS_GUID_VID(&newDevice->generic.guidInstance, sdldevs[index].vendor_id); ++ PUT_JS_GUID_PID(&newDevice->generic.guidInstance, sdldevs[index].product_id); ++ PUT_JS_GUID_INSTANCE(&newDevice->generic.guidInstance, sdldevs[index].nth_instance); + newDevice->generic.guidProduct = DInput_PIDVID_Product_GUID; + newDevice->generic.guidProduct.Data1 = MAKELONG(sdldevs[index].vendor_id, sdldevs[index].product_id); + newDevice->generic.joy_polldev = poll_sdl_device_state; +@@ -1232,17 +1270,30 @@ static JoystickImpl *alloc_device(REFGUID rguid, IDirectInputImpl *dinput, unsig + */ + static unsigned short get_joystick_index(REFGUID guid) + { +- GUID wine_joystick = DInput_Wine_SDL_Joystick_GUID; +- GUID dev_guid = *guid; +- +- wine_joystick.Data3 = 0; +- dev_guid.Data3 = 0; ++ int i; ++ WORD vid, pid; ++ LONG nth_instance; + + /* for the standard joystick GUID use index 0 */ + if(IsEqualGUID(&GUID_Joystick,guid)) return 0; + +- /* for the wine joystick GUIDs use the index stored in Data3 */ +- if(IsEqualGUID(&wine_joystick, &dev_guid)) return guid->Data3; ++ if(guid->Data1 == DInput_Wine_SDL_Joystick_GUID.Data1 && ++ guid->Data2 == DInput_Wine_SDL_Joystick_GUID.Data2 && ++ guid->Data3 == DInput_Wine_SDL_Joystick_GUID.Data3){ ++ vid = GET_JS_GUID_VID(guid); ++ pid = GET_JS_GUID_PID(guid); ++ nth_instance = GET_JS_GUID_INSTANCE(guid); ++ ++ for(i = 0; i < ARRAY_SIZE(sdldevs); ++i){ ++ if(!sdldevs[i].valid) ++ break; ++ if(sdldevs[i].vendor_id == vid && ++ sdldevs[i].product_id == pid && ++ sdldevs[i].nth_instance == nth_instance){ ++ return i; ++ } ++ } ++ } + + return 0xffff; + } +From deb80a74a461eff1646b29c871ffffa3597337f3 Mon Sep 17 00:00:00 2001 +From: Arkadiusz Hiler +Date: Thu, 18 Mar 2021 12:07:58 +0200 +Subject: [PATCH] dinput: Support product GUIDs in CreateDevice with the SDL + backend. + +CW-Bug-Id: 18652 +--- + dlls/dinput/joystick_sdl.c | 20 ++++++++++++++++++++ + 1 file changed, 20 insertions(+) + +diff --git a/dlls/dinput/joystick_sdl.c b/dlls/dinput/joystick_sdl.c +index e8e47b15140..8cb839aa610 100644 +--- a/dlls/dinput/joystick_sdl.c ++++ b/dlls/dinput/joystick_sdl.c +@@ -1273,6 +1273,7 @@ static unsigned short get_joystick_index(REFGUID guid) + int i; + WORD vid, pid; + LONG nth_instance; ++ GUID prod_guid = *guid; + + /* for the standard joystick GUID use index 0 */ + if(IsEqualGUID(&GUID_Joystick,guid)) return 0; +@@ -1295,6 +1296,19 @@ static unsigned short get_joystick_index(REFGUID guid) + } + } + ++ prod_guid.Data1 = 0; ++ if(IsEqualGUID(&prod_guid, &DInput_PIDVID_Product_GUID)){ ++ vid = LOWORD(guid->Data1); ++ pid = HIWORD(guid->Data1); ++ ++ for(i = 0; i < ARRAY_SIZE(sdldevs); ++i){ ++ if(!sdldevs[i].valid) ++ break; ++ if(sdldevs[i].vendor_id == vid && ++ sdldevs[i].product_id == pid) ++ return i; ++ } ++ } + return 0xffff; + } + +@@ -1587,6 +1601,9 @@ static HRESULT WINAPI JoystickAImpl_GetDeviceInfo(LPDIRECTINPUTDEVICE8A iface, + + fill_joystick_dideviceinstanceA(pdidi, This->generic.base.dinput->dwVersion, + get_joystick_index(&This->generic.base.guid)); ++ ++ pdidi->guidInstance = This->generic.base.guid; ++ + return DI_OK; + } + +@@ -1604,6 +1621,9 @@ static HRESULT WINAPI JoystickWImpl_GetDeviceInfo(LPDIRECTINPUTDEVICE8W iface, + + fill_joystick_dideviceinstanceW(pdidi, This->generic.base.dinput->dwVersion, + get_joystick_index(&This->generic.base.guid)); ++ ++ pdidi->guidInstance = This->generic.base.guid; ++ + return DI_OK; + } + + +From 8a9c394a2cc531c40ef18a7f27031ff23a1dc4f5 Mon Sep 17 00:00:00 2001 +From: Andrew Eikum +Date: Tue, 28 Aug 2018 10:35:19 -0500 +Subject: [PATCH] winebus: Show an ERR on old SDL + +--- + dlls/winebus.sys/bus_sdl.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/dlls/winebus.sys/bus_sdl.c b/dlls/winebus.sys/bus_sdl.c +index bf62f448976..8b32c5ee860 100644 +--- a/dlls/winebus.sys/bus_sdl.c ++++ b/dlls/winebus.sys/bus_sdl.c +@@ -1166,6 +1166,9 @@ NTSTATUS sdl_driver_init(void) + pSDL_JoystickGetProduct = dlsym(sdl_handle, "SDL_JoystickGetProduct"); + pSDL_JoystickGetProductVersion = dlsym(sdl_handle, "SDL_JoystickGetProductVersion"); + pSDL_JoystickGetVendor = dlsym(sdl_handle, "SDL_JoystickGetVendor"); ++ if(!pSDL_JoystickGetVendor){ ++ ERR("SDL installation is old! Please upgrade to >=2.0.6 to get accurate joystick information.\n"); ++ } + } + + map_controllers = check_bus_option(&controller_mode, 1); +From 348fbd714c074f5c5b523383d4191ad2eab08b49 Mon Sep 17 00:00:00 2001 +From: Andrew Eikum +Date: Thu, 2 May 2019 10:17:49 -0500 +Subject: [PATCH] winebus.sys: Don't report the guide button + +This breaks our xinput. +--- + dlls/winebus.sys/bus_sdl.c | 5 ++++- + dlls/xinput1_3/main.c | 5 ++--- + 2 files changed, 6 insertions(+), 4 deletions(-) + +diff --git a/dlls/winebus.sys/bus_sdl.c b/dlls/winebus.sys/bus_sdl.c +index 8b32c5ee860..7fcb19a6e88 100644 +--- a/dlls/winebus.sys/bus_sdl.c ++++ b/dlls/winebus.sys/bus_sdl.c +@@ -149,7 +149,7 @@ static const BYTE REPORT_AXIS_TAIL[] = { + }; + #define IDX_ABS_AXIS_COUNT 23 + +-#define CONTROLLER_NUM_BUTTONS 11 ++#define CONTROLLER_NUM_BUTTONS 10 + + static const BYTE CONTROLLER_BUTTONS[] = { + USAGE_PAGE(1, HID_USAGE_PAGE_BUTTON), +@@ -834,7 +834,10 @@ static BOOL set_mapped_report_from_event(SDL_Event *event) + case SDL_CONTROLLER_BUTTON_START: usage = 7; break; + case SDL_CONTROLLER_BUTTON_LEFTSTICK: usage = 8; break; + case SDL_CONTROLLER_BUTTON_RIGHTSTICK: usage = 9; break; ++ ++ /* native HID does not report the guide button + case SDL_CONTROLLER_BUTTON_GUIDE: usage = 10; break; ++ */ + + case SDL_CONTROLLER_BUTTON_DPAD_UP: + case SDL_CONTROLLER_BUTTON_DPAD_DOWN: +diff --git a/dlls/xinput1_3/main.c b/dlls/xinput1_3/main.c +index 8aea638a8d7..7cdca280295 100644 +--- a/dlls/xinput1_3/main.c ++++ b/dlls/xinput1_3/main.c +@@ -182,7 +182,7 @@ static BOOL VerifyGamepad(PHIDP_PREPARSED_DATA ppd, XINPUT_CAPABILITIES *xinput_ + button_count = max(button_count, button_caps[i].NotRange.Usage); + } + free(button_caps); +- if (button_count < 11) ++ if (button_count < 10) + WARN("Too few buttons, continuing anyway\n"); + xinput_caps->Gamepad.wButtons = 0xffff; + +@@ -387,7 +387,7 @@ void HID_update_state(xinput_controller *device, XINPUT_STATE *state) + ULONG report_len = private->caps.InputReportByteLength; + NTSTATUS status; + +- USAGE buttons[11]; ++ USAGE buttons[10]; + ULONG button_length, value; + + if (!controller->enabled) return; +@@ -431,7 +431,6 @@ void HID_update_state(xinput_controller *device, XINPUT_STATE *state) + case 8: controller->state.Gamepad.wButtons |= XINPUT_GAMEPAD_START; break; + case 9: controller->state.Gamepad.wButtons |= XINPUT_GAMEPAD_LEFT_THUMB; break; + case 10: controller->state.Gamepad.wButtons |= XINPUT_GAMEPAD_RIGHT_THUMB; break; +- case 11: controller->state.Gamepad.wButtons |= XINPUT_GAMEPAD_GUIDE; break; + } + } + +From c5d52c73b754568df148013907f26e5da3525166 Mon Sep 17 00:00:00 2001 +From: Andrew Eikum +Date: Tue, 6 Aug 2019 13:27:25 -0500 +Subject: [PATCH] winebus.sys: Disable linuxevent API + +We either go through SDL or hidraw directly. +--- + dlls/winebus.sys/bus_udev.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/dlls/winebus.sys/bus_udev.c b/dlls/winebus.sys/bus_udev.c +index 3505b8bdbe1..aadbd5943ad 100644 +--- a/dlls/winebus.sys/bus_udev.c ++++ b/dlls/winebus.sys/bus_udev.c +@@ -47,7 +47,7 @@ + # include + # undef SW_MAX + # if defined(EVIOCGBIT) && defined(EV_ABS) && defined(BTN_PINKIE) +-# define HAS_PROPER_INPUT_HEADER ++//# define HAS_PROPER_INPUT_HEADER + # endif + # ifndef SYN_DROPPED + # define SYN_DROPPED 3 +From 7b71102f75e07e718e79d1316c68de419668b0cb Mon Sep 17 00:00:00 2001 +From: Andrew Eikum +Date: Mon, 19 Aug 2019 14:01:55 -0500 +Subject: [PATCH] winebus.sys: Try to open devices with hidraw first + +--- + dlls/winebus.sys/bus.h | 2 ++ + dlls/winebus.sys/bus_sdl.c | 31 +++++++++++++++++++------------ + dlls/winebus.sys/bus_udev.c | 22 ++++++++++++++++++++++ + dlls/winebus.sys/main.c | 5 +++-- + 4 files changed, 46 insertions(+), 14 deletions(-) + +diff --git a/dlls/winebus.sys/bus.h b/dlls/winebus.sys/bus.h +index 8aa5535aa1d..8fc90cad5ee 100644 +--- a/dlls/winebus.sys/bus.h ++++ b/dlls/winebus.sys/bus.h +@@ -54,5 +54,7 @@ DEVICE_OBJECT* bus_enumerate_hid_devices(const platform_vtbl *vtbl, enum_func fu + DWORD check_bus_option(const UNICODE_STRING *option, DWORD default_value) DECLSPEC_HIDDEN; + BOOL is_xbox_gamepad(WORD vid, WORD pid) DECLSPEC_HIDDEN; + ++BOOL is_already_opened_by_hidraw(DWORD vid, DWORD pid) DECLSPEC_HIDDEN; ++ + extern HANDLE driver_key DECLSPEC_HIDDEN; + extern DEVICE_OBJECT *bus_pdo DECLSPEC_HIDDEN; +diff --git a/dlls/winebus.sys/bus_sdl.c b/dlls/winebus.sys/bus_sdl.c +index 83a92f1fb1f..887e2e801ba 100644 +--- a/dlls/winebus.sys/bus_sdl.c ++++ b/dlls/winebus.sys/bus_sdl.c +@@ -1007,6 +1007,25 @@ static void try_add_device(unsigned int index, BOOL xinput_hack) + return; + } + ++ if (pSDL_JoystickGetProductVersion != NULL) { ++ vid = pSDL_JoystickGetVendor(joystick); ++ pid = pSDL_JoystickGetProduct(joystick); ++ version = pSDL_JoystickGetProductVersion(joystick); ++ } ++ else ++ { ++ vid = 0x01; ++ pid = pSDL_JoystickInstanceID(joystick) + 1; ++ version = 0; ++ } ++ ++ if(is_already_opened_by_hidraw(vid, pid)) ++ { ++ /* we use SDL only for controllers which hidraw couldn't open */ ++ TRACE("device %04x/%04x already opened by hidraw, skipping\n", vid, pid); ++ return; ++ } ++ + if (map_controllers && pSDL_IsGameController(index)) + controller = pSDL_GameControllerOpen(index); + +@@ -1021,18 +1040,6 @@ static void try_add_device(unsigned int index, BOOL xinput_hack) + if(xinput_hack) + id |= XINPUT_HACK_ID_BIT; + +- if (pSDL_JoystickGetProductVersion != NULL) { +- vid = pSDL_JoystickGetVendor(joystick); +- pid = pSDL_JoystickGetProduct(joystick); +- version = pSDL_JoystickGetProductVersion(joystick); +- } +- else +- { +- vid = 0x01; +- pid = pSDL_JoystickInstanceID(joystick) + 1; +- version = 0; +- } +- + guid = pSDL_JoystickGetGUID(joystick); + pSDL_JoystickGetGUIDString(guid, guid_str, sizeof(guid_str)); + MultiByteToWideChar(CP_ACP, 0, guid_str, -1, serial, sizeof(guid_str)); +diff --git a/dlls/winebus.sys/bus_udev.c b/dlls/winebus.sys/bus_udev.c +index aadbd5943ad..21e9764e6a5 100644 +--- a/dlls/winebus.sys/bus_udev.c ++++ b/dlls/winebus.sys/bus_udev.c +@@ -98,6 +98,10 @@ static int deviceloop_control[2]; + static const WCHAR hidraw_busidW[] = {'H','I','D','R','A','W',0}; + static const WCHAR lnxev_busidW[] = {'L','N','X','E','V',0}; + ++struct vidpid { ++ WORD vid, pid; ++}; ++ + struct platform_private + { + struct udev_device *udev_device; +@@ -105,6 +109,8 @@ struct platform_private + + HANDLE report_thread; + int control_pipe[2]; ++ ++ struct vidpid vidpid; + }; + + static inline struct platform_private *impl_from_DEVICE_OBJECT(DEVICE_OBJECT *device) +@@ -1141,6 +1147,20 @@ static DWORD a_to_bcd(const char *s) + return r; + } + ++static int check_for_vidpid(DEVICE_OBJECT *device, void* context) ++{ ++ struct vidpid *vidpid = context; ++ struct platform_private *dev = impl_from_DEVICE_OBJECT(device); ++ return !(dev->vidpid.vid == vidpid->vid && ++ dev->vidpid.pid == vidpid->pid); ++} ++ ++BOOL is_already_opened_by_hidraw(DWORD vid, DWORD pid) ++{ ++ struct vidpid vidpid = {vid, pid}; ++ return bus_enumerate_hid_devices(&hidraw_vtbl, check_for_vidpid, &vidpid) != NULL; ++} ++ + static void try_add_device(struct udev_device *dev) + { + DWORD vid = 0, pid = 0, version = 0; +@@ -1258,6 +1278,8 @@ static void try_add_device(struct udev_device *dev) + struct platform_private *private = impl_from_DEVICE_OBJECT(device); + private->udev_device = udev_device_ref(dev); + private->device_fd = fd; ++ private->vidpid.vid = vid; ++ private->vidpid.pid = pid; + #ifdef HAS_PROPER_INPUT_HEADER + if (strcmp(subsystem, "input") == 0) + if (!build_report_descriptor((struct wine_input_private*)private, dev)) +diff --git a/dlls/winebus.sys/main.c b/dlls/winebus.sys/main.c +index 55d444b5fe7..22f7f8df225 100644 +--- a/dlls/winebus.sys/main.c ++++ b/dlls/winebus.sys/main.c +@@ -557,6 +557,9 @@ static NTSTATUS fdo_pnp_dispatch(DEVICE_OBJECT *device, IRP *irp) + case IRP_MN_START_DEVICE: + mouse_device_create(); + ++ udev_driver_init(); ++ iohid_driver_init(); ++ + if (check_bus_option(&SDL_enabled, 1)) + { + if (sdl_driver_init() == STATUS_SUCCESS) +@@ -565,8 +568,6 @@ static NTSTATUS fdo_pnp_dispatch(DEVICE_OBJECT *device, IRP *irp) + break; + } + } +- udev_driver_init(); +- iohid_driver_init(); + irp->IoStatus.u.Status = STATUS_SUCCESS; + break; + case IRP_MN_SURPRISE_REMOVAL: +From b8ca845546043d26d96619460c96c9ec7025c4a5 Mon Sep 17 00:00:00 2001 +From: Andrew Eikum +Date: Tue, 6 Aug 2019 13:37:38 -0500 +Subject: [PATCH] winebus.sys: Don't use hidraw for xbox controllers + +Xbox controllers don't present real HID devices. +--- + dlls/winebus.sys/bus_udev.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/dlls/winebus.sys/bus_udev.c b/dlls/winebus.sys/bus_udev.c +index 21e9764e6a5..acdbdd1370f 100644 +--- a/dlls/winebus.sys/bus_udev.c ++++ b/dlls/winebus.sys/bus_udev.c +@@ -1243,7 +1243,11 @@ static void try_add_device(struct udev_device *dev) + #endif + + if (is_xbox_gamepad(vid, pid)) +- is_gamepad = TRUE; ++ { ++ /* SDL handles xbox (and steam) controllers */ ++ close(fd); ++ return; ++ } + #ifdef HAS_PROPER_INPUT_HEADER + else + { +From d015a87a9309059344e50f573fef656de1a82fea Mon Sep 17 00:00:00 2001 +From: Andrew Eikum +Date: Wed, 14 Aug 2019 08:47:53 -0500 +Subject: [PATCH] winebus: Don't report hidraw devices which are being used as + virtual controllers + +--- + dlls/winebus.sys/bus_udev.c | 21 +++++++++++++++++++++ + 1 file changed, 21 insertions(+) + +diff --git a/dlls/winebus.sys/bus_udev.c b/dlls/winebus.sys/bus_udev.c +index acdbdd1370f..50268561ee8 100644 +--- a/dlls/winebus.sys/bus_udev.c ++++ b/dlls/winebus.sys/bus_udev.c +@@ -18,6 +18,7 @@ + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + ++#define _GNU_SOURCE + #include "config.h" + #include + #include +@@ -1161,6 +1162,19 @@ BOOL is_already_opened_by_hidraw(DWORD vid, DWORD pid) + return bus_enumerate_hid_devices(&hidraw_vtbl, check_for_vidpid, &vidpid) != NULL; + } + ++static BOOL is_in_sdl_blacklist(DWORD vid, DWORD pid) ++{ ++ char needle[16]; ++ const char *blacklist = getenv("SDL_GAMECONTROLLER_IGNORE_DEVICES"); ++ ++ if (!blacklist) ++ return FALSE; ++ ++ sprintf(needle, "0x%04x/0x%04x", vid, pid); ++ ++ return strcasestr(blacklist, needle) != NULL; ++} ++ + static void try_add_device(struct udev_device *dev) + { + DWORD vid = 0, pid = 0, version = 0; +@@ -1242,6 +1256,13 @@ static void try_add_device(struct udev_device *dev) + WARN("Could not get device to query VID, PID, Version and Serial\n"); + #endif + ++ if (is_in_sdl_blacklist(vid, pid)) ++ { ++ /* this device is being used as a virtual Steam controller */ ++ close(fd); ++ return; ++ } ++ + if (is_xbox_gamepad(vid, pid)) + { + /* SDL handles xbox (and steam) controllers */ +From 82fd2ca527921e48a87dbc82118637c970b9e1c8 Mon Sep 17 00:00:00 2001 +From: Andrew Eikum +Date: Wed, 14 Aug 2019 09:15:21 -0500 +Subject: [PATCH] winebus.sys: Don't use hidraw for Steam controllers + +--- + dlls/winebus.sys/bus.h | 1 + + dlls/winebus.sys/bus_udev.c | 4 +++- + dlls/winebus.sys/main.c | 24 ++++++++++++++++++++++++ + 3 files changed, 28 insertions(+), 1 deletion(-) + +diff --git a/dlls/winebus.sys/bus.h b/dlls/winebus.sys/bus.h +index 8fc90cad5ee..69bd7ce66d7 100644 +--- a/dlls/winebus.sys/bus.h ++++ b/dlls/winebus.sys/bus.h +@@ -53,6 +53,7 @@ DEVICE_OBJECT* bus_enumerate_hid_devices(const platform_vtbl *vtbl, enum_func fu + /* General Bus Functions */ + DWORD check_bus_option(const UNICODE_STRING *option, DWORD default_value) DECLSPEC_HIDDEN; + BOOL is_xbox_gamepad(WORD vid, WORD pid) DECLSPEC_HIDDEN; ++BOOL is_steam_controller(WORD vid, WORD pid) DECLSPEC_HIDDEN; + + BOOL is_already_opened_by_hidraw(DWORD vid, DWORD pid) DECLSPEC_HIDDEN; + +diff --git a/dlls/winebus.sys/bus_udev.c b/dlls/winebus.sys/bus_udev.c +index 50268561ee8..c3226703c4e 100644 +--- a/dlls/winebus.sys/bus_udev.c ++++ b/dlls/winebus.sys/bus_udev.c +@@ -1256,9 +1256,10 @@ static void try_add_device(struct udev_device *dev) + WARN("Could not get device to query VID, PID, Version and Serial\n"); + #endif + +- if (is_in_sdl_blacklist(vid, pid)) ++ if (is_steam_controller(vid, pid) || is_in_sdl_blacklist(vid, pid)) + { + /* this device is being used as a virtual Steam controller */ ++ TRACE("hidraw %s: ignoring device %04x/%04x with virtual Steam controller\n", debugstr_a(devnode), vid, pid); + close(fd); + return; + } +@@ -1266,6 +1267,7 @@ static void try_add_device(struct udev_device *dev) + if (is_xbox_gamepad(vid, pid)) + { + /* SDL handles xbox (and steam) controllers */ ++ TRACE("hidraw %s: ignoring xinput device %04x/%04x\n", debugstr_a(devnode), vid, pid); + close(fd); + return; + } +diff --git a/dlls/winebus.sys/main.c b/dlls/winebus.sys/main.c +index 22f7f8df225..507e67681b1 100644 +--- a/dlls/winebus.sys/main.c ++++ b/dlls/winebus.sys/main.c +@@ -94,6 +94,18 @@ static const struct product_desc XBOX_CONTROLLERS[] = { + {VID_MICROSOFT, 0x0719, NULL, xbox360_product_string, NULL}, /* Xbox 360 Wireless Adapter */ + }; + ++#define VID_VALVE 0x28de ++ ++static const struct product_desc STEAM_CONTROLLERS[] = { ++ {VID_VALVE, 0x1101, NULL, NULL, NULL}, /* Valve Legacy Steam Controller */ ++ {VID_VALVE, 0x1102, NULL, NULL, NULL}, /* Valve wired Steam Controller */ ++ {VID_VALVE, 0x1105, NULL, NULL, NULL}, /* Valve Bluetooth Steam Controller */ ++ {VID_VALVE, 0x1106, NULL, NULL, NULL}, /* Valve Bluetooth Steam Controller */ ++ {VID_VALVE, 0x1142, NULL, NULL, NULL}, /* Valve wireless Steam Controller */ ++ {VID_VALVE, 0x1201, NULL, NULL, NULL}, /* Valve wired Steam Controller */ ++ {VID_VALVE, 0x1202, NULL, NULL, NULL}, /* Valve Bluetooth Steam Controller */ ++}; ++ + static DRIVER_OBJECT *driver_obj; + + static DEVICE_OBJECT *mouse_obj; +@@ -968,6 +980,18 @@ static NTSTATUS WINAPI driver_add_device(DRIVER_OBJECT *driver, DEVICE_OBJECT *p + return STATUS_SUCCESS; + } + ++BOOL is_steam_controller(WORD vid, WORD pid) ++{ ++ if (vid == VID_VALVE) ++ { ++ int i; ++ for (i = 0; i < ARRAY_SIZE(STEAM_CONTROLLERS); i++) ++ if (pid == STEAM_CONTROLLERS[i].pid) return TRUE; ++ } ++ ++ return FALSE; ++} ++ + static void WINAPI driver_unload(DRIVER_OBJECT *driver) + { + NtClose(driver_key); +From 7a33118076875cd59bdee83a80def75f6a05ddf7 Mon Sep 17 00:00:00 2001 +From: Andrew Eikum +Date: Thu, 22 Aug 2019 09:59:27 -0500 +Subject: [PATCH] winebus.drv: Also respect the SDL device whitelist + +--- + dlls/winebus.sys/bus_udev.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/dlls/winebus.sys/bus_udev.c b/dlls/winebus.sys/bus_udev.c +index c3226703c4e..24c1c548393 100644 +--- a/dlls/winebus.sys/bus_udev.c ++++ b/dlls/winebus.sys/bus_udev.c +@@ -1166,6 +1166,14 @@ static BOOL is_in_sdl_blacklist(DWORD vid, DWORD pid) + { + char needle[16]; + const char *blacklist = getenv("SDL_GAMECONTROLLER_IGNORE_DEVICES"); ++ const char *whitelist = getenv("SDL_GAMECONTROLLER_IGNORE_DEVICES_EXCEPT"); ++ ++ if (whitelist) ++ { ++ sprintf(needle, "0x%04x/0x%04x", vid, pid); ++ ++ return strcasestr(whitelist, needle) == NULL; ++ } + + if (!blacklist) + return FALSE; +From 034330d7bec5ae3e480d917794129068ba3cc736 Mon Sep 17 00:00:00 2001 +From: Andrew Eikum +Date: Thu, 29 Aug 2019 15:04:36 -0500 +Subject: [PATCH] winebus.sys: Ignore blacklisted SDL joysticks, too + +SDL only respects these variables for game controllers. All joysticks +are allowed through. But we don't want to present these at all, so we'll +check the variables manually. +--- + dlls/winebus.sys/bus_sdl.c | 35 +++++++++++++++++++++++++++++++++++ + 1 file changed, 35 insertions(+) + +diff --git a/dlls/winebus.sys/bus_sdl.c b/dlls/winebus.sys/bus_sdl.c +index 887e2e801ba..bfef1fcb6cf 100644 +--- a/dlls/winebus.sys/bus_sdl.c ++++ b/dlls/winebus.sys/bus_sdl.c +@@ -987,6 +987,35 @@ static void try_remove_device(SDL_JoystickID id) + pSDL_HapticClose(sdl_haptic); + } + ++/* logic from SDL2's SDL_ShouldIgnoreGameController */ ++static BOOL is_in_sdl_blacklist(DWORD vid, DWORD pid) ++{ ++ char needle[16]; ++ const char *blacklist = getenv("SDL_GAMECONTROLLER_IGNORE_DEVICES"); ++ const char *whitelist = getenv("SDL_GAMECONTROLLER_IGNORE_DEVICES_EXCEPT"); ++ const char *allow_virtual = getenv("SDL_GAMECONTROLLER_ALLOW_STEAM_VIRTUAL_GAMEPAD"); ++ ++ if (!blacklist && !whitelist) ++ return FALSE; ++ ++ if (allow_virtual && *allow_virtual != '0') ++ { ++ if(vid == 0x28DE && pid == 0x11FF) ++ return FALSE; ++ } ++ ++ if (whitelist) ++ { ++ sprintf(needle, "0x%04x/0x%04x", vid, pid); ++ ++ return strcasestr(whitelist, needle) == NULL; ++ } ++ ++ sprintf(needle, "0x%04x/0x%04x", vid, pid); ++ ++ return strcasestr(blacklist, needle) != NULL; ++} ++ + static void try_add_device(unsigned int index) + { + DWORD vid = 0, pid = 0, version = 0; +@@ -1026,6 +1055,12 @@ static void try_add_device(unsigned int index) + return; + } + ++ if(is_in_sdl_blacklist(vid, pid)) ++ { ++ TRACE("device %04x/%04x is in blacklist, ignoring\n", vid, pid); ++ return; ++ } ++ + if (map_controllers && pSDL_IsGameController(index)) + controller = pSDL_GameControllerOpen(index); + +From 8e9cf558d3b305038f2cc2d82a89d0773b3ffd4b Mon Sep 17 00:00:00 2001 +From: Andrew Eikum +Date: Fri, 30 Aug 2019 10:20:16 -0500 +Subject: [PATCH] winebus.sys: Override Steam virtual controller vid/pid with + Xbox + +Matches Windows Steam client behavior. +--- + dlls/winebus.sys/bus_sdl.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/dlls/winebus.sys/bus_sdl.c b/dlls/winebus.sys/bus_sdl.c +index bfef1fcb6cf..b1b70c20294 100644 +--- a/dlls/winebus.sys/bus_sdl.c ++++ b/dlls/winebus.sys/bus_sdl.c +@@ -1084,6 +1084,13 @@ static void try_add_device(unsigned int index, BOOL xinput_hack) + TRACE("Found sdl game controller 0x%x (vid %04x, pid %04x, version %u, serial %s, xinput_hack: %u)\n", + id, vid, pid, version, debugstr_w(serial), xinput_hack); + is_xbox_gamepad = TRUE; ++ ++ if(vid == 0x28DE && pid == 0x11FF) ++ { ++ TRACE("Steam virtual controller, pretending it's an Xbox 360 controller\n"); ++ vid = 0x045e; ++ pid = 0x028e; ++ } + } + else + { +From bff8eaebcb7ba4f9ef48006062c44f512eae66db Mon Sep 17 00:00:00 2001 +From: Andrew Eikum +Date: Thu, 29 Aug 2019 11:20:23 -0500 +Subject: [PATCH] winebus: Extract bluetooth info from uevent + +udev doesn't report this info. +--- + dlls/winebus.sys/bus_udev.c | 167 ++++++++++++++++++++++-------------- + 1 file changed, 101 insertions(+), 66 deletions(-) + +diff --git a/dlls/winebus.sys/bus_udev.c b/dlls/winebus.sys/bus_udev.c +index 24c1c548393..70fedf46973 100644 +--- a/dlls/winebus.sys/bus_udev.c ++++ b/dlls/winebus.sys/bus_udev.c +@@ -112,6 +112,8 @@ struct platform_private + int control_pipe[2]; + + struct vidpid vidpid; ++ ++ DWORD bus_type; + }; + + static inline struct platform_private *impl_from_DEVICE_OBJECT(DEVICE_OBJECT *device) +@@ -660,6 +662,68 @@ static WCHAR *get_sysattr_string(struct udev_device *dev, const char *sysattr) + return strdupAtoW(attr); + } + ++static void parse_uevent_info(const char *uevent, DWORD *bus_type, DWORD *vendor_id, ++ DWORD *product_id, WORD *input, WCHAR **serial_number, WCHAR **product) ++{ ++ char *tmp; ++ char *saveptr = NULL; ++ char *line; ++ char *key; ++ char *value; ++ ++ tmp = heap_alloc(strlen(uevent) + 1); ++ strcpy(tmp, uevent); ++ line = strtok_r(tmp, "\n", &saveptr); ++ while (line != NULL) ++ { ++ /* line: "KEY=value" */ ++ key = line; ++ value = strchr(line, '='); ++ if (!value) ++ { ++ goto next_line; ++ } ++ *value = '\0'; ++ value++; ++ ++ if (strcmp(key, "HID_ID") == 0) ++ { ++ /** ++ * type vendor product ++ * HID_ID=0003:000005AC:00008242 ++ **/ ++ sscanf(value, "%x:%x:%x", bus_type, vendor_id, product_id); ++ } ++ else if (strcmp(key, "HID_UNIQ") == 0) ++ { ++ /* The caller has to free the serial number */ ++ if (*value) ++ { ++ *serial_number = strdupAtoW(value); ++ } ++ } ++ else if (product && strcmp(key, "HID_NAME") == 0) ++ { ++ /* The caller has to free the product name */ ++ if (*value) ++ { ++ *product = strdupAtoW(value); ++ } ++ } ++ else if (strcmp(key, "HID_PHYS") == 0) ++ { ++ const char *input_no = strstr(value, "input"); ++ if (input_no) ++ *input = atoi(input_no+5 ); ++ } ++ ++next_line: ++ line = strtok_r(NULL, "\n", &saveptr); ++ } ++ ++ heap_free(tmp); ++} ++ + static int compare_platform_device(DEVICE_OBJECT *device, void *platform_dev) + { + struct udev_device *dev1 = impl_from_DEVICE_OBJECT(device)->udev_device; +@@ -701,12 +765,43 @@ static NTSTATUS hidraw_get_reportdescriptor(DEVICE_OBJECT *device, BYTE *buffer, + + static NTSTATUS hidraw_get_string(DEVICE_OBJECT *device, DWORD index, WCHAR *buffer, DWORD length) + { +- struct udev_device *usbdev; ++ struct udev_device *usbdev, *hiddev; + struct platform_private *private = impl_from_DEVICE_OBJECT(device); + WCHAR *str = NULL; + ++ hiddev = udev_device_get_parent_with_subsystem_devtype(private->udev_device, "hid", NULL); + usbdev = udev_device_get_parent_with_subsystem_devtype(private->udev_device, "usb", "usb_device"); +- if (usbdev) ++ ++ if (private->bus_type == BUS_BLUETOOTH && hiddev) ++ { ++ DWORD bus_type, vid, pid; ++ WORD input; ++ WCHAR *serial = NULL, *product = NULL; ++ ++ /* udev doesn't report this info, so we have to extract it from uevent property */ ++ ++ parse_uevent_info(udev_device_get_sysattr_value(hiddev, "uevent"), ++ &bus_type, &vid, &pid, &input, &serial, &product); ++ ++ switch (index) ++ { ++ case HID_STRING_ID_IPRODUCT: ++ str = product; ++ HeapFree(GetProcessHeap(), 0, serial); ++ break; ++ case HID_STRING_ID_IMANUFACTURER: ++ /* TODO */ ++ break; ++ case HID_STRING_ID_ISERIALNUMBER: ++ str = serial; ++ HeapFree(GetProcessHeap(), 0, product); ++ break; ++ default: ++ ERR("Unhandled string index %08x\n", index); ++ return STATUS_NOT_IMPLEMENTED; ++ } ++ } ++ else if (usbdev) + { + switch (index) + { +@@ -1073,68 +1168,6 @@ static int check_same_device(DEVICE_OBJECT *device, void* context) + return !compare_platform_device(device, context); + } + +-static int parse_uevent_info(const char *uevent, DWORD *vendor_id, +- DWORD *product_id, WORD *input, WCHAR **serial_number) +-{ +- DWORD bus_type; +- char *tmp; +- char *saveptr = NULL; +- char *line; +- char *key; +- char *value; +- +- int found_id = 0; +- int found_serial = 0; +- +- tmp = heap_alloc(strlen(uevent) + 1); +- strcpy(tmp, uevent); +- line = strtok_r(tmp, "\n", &saveptr); +- while (line != NULL) +- { +- /* line: "KEY=value" */ +- key = line; +- value = strchr(line, '='); +- if (!value) +- { +- goto next_line; +- } +- *value = '\0'; +- value++; +- +- if (strcmp(key, "HID_ID") == 0) +- { +- /** +- * type vendor product +- * HID_ID=0003:000005AC:00008242 +- **/ +- int ret = sscanf(value, "%x:%x:%x", &bus_type, vendor_id, product_id); +- if (ret == 3) +- found_id = 1; +- } +- else if (strcmp(key, "HID_UNIQ") == 0) +- { +- /* The caller has to free the serial number */ +- if (*value) +- { +- *serial_number = strdupAtoW(value); +- found_serial = 1; +- } +- } +- else if (strcmp(key, "HID_PHYS") == 0) +- { +- const char *input_no = strstr(value, "input"); +- if (input_no) +- *input = atoi(input_no+5 ); +- } +- +-next_line: +- line = strtok_r(NULL, "\n", &saveptr); +- } +- +- heap_free(tmp); +- return (found_id && found_serial); +-} +- + static DWORD a_to_bcd(const char *s) + { + DWORD r = 0; +@@ -1185,7 +1218,7 @@ static BOOL is_in_sdl_blacklist(DWORD vid, DWORD pid) + + static void try_add_device(struct udev_device *dev) + { +- DWORD vid = 0, pid = 0, version = 0; ++ DWORD vid = 0, pid = 0, version = 0, bus_type = 0; + struct udev_device *hiddev = NULL, *walk_device; + DEVICE_OBJECT *device = NULL; + const char *subsystem; +@@ -1228,7 +1261,7 @@ static void try_add_device(struct udev_device *dev) + } + #endif + parse_uevent_info(udev_device_get_sysattr_value(hiddev, "uevent"), +- &vid, &pid, &input, &serial); ++ &bus_type, &vid, &pid, &input, &serial, NULL); + if (serial == NULL) + serial = strdupAtoW(base_serial); + +@@ -1258,6 +1291,7 @@ static void try_add_device(struct udev_device *dev) + vid = device_id.vendor; + pid = device_id.product; + version = device_id.version; ++ bus_type = device_id.bustype; + } + #else + else +@@ -1315,6 +1349,7 @@ static void try_add_device(struct udev_device *dev) + private->device_fd = fd; + private->vidpid.vid = vid; + private->vidpid.pid = pid; ++ private->bus_type = bus_type; + #ifdef HAS_PROPER_INPUT_HEADER + if (strcmp(subsystem, "input") == 0) + if (!build_report_descriptor((struct wine_input_private*)private, dev)) +From 847ac8c5a39061c79488818ea8da66a4f74f3dd6 Mon Sep 17 00:00:00 2001 +From: Andrew Eikum +Date: Fri, 30 Aug 2019 12:12:26 -0500 +Subject: [PATCH] winebus.sys: Bluetooth doesn't report USB device version + +--- + dlls/winebus.sys/bus_udev.c | 19 +++++++++++-------- + 1 file changed, 11 insertions(+), 8 deletions(-) + +diff --git a/dlls/winebus.sys/bus_udev.c b/dlls/winebus.sys/bus_udev.c +index 70fedf46973..0091f2c6d42 100644 +--- a/dlls/winebus.sys/bus_udev.c ++++ b/dlls/winebus.sys/bus_udev.c +@@ -1265,15 +1265,18 @@ static void try_add_device(struct udev_device *dev) + if (serial == NULL) + serial = strdupAtoW(base_serial); + +- walk_device = dev; +- while (walk_device && !bcdDevice) ++ if(bus_type != BUS_BLUETOOTH) + { +- bcdDevice = udev_device_get_sysattr_value(walk_device, "bcdDevice"); +- walk_device = udev_device_get_parent(walk_device); +- } +- if (bcdDevice) +- { +- version = a_to_bcd(bcdDevice); ++ walk_device = dev; ++ while (walk_device && !bcdDevice) ++ { ++ bcdDevice = udev_device_get_sysattr_value(walk_device, "bcdDevice"); ++ walk_device = udev_device_get_parent(walk_device); ++ } ++ if (bcdDevice) ++ { ++ version = a_to_bcd(bcdDevice); ++ } + } + } + #ifdef HAS_PROPER_INPUT_HEADER +From 516a86b246492f4ff65aa1f7601e21db7ad2d505 Mon Sep 17 00:00:00 2001 +From: Andrew Eikum +Date: Fri, 6 Dec 2019 11:00:49 -0600 +Subject: [PATCH] winebus.sys: Process quirky DS4 bluetooth reports + +--- + dlls/winebus.sys/bus_udev.c | 49 ++++++++++++++++++++++++++++++++++++- + 1 file changed, 48 insertions(+), 1 deletion(-) + +diff --git a/dlls/winebus.sys/bus_udev.c b/dlls/winebus.sys/bus_udev.c +index 0091f2c6d42..d9a64374019 100644 +--- a/dlls/winebus.sys/bus_udev.c ++++ b/dlls/winebus.sys/bus_udev.c +@@ -103,6 +103,9 @@ struct vidpid { + WORD vid, pid; + }; + ++/* the kernel is a great place to learn about these DS4 quirks */ ++#define QUIRK_DS4_BT 0x1 ++ + struct platform_private + { + struct udev_device *udev_device; +@@ -113,6 +116,8 @@ struct platform_private + + struct vidpid vidpid; + ++ DWORD quirks; ++ + DWORD bus_type; + }; + +@@ -891,7 +896,20 @@ static DWORD CALLBACK device_report_thread(void *args) + else if (size == 0) + TRACE_(hid_report)("Failed to read report\n"); + else +- process_hid_report(device, report_buffer, size); ++ { ++ if(private->quirks & QUIRK_DS4_BT) ++ { ++ /* Following the kernel example, report 17 is the only type we care about for ++ * DS4 over bluetooth. but it has two extra header bytes, so skip those. */ ++ if(report_buffer[0] == 0x11) ++ { ++ /* update report number to match windows */ ++ report_buffer[2] = 1; ++ process_hid_report(device, report_buffer + 2, size - 2); ++ } ++ }else ++ process_hid_report(device, report_buffer, size); ++ } + } + return 0; + } +@@ -1216,6 +1234,34 @@ static BOOL is_in_sdl_blacklist(DWORD vid, DWORD pid) + return strcasestr(blacklist, needle) != NULL; + } + ++static void set_quirks(struct platform_private *private) ++{ ++#define VID_SONY 0x054c ++#define PID_SONY_DUALSHOCK_4 0x05c4 ++#define PID_SONY_DUALSHOCK_4_2 0x09cc ++#define PID_SONY_DUALSHOCK_4_DONGLE 0x0ba0 ++ ++ private->quirks = 0; ++ ++ switch(private->vidpid.vid) ++ { ++ case VID_SONY: ++ switch(private->vidpid.pid) ++ { ++ case PID_SONY_DUALSHOCK_4: ++ case PID_SONY_DUALSHOCK_4_2: ++ case PID_SONY_DUALSHOCK_4_DONGLE: ++ if(private->bus_type == BUS_BLUETOOTH) ++ private->quirks |= QUIRK_DS4_BT; ++ break; ++ } ++ break; ++ } ++ ++ TRACE("for %04x/%04x, quirks set to: 0x%x\n", private->vidpid.vid, ++ private->vidpid.pid, private->quirks); ++} ++ + static void try_add_device(struct udev_device *dev) + { + DWORD vid = 0, pid = 0, version = 0, bus_type = 0; +@@ -1353,6 +1399,7 @@ static void try_add_device(struct udev_device *dev) + private->vidpid.vid = vid; + private->vidpid.pid = pid; + private->bus_type = bus_type; ++ set_quirks(private); + #ifdef HAS_PROPER_INPUT_HEADER + if (strcmp(subsystem, "input") == 0) + if (!build_report_descriptor((struct wine_input_private*)private, dev)) +From 4d996414499ce64d74307e518a130c6b8a7a4b89 Mon Sep 17 00:00:00 2001 +From: Simon McVittie +Date: Tue, 10 Nov 2020 13:41:51 +0000 +Subject: [PATCH] winebus: Keep track of input device class in instance struct + +This avoids having to keep comparing the subsystem as a string, and in +particular means we don't need a fully-working struct udev_device at +the point when we remove devices. + +Signed-off-by: Simon McVittie +--- + dlls/winebus.sys/bus_udev.c | 54 ++++++++++++++++++++++++------------- + 1 file changed, 36 insertions(+), 18 deletions(-) + +diff --git a/dlls/winebus.sys/bus_udev.c b/dlls/winebus.sys/bus_udev.c +index d9a64374019..4677e1b47ff 100644 +--- a/dlls/winebus.sys/bus_udev.c ++++ b/dlls/winebus.sys/bus_udev.c +@@ -108,6 +108,7 @@ struct vidpid { + + struct platform_private + { ++ const platform_vtbl *vtbl; + struct udev_device *udev_device; + int device_fd; + +@@ -1274,6 +1275,10 @@ static void try_add_device(struct udev_device *dev) + WORD input = -1; + int fd; + static const CHAR *base_serial = "0000"; ++ const platform_vtbl *vtbl = NULL; ++#ifdef HAS_PROPER_INPUT_HEADER ++ const platform_vtbl *other_vtbl = NULL; ++#endif + + if (!(devnode = udev_device_get_devnode(dev))) + return; +@@ -1285,17 +1290,34 @@ static void try_add_device(struct udev_device *dev) + } + + subsystem = udev_device_get_subsystem(dev); ++ ++ if (strcmp(subsystem, "hidraw") == 0) ++ { ++ vtbl = &hidraw_vtbl; ++#ifdef HAS_PROPER_INPUT_HEADER ++ other_vtbl = &lnxev_vtbl; ++#endif ++ } ++#ifdef HAS_PROPER_INPUT_HEADER ++ else if (strcmp(subsystem, "input") == 0) ++ { ++ vtbl = &lnxev_vtbl; ++ other_vtbl = &hidraw_vtbl; ++ } ++#endif ++ else ++ { ++ WARN("Unexpected subsystem %s for %s\n", debugstr_a(subsystem), debugstr_a(devnode)); ++ close(fd); ++ return; ++ } ++ + hiddev = udev_device_get_parent_with_subsystem_devtype(dev, "hid", NULL); + if (hiddev) + { + const char *bcdDevice = NULL; + #ifdef HAS_PROPER_INPUT_HEADER +- const platform_vtbl *other_vtbl = NULL; + DEVICE_OBJECT *dup = NULL; +- if (strcmp(subsystem, "hidraw") == 0) +- other_vtbl = &lnxev_vtbl; +- else if (strcmp(subsystem, "input") == 0) +- other_vtbl = &hidraw_vtbl; + + if (other_vtbl) + dup = bus_enumerate_hid_devices(other_vtbl, check_same_device, dev); +@@ -1378,16 +1400,16 @@ static void try_add_device(struct udev_device *dev) + TRACE("Found udev device %s (vid %04x, pid %04x, version %u, serial %s)\n", + debugstr_a(devnode), vid, pid, version, debugstr_w(serial)); + +- if (strcmp(subsystem, "hidraw") == 0) ++ if (vtbl == &hidraw_vtbl) + { + device = bus_create_hid_device(hidraw_busidW, vid, pid, input, version, 0, serial, is_gamepad, +- &hidraw_vtbl, sizeof(struct platform_private)); ++ vtbl, sizeof(struct platform_private)); + } + #ifdef HAS_PROPER_INPUT_HEADER +- else if (strcmp(subsystem, "input") == 0) ++ else if (vtbl == &lnxev_vtbl) + { + device = bus_create_hid_device(lnxev_busidW, vid, pid, input, version, 0, serial, is_gamepad, +- &lnxev_vtbl, sizeof(struct wine_input_private)); ++ vtbl, sizeof(struct wine_input_private)); + } + #endif + +@@ -1399,9 +1421,11 @@ static void try_add_device(struct udev_device *dev) + private->vidpid.vid = vid; + private->vidpid.pid = pid; + private->bus_type = bus_type; ++ private->vtbl = vtbl; + set_quirks(private); ++ + #ifdef HAS_PROPER_INPUT_HEADER +- if (strcmp(subsystem, "input") == 0) ++ if (private->vtbl == &lnxev_vtbl) + /* FIXME: We should probably move this to IRP_MN_START_DEVICE. */ + if (!build_report_descriptor((struct wine_input_private*)private, dev)) + { +From d183eb51b1804769f48d7ffe0270a1b6eb02872f Mon Sep 17 00:00:00 2001 +From: Simon McVittie +Date: Tue, 10 Nov 2020 14:29:16 +0000 +Subject: [PATCH] winebus: Remove udev-backed devices by comparing their /dev + nodes + +This is a step towards being able to monitor /dev with inotify when +running in a container, where udev monitoring often doesn't work. + +Signed-off-by: Simon McVittie +--- + dlls/winebus.sys/bus_udev.c | 46 +++++++++++++++++++++++++++++++++---- + 1 file changed, 41 insertions(+), 5 deletions(-) + +diff --git a/dlls/winebus.sys/bus_udev.c b/dlls/winebus.sys/bus_udev.c +index 4677e1b47ff..0a0b6e788b3 100644 +--- a/dlls/winebus.sys/bus_udev.c ++++ b/dlls/winebus.sys/bus_udev.c +@@ -1448,17 +1448,45 @@ static void try_add_device(struct udev_device *dev) + HeapFree(GetProcessHeap(), 0, serial); + } + +-static void try_remove_device(struct udev_device *dev) ++/* Return 0 to stop enumeration if @device's canonical path in /dev is @context. */ ++static int stop_if_devnode_equals(DEVICE_OBJECT *device, void *context) ++{ ++ struct platform_private *private = impl_from_DEVICE_OBJECT(device); ++ const char *want_devnode = context; ++ const char *devnode = udev_device_get_devnode(private->udev_device); ++ ++ if (!devnode) ++ return 1; ++ ++ if (strcmp(devnode, want_devnode) == 0) ++ { ++ TRACE("Found device %p with devnode %s\n", private, debugstr_a(want_devnode)); ++ return 0; ++ } ++ ++ return 1; ++} ++ ++static void try_remove_device_by_devnode(const char *devnode) + { + DEVICE_OBJECT *device = NULL; ++ struct platform_private* private; ++ struct udev_device *dev; ++ ++ TRACE("Removing device if present: %s\n", debugstr_a(devnode)); ++ device = bus_enumerate_hid_devices(&hidraw_vtbl, stop_if_devnode_equals, (void *) devnode); + +- device = bus_find_hid_device(&hidraw_vtbl, dev); + #ifdef HAS_PROPER_INPUT_HEADER + if (device == NULL) +- device = bus_find_hid_device(&lnxev_vtbl, dev); ++ device = bus_enumerate_hid_devices(&lnxev_vtbl, stop_if_devnode_equals, (void *) devnode); + #endif + if (!device) return; + ++ private = impl_from_DEVICE_OBJECT(device); ++ TRACE("Removing %s device: devnode %s udev_device %p -> %p\n", ++ (private->vtbl == &hidraw_vtbl ? "hidraw" : "evdev"), ++ debugstr_a(devnode), private->udev_device, private); ++ + bus_unlink_hid_device(device); + IoInvalidateDeviceRelations(bus_pdo, BusRelations); + } +@@ -1495,6 +1520,17 @@ static void try_remove_device(struct udev_device *dev) + udev_device_unref(dev); + } + ++static void try_remove_device(struct udev_device *dev) ++{ ++ const char *devnode = udev_device_get_devnode(dev); ++ ++ /* If it didn't have a device node, then we wouldn't be tracking it anyway */ ++ if (!devnode) ++ return; ++ ++ try_remove_device_by_devnode(devnode); ++} ++ + static void build_initial_deviceset(void) + { + struct udev_enumerate *enumerate; +From 601654cdbf3bd75487e73b5b39c6a23ef9149932 Mon Sep 17 00:00:00 2001 +From: Simon McVittie +Date: Wed, 11 Nov 2020 13:48:18 +0000 +Subject: [PATCH] winebus: Make it more explicit how we are checking for + duplicate devices + +Signed-off-by: Simon McVittie +--- + dlls/winebus.sys/bus_udev.c | 25 +++++++++++++++++++++---- + 1 file changed, 21 insertions(+), 4 deletions(-) + +diff --git a/dlls/winebus.sys/bus_udev.c b/dlls/winebus.sys/bus_udev.c +index 0a0b6e788b3..5524992e477 100644 +--- a/dlls/winebus.sys/bus_udev.c ++++ b/dlls/winebus.sys/bus_udev.c +@@ -1182,9 +1182,23 @@ static const platform_vtbl lnxev_vtbl = { + }; + #endif + +-static int check_same_device(DEVICE_OBJECT *device, void* context) ++/* Return 0 to stop enumeration if @device's canonical path in /sys is @context. */ ++static int stop_if_syspath_equals(DEVICE_OBJECT *device, void *context) + { +- return !compare_platform_device(device, context); ++ struct platform_private *private = impl_from_DEVICE_OBJECT(device); ++ const char *want_syspath = context; ++ const char *syspath = udev_device_get_syspath(private->udev_device); ++ ++ if (!syspath) ++ return 1; ++ ++ if (strcmp(syspath, want_syspath) == 0) ++ { ++ TRACE("Found device %p with syspath %s\n", private, debugstr_a(want_syspath)); ++ return 0; ++ } ++ ++ return 1; + } + + static DWORD a_to_bcd(const char *s) +@@ -1279,6 +1293,7 @@ static void try_add_device(struct udev_device *dev) + #ifdef HAS_PROPER_INPUT_HEADER + const platform_vtbl *other_vtbl = NULL; + #endif ++ const char *syspath; + + if (!(devnode = udev_device_get_devnode(dev))) + return; +@@ -1289,6 +1304,7 @@ static void try_add_device(struct udev_device *dev) + return; + } + ++ syspath = udev_device_get_syspath(dev); + subsystem = udev_device_get_subsystem(dev); + + if (strcmp(subsystem, "hidraw") == 0) +@@ -1320,10 +1336,11 @@ static void try_add_device(struct udev_device *dev) + DEVICE_OBJECT *dup = NULL; + + if (other_vtbl) +- dup = bus_enumerate_hid_devices(other_vtbl, check_same_device, dev); ++ dup = bus_enumerate_hid_devices(other_vtbl, stop_if_syspath_equals, (void *) syspath); + if (dup) + { +- TRACE("Duplicate cross bus device (%p) found, not adding the new one\n", dup); ++ TRACE("Duplicate cross bus device %s (%p) found, not adding the new one\n", ++ debugstr_a(syspath), dup); + close(fd); + return; + } +From f1a1944eff772aa0fcffa70d29a6426d1e29049e Mon Sep 17 00:00:00 2001 +From: Simon McVittie +Date: Wed, 11 Nov 2020 13:49:50 +0000 +Subject: [PATCH] winebus: Treat udev actions other than "remove" as "add" + +As per https://github.com/systemd/systemd/blob/v247-rc1/NEWS#L5 +there are more kernel uevent types than just "add" and "remove", +and we should be treating everything other than "remove" as being +potentially an "add". + +To cope with this, try_add_device() now checks whether the same device +was already added. If so, we ignore it. + +Signed-off-by: Simon McVittie +--- + dlls/winebus.sys/bus_udev.c | 16 +++++++++++----- + 1 file changed, 11 insertions(+), 5 deletions(-) + +diff --git a/dlls/winebus.sys/bus_udev.c b/dlls/winebus.sys/bus_udev.c +index 5524992e477..6954cb9707f 100644 +--- a/dlls/winebus.sys/bus_udev.c ++++ b/dlls/winebus.sys/bus_udev.c +@@ -1282,6 +1282,7 @@ static void try_add_device(struct udev_device *dev) + DWORD vid = 0, pid = 0, version = 0, bus_type = 0; + struct udev_device *hiddev = NULL, *walk_device; + DEVICE_OBJECT *device = NULL; ++ DEVICE_OBJECT *dup = NULL; + const char *subsystem; + const char *devnode; + WCHAR *serial = NULL; +@@ -1328,13 +1329,20 @@ static void try_add_device(struct udev_device *dev) + return; + } + ++ dup = bus_enumerate_hid_devices(vtbl, stop_if_syspath_equals, (void *) syspath); ++ if (dup) ++ { ++ TRACE("Duplicate %s device (%p) found, not adding the new one\n", ++ debugstr_a(syspath), dup); ++ close(fd); ++ return; ++ } ++ + hiddev = udev_device_get_parent_with_subsystem_devtype(dev, "hid", NULL); + if (hiddev) + { + const char *bcdDevice = NULL; + #ifdef HAS_PROPER_INPUT_HEADER +- DEVICE_OBJECT *dup = NULL; +- + if (other_vtbl) + dup = bus_enumerate_hid_devices(other_vtbl, stop_if_syspath_equals, (void *) syspath); + if (dup) +@@ -1658,12 +1666,10 @@ static void process_monitor_event(struct udev_monitor *monitor) + + if (!action) + WARN("No action received\n"); +- else if (strcmp(action, "add") == 0) +- try_add_device(dev); + else if (strcmp(action, "remove") == 0) + try_remove_device(dev); + else +- WARN("Unhandled action %s\n", debugstr_a(action)); ++ try_add_device(dev); + + udev_device_unref(dev); + } +From c7bbf429c39eae32cbb820e22551106dbdffc0be Mon Sep 17 00:00:00 2001 +From: Simon McVittie +Date: Tue, 10 Nov 2020 15:19:59 +0000 +Subject: [PATCH] winebus: Disable evdev at runtime, not at build time + +This lets us try out the evdev code path, even in Proton. + +Signed-off-by: Simon McVittie +--- + dlls/winebus.sys/bus_udev.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/dlls/winebus.sys/bus_udev.c b/dlls/winebus.sys/bus_udev.c +index 6954cb9707f..7b3c753ddef 100644 +--- a/dlls/winebus.sys/bus_udev.c ++++ b/dlls/winebus.sys/bus_udev.c +@@ -48,7 +48,7 @@ + # include + # undef SW_MAX + # if defined(EVIOCGBIT) && defined(EV_ABS) && defined(BTN_PINKIE) +-//# define HAS_PROPER_INPUT_HEADER ++# define HAS_PROPER_INPUT_HEADER + # endif + # ifndef SYN_DROPPED + # define SYN_DROPPED 3 +@@ -1752,9 +1752,9 @@ NTSTATUS udev_driver_init(void) + TRACE("UDEV hidraw devices disabled in registry\n"); + + #ifdef HAS_PROPER_INPUT_HEADER +- disable_input = check_bus_option(&input_disabled, 0); ++ disable_input = check_bus_option(&input_disabled, 1); + if (disable_input) +- TRACE("UDEV input devices disabled in registry\n"); ++ TRACE("UDEV input devices disabled in registry or by default\n"); + #endif + + if (!(events[0] = CreateEventW(NULL, TRUE, FALSE, NULL))) +From eb1c48890dd97ddcbcee22cd672b9360fe8f8a6b Mon Sep 17 00:00:00 2001 +From: Simon McVittie +Date: Tue, 10 Nov 2020 18:28:28 +0000 +Subject: [PATCH] winebus: Add code path to bypass udevd and use inotify + +In a container with a non-trivial user namespace, we cannot rely on +libudev communicating with udevd as a way to monitor device nodes, +for the following reasons: + +* If uid 0 from the host is not mapped to uid 0 in the container, libudev + cannot authenticate netlink messages from the host, because their sender + uid appears to be the overflowuid. Resolving this by mapping uid 0 into + the container is not allowed when creating user namespaces as an + unprivileged user, and even when running as a privileged user, it might + be desirable for the real uid 0 to not be mapped as a way to harden the + security boundary between container and host. + +* Depending on the container configuration, initial enumeration might + not be able to read /run/udev from the host system. If it can't, sysfs + attributes will still work because those are read directly from the + kernel via sysfs, but udev properties coming from user-space rules + (in particular ID_INPUT_JOYSTICK and friends) will appear to be missing. + +* The protocols between udevd and libudev (netlink messages for monitoring, + and /run/udev for initial enumeration) are considered to be private to + a particular version of udev, and are not a stable API; but in a + container, we cannot expect that our copy of libudev is at exactly the + same version as udevd on the host system. + +Sidestep this by adding a code path that continues to use libudev for +the parts that work regardless of whether udevd is running or can be +communicated with, but + +Signed-off-by: Simon McVittie +--- + dlls/winebus.sys/bus_udev.c | 328 ++++++++++++++++++++++++++++++++++-- + 1 file changed, 315 insertions(+), 13 deletions(-) + +diff --git a/dlls/winebus.sys/bus_udev.c b/dlls/winebus.sys/bus_udev.c +index 7b3c753ddef..91f46f7e693 100644 +--- a/dlls/winebus.sys/bus_udev.c ++++ b/dlls/winebus.sys/bus_udev.c +@@ -20,6 +20,8 @@ + + #define _GNU_SOURCE + #include "config.h" ++#include ++#include + #include + #include + #include +@@ -43,6 +45,9 @@ + #ifdef HAVE_SYS_IOCTL_H + # include + #endif ++#ifdef HAVE_SYS_INOTIFY_H ++# include ++#endif + + #ifdef HAVE_LINUX_INPUT_H + # include +@@ -91,6 +96,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(plugplay); + WINE_DECLARE_DEBUG_CHANNEL(hid_report); + + static struct udev *udev_context = NULL; ++static DWORD bypass_udevd = 0; + static DWORD disable_hidraw = 0; + static DWORD disable_input = 0; + static HANDLE deviceloop_handle; +@@ -1277,7 +1283,8 @@ static void set_quirks(struct platform_private *private) + private->vidpid.pid, private->quirks); + } + +-static void try_add_device(struct udev_device *dev) ++static void try_add_device(struct udev_device *dev, ++ int fd) + { + DWORD vid = 0, pid = 0, version = 0, bus_type = 0; + struct udev_device *hiddev = NULL, *walk_device; +@@ -1288,7 +1295,6 @@ static void try_add_device(struct udev_device *dev) + WCHAR *serial = NULL; + BOOL is_gamepad = FALSE; + WORD input = -1; +- int fd; + static const CHAR *base_serial = "0000"; + const platform_vtbl *vtbl = NULL; + #ifdef HAS_PROPER_INPUT_HEADER +@@ -1297,12 +1303,21 @@ static void try_add_device(struct udev_device *dev) + const char *syspath; + + if (!(devnode = udev_device_get_devnode(dev))) ++ { ++ if (fd >= 0) ++ close(fd); ++ + return; ++ } + +- if ((fd = open(devnode, O_RDWR)) == -1) ++ if (fd < 0) + { +- WARN("Unable to open udev device %s: %s\n", debugstr_a(devnode), strerror(errno)); +- return; ++ ++ if ((fd = open(devnode, O_RDWR)) == -1) ++ { ++ WARN("Unable to open udev device %s: %s\n", debugstr_a(devnode), strerror(errno)); ++ return; ++ } + } + + syspath = udev_device_get_syspath(dev); +@@ -1556,7 +1571,149 @@ static void try_remove_device(struct udev_device *dev) + try_remove_device_by_devnode(devnode); + } + +-static void build_initial_deviceset(void) ++/* inotify watch descriptors for create_monitor_direct() */ ++#ifdef HAVE_SYS_INOTIFY_H ++static int dev_watch = -1; ++static int devinput_watch = -1; ++#endif ++ ++static int str_has_prefix(const char *str, ++ const char *prefix) ++{ ++ return (strncmp(str, prefix, strlen(prefix)) == 0); ++} ++ ++static int str_is_integer(const char *str) ++{ ++ const char *p; ++ ++ if (*str == '\0') ++ return 0; ++ ++ for (p = str; *p != '\0'; p++) ++ { ++ if (*p < '0' || *p > '9') ++ return 0; ++ } ++ ++ return 1; ++} ++ ++static void maybe_add_devnode(const platform_vtbl *vtbl, const char *base, const char *dir, ++ const char *base_should_be, const char *subsystem) ++{ ++ const char *udev_devnode; ++ char devnode[MAX_PATH]; ++ char syslink[MAX_PATH]; ++ char *syspath = NULL; ++ struct udev_device *dev = NULL; ++ int fd = -1; ++ ++ TRACE("Considering %s/%s...\n", dir, base); ++ ++ if (!str_has_prefix(base, base_should_be)) ++ return; ++ ++ if (!str_is_integer(base + strlen(base_should_be))) ++ return; ++ ++ snprintf(devnode, sizeof(devnode), "%s/%s", dir, base); ++ fd = open(devnode, O_RDWR); ++ ++ if (fd < 0) ++ { ++ /* When using inotify monitoring, quietly ignore device nodes that we cannot read, ++ * without emitting a warning. ++ * ++ * We can expect that a significant number of device nodes will be permanently ++ * unreadable, such as the device nodes for keyboards and mice. We can also expect ++ * that joysticks and game controllers will be temporarily unreadable until udevd ++ * chmods them; we'll get another chance to open them when their attributes change. */ ++ TRACE("Unable to open %s, ignoring: %s\n", debugstr_a(devnode), strerror(errno)); ++ goto out; ++ } ++ ++ snprintf(syslink, sizeof(syslink), "/sys/class/%s/%s", subsystem, base); ++ TRACE("Resolving real path to %s\n", debugstr_a(syslink)); ++ syspath = realpath(syslink, NULL); ++ ++ if (!syspath) ++ { ++ WARN("Unable to resolve path \"%s\" for \"%s/%s\": %s\n", ++ debugstr_a(syslink), dir, base, strerror(errno)); ++ goto out; ++ } ++ ++ TRACE("Creating udev_device for %s\n", syspath); ++ dev = udev_device_new_from_syspath(udev_context, syspath); ++ udev_devnode = udev_device_get_devnode(dev); ++ ++ if (udev_devnode == NULL || strcmp(devnode, udev_devnode) != 0) ++ { ++ WARN("Tried to get udev device for \"%s\" but device node of \"%s\" -> \"%s\" is \"%s\"\n", ++ debugstr_a(devnode), debugstr_a(syslink), debugstr_a(syspath), ++ debugstr_a(udev_devnode)); ++ goto out; ++ } ++ ++ TRACE("Adding device for %s\n", syspath); ++ try_add_device(dev, fd); ++ /* ownership was taken */ ++ fd = -1; ++ ++out: ++ if (fd >= 0) ++ close(fd); ++ if (dev) ++ udev_device_unref(dev); ++ free(syspath); ++} ++ ++static void build_initial_deviceset_direct(void) ++{ ++ DIR *dir; ++ struct dirent *dent; ++ ++ if (!disable_hidraw) ++ { ++ TRACE("Initial enumeration of /dev/hidraw*\n"); ++ dir = opendir("/dev"); ++ ++ if (dir) ++ { ++ for (dent = readdir(dir); dent; dent = readdir(dir)) ++ maybe_add_devnode(&hidraw_vtbl, dent->d_name, "/dev", "hidraw", "hidraw"); ++ ++ closedir(dir); ++ } ++ else ++ { ++ WARN("Unable to open /dev: %s\n", strerror(errno)); ++ } ++ } ++ ++#ifdef HAS_PROPER_INPUT_HEADER ++ if (!disable_input) ++ { ++ TRACE("Initial enumeration of /dev/input/event*\n"); ++ dir = opendir("/dev/input"); ++ ++ if (dir) ++ { ++ for (dent = readdir(dir); dent; dent = readdir(dir)) ++ maybe_add_devnode(&lnxev_vtbl, dent->d_name, "/dev/input", "event", "input"); ++ ++ closedir(dir); ++ } ++ else ++ { ++ WARN("Unable to open /dev/input: %s\n", strerror(errno)); ++ } ++ } ++#endif ++} ++ ++static void build_initial_deviceset_udevd(void) + { + struct udev_enumerate *enumerate; + struct udev_list_entry *devices, *dev_list_entry; +@@ -1591,7 +1748,7 @@ static void build_initial_deviceset(void) + path = udev_list_entry_get_name(dev_list_entry); + if ((dev = udev_device_new_from_syspath(udev_context, path))) + { +- try_add_device(dev); ++ try_add_device(dev, -1); + udev_device_unref(dev); + } + } +@@ -1599,6 +1756,67 @@ static void build_initial_deviceset(void) + udev_enumerate_unref(enumerate); + } + ++static void create_inotify(struct pollfd *pfd) ++{ ++#ifdef HAVE_SYS_INOTIFY_H ++ int systems = 0; ++ ++ pfd->revents = 0; ++ pfd->fd = inotify_init1(IN_NONBLOCK | IN_CLOEXEC); ++ ++ if (pfd->fd < 0) ++ { ++ WARN("Unable to get inotify fd\n"); ++ goto error; ++ } ++ ++ if (!disable_hidraw) ++ { ++ /* We need to watch for attribute changes in addition to ++ * creation, because when a device is first created, it has ++ * permissions that we can't read. When udev chmods it to ++ * something that we maybe *can* read, we'll get an ++ * IN_ATTRIB event to tell us. */ ++ dev_watch = inotify_add_watch(pfd->fd, "/dev", ++ IN_CREATE | IN_DELETE | IN_MOVE | IN_ATTRIB); ++ if (dev_watch < 0) ++ WARN("Unable to initialize inotify for /dev: %s\n", ++ strerror(errno)); ++ else ++ systems++; ++ } ++#ifdef HAS_PROPER_INPUT_HEADER ++ if (!disable_input) ++ { ++ devinput_watch = inotify_add_watch(pfd[0].fd, "/dev/input", ++ IN_CREATE | IN_DELETE | IN_MOVE | IN_ATTRIB); ++ if (devinput_watch < 0) ++ WARN("Unable to initialize inotify for /dev/input: %s\n", ++ strerror(errno)); ++ else ++ systems++; ++ } ++#endif ++ if (systems == 0) ++ { ++ WARN("No subsystems added to monitor\n"); ++ goto error; ++ } ++ ++ pfd->events = POLLIN; ++ return; ++ ++error: ++ WARN("Failed to start monitoring\n"); ++ if (pfd->fd >= 0) ++ close(pfd->fd); ++ pfd->fd = -1; ++#else ++ WARN("Compiled without inotify support, cannot watch for new input devices\n"); ++ pfd->fd = -1; ++#endif ++} ++ + static struct udev_monitor *create_monitor(struct pollfd *pfd) + { + struct udev_monitor *monitor; +@@ -1648,6 +1866,71 @@ static struct udev_monitor *create_monitor(struct pollfd *pfd) + return NULL; + } + ++static void maybe_remove_devnode(const char *base, const char *dir, const char *base_should_be) ++{ ++ char path[MAX_PATH]; ++ ++ TRACE("Considering %s/%s...\n", dir, base); ++ ++ if (!str_has_prefix(base, base_should_be)) ++ return; ++ ++ if (!str_is_integer(base + strlen(base_should_be))) ++ return; ++ ++ snprintf(path, sizeof(path), "%s/%s", dir, base); ++ try_remove_device_by_devnode(path); ++} ++ ++static void process_inotify_event(int fd) ++{ ++#ifdef HAVE_SYS_INOTIFY_H ++ union ++ { ++ struct inotify_event event; ++ char storage[4096]; ++ char enough_for_inotify[sizeof(struct inotify_event) + NAME_MAX + 1]; ++ } buf; ++ ssize_t bytes; ++ size_t remain = 0; ++ size_t len; ++ ++ bytes = read(fd, &buf, sizeof(buf)); ++ ++ if (bytes > 0) ++ remain = (size_t) bytes; ++ ++ while (remain > 0) ++ { ++ if (buf.event.len > 0) ++ { ++ if (buf.event.wd == dev_watch) ++ { ++ if (buf.event.mask & (IN_CREATE | IN_MOVED_TO | IN_ATTRIB)) ++ maybe_add_devnode(&hidraw_vtbl, buf.event.name, "/dev", "hidraw", "hidraw"); ++ else if (buf.event.mask & (IN_DELETE | IN_MOVED_FROM)) ++ maybe_remove_devnode(buf.event.name, "/dev", "hidraw"); ++ } ++#ifdef HAS_PROPER_INPUT_HEADER ++ else if (buf.event.wd == devinput_watch) ++ { ++ if (buf.event.mask & (IN_CREATE | IN_MOVED_TO | IN_ATTRIB)) ++ maybe_add_devnode(&lnxev_vtbl, buf.event.name, "/dev/input", "event", "input"); ++ else if (buf.event.mask & (IN_DELETE | IN_MOVED_FROM)) ++ maybe_remove_devnode(buf.event.name, "/dev/input", "event"); ++ } ++#endif ++ } ++ ++ len = sizeof(struct inotify_event) + buf.event.len; ++ remain -= len; ++ ++ if (remain != 0) ++ memmove(&buf.storage[0], &buf.storage[len], remain); ++ } ++#endif ++} ++ + static void process_monitor_event(struct udev_monitor *monitor) + { + struct udev_device *dev; +@@ -1669,14 +1952,14 @@ static void process_monitor_event(struct udev_monitor *monitor) + else if (strcmp(action, "remove") == 0) + try_remove_device(dev); + else +- try_add_device(dev); ++ try_add_device(dev, -1); + + udev_device_unref(dev); + } + + static DWORD CALLBACK deviceloop_thread(void *args) + { +- struct udev_monitor *monitor; ++ struct udev_monitor *monitor = NULL; + HANDLE init_done = args; + struct pollfd pfd[2]; + +@@ -1684,15 +1967,28 @@ static DWORD CALLBACK deviceloop_thread(void *args) + pfd[1].events = POLLIN; + pfd[1].revents = 0; + +- monitor = create_monitor(&pfd[0]); +- build_initial_deviceset(); ++ if (bypass_udevd) ++ { ++ create_inotify(&pfd[0]); ++ build_initial_deviceset_direct(); ++ } ++ else ++ { ++ monitor = create_monitor(&pfd[0]); ++ build_initial_deviceset_udevd(); ++ } ++ + SetEvent(init_done); + +- while (monitor) ++ while (pfd[0].fd >= 0) + { + if (poll(pfd, 2, -1) <= 0) continue; + if (pfd[1].revents) break; +- process_monitor_event(monitor); ++ ++ if (monitor) ++ process_monitor_event(monitor); ++ else ++ process_inotify_event(pfd[0].fd); + } + + TRACE("Monitor thread exiting\n"); +@@ -1730,6 +2026,8 @@ NTSTATUS udev_driver_init(void) + { + HANDLE events[2]; + DWORD result; ++ static const WCHAR disable_udevdW[] = {'D','i','s','a','b','l','e','U','d','e','v','d',0}; ++ static const UNICODE_STRING disable_udevd = {sizeof(disable_udevdW) - sizeof(WCHAR), sizeof(disable_udevdW), (WCHAR*)disable_udevdW}; + static const WCHAR hidraw_disabledW[] = {'D','i','s','a','b','l','e','H','i','d','r','a','w',0}; + static const UNICODE_STRING hidraw_disabled = {sizeof(hidraw_disabledW) - sizeof(WCHAR), sizeof(hidraw_disabledW), (WCHAR*)hidraw_disabledW}; + static const WCHAR input_disabledW[] = {'D','i','s','a','b','l','e','I','n','p','u','t',0}; +@@ -1747,6 +2045,10 @@ NTSTATUS udev_driver_init(void) + goto error; + } + ++ bypass_udevd = check_bus_option(&disable_udevd, 0); ++ if (bypass_udevd) ++ TRACE("udev disabled, falling back to inotify\n"); ++ + disable_hidraw = check_bus_option(&hidraw_disabled, 0); + if (disable_hidraw) + TRACE("UDEV hidraw devices disabled in registry\n"); +From c9e5e4535e760edf838c7f11be5d0f8c7bee22ce Mon Sep 17 00:00:00 2001 +From: Simon McVittie +Date: Tue, 10 Nov 2020 18:32:28 +0000 +Subject: [PATCH] winebus: Automatically bypass udevd in Flatpak or + pressure-vessel + +Flatpak uses unprivileged containers that don't normally map uid 0 +into the container, so netlink events won't work there, as described +in previous commits. Steam's pressure-vessel container tool behaves +similarly. + +Signed-off-by: Simon McVittie +--- + dlls/winebus.sys/bus_udev.c | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) + +diff --git a/dlls/winebus.sys/bus_udev.c b/dlls/winebus.sys/bus_udev.c +index 91f46f7e693..60842ff761e 100644 +--- a/dlls/winebus.sys/bus_udev.c ++++ b/dlls/winebus.sys/bus_udev.c +@@ -2045,7 +2045,14 @@ NTSTATUS udev_driver_init(void) + goto error; + } + +- bypass_udevd = check_bus_option(&disable_udevd, 0); ++ if (access ("/run/pressure-vessel", R_OK) ++ || access ("/.flatpak-info", R_OK)) ++ { ++ TRACE("Container detected, bypassing udevd by default\n"); ++ bypass_udevd = 1; ++ } ++ ++ bypass_udevd = check_bus_option(&disable_udevd, bypass_udevd); + if (bypass_udevd) + TRACE("udev disabled, falling back to inotify\n"); + +From 05573d0bc1ee35ea8a1ca711b90abfc100ad2910 Mon Sep 17 00:00:00 2001 +From: Simon McVittie +Date: Tue, 10 Nov 2020 19:03:47 +0000 +Subject: [PATCH] winebus: Guess the type of evdev input devices + +Ordinarily, we can get the type of an evdev input device from udev: +the input_id builtin sets udev properties of the form ID_INPUT_FOO +that we can read. + +However, in a container there is no guarantee that the libudev in the +container will interoperate with the udevd on the host system, so we +need to be prepared to do this ourselves from first principles, using +a heuristic similar to the one in udev's input_id. + +We cannot simply copy the heuristic from udev's input_id, because its +licensing is incompatible (GPL). Instead, use a vaguely similar heuristic +that works from the same inputs and will generally produce similar results. + +Signed-off-by: Simon McVittie +--- + dlls/winebus.sys/bus_udev.c | 331 +++++++++++++++++++++++++++++++++++- + 1 file changed, 329 insertions(+), 2 deletions(-) + +diff --git a/dlls/winebus.sys/bus_udev.c b/dlls/winebus.sys/bus_udev.c +index 60842ff761e..8a0e9f855eb 100644 +--- a/dlls/winebus.sys/bus_udev.c ++++ b/dlls/winebus.sys/bus_udev.c +@@ -24,6 +24,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -265,7 +266,304 @@ static BYTE *add_axis_block(BYTE *report_ptr, BYTE count, BYTE page, BYTE *usage + return report_ptr; + } + +-static const BYTE* what_am_I(struct udev_device *dev) ++/* Minimal compatibility with code taken from steam-runtime-tools */ ++typedef int gboolean; ++#define g_debug(fmt, ...) TRACE(fmt "\n", ## __VA_ARGS__) ++#define G_N_ELEMENTS(arr) (sizeof(arr)/sizeof(arr[0])) ++ ++typedef enum ++{ ++ SRT_INPUT_DEVICE_TYPE_FLAGS_JOYSTICK = (1 << 0), ++ SRT_INPUT_DEVICE_TYPE_FLAGS_ACCELEROMETER = (1 << 1), ++ SRT_INPUT_DEVICE_TYPE_FLAGS_KEYBOARD = (1 << 2), ++ SRT_INPUT_DEVICE_TYPE_FLAGS_HAS_KEYS = (1 << 3), ++ SRT_INPUT_DEVICE_TYPE_FLAGS_MOUSE = (1 << 4), ++ SRT_INPUT_DEVICE_TYPE_FLAGS_TOUCHPAD = (1 << 5), ++ SRT_INPUT_DEVICE_TYPE_FLAGS_TOUCHSCREEN = (1 << 6), ++ SRT_INPUT_DEVICE_TYPE_FLAGS_TABLET = (1 << 7), ++ SRT_INPUT_DEVICE_TYPE_FLAGS_TABLET_PAD = (1 << 8), ++ SRT_INPUT_DEVICE_TYPE_FLAGS_POINTING_STICK = (1 << 9), ++ SRT_INPUT_DEVICE_TYPE_FLAGS_SWITCH = (1 << 10), ++ SRT_INPUT_DEVICE_TYPE_FLAGS_NONE = 0 ++} SrtInputDeviceTypeFlags; ++ ++#define BITS_PER_LONG (sizeof (unsigned long) * CHAR_BIT) ++#define LONGS_FOR_BITS(x) ((((x)-1)/BITS_PER_LONG)+1) ++typedef struct ++{ ++ unsigned long ev[LONGS_FOR_BITS (EV_MAX)]; ++ unsigned long keys[LONGS_FOR_BITS (KEY_MAX)]; ++ unsigned long abs[LONGS_FOR_BITS (ABS_MAX)]; ++ unsigned long rel[LONGS_FOR_BITS (REL_MAX)]; ++ unsigned long ff[LONGS_FOR_BITS (FF_MAX)]; ++ unsigned long props[LONGS_FOR_BITS (INPUT_PROP_MAX)]; ++} SrtEvdevCapabilities; ++ ++static gboolean ++_srt_get_caps_from_evdev (int fd, ++ unsigned int type, ++ unsigned long *bitmask, ++ size_t bitmask_len_longs) ++{ ++ size_t bitmask_len_bytes = bitmask_len_longs * sizeof (*bitmask); ++ ++ memset (bitmask, 0, bitmask_len_bytes); ++ ++ if (ioctl (fd, EVIOCGBIT (type, bitmask_len_bytes), bitmask) < 0) ++ return FALSE; ++ ++ return TRUE; ++} ++ ++static gboolean ++_srt_evdev_capabilities_set_from_evdev (SrtEvdevCapabilities *caps, ++ int fd) ++{ ++ if (_srt_get_caps_from_evdev (fd, 0, caps->ev, G_N_ELEMENTS (caps->ev))) ++ { ++ _srt_get_caps_from_evdev (fd, EV_KEY, caps->keys, G_N_ELEMENTS (caps->keys)); ++ _srt_get_caps_from_evdev (fd, EV_ABS, caps->abs, G_N_ELEMENTS (caps->abs)); ++ _srt_get_caps_from_evdev (fd, EV_REL, caps->rel, G_N_ELEMENTS (caps->rel)); ++ _srt_get_caps_from_evdev (fd, EV_FF, caps->ff, G_N_ELEMENTS (caps->ff)); ++ ioctl (fd, EVIOCGPROP (sizeof (caps->props)), caps->props); ++ return TRUE; ++ } ++ ++ memset (caps, 0, sizeof (*caps)); ++ return FALSE; ++} ++ ++#define JOYSTICK_ABS_AXES \ ++ ((1 << ABS_X) | (1 << ABS_Y) \ ++ | (1 << ABS_RX) | (1 << ABS_RY) \ ++ | (1 << ABS_THROTTLE) | (1 << ABS_RUDDER) \ ++ | (1 << ABS_WHEEL) | (1 << ABS_GAS) | (1 << ABS_BRAKE) \ ++ | (1 << ABS_HAT0X) | (1 << ABS_HAT0Y) \ ++ | (1 << ABS_HAT1X) | (1 << ABS_HAT1Y) \ ++ | (1 << ABS_HAT2X) | (1 << ABS_HAT2Y) \ ++ | (1 << ABS_HAT3X) | (1 << ABS_HAT3Y)) ++ ++static const unsigned int first_mouse_button = BTN_MOUSE; ++static const unsigned int last_mouse_button = BTN_JOYSTICK - 1; ++ ++static const unsigned int first_joystick_button = BTN_JOYSTICK; ++static const unsigned int last_joystick_button = BTN_GAMEPAD - 1; ++ ++static const unsigned int first_gamepad_button = BTN_GAMEPAD; ++static const unsigned int last_gamepad_button = BTN_DIGI - 1; ++ ++static const unsigned int first_dpad_button = BTN_DPAD_UP; ++static const unsigned int last_dpad_button = BTN_DPAD_RIGHT; ++ ++static const unsigned int first_extra_joystick_button = BTN_TRIGGER_HAPPY; ++static const unsigned int last_extra_joystick_button = BTN_TRIGGER_HAPPY40; ++ ++SrtInputDeviceTypeFlags ++_srt_evdev_capabilities_guess_type (const SrtEvdevCapabilities *caps) ++{ ++ SrtInputDeviceTypeFlags flags = SRT_INPUT_DEVICE_TYPE_FLAGS_NONE; ++ unsigned int i; ++ gboolean has_joystick_axes = FALSE; ++ gboolean has_joystick_buttons = FALSE; ++ ++ /* Some properties let us be fairly sure about a device */ ++ if (test_bit (caps->props, INPUT_PROP_ACCELEROMETER)) ++ { ++ g_debug ("INPUT_PROP_ACCELEROMETER => is accelerometer"); ++ flags |= SRT_INPUT_DEVICE_TYPE_FLAGS_ACCELEROMETER; ++ } ++ ++ if (test_bit (caps->props, INPUT_PROP_POINTING_STICK)) ++ { ++ g_debug ("INPUT_PROP_POINTING_STICK => is pointing stick"); ++ flags |= SRT_INPUT_DEVICE_TYPE_FLAGS_POINTING_STICK; ++ } ++ ++ if (test_bit (caps->props, INPUT_PROP_BUTTONPAD) ++ || test_bit (caps->props, INPUT_PROP_TOPBUTTONPAD)) ++ { ++ g_debug ("INPUT_PROP_[TOP]BUTTONPAD => is touchpad"); ++ flags |= SRT_INPUT_DEVICE_TYPE_FLAGS_TOUCHPAD; ++ } ++ ++ /* Devices with a stylus or pen are assumed to be graphics tablets */ ++ if (test_bit (caps->keys, BTN_STYLUS) ++ || test_bit (caps->keys, BTN_TOOL_PEN)) ++ { ++ g_debug ("Stylus or pen => is tablet"); ++ flags |= SRT_INPUT_DEVICE_TYPE_FLAGS_TABLET; ++ } ++ ++ /* Devices that accept a finger touch are assumed to be touchpads or ++ * touchscreens. ++ * ++ * In Steam we mostly only care about these as a way to ++ * reject non-joysticks, so we're not very precise here yet. ++ * ++ * SDL assumes that TOUCH means a touchscreen and FINGER ++ * means a touchpad. */ ++ if (flags == SRT_INPUT_DEVICE_TYPE_FLAGS_NONE ++ && (test_bit (caps->keys, BTN_TOOL_FINGER) ++ || test_bit (caps->keys, BTN_TOUCH) ++ || test_bit (caps->props, INPUT_PROP_SEMI_MT))) ++ { ++ g_debug ("Finger or touch or semi-MT => is touchpad or touchscreen"); ++ ++ if (test_bit (caps->props, INPUT_PROP_POINTER)) ++ flags |= SRT_INPUT_DEVICE_TYPE_FLAGS_TOUCHPAD; ++ else ++ flags |= SRT_INPUT_DEVICE_TYPE_FLAGS_TOUCHSCREEN; ++ } ++ ++ /* Devices with mouse buttons are ... probably mice? */ ++ if (flags == SRT_INPUT_DEVICE_TYPE_FLAGS_NONE) ++ { ++ for (i = first_mouse_button; i <= last_mouse_button; i++) ++ { ++ if (test_bit (caps->keys, i)) ++ { ++ g_debug ("Mouse button => mouse"); ++ flags |= SRT_INPUT_DEVICE_TYPE_FLAGS_MOUSE; ++ } ++ } ++ } ++ ++ if (flags == SRT_INPUT_DEVICE_TYPE_FLAGS_NONE) ++ { ++ for (i = ABS_X; i < ABS_Z; i++) ++ { ++ if (!test_bit (caps->abs, i)) ++ break; ++ } ++ ++ /* If it has 3 axes and no buttons it's probably an accelerometer. */ ++ if (i == ABS_Z && !test_bit (caps->ev, EV_KEY)) ++ { ++ g_debug ("3 left axes and no buttons => accelerometer"); ++ flags |= SRT_INPUT_DEVICE_TYPE_FLAGS_ACCELEROMETER; ++ } ++ ++ /* Same for RX..RZ (e.g. Wiimote) */ ++ for (i = ABS_RX; i < ABS_RZ; i++) ++ { ++ if (!test_bit (caps->abs, i)) ++ break; ++ } ++ ++ if (i == ABS_RZ && !test_bit (caps->ev, EV_KEY)) ++ { ++ g_debug ("3 right axes and no buttons => accelerometer"); ++ flags |= SRT_INPUT_DEVICE_TYPE_FLAGS_ACCELEROMETER; ++ } ++ } ++ ++ /* Bits 1 to 31 are ESC, numbers and Q to D, which SDL and udev both ++ * consider to be enough to count as a fully-functioned keyboard. */ ++ if ((caps->keys[0] & 0xfffffffe) == 0xfffffffe) ++ { ++ g_debug ("First few keys => keyboard"); ++ flags |= SRT_INPUT_DEVICE_TYPE_FLAGS_KEYBOARD; ++ } ++ ++ /* If we have *any* keys, consider it to be something a bit ++ * keyboard-like. Bits 0 to 63 are all keyboard keys. ++ * Make sure we stop before reaching KEY_UP which is sometimes ++ * used on game controller mappings, e.g. for the Wiimote. */ ++ for (i = 0; i < (64 / BITS_PER_LONG); i++) ++ { ++ if (caps->keys[i] != 0) ++ flags |= SRT_INPUT_DEVICE_TYPE_FLAGS_HAS_KEYS; ++ } ++ ++ if (caps->abs[0] & JOYSTICK_ABS_AXES) ++ has_joystick_axes = TRUE; ++ ++ /* Flight stick buttons */ ++ for (i = first_joystick_button; i <= last_joystick_button; i++) ++ { ++ if (test_bit (caps->keys, i)) ++ has_joystick_buttons = TRUE; ++ } ++ ++ /* Gamepad buttons (Xbox, PS3, etc.) */ ++ for (i = first_gamepad_button; i <= last_gamepad_button; i++) ++ { ++ if (test_bit (caps->keys, i)) ++ has_joystick_buttons = TRUE; ++ } ++ ++ /* Gamepad digital dpad */ ++ for (i = first_dpad_button; i <= last_dpad_button; i++) ++ { ++ if (test_bit (caps->keys, i)) ++ has_joystick_buttons = TRUE; ++ } ++ ++ /* Steering wheel gear-change buttons */ ++ for (i = BTN_GEAR_DOWN; i <= BTN_GEAR_UP; i++) ++ { ++ if (test_bit (caps->keys, i)) ++ has_joystick_buttons = TRUE; ++ } ++ ++ /* Reserved space for extra game-controller buttons, e.g. on Corsair ++ * gaming keyboards */ ++ for (i = first_extra_joystick_button; i <= last_extra_joystick_button; i++) ++ { ++ if (test_bit (caps->keys, i)) ++ has_joystick_buttons = TRUE; ++ } ++ ++ if (test_bit (caps->keys, last_mouse_button)) ++ { ++ /* Mice with a very large number of buttons can apparently ++ * overflow into the joystick-button space, but they're still not ++ * joysticks. */ ++ has_joystick_buttons = FALSE; ++ } ++ ++ /* TODO: Do we want to consider BTN_0 up to BTN_9 to be joystick buttons? ++ * libmanette and SDL look for BTN_1, udev does not. ++ * ++ * They're used by some game controllers, like BTN_1 and BTN_2 for the ++ * Wiimote, BTN_1..BTN_9 for the SpaceTec SpaceBall and BTN_0..BTN_3 ++ * for Playstation dance pads, but they're also used by ++ * non-game-controllers like Logitech mice. For now we entirely ignore ++ * these buttons: they are not evidence that it's a joystick, but ++ * neither are they evidence that it *isn't* a joystick. */ ++ ++ /* We consider it to be a joystick if there is some evidence that it is, ++ * and no evidence that it's something else. ++ * ++ * Unlike SDL, we accept devices with only axes and no buttons as a ++ * possible joystick, unless they have X/Y/Z axes in which case we ++ * assume they're accelerometers. */ ++ if ((has_joystick_buttons || has_joystick_axes) ++ && (flags == SRT_INPUT_DEVICE_TYPE_FLAGS_NONE)) ++ { ++ g_debug ("Looks like a joystick"); ++ flags |= SRT_INPUT_DEVICE_TYPE_FLAGS_JOYSTICK; ++ } ++ ++ /* If we have *any* keys below BTN_MISC, consider it to be something ++ * a bit keyboard-like, but don't rule out *also* being considered ++ * to be a joystick (again for e.g. the Wiimote). */ ++ for (i = 0; i < (BTN_MISC / BITS_PER_LONG); i++) ++ { ++ if (caps->keys[i] != 0) ++ flags |= SRT_INPUT_DEVICE_TYPE_FLAGS_HAS_KEYS; ++ } ++ ++ /* Also non-exclusive: don't rule out a device being a joystick and ++ * having a switch */ ++ if (test_bit (caps->ev, EV_SW)) ++ flags |= SRT_INPUT_DEVICE_TYPE_FLAGS_SWITCH; ++ ++ return flags; ++} ++ ++static const BYTE* what_am_I(struct udev_device *dev, ++ int fd) + { + static const BYTE Unknown[2] = {HID_USAGE_PAGE_GENERIC, 0}; + static const BYTE Mouse[2] = {HID_USAGE_PAGE_GENERIC, HID_USAGE_GENERIC_MOUSE}; +@@ -275,6 +573,7 @@ static const BYTE* what_am_I(struct udev_device *dev) + static const BYTE Tablet[2] = {HID_USAGE_PAGE_DIGITIZER, HID_USAGE_DIGITIZER_PEN}; + static const BYTE Touchscreen[2] = {HID_USAGE_PAGE_DIGITIZER, HID_USAGE_DIGITIZER_TOUCH_SCREEN}; + static const BYTE Touchpad[2] = {HID_USAGE_PAGE_DIGITIZER, HID_USAGE_DIGITIZER_TOUCH_PAD}; ++ SrtEvdevCapabilities caps; + + struct udev_device *parent = dev; + +@@ -298,6 +597,34 @@ static const BYTE* what_am_I(struct udev_device *dev) + + parent = udev_device_get_parent_with_subsystem_devtype(parent, "input", NULL); + } ++ ++ /* In a container, udev properties might not be available. Fall back to deriving the device ++ * type from the fd's evdev capabilities. */ ++ if (_srt_evdev_capabilities_set_from_evdev (&caps, fd)) ++ { ++ SrtInputDeviceTypeFlags guessed_type; ++ ++ guessed_type = _srt_evdev_capabilities_guess_type (&caps); ++ ++ if (guessed_type & (SRT_INPUT_DEVICE_TYPE_FLAGS_MOUSE ++ | SRT_INPUT_DEVICE_TYPE_FLAGS_POINTING_STICK)) ++ return Mouse; ++ else if (guessed_type & SRT_INPUT_DEVICE_TYPE_FLAGS_KEYBOARD) ++ return Keyboard; ++ else if (guessed_type & SRT_INPUT_DEVICE_TYPE_FLAGS_JOYSTICK) ++ return Gamepad; ++ else if (guessed_type & SRT_INPUT_DEVICE_TYPE_FLAGS_HAS_KEYS) ++ return Keypad; ++ else if (guessed_type & SRT_INPUT_DEVICE_TYPE_FLAGS_TOUCHPAD) ++ return Touchpad; ++ else if (guessed_type & SRT_INPUT_DEVICE_TYPE_FLAGS_TOUCHSCREEN) ++ return Touchscreen; ++ else if (guessed_type & SRT_INPUT_DEVICE_TYPE_FLAGS_TABLET) ++ return Tablet; ++ ++ /* Mapped to Unknown: ACCELEROMETER, TABLET_PAD, SWITCH. */ ++ } ++ + return Unknown; + } + +@@ -431,7 +758,7 @@ static BOOL build_report_descriptor(struct wine_input_private *ext, struct udev_ + INT i, descript_size; + INT report_size; + INT button_count, abs_count, rel_count, hat_count; +- const BYTE *device_usage = what_am_I(dev); ++ const BYTE *device_usage = what_am_I(dev, ext->base.device_fd); + + if (ioctl(ext->base.device_fd, EVIOCGBIT(EV_REL, sizeof(relbits)), relbits) == -1) + { +From 83f2777cb38c0e3e69073e5a883c1bc2626e34c8 Mon Sep 17 00:00:00 2001 +From: Andrew Eikum +Date: Tue, 15 Dec 2020 12:23:31 -0600 +Subject: [PATCH] winebus: Enable SDL input logging when plugplay channel is + enabled + +--- + dlls/winebus.sys/bus_sdl.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/dlls/winebus.sys/bus_sdl.c b/dlls/winebus.sys/bus_sdl.c +index efe4a8c6b46..8a4e66bec55 100644 +--- a/dlls/winebus.sys/bus_sdl.c ++++ b/dlls/winebus.sys/bus_sdl.c +@@ -111,6 +111,7 @@ MAKE_FUNCPTR(SDL_memset); + MAKE_FUNCPTR(SDL_GameControllerAddMapping); + MAKE_FUNCPTR(SDL_RegisterEvents); + MAKE_FUNCPTR(SDL_PushEvent); ++MAKE_FUNCPTR(SDL_LogSetPriority); + static Uint16 (*pSDL_JoystickGetProduct)(SDL_Joystick * joystick); + static Uint16 (*pSDL_JoystickGetProductVersion)(SDL_Joystick * joystick); + static Uint16 (*pSDL_JoystickGetVendor)(SDL_Joystick * joystick); +@@ -1204,6 +1205,11 @@ static DWORD CALLBACK deviceloop_thread(void *args) + return STATUS_UNSUCCESSFUL; + } + ++ if (TRACE_ON(plugplay)) ++ { ++ pSDL_LogSetPriority(SDL_LOG_CATEGORY_INPUT, SDL_LOG_PRIORITY_VERBOSE); ++ } ++ + pSDL_JoystickEventState(SDL_ENABLE); + pSDL_GameControllerEventState(SDL_ENABLE); + +@@ -1353,6 +1359,7 @@ NTSTATUS sdl_driver_init(void) + LOAD_FUNCPTR(SDL_GameControllerAddMapping); + LOAD_FUNCPTR(SDL_RegisterEvents); + LOAD_FUNCPTR(SDL_PushEvent); ++ LOAD_FUNCPTR(SDL_LogSetPriority); + #undef LOAD_FUNCPTR + pSDL_JoystickGetProduct = dlsym(sdl_handle, "SDL_JoystickGetProduct"); + pSDL_JoystickGetProductVersion = dlsym(sdl_handle, "SDL_JoystickGetProductVersion"); +From edbc93d665fe8494a76a2330d2350babe63716f7 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?R=C3=A9mi=20Bernon?= +Date: Thu, 17 Dec 2020 19:05:37 +0100 +Subject: [PATCH] HACK: steam: winebus.sys: Check Steam overlay presence and + drop reports when enabled. + +--- + dlls/winebus.sys/bus_sdl.c | 12 ++++++++++++ + dlls/winebus.sys/bus_udev.c | 12 ++++++++++++ + 2 files changed, 24 insertions(+) + +diff --git a/dlls/winebus.sys/bus_sdl.c b/dlls/winebus.sys/bus_sdl.c +index 8a4e66bec55..23501931e69 100644 +--- a/dlls/winebus.sys/bus_sdl.c ++++ b/dlls/winebus.sys/bus_sdl.c +@@ -70,6 +70,7 @@ static DWORD map_controllers = 0; + static void *sdl_handle = NULL; + static HANDLE deviceloop_handle; + static UINT quit_event = -1; ++static HANDLE steam_overlay_event; + + #define XINPUT_HACK_ID_BIT 0x80000000 + #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL +@@ -1162,8 +1163,13 @@ static void try_add_device(unsigned int index, BOOL xinput_hack) + + static void process_device_event(SDL_Event *event) + { ++ BOOL overlay_enabled = FALSE; ++ + TRACE_(hid_report)("Received action %x\n", event->type); + ++ if (WaitForSingleObject(steam_overlay_event, 0) == WAIT_OBJECT_0) ++ overlay_enabled = TRUE; ++ + if (event->type == SDL_JOYDEVICEADDED) + { + try_add_device(((SDL_JoyDeviceEvent*)event)->which, TRUE); +@@ -1097,9 +1097,15 @@ static void process_device_event(SDL_Event *event) + else if (event->type == SDL_JOYDEVICEREMOVED) + try_remove_device(((SDL_JoyDeviceEvent*)event)->which); + else if (event->type >= SDL_JOYAXISMOTION && event->type <= SDL_JOYBUTTONUP) ++ { ++ if (overlay_enabled) return; + set_report_from_event(event); ++ } + else if (event->type >= SDL_CONTROLLERAXISMOTION && event->type <= SDL_CONTROLLERBUTTONUP) ++ { ++ if (overlay_enabled) return; + set_mapped_report_from_event(event); ++ } + } + + static DWORD CALLBACK deviceloop_thread(void *args) +@@ -1303,6 +1313,7 @@ void sdl_driver_unload( void ) + WaitForSingleObject(deviceloop_handle, INFINITE); + CloseHandle(deviceloop_handle); + dlclose(sdl_handle); ++ CloseHandle(steam_overlay_event); + } + + NTSTATUS sdl_driver_init(void) +@@ -1312,6 +1323,7 @@ NTSTATUS sdl_driver_init(void) + + HANDLE events[2]; + DWORD result; ++ steam_overlay_event = CreateEventA(NULL, TRUE, FALSE, "__wine_steamclient_GameOverlayActivated"); + + if (sdl_handle == NULL) + { +diff --git a/dlls/winebus.sys/bus_udev.c b/dlls/winebus.sys/bus_udev.c +index 8a0e9f855eb..6fa1bcc3644 100644 +--- a/dlls/winebus.sys/bus_udev.c ++++ b/dlls/winebus.sys/bus_udev.c +@@ -102,6 +102,7 @@ static DWORD disable_hidraw = 0; + static DWORD disable_input = 0; + static HANDLE deviceloop_handle; + static int deviceloop_control[2]; ++static HANDLE steam_overlay_event; + + static const WCHAR hidraw_busidW[] = {'H','I','D','R','A','W',0}; + static const WCHAR lnxev_busidW[] = {'L','N','X','E','V',0}; +@@ -1220,15 +1221,22 @@ static DWORD CALLBACK device_report_thread(void *args) + { + int size; + BYTE report_buffer[1024]; ++ BOOL overlay_enabled = FALSE; + + if (poll(plfds, 2, -1) <= 0) continue; + if (plfds[1].revents) + break; ++ ++ if (WaitForSingleObject(steam_overlay_event, 0) == WAIT_OBJECT_0) ++ overlay_enabled = TRUE; ++ + size = read(plfds[0].fd, report_buffer, sizeof(report_buffer)); + if (size == -1) + TRACE_(hid_report)("Read failed. Likely an unplugged device %d %s\n", errno, strerror(errno)); + else if (size == 0) + TRACE_(hid_report)("Failed to read report\n"); ++ else if (overlay_enabled) ++ TRACE_(hid_report)("Overlay is enabled, dropping report\n"); + else + { + if(private->quirks & QUIRK_DS4_BT) +@@ -2347,6 +2355,8 @@ void udev_driver_unload( void ) + #ifdef HAS_PROPER_INPUT_HEADER + bus_enumerate_hid_devices(&lnxev_vtbl, device_unload, NULL); + #endif ++ ++ CloseHandle(steam_overlay_event); + } + + NTSTATUS udev_driver_init(void) +@@ -2360,6 +2370,8 @@ NTSTATUS udev_driver_init(void) + static const WCHAR input_disabledW[] = {'D','i','s','a','b','l','e','I','n','p','u','t',0}; + static const UNICODE_STRING input_disabled = {sizeof(input_disabledW) - sizeof(WCHAR), sizeof(input_disabledW), (WCHAR*)input_disabledW}; + ++ steam_overlay_event = CreateEventA(NULL, TRUE, FALSE, "__wine_steamclient_GameOverlayActivated"); ++ + if (pipe(deviceloop_control) != 0) + { + ERR("Control pipe creation failed\n"); +From 2071d0fee45e9ad594d5c069ef8578397fc573e6 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?R=C3=A9mi=20Bernon?= +Date: Thu, 14 Jan 2021 16:30:58 +0100 +Subject: [PATCH] HACK: steam: winebus.sys: Pass SDL button up events through + the overlay. + +So that game internal state doesn't keep the button as pressed. Some +game request the Steam overlay to open whenever a button is pressed, +and keep requesting it until its state changes, which never happened +as we were dropping all the events. +--- + dlls/winebus.sys/bus_sdl.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/dlls/winebus.sys/bus_sdl.c b/dlls/winebus.sys/bus_sdl.c +index 23501931e69..5ff6d1d74fd 100644 +--- a/dlls/winebus.sys/bus_sdl.c ++++ b/dlls/winebus.sys/bus_sdl.c +@@ -1184,7 +1184,7 @@ static void process_device_event(SDL_Event *event) + try_remove_device(((SDL_JoyDeviceEvent*)event)->which); + else if (event->type >= SDL_JOYAXISMOTION && event->type <= SDL_JOYBUTTONUP) + { +- if (overlay_enabled) return; ++ if (overlay_enabled && event->type != SDL_JOYBUTTONUP) return; + set_report_from_event(event); + } + else if (event->type >= SDL_CONTROLLERAXISMOTION && event->type <= SDL_CONTROLLERBUTTONUP) +@@ -1195,7 +1195,7 @@ static void process_device_event(SDL_Event *event) + } + else if (event->type >= SDL_CONTROLLERAXISMOTION && event->type <= SDL_CONTROLLERBUTTONUP) + { +- if (overlay_enabled) return; ++ if (overlay_enabled && event->type != SDL_CONTROLLERBUTTONUP) return; + set_mapped_report_from_event(event); + } + } +From ba27a7a35e31e297671e9dcc932ec2edff504646 Mon Sep 17 00:00:00 2001 +From: Ivo Ivanov +Date: Fri, 4 Jun 2021 23:30:24 +0300 +Subject: [PATCH] dinput: Prefer IDirectInputW interfaces over IDirectInputA. + +As per the upstream changes, cleanup all the code from IDirectInputA +interface usage, and update to IDirectInputW interfaces where needed. + +Implement the other changes introduced by upstream till v6.10. + +Signed-off-by: Ivo Ivanov +--- + dlls/dinput/effect_sdl.c | 34 ----- + dlls/dinput/joystick_sdl.c | 288 ++----------------------------------- + 2 files changed, 13 insertions(+), 309 deletions(-) + +diff --git a/dlls/dinput/effect_sdl.c b/dlls/dinput/effect_sdl.c +index a2b00f89082..889a93d30e9 100644 +--- a/dlls/dinput/effect_sdl.c ++++ b/dlls/dinput/effect_sdl.c +@@ -792,40 +792,6 @@ DECLSPEC_HIDDEN HRESULT sdl_create_effect(SDL_Haptic *device, REFGUID rguid, str + return DI_OK; + } + +-DECLSPEC_HIDDEN HRESULT sdl_input_get_info_A( +- SDL_Joystick *dev, +- REFGUID rguid, +- LPDIEFFECTINFOA info) +-{ +- DWORD type = typeFromGUID(rguid); +- +- TRACE("(%p, %s, %p) type=%d\n", dev, _dump_dinput_GUID(rguid), info, type); +- +- if (!info) return E_POINTER; +- +- if (info->dwSize != sizeof(DIEFFECTINFOA)) return DIERR_INVALIDPARAM; +- +- info->guid = *rguid; +- +- info->dwEffType = type; +- /* the event device API does not support querying for all these things +- * therefore we assume that we have support for them +- * that's not as dangerous as it sounds, since drivers are allowed to +- * ignore parameters they claim to support anyway */ +- info->dwEffType |= DIEFT_DEADBAND | DIEFT_FFATTACK | DIEFT_FFFADE +- | DIEFT_POSNEGCOEFFICIENTS | DIEFT_POSNEGSATURATION +- | DIEFT_SATURATION | DIEFT_STARTDELAY; +- +- /* again, assume we have support for everything */ +- info->dwStaticParams = DIEP_ALLPARAMS; +- info->dwDynamicParams = info->dwStaticParams; +- +- /* yes, this is windows behavior (print the GUID_Name for name) */ +- strcpy(info->tszName, _dump_dinput_GUID(rguid)); +- +- return DI_OK; +-} +- + DECLSPEC_HIDDEN HRESULT sdl_input_get_info_W( + SDL_Joystick *dev, + REFGUID rguid, +diff --git a/dlls/dinput/joystick_sdl.c b/dlls/dinput/joystick_sdl.c +index 44ab240bf25..0c477fc4770 100644 +--- a/dlls/dinput/joystick_sdl.c ++++ b/dlls/dinput/joystick_sdl.c +@@ -78,12 +78,10 @@ WINE_DEFAULT_DEBUG_CHANNEL(dinput); + #define PID_MICROSOFT_XBOX_ONE_S_2 0x02fd + + typedef struct JoystickImpl JoystickImpl; +-static const IDirectInputDevice8AVtbl JoystickAvt; + static const IDirectInputDevice8WVtbl JoystickWvt; + + /* implemented in effect_sdl.c */ + HRESULT sdl_create_effect(SDL_Haptic *haptic, REFGUID rguid, struct list *parent_list_entry, LPDIRECTINPUTEFFECT* peff); +-HRESULT sdl_input_get_info_A(SDL_Joystick *dev, REFGUID rguid, LPDIEFFECTINFOA info); + HRESULT sdl_input_get_info_W(SDL_Joystick *dev, REFGUID rguid, LPDIEFFECTINFOW info); + + #define ITEM_TYPE_BUTTON 1 +@@ -553,32 +551,7 @@ static void fill_joystick_dideviceinstanceW(LPDIDEVICEINSTANCEW lpddi, DWORD ver + lpddi->wUsage = lpddiA.wUsage; + } + +-static HRESULT sdl_enum_deviceA(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEA lpddi, DWORD version, int id) +-{ +- find_sdldevs(); +- +- if (id >= ARRAY_SIZE(sdldevs) || !sdldevs[id].valid) +- return E_FAIL; +- +- if (!((dwDevType == 0) || +- ((dwDevType == DIDEVTYPE_JOYSTICK) && (version >= 0x0300 && version < 0x0800)) || +- (((dwDevType == DI8DEVCLASS_GAMECTRL) || (dwDevType == DI8DEVTYPE_JOYSTICK)) && (version >= 0x0800)))) +- return S_FALSE; +- +- if ((dwFlags & DIEDFL_FORCEFEEDBACK) && !sdldevs[id].sdl_haptic) +- return S_FALSE; +- +- if (dwFlags & DIEDFL_ATTACHEDONLY) +- { +- if (!SDL_JoystickGetAttached(sdldevs[id].sdl_js)) +- return S_FALSE; +- } +- +- fill_joystick_dideviceinstanceA(lpddi, version, id); +- return S_OK; +-} +- +-static HRESULT sdl_enum_deviceW(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEW lpddi, DWORD version, int id) ++static HRESULT sdl_enum_device(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEW lpddi, DWORD version, int id) + { + find_sdldevs(); + +@@ -1133,8 +1106,9 @@ static JoystickImpl *alloc_device(REFGUID rguid, IDirectInputImpl *dinput, unsig + if (!SDL_JoystickGetAttached(js)) + return NULL; + +- newDevice = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(JoystickImpl)); +- if (!newDevice) return NULL; ++ if (FAILED(direct_input_device_alloc( sizeof(JoystickImpl), &JoystickWvt, rguid, dinput, (void **)&newDevice ))) ++ return NULL; ++ newDevice->generic.base.crit.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": JoystickImpl*->base.crit"); + + newDevice->generic.guidInstance = DInput_Wine_SDL_Joystick_GUID; + PUT_JS_GUID_VID(&newDevice->generic.guidInstance, sdldevs[index].vendor_id); +@@ -1145,20 +1119,12 @@ static JoystickImpl *alloc_device(REFGUID rguid, IDirectInputImpl *dinput, unsig + newDevice->generic.joy_polldev = poll_sdl_device_state; + newDevice->enum_device_state = select_enum_function(&sdldevs[index]); + +- newDevice->generic.base.IDirectInputDevice8A_iface.lpVtbl = &JoystickAvt; +- newDevice->generic.base.IDirectInputDevice8W_iface.lpVtbl = &JoystickWvt; +- newDevice->generic.base.ref = 1; +- newDevice->generic.base.guid = *rguid; +- newDevice->generic.base.dinput = dinput; + newDevice->sdldev = &sdldevs[index]; + newDevice->generic.name = (char*)newDevice->sdldev->name; + list_init(&newDevice->sdldev->effects); + newDevice->sdldev->autocenter = 1; + newDevice->sdldev->gain = 100; + +- InitializeCriticalSection(&newDevice->generic.base.crit); +- newDevice->generic.base.crit.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": JoystickImpl*->base.crit"); +- + /* Open Device */ + + i = 0; +@@ -1254,8 +1220,6 @@ static JoystickImpl *alloc_device(REFGUID rguid, IDirectInputImpl *dinput, unsig + if (newDevice->sdldev->sdl_haptic) + newDevice->generic.devcaps.dwFlags |= DIDC_FORCEFEEDBACK; + +- IDirectInput_AddRef(&newDevice->generic.base.dinput->IDirectInput7A_iface); +- + return newDevice; + + failed: +@@ -1298,41 +1262,19 @@ static unsigned short get_joystick_index(REFGUID guid) + return 0xffff; + } + +-static HRESULT sdl_create_device(IDirectInputImpl *dinput, REFGUID rguid, REFIID riid, LPVOID *pdev, int unicode) ++static HRESULT sdl_create_device( IDirectInputImpl *dinput, REFGUID rguid, IDirectInputDevice8W **out ) + { + unsigned short index; + +- TRACE("%p %s %s %p %i\n", dinput, debugstr_guid(rguid), debugstr_guid(riid), pdev, unicode); ++ TRACE( "%p %s %p\n", dinput, debugstr_guid( rguid ), out ); + + find_sdldevs(); +- *pdev = NULL; ++ *out = NULL; + + if ((index = get_joystick_index(rguid)) < 0xffff && sdldevs[index].valid) + { + JoystickImpl *This; + +- if (riid == NULL) +- ;/* nothing */ +- else if (IsEqualGUID(&IID_IDirectInputDeviceA, riid) || +- IsEqualGUID(&IID_IDirectInputDevice2A, riid) || +- IsEqualGUID(&IID_IDirectInputDevice7A, riid) || +- IsEqualGUID(&IID_IDirectInputDevice8A, riid)) +- { +- unicode = 0; +- } +- else if (IsEqualGUID(&IID_IDirectInputDeviceW, riid) || +- IsEqualGUID(&IID_IDirectInputDevice2W, riid) || +- IsEqualGUID(&IID_IDirectInputDevice7W, riid) || +- IsEqualGUID(&IID_IDirectInputDevice8W, riid)) +- { +- unicode = 1; +- } +- else +- { +- WARN("no interface\n"); +- return DIERR_NOINTERFACE; +- } +- + This = alloc_device(rguid, dinput, index); + if (!This) + return DIERR_INPUTLOST; +@@ -1340,11 +1282,7 @@ static HRESULT sdl_create_device(IDirectInputImpl *dinput, REFGUID rguid, REFIID + + if (!This) return DIERR_OUTOFMEMORY; + +- if (unicode) +- *pdev = &This->generic.base.IDirectInputDevice8W_iface; +- else +- *pdev = &This->generic.base.IDirectInputDevice8A_iface; +- ++ *out = &This->generic.base.IDirectInputDevice8W_iface; + return DI_OK; + } + +@@ -1353,23 +1291,10 @@ static HRESULT sdl_create_device(IDirectInputImpl *dinput, REFGUID rguid, REFIID + + const struct dinput_device joystick_sdl_device = { + "Wine SDL joystick driver", +- sdl_enum_deviceA, +- sdl_enum_deviceW, ++ sdl_enum_device, + sdl_create_device + }; + +-static ULONG WINAPI JoystickWImpl_Release(LPDIRECTINPUTDEVICE8W iface) +-{ +- TRACE("(this=%p)\n", iface); +- return IDirectInputDevice2WImpl_Release(iface); +-} +- +-static ULONG WINAPI JoystickAImpl_Release(LPDIRECTINPUTDEVICE8A iface) +-{ +- JoystickImpl *This = impl_from_IDirectInputDevice8A(iface); +- return JoystickWImpl_Release(IDirectInputDevice8W_from_impl(This)); +-} +- + /****************************************************************************** + * GetProperty : get input device properties + */ +@@ -1437,12 +1437,6 @@ static HRESULT WINAPI JoystickWImpl_GetProperty(LPDIRECTINPUTDEVICE8W iface, REF + return DI_OK; + } + +-static HRESULT WINAPI JoystickAImpl_GetProperty(LPDIRECTINPUTDEVICE8A iface, REFGUID rguid, LPDIPROPHEADER pdiph) +-{ +- JoystickImpl *This = impl_from_IDirectInputDevice8A(iface); +- return JoystickWImpl_GetProperty(IDirectInputDevice8W_from_impl(This), rguid, pdiph); +-} +- + static BOOL _SetProperty(JoystickImpl *This, const GUID *prop, const DIPROPHEADER *header) + { + int rc; +@@ -1496,42 +1490,9 @@ static HRESULT WINAPI JoystickWImpl_SetProperty(IDirectInputDevice8W *iface, + return JoystickWGenericImpl_SetProperty(iface, prop, header); + } + +-static HRESULT WINAPI JoystickAImpl_SetProperty(IDirectInputDevice8A *iface, +- const GUID *prop, const DIPROPHEADER *header) +-{ +- JoystickImpl *This = impl_from_IDirectInputDevice8A(iface); +- +- TRACE("%p %s %p\n", This, debugstr_guid(prop), header); +- +- if (_SetProperty(This, prop, header)) +- return DI_OK; +- else +- return JoystickAGenericImpl_SetProperty(iface, prop, header); +-} +- + /****************************************************************************** + * GetDeviceInfo : get information about a device's identity + */ +-static HRESULT WINAPI JoystickAImpl_GetDeviceInfo(LPDIRECTINPUTDEVICE8A iface, +- LPDIDEVICEINSTANCEA pdidi) +-{ +- JoystickImpl *This = impl_from_IDirectInputDevice8A(iface); +- +- TRACE("(%p) %p\n", This, pdidi); +- +- if (pdidi == NULL) return E_POINTER; +- if ((pdidi->dwSize != sizeof(DIDEVICEINSTANCE_DX3A)) && +- (pdidi->dwSize != sizeof(DIDEVICEINSTANCEA))) +- return DIERR_INVALIDPARAM; +- +- fill_joystick_dideviceinstanceA(pdidi, This->generic.base.dinput->dwVersion, +- get_joystick_index(&This->generic.base.guid)); +- +- pdidi->guidInstance = This->generic.base.guid; +- +- return DI_OK; +-} +- + static HRESULT WINAPI JoystickWImpl_GetDeviceInfo(LPDIRECTINPUTDEVICE8W iface, + LPDIDEVICEINSTANCEW pdidi) + { +@@ -1665,18 +1557,6 @@ static HRESULT WINAPI JoystickWImpl_CreateEffect(IDirectInputDevice8W *iface, + return DI_OK; + } + +-static HRESULT WINAPI JoystickAImpl_CreateEffect(IDirectInputDevice8A *iface, +- const GUID *type, const DIEFFECT *params, IDirectInputEffect **out, +- IUnknown *outer) +-{ +- JoystickImpl *This = impl_from_IDirectInputDevice8A(iface); +- +- TRACE("%p %s %p %p %p\n", iface, debugstr_guid(type), params, out, outer); +- +- return JoystickWImpl_CreateEffect(&This->generic.base.IDirectInputDevice8W_iface, +- type, params, out, outer); +-} +- + static HRESULT WINAPI JoystickWImpl_EnumEffects(LPDIRECTINPUTDEVICE8W iface, + LPDIENUMEFFECTSCALLBACKW lpCallback, + LPVOID pvRef, +@@ -1758,87 +1638,6 @@ static HRESULT WINAPI JoystickWImpl_EnumEffects(LPDIRECTINPUTDEVICE8W iface, + return DI_OK; + } + +-static HRESULT WINAPI JoystickAImpl_EnumEffects(LPDIRECTINPUTDEVICE8A iface, +- LPDIENUMEFFECTSCALLBACKA lpCallback, +- LPVOID pvRef, +- DWORD dwEffType) +-{ +- DIEFFECTINFOA dei; +- DWORD type = DIEFT_GETTYPE(dwEffType); +- JoystickImpl* This = impl_from_IDirectInputDevice8A(iface); +- unsigned int query; +- +- TRACE("(this=%p,%p,%d) type=%d\n", This, pvRef, dwEffType, type); +- +- dei.dwSize = sizeof(DIEFFECTINFOA); +- query = SDL_HapticQuery(This->sdldev->sdl_haptic); +- TRACE("Effects 0x%x\n",query); +- +- if ((type == DIEFT_ALL || type == DIEFT_CONSTANTFORCE) +- && (query & SDL_HAPTIC_CONSTANT)) +- { +- IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_ConstantForce); +- (*lpCallback)(&dei, pvRef); +- } +- +- if ((type == DIEFT_ALL || type == DIEFT_RAMPFORCE) && +- (query & SDL_HAPTIC_RAMP)) +- { +- IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_RampForce); +- (*lpCallback)(&dei, pvRef); +- } +- +- if (type == DIEFT_ALL || type == DIEFT_PERIODIC) +- { +- if (query & SDL_HAPTIC_SINE) +- { +- IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Sine); +- (*lpCallback)(&dei, pvRef); +- } +- if (query & SDL_HAPTIC_TRIANGLE) +- { +- IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Triangle); +- (*lpCallback)(&dei, pvRef); +- } +- if (query & SDL_HAPTIC_SAWTOOTHUP) +- { +- IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_SawtoothUp); +- (*lpCallback)(&dei, pvRef); +- } +- if (query & SDL_HAPTIC_SAWTOOTHDOWN) +- { +- IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_SawtoothDown); +- (*lpCallback)(&dei, pvRef); +- } +- } +- +- if (type == DIEFT_ALL || type == DIEFT_CONDITION) +- { +- if (query & SDL_HAPTIC_SPRING) +- { +- IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Spring); +- (*lpCallback)(&dei, pvRef); +- } +- if (query & SDL_HAPTIC_DAMPER) +- { +- IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Damper); +- (*lpCallback)(&dei, pvRef); +- } +- if (query & SDL_HAPTIC_INERTIA) +- { +- IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Inertia); +- (*lpCallback)(&dei, pvRef); +- } +- if (query & SDL_HAPTIC_FRICTION) +- { +- IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Friction); +- (*lpCallback)(&dei, pvRef); +- } +- } +- +- return DI_OK; +-} +- + static HRESULT WINAPI JoystickWImpl_GetEffectInfo(LPDIRECTINPUTDEVICE8W iface, + LPDIEFFECTINFOW pdei, + REFGUID guid) +@@ -1849,16 +1648,6 @@ static HRESULT WINAPI JoystickWImpl_GetEffectInfo(LPDIRECTINPUTDEVICE8W iface, + return sdl_input_get_info_W(This->sdldev->sdl_js, guid, pdei); + } + +-static HRESULT WINAPI JoystickAImpl_GetEffectInfo(LPDIRECTINPUTDEVICE8A iface, +- LPDIEFFECTINFOA pdei, +- REFGUID guid) +-{ +- JoystickImpl* This = impl_from_IDirectInputDevice8A(iface); +- TRACE("(this=%p,%p,%s)\n", This, pdei, _dump_dinput_GUID(guid)); +- find_sdldevs(); +- return sdl_input_get_info_A(This->sdldev->sdl_js, guid, pdei); +-} +- + static HRESULT WINAPI JoystickWImpl_SendForceFeedbackCommand(LPDIRECTINPUTDEVICE8W iface, DWORD dwFlags) + { + JoystickImpl* This = impl_from_IDirectInputDevice8W(iface); +@@ -1911,12 +1700,6 @@ static HRESULT WINAPI JoystickWImpl_SendForceFeedbackCommand(LPDIRECTINPUTDEVICE + return DI_OK; + } + +-static HRESULT WINAPI JoystickAImpl_SendForceFeedbackCommand(LPDIRECTINPUTDEVICE8A iface, DWORD dwFlags) +-{ +- JoystickImpl *This = impl_from_IDirectInputDevice8A(iface); +- return JoystickWImpl_SendForceFeedbackCommand(IDirectInputDevice8W_from_impl(This), dwFlags); +-} +- + static HRESULT WINAPI JoystickWImpl_EnumCreatedEffectObjects(LPDIRECTINPUTDEVICE8W iface, + LPDIENUMCREATEDEFFECTOBJECTSCALLBACK lpCallback, + LPVOID pvRef, DWORD dwFlags) +@@ -1938,55 +1721,11 @@ static HRESULT WINAPI JoystickWImpl_EnumCreatedEffectObjects(LPDIRECTINPUTDEVICE + return DI_OK; + } + +-static HRESULT WINAPI JoystickAImpl_EnumCreatedEffectObjects(LPDIRECTINPUTDEVICE8A iface, +- LPDIENUMCREATEDEFFECTOBJECTSCALLBACK lpCallback, +- LPVOID pvRef, DWORD dwFlags) +-{ +- JoystickImpl *This = impl_from_IDirectInputDevice8A(iface); +- return JoystickWImpl_EnumCreatedEffectObjects(IDirectInputDevice8W_from_impl(This), lpCallback, pvRef, dwFlags); +-} +- +-static const IDirectInputDevice8AVtbl JoystickAvt = +-{ +- IDirectInputDevice2AImpl_QueryInterface, +- IDirectInputDevice2AImpl_AddRef, +- JoystickAImpl_Release, +- JoystickAGenericImpl_GetCapabilities, +- IDirectInputDevice2AImpl_EnumObjects, +- JoystickAImpl_GetProperty, +- JoystickAImpl_SetProperty, +- IDirectInputDevice2AImpl_Acquire, +- IDirectInputDevice2AImpl_Unacquire, +- JoystickAGenericImpl_GetDeviceState, +- IDirectInputDevice2AImpl_GetDeviceData, +- IDirectInputDevice2AImpl_SetDataFormat, +- IDirectInputDevice2AImpl_SetEventNotification, +- IDirectInputDevice2AImpl_SetCooperativeLevel, +- JoystickAGenericImpl_GetObjectInfo, +- JoystickAImpl_GetDeviceInfo, +- IDirectInputDevice2AImpl_RunControlPanel, +- IDirectInputDevice2AImpl_Initialize, +- JoystickAImpl_CreateEffect, +- JoystickAImpl_EnumEffects, +- JoystickAImpl_GetEffectInfo, +- IDirectInputDevice2AImpl_GetForceFeedbackState, +- JoystickAImpl_SendForceFeedbackCommand, +- JoystickAImpl_EnumCreatedEffectObjects, +- IDirectInputDevice2AImpl_Escape, +- JoystickAGenericImpl_Poll, +- IDirectInputDevice2AImpl_SendDeviceData, +- IDirectInputDevice7AImpl_EnumEffectsInFile, +- IDirectInputDevice7AImpl_WriteEffectToFile, +- JoystickAGenericImpl_BuildActionMap, +- JoystickAGenericImpl_SetActionMap, +- IDirectInputDevice8AImpl_GetImageInfo +-}; +- + static const IDirectInputDevice8WVtbl JoystickWvt = + { + IDirectInputDevice2WImpl_QueryInterface, + IDirectInputDevice2WImpl_AddRef, +- JoystickWImpl_Release, ++ IDirectInputDevice2WImpl_Release, + JoystickWGenericImpl_GetCapabilities, + IDirectInputDevice2WImpl_EnumObjects, + JoystickWImpl_GetProperty, +@@ -2023,7 +1762,6 @@ static const IDirectInputDevice8WVtbl JoystickWvt = + const struct dinput_device joystick_sdl_device = { + "Wine SDL joystick driver", + NULL, +- NULL, + NULL + }; + +From 276a410246381e969d6999150bde35f4a9969232 Mon Sep 17 00:00:00 2001 +From: Arkadiusz Hiler +Date: Mon, 19 Apr 2021 14:25:14 +0300 +Subject: [PATCH] dinput: Extract SDL controller vidpid and name hacks to + separate functions. + +So they can be moved to their own file and shared with other parts of +Wine. + +CW-Bug-Id: #18761 +--- + dlls/dinput/joystick_sdl.c | 228 +++++++++++++++++++------------------ + 1 file changed, 115 insertions(+), 113 deletions(-) + +diff --git a/dlls/dinput/joystick_sdl.c b/dlls/dinput/joystick_sdl.c +index 8cb839aa610..ffb1e14e885 100644 +--- a/dlls/dinput/joystick_sdl.c ++++ b/dlls/dinput/joystick_sdl.c +@@ -77,6 +77,85 @@ WINE_DEFAULT_DEBUG_CHANNEL(dinput); + #define PID_MICROSOFT_XBOX_ONE_S 0x02ea + #define PID_MICROSOFT_XBOX_ONE_S_2 0x02fd + ++static BOOL __controller_hack_sdl_is_vid_pid_xbox_360(WORD vid, WORD pid) ++{ ++ if(vid != VID_MICROSOFT) ++ return FALSE; ++ ++ if(pid == PID_MICROSOFT_XBOX_360 || ++ pid == PID_MICROSOFT_XBOX_360_WIRELESS || ++ pid == PID_MICROSOFT_XBOX_360_ADAPTER) ++ return TRUE; ++ ++ return FALSE; ++} ++static BOOL __controller_hack_sdl_is_vid_pid_xbox_one(WORD vid, WORD pid) { ++ if(vid != VID_MICROSOFT) ++ return FALSE; ++ ++ if(pid == PID_MICROSOFT_XBOX_ONE || ++ pid == PID_MICROSOFT_XBOX_ONE_CF || ++ pid == PID_MICROSOFT_XBOX_ONE_ELITE || ++ pid == PID_MICROSOFT_XBOX_ONE_S || ++ pid == PID_MICROSOFT_XBOX_ONE_S_2) ++ return TRUE; ++ ++ return FALSE; ++} ++ ++static BOOL __controller_hack_sdl_is_vid_pid_sony_dualshock4(WORD vid, WORD pid) ++{ ++ if(vid != VID_SONY) ++ return FALSE; ++ ++ if(pid == PID_SONY_DUALSHOCK_4 || ++ pid == PID_SONY_DUALSHOCK_4_2 || ++ pid == PID_SONY_DUALSHOCK_4_DONGLE) ++ return TRUE; ++ ++ return FALSE; ++} ++ ++static BOOL __controller_hack_sdl_is_vid_pid_sony_dualsense(WORD vid, WORD pid) ++{ ++ if(vid == VID_SONY && pid == PID_SONY_DUALSENSE) ++ return TRUE; ++ ++ return FALSE; ++} ++ ++static void __controller_hack_sdl_vid_pid_override(WORD *vid, WORD *pid) ++{ ++ TRACE("(*vid = %04hx, *pid = *%04hx\n", *vid, *pid); ++ if(*vid == VID_VALVE && *pid == PID_VALVE_VIRTUAL_CONTROLLER) ++ { ++ TRACE("Valve Virtual Controller found - pretending it's x360\n"); ++ *vid = VID_MICROSOFT; ++ *pid = PID_MICROSOFT_XBOX_360; ++ } ++} ++ ++static void __controller_hack_sdl_name_override(WORD vid, WORD pid, const char **name) ++{ ++ const char *new_name = NULL; ++ ++ TRACE("vid = %04hx, pid = %04hx, *name = %s\n", vid, pid, debugstr_a(*name)); ++ ++ if(__controller_hack_sdl_is_vid_pid_xbox_360(vid, pid)) ++ new_name = "Controller (XBOX 360 For Windows)"; ++ else if(__controller_hack_sdl_is_vid_pid_xbox_one(vid, pid)) ++ new_name = "Controller (XBOX One For Windows)"; ++ else if(__controller_hack_sdl_is_vid_pid_sony_dualshock4(vid, pid) || ++ __controller_hack_sdl_is_vid_pid_sony_dualsense(vid, pid)) ++ new_name = "Wireless Controller"; ++ ++ if(new_name) ++ { ++ TRACE("new name for the controller = %s\n", debugstr_a(new_name)); ++ *name = new_name; ++ } ++} ++ + typedef struct JoystickImpl JoystickImpl; + static const IDirectInputDevice8AVtbl JoystickAvt; + static const IDirectInputDevice8WVtbl JoystickWvt; +@@ -388,11 +467,7 @@ static void find_sdldevs(void) + continue; + } + +- if(sdldev->vendor_id == VID_VALVE && sdldev->product_id == PID_VALVE_VIRTUAL_CONTROLLER) +- { +- sdldev->vendor_id = VID_MICROSOFT; +- sdldev->product_id = PID_MICROSOFT_XBOX_360; +- } ++ __controller_hack_sdl_vid_pid_override(&sdldev->vendor_id, &sdldev->product_id); + + sdldev->nth_instance = get_num_vidpids(sdldev->vendor_id, sdldev->product_id); + +@@ -410,66 +485,10 @@ static void find_sdldevs(void) + LeaveCriticalSection(&sdldevs_lock); + } + +-static struct device_info_override { +- WORD vid; +- WORD pid; +- const char *instance_name; +- const char *product_name; +- DWORD dev_type; +- DWORD dev_type8; +-} device_info_overrides[] = { +- { VID_SONY, PID_SONY_DUALSHOCK_4, "Wireless Controller", "Wireless Controller", +- DIDEVTYPE_HID | DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_GAMEPAD << 8), +- DIDEVTYPE_HID | DI8DEVTYPE_1STPERSON | (DI8DEVTYPE1STPERSON_SIXDOF << 8) }, +- +- { VID_SONY, PID_SONY_DUALSHOCK_4_2, "Wireless Controller", "Wireless Controller", +- DIDEVTYPE_HID | DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_GAMEPAD << 8), +- DIDEVTYPE_HID | DI8DEVTYPE_1STPERSON | (DI8DEVTYPE1STPERSON_SIXDOF << 8) }, +- +- { VID_SONY, PID_SONY_DUALSHOCK_4_DONGLE, "Wireless Controller", "Wireless Controller", +- DIDEVTYPE_HID | DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_GAMEPAD << 8), +- DIDEVTYPE_HID | DI8DEVTYPE_1STPERSON | (DI8DEVTYPE1STPERSON_SIXDOF << 8) }, +- +- { VID_SONY, PID_SONY_DUALSENSE, "Wireless Controller", "Wireless Controller", +- DIDEVTYPE_HID | DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_GAMEPAD << 8), +- DIDEVTYPE_HID | DI8DEVTYPE_1STPERSON | (DI8DEVTYPE1STPERSON_SIXDOF << 8) }, +- +- { VID_MICROSOFT, PID_MICROSOFT_XBOX_360, "Controller (XBOX 360 For Windows)", "Controller (XBOX 360 For Windows)", +- DIDEVTYPE_HID | DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_GAMEPAD << 8), +- DIDEVTYPE_HID | DI8DEVTYPE_GAMEPAD | (DI8DEVTYPEGAMEPAD_STANDARD << 8) }, +- +- { VID_MICROSOFT, PID_MICROSOFT_XBOX_360_WIRELESS, "Controller (XBOX 360 For Windows)", "Controller (XBOX 360 For Windows)", +- DIDEVTYPE_HID | DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_GAMEPAD << 8), +- DIDEVTYPE_HID | DI8DEVTYPE_GAMEPAD | (DI8DEVTYPEGAMEPAD_STANDARD << 8) }, +- +- { VID_MICROSOFT, PID_MICROSOFT_XBOX_360_ADAPTER, "Controller (XBOX 360 For Windows)", "Controller (XBOX 360 For Windows)", +- DIDEVTYPE_HID | DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_GAMEPAD << 8), +- DIDEVTYPE_HID | DI8DEVTYPE_GAMEPAD | (DI8DEVTYPEGAMEPAD_STANDARD << 8) }, +- +- { VID_MICROSOFT, PID_MICROSOFT_XBOX_ONE, "Controller (XBOX One For Windows)", "Controller (XBOX One For Windows)", +- DIDEVTYPE_HID | DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_GAMEPAD << 8), +- DIDEVTYPE_HID | DI8DEVTYPE_GAMEPAD | (DI8DEVTYPEGAMEPAD_STANDARD << 8) }, +- +- { VID_MICROSOFT, PID_MICROSOFT_XBOX_ONE_CF, "Controller (XBOX One For Windows)", "Controller (XBOX One For Windows)", +- DIDEVTYPE_HID | DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_GAMEPAD << 8), +- DIDEVTYPE_HID | DI8DEVTYPE_GAMEPAD | (DI8DEVTYPEGAMEPAD_STANDARD << 8) }, +- +- { VID_MICROSOFT, PID_MICROSOFT_XBOX_ONE_ELITE, "Controller (XBOX One For Windows)", "Controller (XBOX One For Windows)", +- DIDEVTYPE_HID | DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_GAMEPAD << 8), +- DIDEVTYPE_HID | DI8DEVTYPE_GAMEPAD | (DI8DEVTYPEGAMEPAD_STANDARD << 8) }, +- +- { VID_MICROSOFT, PID_MICROSOFT_XBOX_ONE_S, "Controller (XBOX One For Windows)", "Controller (XBOX One For Windows)", +- DIDEVTYPE_HID | DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_GAMEPAD << 8), +- DIDEVTYPE_HID | DI8DEVTYPE_GAMEPAD | (DI8DEVTYPEGAMEPAD_STANDARD << 8) }, +- +- { VID_MICROSOFT, PID_MICROSOFT_XBOX_ONE_S_2, "Controller (XBOX One For Windows)", "Controller (XBOX One For Windows)", +- DIDEVTYPE_HID | DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_GAMEPAD << 8), +- DIDEVTYPE_HID | DI8DEVTYPE_GAMEPAD | (DI8DEVTYPEGAMEPAD_STANDARD << 8) }, +-}; +- + static void fill_joystick_dideviceinstanceA(LPDIDEVICEINSTANCEA lpddi, DWORD version, int id) + { +- DWORD dwSize = lpddi->dwSize, i; ++ DWORD dwSize = lpddi->dwSize; ++ const char *name; + + TRACE("%d %p\n", dwSize, lpddi); + memset(lpddi, 0, dwSize); +@@ -503,30 +522,26 @@ static void fill_joystick_dideviceinstanceA(LPDIDEVICEINSTANCEA lpddi, DWORD ver + lpddi->wUsage = 0x05; /* Game Pad */ + } + +- for(i = 0; i < ARRAY_SIZE(device_info_overrides); ++i) ++ name = sdldevs[id].name; ++ __controller_hack_sdl_name_override(sdldevs[id].vendor_id, sdldevs[id].product_id, &name); ++ strcpy(lpddi->tszInstanceName, name); ++ strcpy(lpddi->tszProductName, name); ++ ++ if(__controller_hack_sdl_is_vid_pid_xbox_one(sdldevs[id].vendor_id, sdldevs[id].product_id) || ++ __controller_hack_sdl_is_vid_pid_xbox_360(sdldevs[id].vendor_id, sdldevs[id].product_id)) + { +- const struct device_info_override *override = &device_info_overrides[i]; +- if(sdldevs[id].vendor_id == override->vid && +- sdldevs[id].product_id == override->pid) +- { +- TRACE("found devinfo override for %04hx/%04hx\n", +- override->vid, override->pid); + if(version >= 0x800) +- lpddi->dwDevType = override->dev_type8; ++ lpddi->dwDevType = DIDEVTYPE_HID | DI8DEVTYPE_GAMEPAD | (DI8DEVTYPEGAMEPAD_STANDARD << 8); + else +- lpddi->dwDevType = override->dev_type; +- +- strcpy(lpddi->tszInstanceName, override->instance_name); +- strcpy(lpddi->tszProductName, override->product_name); +- +- break; +- } ++ lpddi->dwDevType = DIDEVTYPE_HID | DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_GAMEPAD << 8); + } +- +- if(i >= ARRAY_SIZE(device_info_overrides)) ++ else if(__controller_hack_sdl_is_vid_pid_sony_dualshock4(sdldevs[id].vendor_id, sdldevs[id].product_id) || ++ __controller_hack_sdl_is_vid_pid_sony_dualsense(sdldevs[id].vendor_id, sdldevs[id].product_id)) + { +- strcpy(lpddi->tszInstanceName, sdldevs[id].name); +- strcpy(lpddi->tszProductName, sdldevs[id].name); ++ if (version >= 0x800) ++ lpddi->dwDevType = DIDEVTYPE_HID | DI8DEVTYPE_1STPERSON | (DI8DEVTYPE1STPERSON_SIXDOF << 8); ++ else ++ lpddi->dwDevType = DIDEVTYPE_HID | DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_GAMEPAD << 8); + } + } + +@@ -1081,38 +1096,25 @@ static HRESULT poll_sdl_device_state(LPDIRECTINPUTDEVICE8A iface) + + static enum_device_state_function select_enum_function(struct SDLDev *sdldev) + { +- switch(sdldev->vendor_id){ +- case VID_SONY: +- switch(sdldev->product_id){ +- case PID_SONY_DUALSHOCK_4: +- case PID_SONY_DUALSHOCK_4_2: +- case PID_SONY_DUALSHOCK_4_DONGLE: +- TRACE("for %04x/%04x, polling ds4 controller\n", sdldev->vendor_id, sdldev->product_id); +- if(sdldev->n_buttons >= 16) +- return enum_device_state_ds4_16button; +- +- TRACE("SDL only reports %u buttons for this PS4 controller. Please upgrade SDL to > 2.0.10 and/or give your user hidraw access.\n", +- sdldev->n_buttons); +- return enum_device_state_ds4_13button; +- } +- case PID_SONY_DUALSENSE: +- return enum_device_state_dualsense; +- break; ++ if(__controller_hack_sdl_is_vid_pid_sony_dualshock4(sdldev->vendor_id, sdldev->product_id)) ++ { ++ TRACE("for %04x/%04x, polling ds4 controller\n", sdldev->vendor_id, sdldev->product_id); ++ if(sdldev->n_buttons >= 16) ++ return enum_device_state_ds4_16button; + +- case VID_MICROSOFT: +- switch(sdldev->product_id){ +- case PID_MICROSOFT_XBOX_360: +- case PID_MICROSOFT_XBOX_360_WIRELESS: +- case PID_MICROSOFT_XBOX_360_ADAPTER: +- case PID_MICROSOFT_XBOX_ONE: +- case PID_MICROSOFT_XBOX_ONE_CF: +- case PID_MICROSOFT_XBOX_ONE_ELITE: +- case PID_MICROSOFT_XBOX_ONE_S: +- case PID_MICROSOFT_XBOX_ONE_S_2: +- TRACE("for %04x/%04x, polling xbox 360/one controller\n", sdldev->vendor_id, sdldev->product_id); +- return enum_device_state_ms_xb360; +- } +- break; ++ TRACE("SDL only reports %u buttons for this PS4 controller. Please upgrade SDL to > 2.0.10 and/or give your user hidraw access.\n", ++ sdldev->n_buttons); ++ return enum_device_state_ds4_13button; ++ } ++ else if(__controller_hack_sdl_is_vid_pid_sony_dualsense(sdldev->vendor_id, sdldev->product_id)) ++ { ++ return enum_device_state_dualsense; ++ } ++ else if(__controller_hack_sdl_is_vid_pid_xbox_360(sdldev->vendor_id, sdldev->product_id) || ++ __controller_hack_sdl_is_vid_pid_xbox_one(sdldev->vendor_id, sdldev->product_id)) ++ { ++ TRACE("for %04x/%04x, polling xbox 360/one controller\n", sdldev->vendor_id, sdldev->product_id); ++ return enum_device_state_ms_xb360; + } + + TRACE("for %04x/%04x, using no maps\n", sdldev->vendor_id, sdldev->product_id); +From 14f1dbc4111700d87ac0c36a8870f16c40deeedc Mon Sep 17 00:00:00 2001 +From: Arkadiusz Hiler +Date: Thu, 20 May 2021 17:04:35 +0300 +Subject: [PATCH] dinput: Move controller vidpid and name wrangling to a + separate file. + +... so we can share it with winebus.sys/bus_sdl.c + +CW-Bug-Id: #18761 +--- + dlls/dinput/joystick_sdl.c | 98 +------------------ + include/wine/sdl_controller_overrides.h | 119 ++++++++++++++++++++++++ + 2 files changed, 120 insertions(+), 97 deletions(-) + create mode 100644 include/wine/sdl_controller_overrides.h + +diff --git a/dlls/dinput/joystick_sdl.c b/dlls/dinput/joystick_sdl.c +index ffb1e14e885..57a5eabf8f3 100644 +--- a/dlls/dinput/joystick_sdl.c ++++ b/dlls/dinput/joystick_sdl.c +@@ -58,103 +58,7 @@ + + WINE_DEFAULT_DEBUG_CHANNEL(dinput); + +-#define VID_SONY 0x054c +-#define PID_SONY_DUALSHOCK_4 0x05c4 +-#define PID_SONY_DUALSHOCK_4_2 0x09cc +-#define PID_SONY_DUALSHOCK_4_DONGLE 0x0ba0 +-#define PID_SONY_DUALSENSE 0x0ce6 +- +-#define VID_VALVE 0x28de +-#define PID_VALVE_VIRTUAL_CONTROLLER 0x11ff +- +-#define VID_MICROSOFT 0x045e +-#define PID_MICROSOFT_XBOX_360 0x028e +-#define PID_MICROSOFT_XBOX_360_WIRELESS 0x028f +-#define PID_MICROSOFT_XBOX_360_ADAPTER 0x0719 +-#define PID_MICROSOFT_XBOX_ONE 0x02d1 +-#define PID_MICROSOFT_XBOX_ONE_CF 0x02dd +-#define PID_MICROSOFT_XBOX_ONE_ELITE 0x02e3 +-#define PID_MICROSOFT_XBOX_ONE_S 0x02ea +-#define PID_MICROSOFT_XBOX_ONE_S_2 0x02fd +- +-static BOOL __controller_hack_sdl_is_vid_pid_xbox_360(WORD vid, WORD pid) +-{ +- if(vid != VID_MICROSOFT) +- return FALSE; +- +- if(pid == PID_MICROSOFT_XBOX_360 || +- pid == PID_MICROSOFT_XBOX_360_WIRELESS || +- pid == PID_MICROSOFT_XBOX_360_ADAPTER) +- return TRUE; +- +- return FALSE; +-} +-static BOOL __controller_hack_sdl_is_vid_pid_xbox_one(WORD vid, WORD pid) { +- if(vid != VID_MICROSOFT) +- return FALSE; +- +- if(pid == PID_MICROSOFT_XBOX_ONE || +- pid == PID_MICROSOFT_XBOX_ONE_CF || +- pid == PID_MICROSOFT_XBOX_ONE_ELITE || +- pid == PID_MICROSOFT_XBOX_ONE_S || +- pid == PID_MICROSOFT_XBOX_ONE_S_2) +- return TRUE; +- +- return FALSE; +-} +- +-static BOOL __controller_hack_sdl_is_vid_pid_sony_dualshock4(WORD vid, WORD pid) +-{ +- if(vid != VID_SONY) +- return FALSE; +- +- if(pid == PID_SONY_DUALSHOCK_4 || +- pid == PID_SONY_DUALSHOCK_4_2 || +- pid == PID_SONY_DUALSHOCK_4_DONGLE) +- return TRUE; +- +- return FALSE; +-} +- +-static BOOL __controller_hack_sdl_is_vid_pid_sony_dualsense(WORD vid, WORD pid) +-{ +- if(vid == VID_SONY && pid == PID_SONY_DUALSENSE) +- return TRUE; +- +- return FALSE; +-} +- +-static void __controller_hack_sdl_vid_pid_override(WORD *vid, WORD *pid) +-{ +- TRACE("(*vid = %04hx, *pid = *%04hx\n", *vid, *pid); +- if(*vid == VID_VALVE && *pid == PID_VALVE_VIRTUAL_CONTROLLER) +- { +- TRACE("Valve Virtual Controller found - pretending it's x360\n"); +- *vid = VID_MICROSOFT; +- *pid = PID_MICROSOFT_XBOX_360; +- } +-} +- +-static void __controller_hack_sdl_name_override(WORD vid, WORD pid, const char **name) +-{ +- const char *new_name = NULL; +- +- TRACE("vid = %04hx, pid = %04hx, *name = %s\n", vid, pid, debugstr_a(*name)); +- +- if(__controller_hack_sdl_is_vid_pid_xbox_360(vid, pid)) +- new_name = "Controller (XBOX 360 For Windows)"; +- else if(__controller_hack_sdl_is_vid_pid_xbox_one(vid, pid)) +- new_name = "Controller (XBOX One For Windows)"; +- else if(__controller_hack_sdl_is_vid_pid_sony_dualshock4(vid, pid) || +- __controller_hack_sdl_is_vid_pid_sony_dualsense(vid, pid)) +- new_name = "Wireless Controller"; +- +- if(new_name) +- { +- TRACE("new name for the controller = %s\n", debugstr_a(new_name)); +- *name = new_name; +- } +-} ++#include "wine/sdl_controller_overrides.h" + + typedef struct JoystickImpl JoystickImpl; + static const IDirectInputDevice8AVtbl JoystickAvt; +diff --git a/include/wine/sdl_controller_overrides.h b/include/wine/sdl_controller_overrides.h +new file mode 100644 +index 00000000000..80813b9cc4f +--- /dev/null ++++ b/include/wine/sdl_controller_overrides.h +@@ -0,0 +1,119 @@ ++/* ++ * Copyright 2021 Arkadiusz Hiler for CodeWeavers ++ * ++ * 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 ++ */ ++ ++#ifndef __SDL_CONTROLLER_OVERRIDES_H ++#define __SDL_CONTROLLER_OVERRIDES_H ++ ++#define VID_SONY 0x054c ++#define PID_SONY_DUALSHOCK_4 0x05c4 ++#define PID_SONY_DUALSHOCK_4_2 0x09cc ++#define PID_SONY_DUALSHOCK_4_DONGLE 0x0ba0 ++#define PID_SONY_DUALSENSE 0x0ce6 ++ ++#define VID_VALVE 0x28de ++#define PID_VALVE_VIRTUAL_CONTROLLER 0x11ff ++ ++#define VID_MICROSOFT 0x045e ++#define PID_MICROSOFT_XBOX_360 0x028e ++#define PID_MICROSOFT_XBOX_360_WIRELESS 0x028f ++#define PID_MICROSOFT_XBOX_360_ADAPTER 0x0719 ++#define PID_MICROSOFT_XBOX_ONE 0x02d1 ++#define PID_MICROSOFT_XBOX_ONE_CF 0x02dd ++#define PID_MICROSOFT_XBOX_ONE_ELITE 0x02e3 ++#define PID_MICROSOFT_XBOX_ONE_S 0x02ea ++#define PID_MICROSOFT_XBOX_ONE_S_2 0x02fd ++ ++static BOOL __controller_hack_sdl_is_vid_pid_xbox_360(WORD vid, WORD pid) ++{ ++ if (vid != VID_MICROSOFT) ++ return FALSE; ++ ++ if (pid == PID_MICROSOFT_XBOX_360 || ++ pid == PID_MICROSOFT_XBOX_360_WIRELESS || ++ pid == PID_MICROSOFT_XBOX_360_ADAPTER) ++ return TRUE; ++ ++ return FALSE; ++} ++static BOOL __controller_hack_sdl_is_vid_pid_xbox_one(WORD vid, WORD pid) { ++ if (vid != VID_MICROSOFT) ++ return FALSE; ++ ++ if (pid == PID_MICROSOFT_XBOX_ONE || ++ pid == PID_MICROSOFT_XBOX_ONE_CF || ++ pid == PID_MICROSOFT_XBOX_ONE_ELITE || ++ pid == PID_MICROSOFT_XBOX_ONE_S || ++ pid == PID_MICROSOFT_XBOX_ONE_S_2) ++ return TRUE; ++ ++ return FALSE; ++} ++ ++static BOOL __controller_hack_sdl_is_vid_pid_sony_dualshock4(WORD vid, WORD pid) ++{ ++ if (vid != VID_SONY) ++ return FALSE; ++ ++ if (pid == PID_SONY_DUALSHOCK_4 || ++ pid == PID_SONY_DUALSHOCK_4_2 || ++ pid == PID_SONY_DUALSHOCK_4_DONGLE) ++ return TRUE; ++ ++ return FALSE; ++} ++ ++static BOOL __controller_hack_sdl_is_vid_pid_sony_dualsense(WORD vid, WORD pid) ++{ ++ if (vid == VID_SONY && pid == PID_SONY_DUALSENSE) ++ return TRUE; ++ ++ return FALSE; ++} ++ ++static void __controller_hack_sdl_vid_pid_override(WORD *vid, WORD *pid) ++{ ++ TRACE("(*vid = %04hx, *pid = *%04hx\n", *vid, *pid); ++ if (*vid == VID_VALVE && *pid == PID_VALVE_VIRTUAL_CONTROLLER) ++ { ++ TRACE("Valve Virtual Controller found - pretending it's x360\n"); ++ *vid = VID_MICROSOFT; ++ *pid = PID_MICROSOFT_XBOX_360; ++ } ++} ++ ++static void __controller_hack_sdl_name_override(WORD vid, WORD pid, const char **name) ++{ ++ const char *new_name = NULL; ++ ++ TRACE("vid = %04hx, pid = %04hx, *name = %s\n", vid, pid, debugstr_a(*name)); ++ ++ if (__controller_hack_sdl_is_vid_pid_xbox_360(vid, pid)) ++ new_name = "Controller (XBOX 360 For Windows)"; ++ else if (__controller_hack_sdl_is_vid_pid_xbox_one(vid, pid)) ++ new_name = "Controller (XBOX One For Windows)"; ++ else if (__controller_hack_sdl_is_vid_pid_sony_dualshock4(vid, pid) || ++ __controller_hack_sdl_is_vid_pid_sony_dualsense(vid, pid)) ++ new_name = "Wireless Controller"; ++ ++ if (new_name) ++ { ++ TRACE("new name for the controller = %s\n", debugstr_a(new_name)); ++ *name = new_name; ++ } ++} ++#endif /* __SDL_CONTROLLER_OVERRIDES_H */ +From 4bef8cf8bafa30bf8b59df726fb96b7c04b1e139 Mon Sep 17 00:00:00 2001 +From: Arkadiusz Hiler +Date: Thu, 20 May 2021 15:45:38 +0300 +Subject: [PATCH] sdl_controller_overrides: Rename Xbox One S 2 to WIRELESS. + +CW-Bug-Id: #18761 +--- + include/wine/sdl_controller_overrides.h | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/include/wine/sdl_controller_overrides.h b/include/wine/sdl_controller_overrides.h +index 80813b9cc4f..8273c31ee8a 100644 +--- a/include/wine/sdl_controller_overrides.h ++++ b/include/wine/sdl_controller_overrides.h +@@ -36,7 +36,7 @@ + #define PID_MICROSOFT_XBOX_ONE_CF 0x02dd + #define PID_MICROSOFT_XBOX_ONE_ELITE 0x02e3 + #define PID_MICROSOFT_XBOX_ONE_S 0x02ea +-#define PID_MICROSOFT_XBOX_ONE_S_2 0x02fd ++#define PID_MICROSOFT_XBOX_ONE_S_WIRELESS 0x02fd + + static BOOL __controller_hack_sdl_is_vid_pid_xbox_360(WORD vid, WORD pid) + { +@@ -58,7 +58,7 @@ static BOOL __controller_hack_sdl_is_vid_pid_xbox_one(WORD vid, WORD pid) { + pid == PID_MICROSOFT_XBOX_ONE_CF || + pid == PID_MICROSOFT_XBOX_ONE_ELITE || + pid == PID_MICROSOFT_XBOX_ONE_S || +- pid == PID_MICROSOFT_XBOX_ONE_S_2) ++ pid == PID_MICROSOFT_XBOX_ONE_S_WIRELESS) + return TRUE; + + return FALSE; + +From 8e7234f124581cb1d1f4830e1eddb5f734afa806 Mon Sep 17 00:00:00 2001 +From: Arkadiusz Hiler +Date: Mon, 17 May 2021 14:35:12 +0300 +Subject: [PATCH] sdl_controller_overrides: Pretend that unknown xinput + controllers are X360. + +Some input systems (e.g. InControl) have vid/pid/string databases and +use them for controller matching. Since we cannot report the same values +as Windows for all the controllers on the market, let's just pretend +that the unknown ones are X360. + +CW-Bug-Id: #18761 +--- + dlls/dinput/joystick_sdl.c | 2 +- + include/wine/sdl_controller_overrides.h | 14 +++++++++++++- + 2 files changed, 14 insertions(+), 2 deletions(-) + +diff --git a/dlls/dinput/joystick_sdl.c b/dlls/dinput/joystick_sdl.c +index 57a5eabf8f3..dd94619d5eb 100644 +--- a/dlls/dinput/joystick_sdl.c ++++ b/dlls/dinput/joystick_sdl.c +@@ -371,7 +371,7 @@ static void find_sdldevs(void) + continue; + } + +- __controller_hack_sdl_vid_pid_override(&sdldev->vendor_id, &sdldev->product_id); ++ __controller_hack_sdl_vid_pid_override(&sdldev->vendor_id, &sdldev->product_id, sdldev->name); + + sdldev->nth_instance = get_num_vidpids(sdldev->vendor_id, sdldev->product_id); + +diff --git a/include/wine/sdl_controller_overrides.h b/include/wine/sdl_controller_overrides.h +index 8273c31ee8a..22f50e5d54b 100644 +--- a/include/wine/sdl_controller_overrides.h ++++ b/include/wine/sdl_controller_overrides.h +@@ -85,7 +85,7 @@ static BOOL __controller_hack_sdl_is_vid_pid_sony_dualsense(WORD vid, WORD pid) + return FALSE; + } + +-static void __controller_hack_sdl_vid_pid_override(WORD *vid, WORD *pid) ++static void __controller_hack_sdl_vid_pid_override(WORD *vid, WORD *pid, const char *sdl_joystick_name) + { + TRACE("(*vid = %04hx, *pid = *%04hx\n", *vid, *pid); + if (*vid == VID_VALVE && *pid == PID_VALVE_VIRTUAL_CONTROLLER) +@@ -94,6 +94,18 @@ static void __controller_hack_sdl_vid_pid_override(WORD *vid, WORD *pid) + *vid = VID_MICROSOFT; + *pid = PID_MICROSOFT_XBOX_360; + } ++ else if (sdl_joystick_name && ++ (strstr(sdl_joystick_name, "Xbox") || ++ strstr(sdl_joystick_name, "XBOX") || ++ strstr(sdl_joystick_name, "X-Box")) && ++ !(__controller_hack_sdl_is_vid_pid_xbox_one(*vid, *pid) || ++ __controller_hack_sdl_is_vid_pid_xbox_360(*vid, *pid))) ++ { ++ WARN("Unknown xinput controller found - pretending it's x360\n"); ++ ++ *vid = VID_MICROSOFT; ++ *pid = PID_MICROSOFT_XBOX_360; ++ } + } + + static void __controller_hack_sdl_name_override(WORD vid, WORD pid, const char **name) +From ab43b7f1c87789d8ada8220f9ac71fdc55b11551 Mon Sep 17 00:00:00 2001 +From: Arkadiusz Hiler +Date: Mon, 17 May 2021 14:35:42 +0300 +Subject: [PATCH] sdl_controller_overrides: Fix casing of 'Xbox' for Xbox One + controllers. + +CW-Bug-Id: #18761 +--- + include/wine/sdl_controller_overrides.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/include/wine/sdl_controller_overrides.h b/include/wine/sdl_controller_overrides.h +index 22f50e5d54b..178ef15d522 100644 +--- a/include/wine/sdl_controller_overrides.h ++++ b/include/wine/sdl_controller_overrides.h +@@ -117,7 +117,7 @@ static void __controller_hack_sdl_name_override(WORD vid, WORD pid, const char * + if (__controller_hack_sdl_is_vid_pid_xbox_360(vid, pid)) + new_name = "Controller (XBOX 360 For Windows)"; + else if (__controller_hack_sdl_is_vid_pid_xbox_one(vid, pid)) +- new_name = "Controller (XBOX One For Windows)"; ++ new_name = "Controller (Xbox One For Windows)"; + else if (__controller_hack_sdl_is_vid_pid_sony_dualshock4(vid, pid) || + __controller_hack_sdl_is_vid_pid_sony_dualsense(vid, pid)) + new_name = "Wireless Controller"; +From 54320ab915c69654c9f1e93c633c287de6b21999 Mon Sep 17 00:00:00 2001 +From: Arkadiusz Hiler +Date: Mon, 19 Apr 2021 14:25:44 +0300 +Subject: [PATCH] sdl_controller_overrides: Add newer Xbox controllers. + +All of those claim to be "Xbox One". + +CW-Bug-Id: #18761 +--- + include/wine/sdl_controller_overrides.h | 10 +++++++++- + 1 file changed, 9 insertions(+), 1 deletion(-) + +diff --git a/include/wine/sdl_controller_overrides.h b/include/wine/sdl_controller_overrides.h +index 178ef15d522..68a39d3e5c2 100644 +--- a/include/wine/sdl_controller_overrides.h ++++ b/include/wine/sdl_controller_overrides.h +@@ -37,6 +37,10 @@ + #define PID_MICROSOFT_XBOX_ONE_ELITE 0x02e3 + #define PID_MICROSOFT_XBOX_ONE_S 0x02ea + #define PID_MICROSOFT_XBOX_ONE_S_WIRELESS 0x02fd ++#define PID_MICROSOFT_XBOX_ELITE_2 0x0b00 ++#define PID_MICROSOFT_XBOX_ELITE_2_WIRELESS 0x0b05 ++#define PID_MICROSOFT_XBOX_SERIES 0x0b12 ++#define PID_MICROSOFT_XBOX_SERIES_WIRELESS 0x0b13 + + static BOOL __controller_hack_sdl_is_vid_pid_xbox_360(WORD vid, WORD pid) + { +@@ -58,7 +62,11 @@ static BOOL __controller_hack_sdl_is_vid_pid_xbox_one(WORD vid, WORD pid) { + pid == PID_MICROSOFT_XBOX_ONE_CF || + pid == PID_MICROSOFT_XBOX_ONE_ELITE || + pid == PID_MICROSOFT_XBOX_ONE_S || +- pid == PID_MICROSOFT_XBOX_ONE_S_WIRELESS) ++ pid == PID_MICROSOFT_XBOX_ONE_S_WIRELESS || ++ pid == PID_MICROSOFT_XBOX_ELITE_2 || ++ pid == PID_MICROSOFT_XBOX_ELITE_2_WIRELESS || ++ pid == PID_MICROSOFT_XBOX_SERIES || ++ pid == PID_MICROSOFT_XBOX_SERIES_WIRELESS) + return TRUE; + + return FALSE; diff --git a/wine-tkg-git/wine-tkg-patches/proton-tkg-specific/proton-sdl-joy.patch b/wine-tkg-git/wine-tkg-patches/proton-tkg-specific/proton-sdl-joy.patch index a1eb4cfc5..2ce2751a2 100644 --- a/wine-tkg-git/wine-tkg-patches/proton-tkg-specific/proton-sdl-joy.patch +++ b/wine-tkg-git/wine-tkg-patches/proton-tkg-specific/proton-sdl-joy.patch @@ -6598,25 +6598,25 @@ index 8aea638a8d7..7cdca280295 100644 - if (button_count < 11) + if (button_count < 10) WARN("Too few buttons, continuing anyway\n"); - xinput_caps->Gamepad.wButtons = 0xffff; + caps->Gamepad.wButtons = 0xffff; @@ -387,7 +387,7 @@ void HID_update_state(xinput_controller *device, XINPUT_STATE *state) - ULONG report_len = private->caps.InputReportByteLength; + char *report_buf = controller->hid.input_report_buf; + XINPUT_STATE state; NTSTATUS status; - - USAGE buttons[11]; + USAGE buttons[10]; - ULONG button_length, value; + ULONG i, button_length, value; - if (!controller->enabled) return; + if (!GetOverlappedResult(controller->device, &controller->hid.read_ovl, &read_len, TRUE)) @@ -431,7 +431,6 @@ void HID_update_state(xinput_controller *device, XINPUT_STATE *state) - case 8: controller->state.Gamepad.wButtons |= XINPUT_GAMEPAD_START; break; - case 9: controller->state.Gamepad.wButtons |= XINPUT_GAMEPAD_LEFT_THUMB; break; - case 10: controller->state.Gamepad.wButtons |= XINPUT_GAMEPAD_RIGHT_THUMB; break; -- case 11: controller->state.Gamepad.wButtons |= XINPUT_GAMEPAD_GUIDE; break; - } + case 8: state.Gamepad.wButtons |= XINPUT_GAMEPAD_START; break; + case 9: state.Gamepad.wButtons |= XINPUT_GAMEPAD_LEFT_THUMB; break; + case 10: state.Gamepad.wButtons |= XINPUT_GAMEPAD_RIGHT_THUMB; break; +- case 11: state.Gamepad.wButtons |= XINPUT_GAMEPAD_GUIDE; break; } - + } + From c5d52c73b754568df148013907f26e5da3525166 Mon Sep 17 00:00:00 2001 From: Andrew Eikum Date: Tue, 6 Aug 2019 13:27:25 -0500 diff --git a/wine-tkg-git/wine-tkg-scripts/prepare.sh b/wine-tkg-git/wine-tkg-scripts/prepare.sh index 2de022d87..5ca9b4ac4 100644 --- a/wine-tkg-git/wine-tkg-scripts/prepare.sh +++ b/wine-tkg-git/wine-tkg-scripts/prepare.sh @@ -2417,8 +2417,10 @@ EOM # SDL Joystick support - from Proton if [ "$_sdl_joy_support" = "true" ] && [ "$_use_staging" = "true" ]; then - if ( cd "${srcdir}"/"${_winesrcdir}" && git merge-base --is-ancestor 914633723383f321303d78eb62cb19e8a6fb7bb4 HEAD ); then + if ( cd "${srcdir}"/"${_winesrcdir}" && git merge-base --is-ancestor 43f0c8096b2d81052a30d8542372adc46dab8292 HEAD ); then _patchname='proton-sdl-joy.patch' && _patchmsg="Enable SDL Joystick support (from Proton)" && nonuser_patcher + elif ( cd "${srcdir}"/"${_winesrcdir}" && git merge-base --is-ancestor 914633723383f321303d78eb62cb19e8a6fb7bb4 HEAD ); then + _patchname='proton-sdl-joy-43f0c80.patch' && _patchmsg="Enable SDL Joystick support (from Proton)" && nonuser_patcher elif ( cd "${srcdir}"/"${_winesrcdir}" && git merge-base --is-ancestor 01d3527065e6f29997eb0ec88e36aeeecbf8ff76 HEAD ); then _patchname='proton-sdl-joy-9146337.patch' && _patchmsg="Enable SDL Joystick support (from Proton)" && nonuser_patcher elif ( cd "${srcdir}"/"${_winesrcdir}" && git merge-base --is-ancestor 828b9b8cc49fe24a306235c056a38c7ae079560f HEAD ); then