[PATCH 4/4] dinput: Implement DIPROP_APPDATA.
Arkadiusz Hiler
ahiler at codeweavers.com
Mon Mar 8 06:36:11 CST 2021
This fixes not working analog inputs on game controllers in Slay the Spire.
Signed-off-by: Arkadiusz Hiler <ahiler at codeweavers.com>
---
dlls/dinput/device.c | 71 +++++++++++++++++
dlls/dinput8/tests/device.c | 147 ++++++++++++++++++++++++++++++++++++
2 files changed, 218 insertions(+)
diff --git a/dlls/dinput/device.c b/dlls/dinput/device.c
index 14c47dd3c7d..f1b334680e8 100644
--- a/dlls/dinput/device.c
+++ b/dlls/dinput/device.c
@@ -571,6 +571,22 @@ failed:
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 */
static int offset_to_object(const DataFormat *df, int offset)
{
@@ -759,6 +775,44 @@ static BOOL load_mapping_settings(IDirectInputDeviceImpl *This, LPDIACTIONFORMAT
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)
{
IDirectInputDeviceImpl *This = impl_from_IDirectInputDevice8W(iface);
@@ -1447,6 +1501,23 @@ HRESULT WINAPI IDirectInputDevice2WImpl_SetProperty(
lstrcpynW(device_player->username, ps->wsz, ARRAY_SIZE(device_player->username));
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:
WARN("Unknown property %s\n", debugstr_guid(rguid));
return DIERR_UNSUPPORTED;
diff --git a/dlls/dinput8/tests/device.c b/dlls/dinput8/tests/device.c
index 4a766280982..3e6da23b4ab 100644
--- a/dlls/dinput8/tests/device.c
+++ b/dlls/dinput8/tests/device.c
@@ -294,6 +294,48 @@ static BOOL CALLBACK enumeration_callback(const DIDEVICEINSTANCEA *lpddi, IDirec
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)
{
HRESULT hr;
@@ -374,6 +416,8 @@ static void test_action_mapping(void)
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 */
IDirectInputDevice_Unacquire(data.keyboard);
af.dwDataSize = 4 * DITEST_KEYBOARDSPACE;
@@ -865,6 +909,108 @@ static void test_keyboard_events(void)
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)
{
CoInitialize(NULL);
@@ -873,6 +1019,7 @@ START_TEST(device)
test_save_settings();
test_mouse_keyboard();
test_keyboard_events();
+ test_appdata_property();
CoUninitialize();
}
--
2.30.1
More information about the wine-devel
mailing list