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