[DINPUT_WINETEST] Sync with Wine Staging 1.7.55. CORE-10536
[reactos.git] / rostests / winetests / dinput / device.c
1 /*
2 * Copyright (c) 2006 Vitaliy Margolen
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17 */
18
19 #define WIN32_NO_STATUS
20 #define _INC_WINDOWS
21 #define COM_NO_WINDOWS_H
22
23 #define DIRECTINPUT_VERSION 0x0700
24
25 #define COBJMACROS
26 //#include <windows.h>
27
28 #include <wine/test.h>
29 //#include "windef.h"
30 #include <dinput.h>
31
32 static const DIOBJECTDATAFORMAT obj_data_format[] = {
33 { &GUID_YAxis, 16, DIDFT_OPTIONAL|DIDFT_AXIS |DIDFT_MAKEINSTANCE(1), 0},
34 { &GUID_Button,15, DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(3), 0},
35 { &GUID_Key, 0, DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(16),0},
36 { &GUID_Key, 1, DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(17),0},
37 { &GUID_Key, 2, DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(18),0},
38 { &GUID_Key, 3, DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(19),0},
39 { &GUID_Key, 4, DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(20),0},
40 { &GUID_Key, 5, DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(21),0},
41 { &GUID_Key, 6, DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(22),0},
42 { &GUID_Key, 7, DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(23),0},
43 { &GUID_Key, 8, DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(24),0},
44 { &GUID_Key, 9, DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(25),0},
45 { &GUID_Key, 10, DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(26),0},
46 { &GUID_Key, 11, DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(27),0},
47 { &GUID_Key, 12, DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(28),0},
48 { NULL, 13, DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(5),0},
49
50 { &GUID_Button,14, DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(32),0}
51 };
52
53 static const DIDATAFORMAT data_format = {
54 sizeof(DIDATAFORMAT),
55 sizeof(DIOBJECTDATAFORMAT),
56 DIDF_ABSAXIS,
57 32,
58 sizeof(obj_data_format) / sizeof(obj_data_format[0]),
59 (LPDIOBJECTDATAFORMAT)obj_data_format
60 };
61
62 static BOOL CALLBACK enum_callback(const DIDEVICEOBJECTINSTANCEA *oi, void *info)
63 {
64 if (winetest_debug > 1)
65 trace(" Type:%4x Ofs:%3d Flags:%08x Name:%s\n",
66 oi->dwType, oi->dwOfs, oi->dwFlags, oi->tszName);
67 (*(int*)info)++;
68 return DIENUM_CONTINUE;
69 }
70
71 static BOOL CALLBACK enum_type_callback(const DIDEVICEOBJECTINSTANCEA *oi, void *info)
72 {
73 DWORD expected = *(DWORD*)info;
74 ok (expected & DIDFT_GETTYPE(oi->dwType), "EnumObjects() enumerated wrong type for obj %s, expected: %08x got: %08x\n", oi->tszName, expected, oi->dwType);
75 return DIENUM_CONTINUE;
76 }
77
78 static void test_object_info(IDirectInputDeviceA *device, HWND hwnd)
79 {
80 HRESULT hr;
81 DIPROPDWORD dp;
82 DIDEVICEOBJECTINSTANCEA obj_info;
83 DWORD obj_types[] = {DIDFT_BUTTON, DIDFT_AXIS, DIDFT_POV};
84 int type_index;
85 int cnt1 = 0;
86 DWORD cnt = 0;
87 DIDEVICEOBJECTDATA buffer[5];
88
89 hr = IDirectInputDevice_EnumObjects(device, enum_callback, &cnt, DIDFT_ALL);
90 ok(SUCCEEDED(hr), "EnumObjects() failed: %08x\n", hr);
91
92 hr = IDirectInputDevice_SetDataFormat(device, &data_format);
93 ok(SUCCEEDED(hr), "SetDataFormat() failed: %08x\n", hr);
94
95 hr = IDirectInputDevice_EnumObjects(device, enum_callback, &cnt1, DIDFT_ALL);
96 ok(SUCCEEDED(hr), "EnumObjects() failed: %08x\n", hr);
97 if (0) /* fails for joystick only */
98 ok(cnt == cnt1, "Enum count changed from %d to %d\n", cnt, cnt1);
99
100 /* Testing EnumObjects with different types of device objects */
101 for (type_index=0; type_index < sizeof(obj_types)/sizeof(obj_types[0]); type_index++)
102 {
103 hr = IDirectInputDevice_EnumObjects(device, enum_type_callback, &obj_types[type_index], obj_types[type_index]);
104 ok(SUCCEEDED(hr), "EnumObjects() failed: %08x\n", hr);
105 }
106
107 /* Test buffered mode */
108 memset(&dp, 0, sizeof(dp));
109 dp.diph.dwSize = sizeof(DIPROPDWORD);
110 dp.diph.dwHeaderSize = sizeof(DIPROPHEADER);
111 dp.diph.dwHow = DIPH_DEVICE;
112 dp.diph.dwObj = 0;
113 dp.dwData = 0;
114
115 hr = IDirectInputDevice_SetProperty(device, DIPROP_BUFFERSIZE, (LPCDIPROPHEADER)&dp.diph);
116 ok(hr == DI_OK, "SetProperty() failed: %08x\n", hr);
117 cnt = 5;
118 hr = IDirectInputDevice_GetDeviceData(device, sizeof(buffer[0]), buffer, &cnt, 0);
119 ok(hr == DI_OK && cnt == 5, "GetDeviceData() failed: %08x cnt: %d\n", hr, cnt);
120 hr = IDirectInputDevice_GetDeviceData(device, sizeof(DIDEVICEOBJECTDATA_DX3), buffer, &cnt, 0);
121 ok(hr == DIERR_NOTBUFFERED, "GetDeviceData() should have failed: %08x\n", hr);
122 IDirectInputDevice_Acquire(device);
123 hr = IDirectInputDevice_GetDeviceData(device, sizeof(DIDEVICEOBJECTDATA_DX3), buffer, &cnt, 0);
124 ok(hr == DIERR_NOTBUFFERED, "GetDeviceData() should have failed: %08x\n", hr);
125 IDirectInputDevice_Unacquire(device);
126
127 dp.dwData = 20;
128 hr = IDirectInputDevice_SetProperty(device, DIPROP_BUFFERSIZE, (LPCDIPROPHEADER)&dp.diph);
129 ok(hr == DI_OK, "SetProperty() failed: %08x\n", hr);
130 cnt = 5;
131 hr = IDirectInputDevice_GetDeviceData(device, sizeof(buffer[0]), buffer, &cnt, 0);
132 ok(hr == DI_OK, "GetDeviceData() failed: %08x\n", hr);
133 hr = IDirectInputDevice_GetDeviceData(device, sizeof(DIDEVICEOBJECTDATA_DX3), buffer, &cnt, 0);
134 ok(hr == DIERR_NOTACQUIRED, "GetDeviceData() should have failed: %08x\n", hr);
135 hr = IDirectInputDevice_Acquire(device);
136 ok(hr == DI_OK, "Acquire() failed: %08x\n", hr);
137 cnt = 1;
138 hr = IDirectInputDevice_GetDeviceData(device, sizeof(buffer[0]), buffer, &cnt, 0);
139 ok(hr == DI_OK, "GetDeviceData() failed: %08x\n", hr);
140 hr = IDirectInputDevice_Unacquire(device);
141 ok(hr == DI_OK, "Unacquire() failed: %08x\n", hr);
142 cnt = 1;
143 hr = IDirectInputDevice_GetDeviceData(device, sizeof(buffer[0]), buffer, &cnt, 0);
144 ok(hr == DI_OK, "GetDeviceData() failed: %08x\n", hr);
145
146 /* No need to test devices without axis */
147 obj_info.dwSize = sizeof(obj_info);
148 hr = IDirectInputDevice_GetObjectInfo(device, &obj_info, 16, DIPH_BYOFFSET);
149 if (SUCCEEDED(hr))
150 {
151 /* No device supports per axis relative/absolute mode */
152 dp.diph.dwHow = DIPH_BYOFFSET;
153 dp.diph.dwObj = 16;
154 dp.dwData = DIPROPAXISMODE_ABS;
155 hr = IDirectInputDevice_SetProperty(device, DIPROP_AXISMODE, &dp.diph);
156 ok(hr == DIERR_UNSUPPORTED, "SetProperty() returned: %08x\n", hr);
157 dp.diph.dwHow = DIPH_DEVICE;
158 hr = IDirectInputDevice_SetProperty(device, DIPROP_AXISMODE, &dp.diph);
159 ok(hr == DIERR_INVALIDPARAM, "SetProperty() returned: %08x\n", hr);
160 dp.diph.dwObj = 0;
161 hr = IDirectInputDevice_SetProperty(device, DIPROP_AXISMODE, &dp.diph);
162 ok(hr == DI_OK, "SetProperty() failed: %08x\n", hr);
163
164 /* Cannot change mode while acquired */
165 hr = IDirectInputDevice_Acquire(device);
166 ok(hr == DI_OK, "Acquire() failed: %08x\n", hr);
167
168 hr = IDirectInputDevice_SetProperty(device, DIPROP_AXISMODE, &dp.diph);
169 ok(hr == DIERR_ACQUIRED, "SetProperty() returned: %08x\n", hr);
170 hr = IDirectInputDevice_Unacquire(device);
171 ok(hr == DI_OK, "Unacquire() failed: %08x\n", hr);
172 }
173 }
174
175 struct enum_data
176 {
177 IDirectInputA *pDI;
178 HWND hwnd;
179 };
180
181 static BOOL CALLBACK enum_devices(const DIDEVICEINSTANCEA *lpddi, void *pvRef)
182 {
183 struct enum_data *data = pvRef;
184 IDirectInputDeviceA *device, *obj = NULL;
185 HRESULT hr;
186
187 hr = IDirectInput_GetDeviceStatus(data->pDI, &lpddi->guidInstance);
188 ok(hr == DI_OK, "IDirectInput_GetDeviceStatus() failed: %08x\n", hr);
189
190 if (hr == DI_OK)
191 {
192 hr = IDirectInput_CreateDevice(data->pDI, &lpddi->guidInstance, &device, NULL);
193 ok(SUCCEEDED(hr), "IDirectInput_CreateDevice() failed: %08x\n", hr);
194 trace("Testing device %p \"%s\"\n", device, lpddi->tszInstanceName);
195
196 hr = IUnknown_QueryInterface(device, &IID_IDirectInputDevice2A, (LPVOID*)&obj);
197 ok(SUCCEEDED(hr), "IUnknown_QueryInterface(IID_IDirectInputDevice7A) failed: %08x\n", hr);
198 test_object_info(obj, data->hwnd);
199 if (obj) IUnknown_Release(obj);
200 obj = NULL;
201
202 hr = IUnknown_QueryInterface(device, &IID_IDirectInputDevice2W, (LPVOID*)&obj);
203 ok(SUCCEEDED(hr), "IUnknown_QueryInterface(IID_IDirectInputDevice7W) failed: %08x\n", hr);
204 test_object_info(obj, data->hwnd);
205 if (obj) IUnknown_Release(obj);
206
207 IUnknown_Release(device);
208 }
209 return DIENUM_CONTINUE;
210 }
211
212 static void device_tests(void)
213 {
214 HRESULT hr;
215 IDirectInputA *pDI = NULL, *obj = NULL;
216 HINSTANCE hInstance = GetModuleHandleW(NULL);
217 HWND hwnd;
218 struct enum_data data;
219
220 hr = CoCreateInstance(&CLSID_DirectInput, 0, 1, &IID_IDirectInput2A, (LPVOID*)&pDI);
221 if (hr == DIERR_OLDDIRECTINPUTVERSION || hr == DIERR_DEVICENOTREG)
222 {
223 skip("Tests require a newer dinput version\n");
224 return;
225 }
226 ok(SUCCEEDED(hr), "DirectInputCreateA() failed: %08x\n", hr);
227 if (FAILED(hr)) return;
228
229 hr = IDirectInput_Initialize(pDI, hInstance, DIRECTINPUT_VERSION);
230 ok(SUCCEEDED(hr), "Initialize() failed: %08x\n", hr);
231 if (FAILED(hr)) return;
232
233 hr = IUnknown_QueryInterface(pDI, &IID_IDirectInput2W, (LPVOID*)&obj);
234 ok(SUCCEEDED(hr), "QueryInterface(IDirectInput7W) failed: %08x\n", hr);
235
236 hwnd = CreateWindowA("static", "Title", WS_OVERLAPPEDWINDOW, 10, 10, 200, 200, NULL, NULL,
237 NULL, NULL);
238 ok(hwnd != NULL, "err: %d\n", GetLastError());
239 if (hwnd)
240 {
241 ShowWindow(hwnd, SW_SHOW);
242
243 data.pDI = pDI;
244 data.hwnd = hwnd;
245 hr = IDirectInput_EnumDevices(pDI, 0, enum_devices, &data, DIEDFL_ALLDEVICES);
246 ok(SUCCEEDED(hr), "IDirectInput_EnumDevices() failed: %08x\n", hr);
247
248
249 /* If GetDeviceStatus returns DI_OK the device must exist */
250 hr = IDirectInput_GetDeviceStatus(pDI, &GUID_Joystick);
251 if (hr == DI_OK)
252 {
253 IDirectInputDeviceA *device = NULL;
254
255 hr = IDirectInput_CreateDevice(pDI, &GUID_Joystick, &device, NULL);
256 ok(SUCCEEDED(hr), "IDirectInput_CreateDevice() failed: %08x\n", hr);
257 if (device) IUnknown_Release(device);
258 }
259
260 DestroyWindow(hwnd);
261 }
262 if (obj) IUnknown_Release(obj);
263 if (pDI) IUnknown_Release(pDI);
264 }
265
266 START_TEST(device)
267 {
268 CoInitialize(NULL);
269
270 device_tests();
271
272 CoUninitialize();
273 }