[v3 2/2] dinput: Handle username in EnumDevicesBySemantics.

Jetro Jormalainen jje-wine at jv.jetro.fi
Thu Mar 2 12:51:41 CST 2017


EnumDevicesBySemantics enums only devices with given username when
DIEDBSFL_THISUSER is set and only unowned devices when
DIEDBSFL_AVAILABLEDEVICES is set.

v2: Fixed problems noted by Andrew Eikum.
v3: Combined test for username in EnumDevicesBySemantics from previous
patch.

Tested on Windows 10, Windows XP, Arch Linux and Rally Trophy Demo.

Signed-off-by: Jetro Jormalainen <jje-wine at jv.jetro.fi>
---
 dlls/dinput/dinput_main.c   | 111 ++++++++++++++++++++++++++++++++++++++------
 dlls/dinput8/tests/dinput.c |  11 ++++-
 2 files changed, 105 insertions(+), 17 deletions(-)

diff --git a/dlls/dinput/dinput_main.c b/dlls/dinput/dinput_main.c
index 2bf9f38ba4..a59217472c 100644
--- a/dlls/dinput/dinput_main.c
+++ b/dlls/dinput/dinput_main.c
@@ -923,6 +923,47 @@ static HRESULT WINAPI IDirectInput8WImpl_FindDevice(LPDIRECTINPUT8W iface, REFGU
     return IDirectInput2WImpl_FindDevice( &This->IDirectInput7W_iface, rguid, pszName, pguidInstance );
 }
 
