mshtml: Wine Gecko 1.4 release.
[wine] / dlls / dinput8 / tests / dinput.c
1 /*
2  * Copyright (c) 2011 Andrew Nguyen
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 DIRECTINPUT_VERSION 0x0800
20
21 #define COBJMACROS
22 #include <initguid.h>
23 #include <windows.h>
24 #include <dinput.h>
25
26 #include "wine/test.h"
27
28 HINSTANCE hInstance;
29
30 static BOOL CALLBACK dummy_callback(const DIDEVICEINSTANCEA *instance, void *context)
31 {
32     ok(0, "Callback was invoked with parameters (%p, %p)\n", instance, context);
33     return DIENUM_STOP;
34 }
35
36 static void test_preinitialization(void)
37 {
38     static const struct
39     {
40         REFGUID rguid;
41         BOOL pdev;
42         HRESULT expected_hr;
43     } create_device_tests[] =
44     {
45         {NULL, FALSE, E_POINTER},
46         {NULL, TRUE, E_POINTER},
47         {&GUID_Unknown, FALSE, E_POINTER},
48         {&GUID_Unknown, TRUE, DIERR_NOTINITIALIZED},
49         {&GUID_SysMouse, FALSE, E_POINTER},
50         {&GUID_SysMouse, TRUE, DIERR_NOTINITIALIZED},
51     };
52
53     static const struct
54     {
55         DWORD dwDevType;
56         LPDIENUMDEVICESCALLBACKA lpCallback;
57         DWORD dwFlags;
58         HRESULT expected_hr;
59         int todo;
60     } enum_devices_tests[] =
61     {
62         {0, NULL, 0, DIERR_INVALIDPARAM},
63         {0, NULL, ~0u, DIERR_INVALIDPARAM},
64         {0, dummy_callback, 0, DIERR_NOTINITIALIZED},
65         {0, dummy_callback, ~0u, DIERR_INVALIDPARAM, 1},
66         {0xdeadbeef, NULL, 0, DIERR_INVALIDPARAM},
67         {0xdeadbeef, NULL, ~0u, DIERR_INVALIDPARAM},
68         {0xdeadbeef, dummy_callback, 0, DIERR_INVALIDPARAM, 1},
69         {0xdeadbeef, dummy_callback, ~0u, DIERR_INVALIDPARAM, 1},
70     };
71
72     IDirectInput8A *pDI;
73     HRESULT hr;
74     int i;
75     IDirectInputDevice8A *pDID;
76
77     hr = CoCreateInstance(&CLSID_DirectInput8, NULL, CLSCTX_INPROC_SERVER, &IID_IDirectInput8A, (void **)&pDI);
78     if (FAILED(hr))
79     {
80         skip("Failed to instantiate a IDirectInputA instance: 0x%08x\n", hr);
81         return;
82     }
83
84     for (i = 0; i < sizeof(create_device_tests)/sizeof(create_device_tests[0]); i++)
85     {
86         if (create_device_tests[i].pdev) pDID = (void *)0xdeadbeef;
87         hr = IDirectInput8_CreateDevice(pDI, create_device_tests[i].rguid,
88                                             create_device_tests[i].pdev ? &pDID : NULL,
89                                             NULL);
90         ok(hr == create_device_tests[i].expected_hr, "[%d] IDirectInput8_CreateDevice returned 0x%08x\n", i, hr);
91         if (create_device_tests[i].pdev)
92             ok(pDID == NULL, "[%d] Output interface pointer is %p\n", i, pDID);
93     }
94
95     for (i = 0; i < sizeof(enum_devices_tests)/sizeof(enum_devices_tests[0]); i++)
96     {
97         hr = IDirectInput8_EnumDevices(pDI, enum_devices_tests[i].dwDevType,
98                                            enum_devices_tests[i].lpCallback,
99                                            NULL,
100                                            enum_devices_tests[i].dwFlags);
101         if (enum_devices_tests[i].todo)
102         {
103             todo_wine
104             ok(hr == enum_devices_tests[i].expected_hr, "[%d] IDirectInput8_EnumDevice returned 0x%08x\n", i, hr);
105         }
106         else
107             ok(hr == enum_devices_tests[i].expected_hr, "[%d] IDirectInput8_EnumDevice returned 0x%08x\n", i, hr);
108     }
109
110     hr = IDirectInput8_GetDeviceStatus(pDI, NULL);
111     todo_wine
112     ok(hr == E_POINTER, "IDirectInput8_GetDeviceStatus returned 0x%08x\n", hr);
113
114     hr = IDirectInput8_GetDeviceStatus(pDI, &GUID_Unknown);
115     ok(hr == DIERR_NOTINITIALIZED, "IDirectInput8_GetDeviceStatus returned 0x%08x\n", hr);
116
117     hr = IDirectInput8_GetDeviceStatus(pDI, &GUID_SysMouse);
118     ok(hr == DIERR_NOTINITIALIZED, "IDirectInput8_GetDeviceStatus returned 0x%08x\n", hr);
119
120     hr = IDirectInput8_RunControlPanel(pDI, NULL, 0);
121     ok(hr == DIERR_NOTINITIALIZED, "IDirectInput8_RunControlPanel returned 0x%08x\n", hr);
122
123     hr = IDirectInput8_RunControlPanel(pDI, NULL, ~0u);
124     ok(hr == DIERR_INVALIDPARAM, "IDirectInput8_RunControlPanel returned 0x%08x\n", hr);
125
126     hr = IDirectInput8_RunControlPanel(pDI, (HWND)0xdeadbeef, 0);
127     ok(hr == E_HANDLE, "IDirectInput8_RunControlPanel returned 0x%08x\n", hr);
128
129     hr = IDirectInput8_RunControlPanel(pDI, (HWND)0xdeadbeef, ~0u);
130     ok(hr == E_HANDLE, "IDirectInput8_RunControlPanel returned 0x%08x\n", hr);
131
132     IDirectInput8_Release(pDI);
133 }
134
135 static void test_DirectInput8Create(void)
136 {
137     static const struct
138     {
139         BOOL hinst;
140         DWORD dwVersion;
141         REFIID riid;
142         BOOL ppdi;
143         HRESULT expected_hr;
144     } invalid_param_list[] =
145     {
146         {FALSE, 0,                       &IID_IDirectInputA,  FALSE, E_POINTER},
147         {FALSE, 0,                       &IID_IDirectInputA,  TRUE,  DIERR_NOINTERFACE},
148         {FALSE, 0,                       &IID_IDirectInput8A, FALSE, E_POINTER},
149         {FALSE, 0,                       &IID_IDirectInput8A, TRUE,  DIERR_INVALIDPARAM},
150         {FALSE, DIRECTINPUT_VERSION,     &IID_IDirectInputA,  FALSE, E_POINTER},
151         {FALSE, DIRECTINPUT_VERSION,     &IID_IDirectInputA,  TRUE,  DIERR_NOINTERFACE},
152         {FALSE, DIRECTINPUT_VERSION,     &IID_IDirectInput8A, FALSE, E_POINTER},
153         {FALSE, DIRECTINPUT_VERSION,     &IID_IDirectInput8A, TRUE,  DIERR_INVALIDPARAM},
154         {FALSE, DIRECTINPUT_VERSION - 1, &IID_IDirectInputA,  FALSE, E_POINTER},
155         {FALSE, DIRECTINPUT_VERSION - 1, &IID_IDirectInputA,  TRUE,  DIERR_NOINTERFACE},
156         {FALSE, DIRECTINPUT_VERSION - 1, &IID_IDirectInput8A, FALSE, E_POINTER},
157         {FALSE, DIRECTINPUT_VERSION - 1, &IID_IDirectInput8A, TRUE,  DIERR_INVALIDPARAM},
158         {FALSE, DIRECTINPUT_VERSION + 1, &IID_IDirectInputA,  FALSE, E_POINTER},
159         {FALSE, DIRECTINPUT_VERSION + 1, &IID_IDirectInputA,  TRUE,  DIERR_NOINTERFACE},
160         {FALSE, DIRECTINPUT_VERSION + 1, &IID_IDirectInput8A, FALSE, E_POINTER},
161         {FALSE, DIRECTINPUT_VERSION + 1, &IID_IDirectInput8A, TRUE,  DIERR_INVALIDPARAM},
162         {TRUE,  0,                       &IID_IDirectInputA,  FALSE, E_POINTER},
163         {TRUE,  0,                       &IID_IDirectInputA,  TRUE,  DIERR_NOINTERFACE},
164         {TRUE,  0,                       &IID_IDirectInput8A, FALSE, E_POINTER},
165         {TRUE,  0,                       &IID_IDirectInput8A, TRUE,  DIERR_NOTINITIALIZED},
166         {TRUE,  DIRECTINPUT_VERSION,     &IID_IDirectInputA,  FALSE, E_POINTER},
167         {TRUE,  DIRECTINPUT_VERSION,     &IID_IDirectInputA,  TRUE,  DIERR_NOINTERFACE},
168         {TRUE,  DIRECTINPUT_VERSION,     &IID_IDirectInput8A, FALSE, E_POINTER},
169         {TRUE,  DIRECTINPUT_VERSION - 1, &IID_IDirectInputA,  FALSE, E_POINTER},
170         {TRUE,  DIRECTINPUT_VERSION - 1, &IID_IDirectInputA,  TRUE,  DIERR_NOINTERFACE},
171         {TRUE,  DIRECTINPUT_VERSION - 1, &IID_IDirectInput8A, FALSE, E_POINTER},
172         {TRUE,  DIRECTINPUT_VERSION - 1, &IID_IDirectInput8A, TRUE,  DIERR_BETADIRECTINPUTVERSION},
173         {TRUE,  DIRECTINPUT_VERSION + 1, &IID_IDirectInputA,  FALSE, E_POINTER},
174         {TRUE,  DIRECTINPUT_VERSION + 1, &IID_IDirectInputA,  TRUE,  DIERR_NOINTERFACE},
175         {TRUE,  DIRECTINPUT_VERSION + 1, &IID_IDirectInput8A, FALSE, E_POINTER},
176         {TRUE,  DIRECTINPUT_VERSION + 1, &IID_IDirectInput8A, TRUE,  DIERR_OLDDIRECTINPUTVERSION},
177     };
178
179     static REFIID no_interface_list[] = {&IID_IDirectInputA, &IID_IDirectInputW,
180                                          &IID_IDirectInput2A, &IID_IDirectInput2W,
181                                          &IID_IDirectInput7A, &IID_IDirectInput7W,
182                                          &IID_IDirectInputDeviceA, &IID_IDirectInputDeviceW,
183                                          &IID_IDirectInputDevice2A, &IID_IDirectInputDevice2W,
184                                          &IID_IDirectInputDevice7A, &IID_IDirectInputDevice7W,
185                                          &IID_IDirectInputDevice8A, &IID_IDirectInputDevice8W,
186                                          &IID_IDirectInputEffect};
187
188     static REFIID iid_list[] = {&IID_IUnknown, &IID_IDirectInput8A, &IID_IDirectInput8W};
189
190     int i;
191     IUnknown *pUnk;
192     HRESULT hr;
193
194     for (i = 0; i < sizeof(invalid_param_list)/sizeof(invalid_param_list[0]); i++)
195     {
196         if (invalid_param_list[i].ppdi) pUnk = (void *)0xdeadbeef;
197         hr = DirectInput8Create(invalid_param_list[i].hinst ? hInstance : NULL,
198                                 invalid_param_list[i].dwVersion,
199                                 invalid_param_list[i].riid,
200                                 invalid_param_list[i].ppdi ? (void **)&pUnk : NULL,
201                                 NULL);
202         ok(hr == invalid_param_list[i].expected_hr, "[%d] DirectInput8Create returned 0x%08x\n", i, hr);
203         if (invalid_param_list[i].ppdi)
204             ok(pUnk == NULL, "[%d] Output interface pointer is %p\n", i, pUnk);
205     }
206
207     for (i = 0; i < sizeof(no_interface_list)/sizeof(no_interface_list[0]); i++)
208     {
209         pUnk = (void *)0xdeadbeef;
210         hr = DirectInput8Create(hInstance, DIRECTINPUT_VERSION, no_interface_list[i], (void **)&pUnk, NULL);
211         ok(hr == DIERR_NOINTERFACE, "[%d] DirectInput8Create returned 0x%08x\n", i, hr);
212         ok(pUnk == NULL, "[%d] Output interface pointer is %p\n", i, pUnk);
213     }
214
215     for (i = 0; i < sizeof(iid_list)/sizeof(iid_list[0]); i++)
216     {
217         pUnk = NULL;
218         hr = DirectInput8Create(hInstance, DIRECTINPUT_VERSION, iid_list[i], (void **)&pUnk, NULL);
219         ok(hr == DI_OK, "[%d] DirectInput8Create returned 0x%08x\n", i, hr);
220         ok(pUnk != NULL, "[%d] Output interface pointer is NULL\n", i);
221         if (pUnk)
222             IUnknown_Release(pUnk);
223     }
224 }
225
226 static void test_QueryInterface(void)
227 {
228     static REFIID iid_list[] = {&IID_IUnknown, &IID_IDirectInput8A, &IID_IDirectInput8W};
229
230     static const struct
231     {
232         REFIID riid;
233         int test_todo;
234     } no_interface_list[] =
235     {
236         {&IID_IDirectInputA, 1},
237         {&IID_IDirectInputW, 1},
238         {&IID_IDirectInput2A, 1},
239         {&IID_IDirectInput2W, 1},
240         {&IID_IDirectInput7A, 1},
241         {&IID_IDirectInput7W, 1},
242         {&IID_IDirectInputDeviceA},
243         {&IID_IDirectInputDeviceW},
244         {&IID_IDirectInputDevice2A},
245         {&IID_IDirectInputDevice2W},
246         {&IID_IDirectInputDevice7A},
247         {&IID_IDirectInputDevice7W},
248         {&IID_IDirectInputDevice8A},
249         {&IID_IDirectInputDevice8W},
250         {&IID_IDirectInputEffect},
251     };
252
253     IDirectInput8A *pDI;
254     HRESULT hr;
255     IUnknown *pUnk;
256     int i;
257
258     hr = DirectInput8Create(hInstance, DIRECTINPUT_VERSION, &IID_IDirectInput8A, (void **)&pDI, NULL);
259     if (FAILED(hr))
260     {
261         win_skip("Failed to instantiate a IDirectInputA instance: 0x%08x\n", hr);
262         return;
263     }
264
265     hr = IDirectInput8_QueryInterface(pDI, NULL, NULL);
266     ok(hr == E_POINTER, "IDirectInput8_QueryInterface returned 0x%08x\n", hr);
267
268     pUnk = (void *)0xdeadbeef;
269     hr = IDirectInput8_QueryInterface(pDI, NULL, (void **)&pUnk);
270     ok(hr == E_POINTER, "IDirectInput8_QueryInterface returned 0x%08x\n", hr);
271     ok(pUnk == (void *)0xdeadbeef, "Output interface pointer is %p\n", pUnk);
272
273     hr = IDirectInput8_QueryInterface(pDI, &IID_IUnknown, NULL);
274     ok(hr == E_POINTER, "IDirectInput8_QueryInterface returned 0x%08x\n", hr);
275
276     for (i = 0; i < sizeof(iid_list)/sizeof(iid_list[0]); i++)
277     {
278         pUnk = NULL;
279         hr = IDirectInput8_QueryInterface(pDI, iid_list[i], (void **)&pUnk);
280         ok(hr == S_OK, "[%d] IDirectInput8_QueryInterface returned 0x%08x\n", i, hr);
281         ok(pUnk != NULL, "[%d] Output interface pointer is NULL\n", i);
282         if (pUnk) IUnknown_Release(pUnk);
283     }
284
285     for (i = 0; i < sizeof(no_interface_list)/sizeof(no_interface_list[0]); i++)
286     {
287         pUnk = (void *)0xdeadbeef;
288         hr = IDirectInput8_QueryInterface(pDI, no_interface_list[i].riid, (void **)&pUnk);
289         if (no_interface_list[i].test_todo)
290         {
291             todo_wine
292             ok(hr == E_NOINTERFACE, "[%d] IDirectInput8_QueryInterface returned 0x%08x\n", i, hr);
293             todo_wine
294             ok(pUnk == NULL, "[%d] Output interface pointer is %p\n", i, pUnk);
295
296             if (pUnk) IUnknown_Release(pUnk);
297         }
298         else
299         {
300             ok(hr == E_NOINTERFACE, "[%d] IDirectInput8_QueryInterface returned 0x%08x\n", i, hr);
301             ok(pUnk == NULL, "[%d] Output interface pointer is %p\n", i, pUnk);
302         }
303     }
304
305     IDirectInput8_Release(pDI);
306 }
307
308 static void test_CreateDevice(void)
309 {
310     IDirectInput8A *pDI;
311     HRESULT hr;
312     IDirectInputDevice8A *pDID;
313
314     hr = DirectInput8Create(hInstance, DIRECTINPUT_VERSION, &IID_IDirectInput8A, (void **)&pDI, NULL);
315     if (FAILED(hr))
316     {
317         win_skip("Failed to instantiate a IDirectInputA instance: 0x%08x\n", hr);
318         return;
319     }
320
321     hr = IDirectInput8_CreateDevice(pDI, NULL, NULL, NULL);
322     ok(hr == E_POINTER, "IDirectInput8_CreateDevice returned 0x%08x\n", hr);
323
324     pDID = (void *)0xdeadbeef;
325     hr = IDirectInput8_CreateDevice(pDI, NULL, &pDID, NULL);
326     ok(hr == E_POINTER, "IDirectInput8_CreateDevice returned 0x%08x\n", hr);
327     ok(pDID == NULL, "Output interface pointer is %p\n", pDID);
328
329     hr = IDirectInput8_CreateDevice(pDI, &GUID_Unknown, NULL, NULL);
330     ok(hr == E_POINTER, "IDirectInput8_CreateDevice returned 0x%08x\n", hr);
331
332     pDID = (void *)0xdeadbeef;
333     hr = IDirectInput8_CreateDevice(pDI, &GUID_Unknown, &pDID, NULL);
334     ok(hr == DIERR_DEVICENOTREG, "IDirectInput8_CreateDevice returned 0x%08x\n", hr);
335     ok(pDID == NULL, "Output interface pointer is %p\n", pDID);
336
337     hr = IDirectInput8_CreateDevice(pDI, &GUID_SysMouse, NULL, NULL);
338     ok(hr == E_POINTER, "IDirectInput8_CreateDevice returned 0x%08x\n", hr);
339
340     hr = IDirectInput8_CreateDevice(pDI, &GUID_SysMouse, &pDID, NULL);
341     ok(hr == DI_OK, "IDirectInput8_CreateDevice returned 0x%08x\n", hr);
342
343     IDirectInputDevice_Release(pDID);
344     IDirectInput8_Release(pDI);
345 }
346
347 struct enum_devices_test
348 {
349     unsigned int device_count;
350     BOOL return_value;
351 };
352
353 static BOOL CALLBACK enum_devices_callback(const DIDEVICEINSTANCEA *instance, void *context)
354 {
355     struct enum_devices_test *enum_test = context;
356
357     enum_test->device_count++;
358     return enum_test->return_value;
359 }
360
361 static void test_EnumDevices(void)
362 {
363     IDirectInput8A *pDI;
364     HRESULT hr;
365     struct enum_devices_test enum_test, enum_test_return;
366
367     hr = DirectInput8Create(hInstance, DIRECTINPUT_VERSION, &IID_IDirectInput8A, (void **)&pDI, NULL);
368     if (FAILED(hr))
369     {
370         win_skip("Failed to instantiate a IDirectInputA instance: 0x%08x\n", hr);
371         return;
372     }
373
374     hr = IDirectInput8_EnumDevices(pDI, 0, NULL, NULL, 0);
375     ok(hr == DIERR_INVALIDPARAM, "IDirectInput8_EnumDevices returned 0x%08x\n", hr);
376
377     hr = IDirectInput8_EnumDevices(pDI, 0, NULL, NULL, ~0u);
378     ok(hr == DIERR_INVALIDPARAM, "IDirectInput8_EnumDevices returned 0x%08x\n", hr);
379
380     /* Test crashes on Wine. */
381     if (0)
382     {
383         hr = IDirectInput8_EnumDevices(pDI, 0, enum_devices_callback, NULL, ~0u);
384         ok(hr == DIERR_INVALIDPARAM, "IDirectInput8_EnumDevices returned 0x%08x\n", hr);
385     }
386
387     hr = IDirectInput8_EnumDevices(pDI, 0xdeadbeef, NULL, NULL, 0);
388     ok(hr == DIERR_INVALIDPARAM, "IDirectInput8_EnumDevices returned 0x%08x\n", hr);
389
390     hr = IDirectInput8_EnumDevices(pDI, 0xdeadbeef, NULL, NULL, ~0u);
391     ok(hr == DIERR_INVALIDPARAM, "IDirectInput8_EnumDevices returned 0x%08x\n", hr);
392
393     hr = IDirectInput8_EnumDevices(pDI, 0xdeadbeef, enum_devices_callback, NULL, 0);
394     todo_wine
395     ok(hr == DIERR_INVALIDPARAM, "IDirectInput8_EnumDevices returned 0x%08x\n", hr);
396
397     hr = IDirectInput8_EnumDevices(pDI, 0xdeadbeef, enum_devices_callback, NULL, ~0u);
398     todo_wine
399     ok(hr == DIERR_INVALIDPARAM, "IDirectInput8_EnumDevices returned 0x%08x\n", hr);
400
401     enum_test.device_count = 0;
402     enum_test.return_value = DIENUM_CONTINUE;
403     hr = IDirectInput8_EnumDevices(pDI, 0, enum_devices_callback, &enum_test, 0);
404     ok(hr == DI_OK, "IDirectInput8_EnumDevices returned 0x%08x\n", hr);
405     ok(enum_test.device_count != 0, "Device count is %u\n", enum_test.device_count);
406
407     /* Enumeration only stops with an explicit DIENUM_STOP. */
408     enum_test_return.device_count = 0;
409     enum_test_return.return_value = 42;
410     hr = IDirectInput8_EnumDevices(pDI, 0, enum_devices_callback, &enum_test_return, 0);
411     ok(hr == DI_OK, "IDirectInput8_EnumDevices returned 0x%08x\n", hr);
412     ok(enum_test_return.device_count == enum_test.device_count,
413        "Device count is %u vs. %u\n", enum_test_return.device_count, enum_test.device_count);
414
415     enum_test.device_count = 0;
416     enum_test.return_value = DIENUM_STOP;
417     hr = IDirectInput8_EnumDevices(pDI, 0, enum_devices_callback, &enum_test, 0);
418     ok(hr == DI_OK, "IDirectInput8_EnumDevices returned 0x%08x\n", hr);
419     ok(enum_test.device_count == 1, "Device count is %u\n", enum_test.device_count);
420
421     IDirectInput8_Release(pDI);
422 }
423
424 struct enum_semantics_test
425 {
426     unsigned int device_count;
427     BOOL mouse;
428     BOOL keyboard;
429     LPDIACTIONFORMAT lpdiaf;
430     const char* username;
431 };
432
433 static DIACTION actionMapping[]=
434 {
435   /* axis */
436   { 0, 0x01008A01 /* DIAXIS_DRIVINGR_STEER */,      0, { "Steer" }   },
437   /* button */
438   { 1, 0x01000C01 /* DIBUTTON_DRIVINGR_SHIFTUP */,  0, { "Upshift" } },
439   /* keyboard key */
440   { 2, DIKEYBOARD_SPACE,                            0, { "Missile" } },
441   /* mouse button */
442   { 3, DIMOUSE_BUTTON0,                             0, { "Select" }  },
443   /* mouse axis */
444   { 4, DIMOUSE_YAXIS,                               0, { "Y Axis" }  }
445 };
446
447 static BOOL CALLBACK enum_semantics_callback(LPCDIDEVICEINSTANCE lpddi, IDirectInputDevice8A *lpdid, DWORD dwFlags, DWORD dwRemaining, void *context)
448 {
449     struct enum_semantics_test *data = context;
450
451     if (context == NULL) return DIENUM_STOP;
452
453     data->device_count++;
454
455     if (IsEqualGUID(&lpddi->guidInstance, &GUID_SysKeyboard)) data->keyboard = TRUE;
456
457     if (IsEqualGUID(&lpddi->guidInstance, &GUID_SysMouse)) data->mouse = TRUE;
458
459     return DIENUM_CONTINUE;
460 }
461
462 static BOOL CALLBACK set_action_map_callback(LPCDIDEVICEINSTANCE lpddi, IDirectInputDevice8A *lpdid, DWORD dwFlags, DWORD dwRemaining, void *context)
463 {
464     HRESULT hr;
465     struct enum_semantics_test *data = context;
466
467     /* Building and setting an action map */
468     /* It should not use any pre-stored mappings so we use DIDBAM_INITIALIZE */
469     hr = IDirectInputDevice8_BuildActionMap(lpdid, data->lpdiaf, NULL, DIDBAM_INITIALIZE);
470     ok (SUCCEEDED(hr), "BuildActionMap failed hr=%08x\n", hr);
471
472     hr = IDirectInputDevice8_SetActionMap(lpdid, data->lpdiaf, data->username, 0);
473     ok (SUCCEEDED(hr), "SetActionMap failed hr=%08x\n", hr);
474
475     return DIENUM_CONTINUE;
476 }
477
478 static void test_EnumDevicesBySemantics(void)
479 {
480     IDirectInput8A *pDI;
481     HRESULT hr;
482     DIACTIONFORMATA diaf;
483     const GUID ACTION_MAPPING_GUID = { 0x1, 0x2, 0x3, { 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb } };
484     struct enum_semantics_test data = { 0, FALSE, FALSE, &diaf, NULL };
485     int device_total = 0;
486
487     hr = DirectInput8Create(hInstance, DIRECTINPUT_VERSION, &IID_IDirectInput8A, (void **)&pDI, NULL);
488     if (FAILED(hr))
489     {
490         win_skip("Failed to instantiate a IDirectInputA instance: 0x%08x\n", hr);
491         return;
492     }
493
494     memset (&diaf, 0, sizeof(diaf));
495     diaf.dwSize = sizeof(diaf);
496     diaf.dwActionSize = sizeof(DIACTION);
497     diaf.dwNumActions = sizeof(actionMapping) / sizeof(actionMapping[0]);
498     diaf.dwDataSize = 4 * diaf.dwNumActions;
499     diaf.rgoAction = actionMapping;
500     diaf.guidActionMap = ACTION_MAPPING_GUID;
501     diaf.dwGenre = 0x01000000; /* DIVIRTUAL_DRIVING_RACE */
502     diaf.dwBufferSize = 32;
503
504     /* Test enumerating all attached and installed devices */
505     data.keyboard = FALSE;
506     data.mouse = FALSE;
507     data.device_count = 0;
508     hr = IDirectInput8_EnumDevicesBySemantics(pDI, NULL, &diaf, enum_semantics_callback, &data, DIEDBSFL_ATTACHEDONLY);
509     ok (data.device_count > 0, "EnumDevicesBySemantics did not call the callback hr=%08x\n", hr);
510     ok (data.keyboard, "EnumDevicesBySemantics should enumerate the keyboard\n");
511     ok (data.mouse, "EnumDevicesBySemantics should enumerate the mouse\n");
512
513     /* Enumerate Force feedback devices. We should get no mouse nor keyboard */
514     data.keyboard = FALSE;
515     data.mouse = FALSE;
516     hr = IDirectInput8_EnumDevicesBySemantics(pDI, NULL, &diaf, enum_semantics_callback, &data, DIEDBSFL_FORCEFEEDBACK);
517     ok (SUCCEEDED(hr), "EnumDevicesBySemantics failed hr=%08x\n", hr);
518     ok (!data.keyboard, "Keyboard should not be enumerated when asking for forcefeedback\n");
519     ok (!data.mouse, "Mouse should not be enumerated when asking for forcefeedback\n");
520
521     /* Enumerate available devices. That is devices not owned by any user.
522        Before setting the action map for all devices we still have them available. */
523     data.device_count = 0;
524     hr = IDirectInput8_EnumDevicesBySemantics(pDI, NULL, &diaf, enum_semantics_callback, &data, DIEDBSFL_AVAILABLEDEVICES);
525     ok (SUCCEEDED(hr), "EnumDevicesBySemantics failed hr=%08x\n", hr);
526     ok (data.device_count > 0, "There should be devices available before action mapping available=%d\n", data.device_count);
527
528     /* Keep the device total */
529     device_total = data.device_count;
530
531     /* This enumeration builds and sets the action map for all devices with a NULL username */
532     hr = IDirectInput8_EnumDevicesBySemantics(pDI, NULL, &diaf, set_action_map_callback, &data, DIEDBSFL_ATTACHEDONLY);
533     ok (SUCCEEDED(hr), "EnumDevicesBySemantics failed: hr=%08x\n", hr);
534
535     /* After a successful action mapping we should have no devices available */
536     data.device_count = 0;
537     hr = IDirectInput8_EnumDevicesBySemantics(pDI, NULL, &diaf, enum_semantics_callback, &data, DIEDBSFL_AVAILABLEDEVICES);
538     ok (SUCCEEDED(hr), "EnumDevicesBySemantics failed hr=%08x\n", hr);
539     todo_wine ok (data.device_count == 0, "No device should be available after action mapping available=%d\n", data.device_count);
540
541     /* Now we'll give all the devices to a specific user */
542     data.username = "Sh4d0w M4g3";
543     hr = IDirectInput8_EnumDevicesBySemantics(pDI, NULL, &diaf, set_action_map_callback, &data, DIEDBSFL_ATTACHEDONLY);
544     ok (SUCCEEDED(hr), "EnumDevicesBySemantics failed: hr=%08x\n", hr);
545
546     /* Testing with the default user, DIEDBSFL_THISUSER has no effect */
547     data.device_count = 0;
548     hr = IDirectInput8_EnumDevicesBySemantics(pDI, NULL, &diaf, enum_semantics_callback, &data, DIEDBSFL_THISUSER);
549     ok (SUCCEEDED(hr), "EnumDevicesBySemantics failed hr=%08x\n", hr);
550     ok (data.device_count == device_total, "THISUSER has no effect with NULL username owned=%d, expected=%d\n", data.device_count, device_total);
551
552     /* Using an empty user string is the same as passing NULL, DIEDBSFL_THISUSER has no effect */
553     data.device_count = 0;
554     hr = IDirectInput8_EnumDevicesBySemantics(pDI, "", &diaf, enum_semantics_callback, &data, DIEDBSFL_THISUSER);
555     ok (SUCCEEDED(hr), "EnumDevicesBySemantics failed hr=%08x\n", hr);
556     ok (data.device_count == device_total, "THISUSER has no effect with \"\" as username owned=%d, expected=%d\n", data.device_count, device_total);
557
558     /* Testing with a user with no ownership of the devices */
559     data.device_count = 0;
560     hr = IDirectInput8_EnumDevicesBySemantics(pDI, "Ninja Brian", &diaf, enum_semantics_callback, &data, DIEDBSFL_THISUSER);
561     ok (SUCCEEDED(hr), "EnumDevicesBySemantics failed hr=%08x\n", hr);
562     todo_wine ok (data.device_count == 0, "This user should own no devices owned=%d\n", data.device_count);
563
564     /* Sh4d0w M4g3 has ownership of all devices */
565     data.device_count = 0;
566     hr = IDirectInput8_EnumDevicesBySemantics(pDI, "Sh4d0w M4g3", &diaf, enum_semantics_callback, &data, DIEDBSFL_THISUSER);
567     ok (SUCCEEDED(hr), "EnumDevicesBySemantics failed hr=%08x\n", hr);
568     ok (data.device_count == device_total, "This user should own %d devices owned=%d\n", device_total, data.device_count);
569
570     /* The call fails with a zeroed GUID */
571     memset(&diaf.guidActionMap, 0, sizeof(GUID));
572     hr = IDirectInput8_EnumDevicesBySemantics(pDI, NULL, &diaf, enum_semantics_callback, NULL, 0);
573     todo_wine ok(FAILED(hr), "EnumDevicesBySemantics succeeded with invalid GUID hr=%08x\n", hr);
574
575     IDirectInput8_Release(pDI);
576 }
577
578 static void test_GetDeviceStatus(void)
579 {
580     IDirectInput8A *pDI;
581     HRESULT hr;
582
583     hr = DirectInput8Create(hInstance, DIRECTINPUT_VERSION, &IID_IDirectInput8A, (void **)&pDI, NULL);
584     if (FAILED(hr))
585     {
586         win_skip("Failed to instantiate a IDirectInputA instance: 0x%08x\n", hr);
587         return;
588     }
589
590     hr = IDirectInput8_GetDeviceStatus(pDI, NULL);
591     todo_wine
592     ok(hr == E_POINTER, "IDirectInput8_GetDeviceStatus returned 0x%08x\n", hr);
593
594     hr = IDirectInput8_GetDeviceStatus(pDI, &GUID_Unknown);
595     todo_wine
596     ok(hr == DIERR_DEVICENOTREG, "IDirectInput8_GetDeviceStatus returned 0x%08x\n", hr);
597
598     hr = IDirectInput8_GetDeviceStatus(pDI, &GUID_SysMouse);
599     ok(hr == DI_OK, "IDirectInput8_GetDeviceStatus returned 0x%08x\n", hr);
600
601     IDirectInput8_Release(pDI);
602 }
603
604 static void test_RunControlPanel(void)
605 {
606     IDirectInput8A *pDI;
607     HRESULT hr;
608
609     hr = DirectInput8Create(hInstance, DIRECTINPUT_VERSION, &IID_IDirectInput8A, (void **)&pDI, NULL);
610     if (FAILED(hr))
611     {
612         win_skip("Failed to instantiate a IDirectInputA instance: 0x%08x\n", hr);
613         return;
614     }
615
616     if (winetest_interactive)
617     {
618         hr = IDirectInput8_RunControlPanel(pDI, NULL, 0);
619         ok(hr == S_OK, "IDirectInput8_RunControlPanel returned 0x%08x\n", hr);
620
621         hr = IDirectInput8_RunControlPanel(pDI, GetDesktopWindow(), 0);
622         ok(hr == S_OK, "IDirectInput8_RunControlPanel returned 0x%08x\n", hr);
623     }
624
625     hr = IDirectInput8_RunControlPanel(pDI, NULL, ~0u);
626     ok(hr == DIERR_INVALIDPARAM, "IDirectInput8_RunControlPanel returned 0x%08x\n", hr);
627
628     hr = IDirectInput8_RunControlPanel(pDI, (HWND)0xdeadbeef, 0);
629     ok(hr == E_HANDLE, "IDirectInput8_RunControlPanel returned 0x%08x\n", hr);
630
631     hr = IDirectInput8_RunControlPanel(pDI, (HWND)0xdeadbeef, ~0u);
632     ok(hr == E_HANDLE, "IDirectInput8_RunControlPanel returned 0x%08x\n", hr);
633
634     IDirectInput8_Release(pDI);
635 }
636
637 static void test_Initialize(void)
638 {
639     IDirectInput8A *pDI;
640     HRESULT hr;
641
642     hr = DirectInput8Create(hInstance, DIRECTINPUT_VERSION, &IID_IDirectInput8A, (void **)&pDI, NULL);
643     if (FAILED(hr))
644     {
645         win_skip("Failed to instantiate a IDirectInputA instance: 0x%08x\n", hr);
646         return;
647     }
648
649     hr = IDirectInput8_Initialize(pDI, NULL, 0);
650     ok(hr == DIERR_INVALIDPARAM, "IDirectInput8_Initialize returned 0x%08x\n", hr);
651
652     hr = IDirectInput8_Initialize(pDI, NULL, DIRECTINPUT_VERSION);
653     ok(hr == DIERR_INVALIDPARAM, "IDirectInput8_Initialize returned 0x%08x\n", hr);
654
655     hr = IDirectInput8_Initialize(pDI, hInstance, 0);
656     ok(hr == DIERR_NOTINITIALIZED, "IDirectInput8_Initialize returned 0x%08x\n", hr);
657
658     /* Invalid DirectInput versions less than DIRECTINPUT_VERSION yield DIERR_BETADIRECTINPUTVERSION. */
659     hr = IDirectInput8_Initialize(pDI, hInstance, DIRECTINPUT_VERSION - 1);
660     ok(hr == DIERR_BETADIRECTINPUTVERSION, "IDirectInput8_Initialize returned 0x%08x\n", hr);
661
662     /* Invalid DirectInput versions greater than DIRECTINPUT_VERSION yield DIERR_BETADIRECTINPUTVERSION. */
663     hr = IDirectInput8_Initialize(pDI, hInstance, DIRECTINPUT_VERSION + 1);
664     ok(hr == DIERR_OLDDIRECTINPUTVERSION, "IDirectInput8_Initialize returned 0x%08x\n", hr);
665
666     hr = IDirectInput8_Initialize(pDI, hInstance, DIRECTINPUT_VERSION);
667     ok(hr == DI_OK, "IDirectInput8_Initialize returned 0x%08x\n", hr);
668
669     /* Parameters are still validated after successful initialization. */
670     hr = IDirectInput8_Initialize(pDI, hInstance, 0);
671     ok(hr == DIERR_NOTINITIALIZED, "IDirectInput8_Initialize returned 0x%08x\n", hr);
672
673     IDirectInput8_Release(pDI);
674 }
675
676 START_TEST(dinput)
677 {
678     hInstance = GetModuleHandleA(NULL);
679
680     CoInitialize(NULL);
681     test_preinitialization();
682     test_DirectInput8Create();
683     test_QueryInterface();
684     test_CreateDevice();
685     test_EnumDevices();
686     test_EnumDevicesBySemantics();
687     test_GetDeviceStatus();
688     test_RunControlPanel();
689     test_Initialize();
690     CoUninitialize();
691 }