Some games expect the DualSense audio device (used for haptic feedback and controller speaker) to be called “Wireless Controller”.
This is the case of Final Fantasy XIV Online and Final Fantasy VII Remake Intergrade, and possibly other games as well. Together with !337, this is enough for all DualSense features to properly work with those games (provided the controller is plugged in before the game is started).
Note that this is not sufficient for many other games which have more elaborate logic for finding the DualSense audio output.
From: Claire Girka claire@sitedethib.com
Some games expect the DualSense audio device (used for haptic feedback and controller speaker) to be called “Wireless Controller”. --- dlls/mmdevapi/devenum.c | 38 +++++++++++++++++++++++++++++++++++--- 1 file changed, 35 insertions(+), 3 deletions(-)
diff --git a/dlls/mmdevapi/devenum.c b/dlls/mmdevapi/devenum.c index 053275cac45..dbbcfa7ce07 100644 --- a/dlls/mmdevapi/devenum.c +++ b/dlls/mmdevapi/devenum.c @@ -255,6 +255,30 @@ static HRESULT set_driver_prop_value(GUID *id, const EDataFlow flow, const PROPE return hr; }
+struct device_strings +{ + const WCHAR *id; + const WCHAR *product; +}; + +static const struct device_strings device_strings[] = +{ + /* Sony controllers */ + { .id = L"VID_054C&PID_0CE6", .product = L"Wireless Controller" }, +}; + +static const WCHAR *find_device_string(const WCHAR *device_id) +{ + const WCHAR *match_id = wcschr( device_id, '\' ) + 1; + DWORD i; + + for (i = 0; i < ARRAY_SIZE(device_strings); ++i) + if (!wcsnicmp( device_strings[i].id, match_id, 17 )) + return device_strings[i].product; + + return NULL; +} + /* Creates or updates the state of a device * If GUID is null, a random guid will be assigned * and the device will be created @@ -318,9 +342,19 @@ static MMDevice *MMDevice_Create(WCHAR *name, GUID *id, EDataFlow flow, DWORD st if (!RegCreateKeyExW(key, L"Properties", 0, NULL, 0, KEY_WRITE|KEY_READ|KEY_WOW64_64KEY, NULL, &keyprop, NULL)) { PROPVARIANT pv; + pv.pwszVal = NULL; + + if (SUCCEEDED(drvs.pGetPropValue(id, &devicepath_key, &pv))) { + MMDevice_SetPropValue(id, flow, &devicepath_key, &pv); + + /* Some applications expect a specific name for the DualSense audio device */ + pv.pwszVal = find_device_string(pv.pwszVal); + }
pv.vt = VT_LPWSTR; - pv.pwszVal = name; + if (pv.pwszVal == NULL) + pv.pwszVal = name; + MMDevice_SetPropValue(id, flow, (const PROPERTYKEY*)&DEVPKEY_Device_FriendlyName, &pv); MMDevice_SetPropValue(id, flow, (const PROPERTYKEY*)&DEVPKEY_DeviceInterface_FriendlyName, &pv); MMDevice_SetPropValue(id, flow, (const PROPERTYKEY*)&DEVPKEY_Device_DeviceDesc, &pv); @@ -328,8 +362,6 @@ static MMDevice *MMDevice_Create(WCHAR *name, GUID *id, EDataFlow flow, DWORD st pv.pwszVal = guidstr; MMDevice_SetPropValue(id, flow, &deviceinterface_key, &pv);
- set_driver_prop_value(id, flow, &devicepath_key); - if (FAILED(set_driver_prop_value(id, flow, &PKEY_AudioEndpoint_FormFactor))) { pv.vt = VT_UI4;
Andrew Eikum (@aeikum) commented about dlls/mmdevapi/devenum.c:
return hr;
}
+struct device_strings +{
- const WCHAR *id;
- const WCHAR *product;
+};
+static const struct device_strings device_strings[] = +{
- /* Sony controllers */
- { .id = L"VID_054C&PID_0CE6", .product = L"Wireless Controller" },
+};
+static const WCHAR *find_device_string(const WCHAR *device_id)
I know this function came from `hidclass`, but I think I'd call it something more descriptive like `product_name_override`.
Andrew Eikum (@aeikum) commented about dlls/mmdevapi/devenum.c:
if (!RegCreateKeyExW(key, L"Properties", 0, NULL, 0, KEY_WRITE|KEY_READ|KEY_WOW64_64KEY, NULL, &keyprop, NULL)) { PROPVARIANT pv;
pv.pwszVal = NULL;
if (SUCCEEDED(drvs.pGetPropValue(id, &devicepath_key, &pv))) {
MMDevice_SetPropValue(id, flow, &devicepath_key, &pv);
/* Some applications expect a specific name for the DualSense audio device */
pv.pwszVal = find_device_string(pv.pwszVal);
This comment shouldn't be specific to DualSense controllers, and I think you could even remove the comment entirely if you rename the function.
Andrew Eikum (@aeikum) commented about dlls/mmdevapi/devenum.c:
if (!RegCreateKeyExW(key, L"Properties", 0, NULL, 0, KEY_WRITE|KEY_READ|KEY_WOW64_64KEY, NULL, &keyprop, NULL)) { PROPVARIANT pv;
pv.pwszVal = NULL;
if (SUCCEEDED(drvs.pGetPropValue(id, &devicepath_key, &pv))) {
Not all drivers implement GetPropValue, so you can't unconditionally call it. `set_driver_prop_value` could maybe use a refactor so this doesn't get messy.
Andrew Eikum (@aeikum) commented about dlls/mmdevapi/devenum.c:
if (!RegCreateKeyExW(key, L"Properties", 0, NULL, 0, KEY_WRITE|KEY_READ|KEY_WOW64_64KEY, NULL, &keyprop, NULL)) { PROPVARIANT pv;
pv.pwszVal = NULL;
Why not just assign to `name` here and remove the if-NULL check later in the function?
On Wed Jun 29 13:40:34 2022 +0000, Andrew Eikum wrote:
Why not just assign to `name` here and remove the if-NULL check later in the function?
Because I was re-using `pv` so it would have been overridden. But I'll just use a second `PROPVARIANT` as is already done a few lines below.