+static BOOL should_enumerate_device(const WCHAR *username, DWORD dwFlags,
+    struct list *device_players, REFGUID guid)
+{
+    BOOL should_enumerate = TRUE;
+    struct DevicePlayer *device_player;
+
+    /* Check if user owns this device */
+    if (dwFlags & DIEDBSFL_THISUSER && username && *username)
+    {
+        should_enumerate = FALSE;
+        LIST_FOR_EACH_ENTRY(device_player, device_players, struct DevicePlayer, entry)
+        {
+            if (IsEqualGUID(&device_player->instance_guid, guid))
+            {
+                if (*device_player->username && !lstrcmpW(username, device_player->username))
+                    return TRUE; /* Device username matches */
+                break;
+            }
+        }
+    }
+
+    /* Check if this device is not owned by anyone */
+    if (dwFlags & DIEDBSFL_AVAILABLEDEVICES) {
+        BOOL found = FALSE;
+        should_enumerate = FALSE;
+        LIST_FOR_EACH_ENTRY(device_player, device_players, struct DevicePlayer, entry)
+        {
+            if (IsEqualGUID(&device_player->instance_guid, guid))
+            {
+                if (*device_player->username)
+                    found = TRUE;
+                break;
+            }
+        }
+        if (!found)
+            return TRUE; /* Device does not have a username */
+    }
+
+    return should_enumerate;
+}
+
 static HRESULT WINAPI IDirectInput8AImpl_EnumDevicesBySemantics(
       LPDIRECTINPUT8A iface, LPCSTR ptszUserName, LPDIACTIONFORMATA lpdiActionFormat,
       LPDIENUMDEVICESBYSEMANTICSCBA lpCallback,
@@ -939,6 +980,7 @@ static HRESULT WINAPI IDirectInput8AImpl_EnumDevicesBySemantics(
     int device_count = 0;
     int remain;
     DIDEVICEINSTANCEA *didevis = 0;
+    WCHAR *username_w = 0;
 
     FIXME("(this=%p,%s,%p,%p,%p,%04x): semi-stub\n", This, debugstr_a(ptszUserName), lpdiActionFormat,
           lpCallback, pvRef, dwFlags);
@@ -955,6 +997,14 @@ static HRESULT WINAPI IDirectInput8AImpl_EnumDevicesBySemantics(
 
     didevi.dwSize = sizeof(didevi);
 
+    if (ptszUserName)
+    {
+        int len = MultiByteToWideChar(CP_ACP, 0, ptszUserName, -1, 0, 0);
+
+        username_w = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*len);
+        MultiByteToWideChar(CP_ACP, 0, ptszUserName, -1, username_w, len);
+    }
+
     /* Enumerate all the joysticks */
     for (i = 0; i < NB_DINPUT_DEVICES; i++)
     {
@@ -968,7 +1018,8 @@ static HRESULT WINAPI IDirectInput8AImpl_EnumDevicesBySemantics(
 
             /* Default behavior is to enumerate attached game controllers */
             enumSuccess = dinput_devices[i]->enum_deviceA(DI8DEVCLASS_GAMECTRL, DIEDFL_ATTACHEDONLY | dwFlags, &didevi, This->dwVersion, j);
-            if (enumSuccess == S_OK)
+            if (enumSuccess == S_OK &&
+                should_enumerate_device(username_w, dwFlags, &This->device_players, &didevi.guidInstance))
             {
                 if (device_count++)
                     didevis = HeapReAlloc(GetProcessHeap(), 0, didevis, sizeof(DIDEVICEINSTANCEA)*device_count);
@@ -980,8 +1031,15 @@ static HRESULT WINAPI IDirectInput8AImpl_EnumDevicesBySemantics(
     }
 
     remain = device_count;
+    /* Add keyboard and mouse to remaining device count */
     if (!(dwFlags & DIEDBSFL_FORCEFEEDBACK))
-        remain += sizeof(guids)/sizeof(guids[0]);
+    {
+        for (i = 0; i < sizeof(guids) / sizeof(guids[0]); i++)
+        {
+            if (should_enumerate_device(username_w, dwFlags, &This->device_players, guids[i]))
+                remain++;
+        }
+    }
 
     for (i = 0; i < device_count; i++)
     {
@@ -991,26 +1049,38 @@ static HRESULT WINAPI IDirectInput8AImpl_EnumDevicesBySemantics(
         if (lpCallback(&didevis[i], lpdid, callbackFlags, --remain, pvRef) == DIENUM_STOP)
         {
             HeapFree(GetProcessHeap(), 0, didevis);
+            HeapFree(GetProcessHeap(), 0, username_w);
             return DI_OK;
         }
     }
 
     HeapFree(GetProcessHeap(), 0, didevis);
 
-    if (dwFlags & DIEDBSFL_FORCEFEEDBACK) return DI_OK;
+    if (dwFlags & DIEDBSFL_FORCEFEEDBACK)
+    {
+        HeapFree(GetProcessHeap(), 0, username_w);
+        return DI_OK;
+    }
 
     /* Enumerate keyboard and mouse */
     for(i=0; i < sizeof(guids)/sizeof(guids[0]); i++)
     {
-        callbackFlags = diactionformat_priorityA(lpdiActionFormat, actionMasks[i]);
+        if (should_enumerate_device(username_w, dwFlags, &This->device_players, guids[i]))
+        {
+            callbackFlags = diactionformat_priorityA(lpdiActionFormat, actionMasks[i]);
 
-        IDirectInput_CreateDevice(iface, guids[i], &lpdid, NULL);
-        IDirectInputDevice_GetDeviceInfo(lpdid, &didevi);
+            IDirectInput_CreateDevice(iface, guids[i], &lpdid, NULL);
+            IDirectInputDevice_GetDeviceInfo(lpdid, &didevi);
 
-        if (lpCallback(&didevi, lpdid, callbackFlags, sizeof(guids)/sizeof(guids[0]) - (i+1), pvRef) == DIENUM_STOP)
-            return DI_OK;
+            if (lpCallback(&didevi, lpdid, callbackFlags, --remain, pvRef) == DIENUM_STOP)
+            {
+                HeapFree(GetProcessHeap(), 0, username_w);
+                return DI_OK;
+            }
+        }
     }
 
+    HeapFree(GetProcessHeap(), 0, username_w);
     return DI_OK;
 }
 
@@ -1049,7 +1119,8 @@ static HRESULT WINAPI IDirectInput8WImpl_EnumDevicesBySemantics(
 
             /* Default behavior is to enumerate attached game controllers */
             enumSuccess = dinput_devices[i]->enum_deviceW(DI8DEVCLASS_GAMECTRL, DIEDFL_ATTACHEDONLY | dwFlags, &didevi, This->dwVersion, j);
-            if (enumSuccess == S_OK)
+            if (enumSuccess == S_OK &&
+                should_enumerate_device(ptszUserName, dwFlags, &This->device_players, &didevi.guidInstance))
             {
                 if (device_count++)
                     didevis = HeapReAlloc(GetProcessHeap(), 0, didevis, sizeof(DIDEVICEINSTANCEW)*device_count);
@@ -1061,8 +1132,15 @@ static HRESULT WINAPI IDirectInput8WImpl_EnumDevicesBySemantics(
     }
 
     remain = device_count;
+    /* Add keyboard and mouse to remaining device count */
     if (!(dwFlags & DIEDBSFL_FORCEFEEDBACK))
-        remain += sizeof(guids)/sizeof(guids[0]);
+    {
+        for (i = 0; i < sizeof(guids) / sizeof(guids[0]); i++)
+        {
+            if (should_enumerate_device(ptszUserName, dwFlags, &This->device_players, guids[i]))
+                remain++;
+        }
+    }
 
     for (i = 0; i < device_count; i++)
     {
@@ -1083,13 +1161,16 @@ static HRESULT WINAPI IDirectInput8WImpl_EnumDevicesBySemantics(
     /* Enumerate keyboard and mouse */
     for(i=0; i < sizeof(guids)/sizeof(guids[0]); i++)
     {
-        callbackFlags = diactionformat_priorityW(lpdiActionFormat, actionMasks[i]);
+        if (should_enumerate_device(ptszUserName, dwFlags, &This->device_players, guids[i]))
+        {
+            callbackFlags = diactionformat_priorityW(lpdiActionFormat, actionMasks[i]);
 
-        IDirectInput_CreateDevice(iface, guids[i], &lpdid, NULL);
-        IDirectInputDevice_GetDeviceInfo(lpdid, &didevi);
+            IDirectInput_CreateDevice(iface, guids[i], &lpdid, NULL);
+            IDirectInputDevice_GetDeviceInfo(lpdid, &didevi);
 
-        if (lpCallback(&didevi, lpdid, callbackFlags, sizeof(guids)/sizeof(guids[0]) - (i+1), pvRef) == DIENUM_STOP)
-            return DI_OK;
+            if (lpCallback(&didevi, lpdid, callbackFlags, --remain, pvRef) == DIENUM_STOP)
+                return DI_OK;
+        }
     }
 
     return DI_OK;
diff --git a/dlls/dinput8/tests/dinput.c b/dlls/dinput8/tests/dinput.c
index 18f3001596..e16542ab13 100644
--- a/dlls/dinput8/tests/dinput.c
+++ b/dlls/dinput8/tests/dinput.c
@@ -562,6 +562,13 @@ static void test_EnumDevicesBySemantics(void)
     /* Keep the device total */
     device_total = data.device_count;
 
+    /* There should be no devices for any user. No device should be enumerated with DIEDBSFL_THISUSER.
+       MSDN defines that all unowned devices are also enumerated but this doesn't seem to be happening. */
+    data.device_count = 0;
+    hr = IDirectInput8_EnumDevicesBySemantics(pDI, "Sh4d0w M4g3", &diaf, enum_semantics_callback, &data, DIEDBSFL_THISUSER);
+    ok (SUCCEEDED(hr), "EnumDevicesBySemantics failed hr=%08x\n", hr);
+    ok (data.device_count == 0, "No devices should be assigned for this user assigned=%d\n", data.device_count);
+
     /* This enumeration builds and sets the action map for all devices with a NULL username */
     hr = IDirectInput8_EnumDevicesBySemantics(pDI, NULL, &diaf, set_action_map_callback, &data, DIEDBSFL_ATTACHEDONLY);
     ok (SUCCEEDED(hr), "EnumDevicesBySemantics failed: hr=%08x\n", hr);
@@ -570,7 +577,7 @@ static void test_EnumDevicesBySemantics(void)
     data.device_count = 0;
     hr = IDirectInput8_EnumDevicesBySemantics(pDI, NULL, &diaf, enum_semantics_callback, &data, DIEDBSFL_AVAILABLEDEVICES);
     ok (SUCCEEDED(hr), "EnumDevicesBySemantics failed hr=%08x\n", hr);
-    todo_wine ok (data.device_count == 0, "No device should be available after action mapping available=%d\n", data.device_count);
+    ok (data.device_count == 0, "No device should be available after action mapping available=%d\n", data.device_count);
 
     /* Now we'll give all the devices to a specific user */
     data.username = "Sh4d0w M4g3";
@@ -593,7 +600,7 @@ static void test_EnumDevicesBySemantics(void)
     data.device_count = 0;
     hr = IDirectInput8_EnumDevicesBySemantics(pDI, "Ninja Brian", &diaf, enum_semantics_callback, &data, DIEDBSFL_THISUSER);
     ok (SUCCEEDED(hr), "EnumDevicesBySemantics failed hr=%08x\n", hr);
-    todo_wine ok (data.device_count == 0, "This user should own no devices owned=%d\n", data.device_count);
+    ok (data.device_count == 0, "This user should own no devices owned=%d\n", data.device_count);
 
     /* Sh4d0w M4g3 has ownership of all devices */
     data.device_count = 0;
-- 
2.11.0




More information about the wine-patches mailing list