Commit 8d206333 authored by Arkadiusz Hiler's avatar Arkadiusz Hiler Committed by Alexandre Julliard

dinput: Implement DIPROP_APPDATA.

This fixes not working analog inputs on game controllers in Slay the Spire. Signed-off-by: 's avatarArkadiusz Hiler <ahiler@codeweavers.com> Signed-off-by: 's avatarAlexandre Julliard <julliard@winehq.org>
parent fb56afae
...@@ -571,6 +571,22 @@ failed: ...@@ -571,6 +571,22 @@ failed:
return DIERR_OUTOFMEMORY; return DIERR_OUTOFMEMORY;
} }
static int verify_offset(const DataFormat *df, int offset)
{
int i;
if (!df->offsets)
return -1;
for (i = df->wine_df->dwNumObjs - 1; i >= 0; i--)
{
if (df->offsets[i] == offset)
return offset;
}
return -1;
}
/* find an object by its offset in a data format */ /* find an object by its offset in a data format */
static int offset_to_object(const DataFormat *df, int offset) static int offset_to_object(const DataFormat *df, int offset)
{ {
...@@ -759,6 +775,46 @@ static BOOL load_mapping_settings(IDirectInputDeviceImpl *This, LPDIACTIONFORMAT ...@@ -759,6 +775,46 @@ static BOOL load_mapping_settings(IDirectInputDeviceImpl *This, LPDIACTIONFORMAT
return mapped > 0; return mapped > 0;
} }
static BOOL set_app_data(IDirectInputDeviceImpl *dev, int offset, UINT_PTR app_data)
{
int num_actions = dev->num_actions;
ActionMap *action_map = dev->action_map, *target_map = NULL;
if (num_actions == 0)
{
num_actions = 1;
action_map = HeapAlloc(GetProcessHeap(), 0, sizeof(ActionMap));
if (!action_map) return FALSE;
target_map = &action_map[0];
}
else
{
int i;
for (i = 0; i < num_actions; i++)
{
if (dev->action_map[i].offset != offset) continue;
target_map = &dev->action_map[i];
break;
}
if (!target_map)
{
num_actions++;
action_map = HeapReAlloc(GetProcessHeap(), 0, action_map, sizeof(ActionMap)*num_actions);
if (!action_map) return FALSE;
target_map = &action_map[num_actions-1];
}
}
target_map->offset = offset;
target_map->uAppData = app_data;
dev->action_map = action_map;
dev->num_actions = num_actions;
return TRUE;
}
HRESULT _build_action_map(LPDIRECTINPUTDEVICE8W iface, LPDIACTIONFORMATW lpdiaf, LPCWSTR lpszUserName, DWORD dwFlags, DWORD devMask, LPCDIDATAFORMAT df) HRESULT _build_action_map(LPDIRECTINPUTDEVICE8W iface, LPDIACTIONFORMATW lpdiaf, LPCWSTR lpszUserName, DWORD dwFlags, DWORD devMask, LPCDIDATAFORMAT df)
{ {
IDirectInputDeviceImpl *This = impl_from_IDirectInputDevice8W(iface); IDirectInputDeviceImpl *This = impl_from_IDirectInputDevice8W(iface);
...@@ -1447,6 +1503,23 @@ HRESULT WINAPI IDirectInputDevice2WImpl_SetProperty( ...@@ -1447,6 +1503,23 @@ HRESULT WINAPI IDirectInputDevice2WImpl_SetProperty(
lstrcpynW(device_player->username, ps->wsz, ARRAY_SIZE(device_player->username)); lstrcpynW(device_player->username, ps->wsz, ARRAY_SIZE(device_player->username));
break; break;
} }
case (DWORD_PTR) DIPROP_APPDATA:
{
int offset = -1;
LPCDIPROPPOINTER pp = (LPCDIPROPPOINTER)pdiph;
if (pdiph->dwSize != sizeof(DIPROPPOINTER)) return DIERR_INVALIDPARAM;
if (pdiph->dwHow == DIPH_BYID)
offset = id_to_offset(&This->data_format, pdiph->dwObj);
else if (pdiph->dwHow == DIPH_BYOFFSET)
offset = verify_offset(&This->data_format, pdiph->dwObj);
else
return DIERR_UNSUPPORTED;
if (offset == -1) return DIERR_OBJECTNOTFOUND;
if (!set_app_data(This, offset, pp->uData)) return DIERR_OUTOFMEMORY;
break;
}
default: default:
WARN("Unknown property %s\n", debugstr_guid(rguid)); WARN("Unknown property %s\n", debugstr_guid(rguid));
return DIERR_UNSUPPORTED; return DIERR_UNSUPPORTED;
......
...@@ -294,6 +294,48 @@ static BOOL CALLBACK enumeration_callback(const DIDEVICEINSTANCEA *lpddi, IDirec ...@@ -294,6 +294,48 @@ static BOOL CALLBACK enumeration_callback(const DIDEVICEINSTANCEA *lpddi, IDirec
return DIENUM_CONTINUE; return DIENUM_CONTINUE;
} }
static void test_appdata_property_vs_map(struct enum_data *data)
{
HRESULT hr;
DIPROPPOINTER dp;
dp.diph.dwSize = sizeof(dp);
dp.diph.dwHeaderSize = sizeof(DIPROPHEADER);
dp.diph.dwHow = DIPH_BYID;
dp.diph.dwObj = DIDFT_MAKEINSTANCE(DIK_SPACE) | DIDFT_PSHBUTTON;
dp.uData = 10;
hr = IDirectInputDevice8_SetProperty(data->keyboard, DIPROP_APPDATA, &(dp.diph));
ok(SUCCEEDED(hr), "IDirectInputDevice8_SetProperty failed hr=%08x\n", hr);
test_device_input(data->keyboard, INPUT_KEYBOARD, VK_SPACE, 10);
dp.diph.dwHow = DIPH_BYID;
dp.diph.dwObj = DIDFT_MAKEINSTANCE(DIK_V) | DIDFT_PSHBUTTON;
dp.uData = 11;
hr = IDirectInputDevice8_SetProperty(data->keyboard, DIPROP_APPDATA, &(dp.diph));
ok(hr == DIERR_OBJECTNOTFOUND, "IDirectInputDevice8_SetProperty should not find key that's not in the action map hr=%08x\n", hr);
/* setting format should reset action map */
hr = IDirectInputDevice8_SetDataFormat(data->keyboard, &c_dfDIKeyboard);
ok(SUCCEEDED(hr), "SetDataFormat failed: %08x\n", hr);
test_device_input(data->keyboard, INPUT_KEYBOARD, VK_SPACE, -1);
dp.diph.dwHow = DIPH_BYID;
dp.diph.dwObj = DIDFT_MAKEINSTANCE(DIK_V) | DIDFT_PSHBUTTON;
dp.uData = 11;
hr = IDirectInputDevice8_SetProperty(data->keyboard, DIPROP_APPDATA, &(dp.diph));
ok(SUCCEEDED(hr), "IDirectInputDevice8_SetProperty failed hr=%08x\n", hr);
test_device_input(data->keyboard, INPUT_KEYBOARD, 'V', 11);
/* back to action map */
hr = IDirectInputDevice8_SetActionMap(data->keyboard, data->lpdiaf, NULL, 0);
ok(SUCCEEDED(hr), "SetActionMap failed hr=%08x\n", hr);
test_device_input(data->keyboard, INPUT_KEYBOARD, VK_SPACE, 2);
}
static void test_action_mapping(void) static void test_action_mapping(void)
{ {
HRESULT hr; HRESULT hr;
...@@ -374,6 +416,8 @@ static void test_action_mapping(void) ...@@ -374,6 +416,8 @@ static void test_action_mapping(void)
test_device_input(data.keyboard, INPUT_KEYBOARD, VK_SPACE, 2); test_device_input(data.keyboard, INPUT_KEYBOARD, VK_SPACE, 2);
test_appdata_property_vs_map(&data);
/* Test BuildActionMap with no suitable actions for a device */ /* Test BuildActionMap with no suitable actions for a device */
IDirectInputDevice_Unacquire(data.keyboard); IDirectInputDevice_Unacquire(data.keyboard);
af.dwDataSize = 4 * DITEST_KEYBOARDSPACE; af.dwDataSize = 4 * DITEST_KEYBOARDSPACE;
...@@ -865,6 +909,108 @@ static void test_keyboard_events(void) ...@@ -865,6 +909,108 @@ static void test_keyboard_events(void)
DestroyWindow(hwnd); DestroyWindow(hwnd);
} }
static void test_appdata_property(void)
{
HRESULT hr;
HINSTANCE hinst = GetModuleHandleA(NULL);
IDirectInputDevice8A *di_keyboard;
IDirectInput8A *pDI = NULL;
HWND hwnd;
DIPROPDWORD dw;
DIPROPPOINTER dp;
hr = CoCreateInstance(&CLSID_DirectInput8, 0, CLSCTX_INPROC_SERVER, &IID_IDirectInput8A, (LPVOID*)&pDI);
if (hr == DIERR_OLDDIRECTINPUTVERSION ||
hr == DIERR_BETADIRECTINPUTVERSION ||
hr == REGDB_E_CLASSNOTREG)
{
win_skip("DIPROP_APPDATA requires dinput8\n");
return;
}
ok(SUCCEEDED(hr), "DirectInput8 Create failed: hr=%08x\n", hr);
if (FAILED(hr)) return;
hr = IDirectInput8_Initialize(pDI,hinst, DIRECTINPUT_VERSION);
if (hr == DIERR_OLDDIRECTINPUTVERSION || hr == DIERR_BETADIRECTINPUTVERSION)
{
win_skip("DIPROP_APPDATA requires dinput8\n");
return;
}
ok(SUCCEEDED(hr), "DirectInput8 Initialize failed: hr=%08x\n", hr);
if (FAILED(hr)) return;
hwnd = CreateWindowExA(WS_EX_TOPMOST, "static", "dinput",
WS_POPUP | WS_VISIBLE, 0, 0, 100, 100, NULL, NULL, NULL, NULL);
ok(hwnd != NULL, "failed to create window\n");
hr = IDirectInput8_CreateDevice(pDI, &GUID_SysKeyboard, &di_keyboard, NULL);
ok(SUCCEEDED(hr), "IDirectInput8_CreateDevice failed: %08x\n", hr);
hr = IDirectInputDevice8_SetDataFormat(di_keyboard, &c_dfDIKeyboard);
ok(SUCCEEDED(hr), "IDirectInputDevice8_SetDataFormat failed: %08x\n", hr);
dw.diph.dwSize = sizeof(DIPROPDWORD);
dw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
dw.diph.dwObj = 0;
dw.diph.dwHow = DIPH_DEVICE;
dw.dwData = 32;
hr = IDirectInputDevice8_SetProperty(di_keyboard, DIPROP_BUFFERSIZE, &(dw.diph));
ok(SUCCEEDED(hr), "IDirectInputDevice8_SetProperty failed hr=%08x\n", hr);
/* the default value */
test_device_input(di_keyboard, INPUT_KEYBOARD, 'A', -1);
dp.diph.dwHow = DIPH_DEVICE;
dp.diph.dwObj = 0;
dp.uData = 1;
hr = IDirectInputDevice8_SetProperty(di_keyboard, DIPROP_APPDATA, &(dp.diph));
ok(hr == DIERR_INVALIDPARAM, "IDirectInputDevice8_SetProperty APPDATA for the device should be invalid hr=%08x\n", hr);
dp.diph.dwSize = sizeof(dp);
dp.diph.dwHeaderSize = sizeof(DIPROPHEADER);
dp.diph.dwHow = DIPH_BYUSAGE;
dp.diph.dwObj = 2;
dp.uData = 2;
hr = IDirectInputDevice8_SetProperty(di_keyboard, DIPROP_APPDATA, &(dp.diph));
ok(hr == DIERR_UNSUPPORTED, "IDirectInputDevice8_SetProperty APPDATA by usage should be unsupported hr=%08x\n", hr);
dp.diph.dwHow = DIPH_BYID;
dp.diph.dwObj = DIDFT_MAKEINSTANCE(DIK_SPACE) | DIDFT_PSHBUTTON;
dp.uData = 3;
hr = IDirectInputDevice8_SetProperty(di_keyboard, DIPROP_APPDATA, &(dp.diph));
ok(SUCCEEDED(hr), "IDirectInputDevice8_SetProperty failed hr=%08x\n", hr);
dp.diph.dwHow = DIPH_BYOFFSET;
dp.diph.dwObj = DIK_A;
dp.uData = 4;
hr = IDirectInputDevice8_SetProperty(di_keyboard, DIPROP_APPDATA, &(dp.diph));
ok(SUCCEEDED(hr), "IDirectInputDevice8_SetProperty failed hr=%08x\n", hr);
dp.diph.dwHow = DIPH_BYOFFSET;
dp.diph.dwObj = DIK_B;
dp.uData = 5;
hr = IDirectInputDevice8_SetProperty(di_keyboard, DIPROP_APPDATA, &(dp.diph));
ok(SUCCEEDED(hr), "IDirectInputDevice8_SetProperty failed hr=%08x\n", hr);
test_device_input(di_keyboard, INPUT_KEYBOARD, VK_SPACE, 3);
test_device_input(di_keyboard, INPUT_KEYBOARD, 'A', 4);
test_device_input(di_keyboard, INPUT_KEYBOARD, 'B', 5);
test_device_input(di_keyboard, INPUT_KEYBOARD, 'C', -1);
/* setting data format resets APPDATA */
hr = IDirectInputDevice8_SetDataFormat(di_keyboard, &c_dfDIKeyboard);
ok(SUCCEEDED(hr), "IDirectInputDevice8_SetDataFormat failed: %08x\n", hr);
test_device_input(di_keyboard, INPUT_KEYBOARD, VK_SPACE, -1);
test_device_input(di_keyboard, INPUT_KEYBOARD, 'A', -1);
test_device_input(di_keyboard, INPUT_KEYBOARD, 'B', -1);
test_device_input(di_keyboard, INPUT_KEYBOARD, 'C', -1);
DestroyWindow(hwnd);
IDirectInputDevice_Release(di_keyboard);
IDirectInput_Release(pDI);
}
START_TEST(device) START_TEST(device)
{ {
CoInitialize(NULL); CoInitialize(NULL);
...@@ -873,6 +1019,7 @@ START_TEST(device) ...@@ -873,6 +1019,7 @@ START_TEST(device)
test_save_settings(); test_save_settings();
test_mouse_keyboard(); test_mouse_keyboard();
test_keyboard_events(); test_keyboard_events();
test_appdata_property();
CoUninitialize(); CoUninitialize();
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment