diff --git a/dlls/dinput/dinput_main.c b/dlls/dinput/dinput_main.c index 2bf9f38ba45..a59217472c3 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 18f3001596e..e16542ab130 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;