include: Assorted spelling fixes.
[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 #include <dinputd.h>
26
27 #include "wine/test.h"
28
29 HINSTANCE hInstance;
30
31 static BOOL CALLBACK dummy_callback(const DIDEVICEINSTANCEA *instance, void *context)
32 {
33     ok(0, "Callback was invoked with parameters (%p, %p)\n", instance, context);
34     return DIENUM_STOP;
35 }
36
37 static void test_preinitialization(void)
38 {
39     static const struct
40     {
41         REFGUID rguid;
42         BOOL pdev;
43         HRESULT expected_hr;
44     } create_device_tests[] =
45     {
46         {NULL, FALSE, E_POINTER},
47         {NULL, TRUE, E_POINTER},
48         {&GUID_Unknown, FALSE, E_POINTER},
49         {&GUID_Unknown, TRUE, DIERR_NOTINITIALIZED},
50         {&GUID_SysMouse, FALSE, E_POINTER},
51         {&GUID_SysMouse, TRUE, DIERR_NOTINITIALIZED},
52     };
53
54     static const struct
55     {
56         DWORD dwDevType;
57         LPDIENUMDEVICESCALLBACKA lpCallback;
58         DWORD dwFlags;
59         HRESULT expected_hr;
60         int todo;
61     } enum_devices_tests[] =
62     {
63         {0, NULL, 0, DIERR_INVALIDPARAM},
64         {0, NULL, ~0u, DIERR_INVALIDPARAM},
65         {0, dummy_callback, 0, DIERR_NOTINITIALIZED},
66         {0, dummy_callback, ~0u, DIERR_INVALIDPARAM},
67         {0xdeadbeef, NULL, 0, DIERR_INVALIDPARAM},
68         {0xdeadbeef, NULL, ~0u, DIERR_INVALIDPARAM},
69         {0xdeadbeef, dummy_callback, 0, DIERR_INVALIDPARAM},
70         {0xdeadbeef, dummy_callback, ~0u, DIERR_INVALIDPARAM},
71     };
72
73     IDirectInput8A *pDI;
74     HRESULT hr;
75     int i;
76     IDirectInputDevice8A *pDID;
77
78     hr = CoCreateInstance(&CLSID_DirectInput8, NULL, CLSCTX_INPROC_SERVER, &IID_IDirectInput8A, (void **)&pDI);
79     if (FAILED(hr))
80     {
81         skip("Failed to instantiate a IDirectInputA instance: 0x%08x\n", hr);
82         return;
83     }
84
85     for (i = 0; i < sizeof(create_device_tests)/sizeof(create_device_tests[0]); i++)
86     {
87         if (create_device_tests[i].pdev) pDID = (void *)0xdeadbeef;
88         hr = IDirectInput8_CreateDevice(pDI, create_device_tests[i].rguid,
89                                             create_device_tests[i].pdev ? &pDID : NULL,
90                                             NULL);
91         ok(hr == create_device_tests[i].expected_hr, "[%d] IDirectInput8_CreateDevice returned 0x%08x\n", i, hr);
92         if (create_device_tests[i].pdev)
93             ok(pDID == NULL, "[%d] Output interface pointer is %p\n", i, pDID);
94     }
95
96     for (i = 0; i < sizeof(enum_devices_tests)/sizeof(enum_devices_tests[0]); i++)
97     {
98         hr = IDirectInput8_EnumDevices(pDI, enum_devices_tests[i].dwDevType,
99                                            enum_devices_tests[i].lpCallback,
100                                            NULL,
101                                            enum_devices_tests[i].dwFlags);
102         if (enum_devices_tests[i].todo)
103         {
104             todo_wine
105             ok(hr == enum_devices_tests[i].expected_hr, "[%d] IDirectInput8_EnumDevice returned 0x%08x\n", i, hr);
106         }
107         else
108             ok(hr == enum_devices_tests[i].expected_hr, "[%d] IDirectInput8_EnumDevice returned 0x%08x\n", i, hr);
109     }
110
111     hr = IDirectInput8_GetDeviceStatus(pDI, NULL);
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, &IID_IDirectInputJoyConfig8};
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)
283         {
284             int j;
285             for (j = 0; j < sizeof(iid_list)/sizeof(iid_list[0]); j++)
286             {
287                 IUnknown *pUnk1 = NULL;
288                 hr = IDirectInput8_QueryInterface(pUnk, iid_list[j], (void **)&pUnk1);
289                 ok(hr == S_OK, "[%d] IDirectInput8_QueryInterface(pUnk) returned 0x%08x\n", j, hr);
290                 ok(pUnk1 != NULL, "[%d] Output interface pointer is NULL\n", i);
291                 if (pUnk1) IUnknown_Release(pUnk1);
292             }
293             IUnknown_Release(pUnk);
294         }
295     }
296
297     for (i = 0; i < sizeof(no_interface_list)/sizeof(no_interface_list[0]); i++)
298     {
299         pUnk = (void *)0xdeadbeef;
300         hr = IDirectInput8_QueryInterface(pDI, no_interface_list[i].riid, (void **)&pUnk);
301         if (no_interface_list[i].test_todo)
302         {
303             todo_wine
304             ok(hr == E_NOINTERFACE, "[%d] IDirectInput8_QueryInterface returned 0x%08x\n", i, hr);
305             todo_wine
306             ok(pUnk == NULL, "[%d] Output interface pointer is %p\n", i, pUnk);
307
308             if (pUnk) IUnknown_Release(pUnk);
309         }
310         else
311         {
312             ok(hr == E_NOINTERFACE, "[%d] IDirectInput8_QueryInterface returned 0x%08x\n", i, hr);
313             ok(pUnk == NULL, "[%d] Output interface pointer is %p\n", i, pUnk);
314         }
315     }
316
317     IDirectInput8_Release(pDI);
318 }
319
320 static void test_CreateDevice(void)
321 {
322     IDirectInput8A *pDI;
323     HRESULT hr;
324     IDirectInputDevice8A *pDID;
325
326     hr = DirectInput8Create(hInstance, DIRECTINPUT_VERSION, &IID_IDirectInput8A, (void **)&pDI, NULL);
327     if (FAILED(hr))
328     {
329         win_skip("Failed to instantiate a IDirectInputA instance: 0x%08x\n", hr);
330         return;
331     }
332
333     hr = IDirectInput8_CreateDevice(pDI, NULL, NULL, NULL);
334     ok(hr == E_POINTER, "IDirectInput8_CreateDevice returned 0x%08x\n", hr);
335
336     pDID = (void *)0xdeadbeef;
337     hr = IDirectInput8_CreateDevice(pDI, NULL, &pDID, NULL);
338     ok(hr == E_POINTER, "IDirectInput8_CreateDevice returned 0x%08x\n", hr);
339     ok(pDID == NULL, "Output interface pointer is %p\n", pDID);
340
341     hr = IDirectInput8_CreateDevice(pDI, &GUID_Unknown, NULL, NULL);
342     ok(hr == E_POINTER, "IDirectInput8_CreateDevice returned 0x%08x\n", hr);
343
344     pDID = (void *)0xdeadbeef;
345     hr = IDirectInput8_CreateDevice(pDI, &GUID_Unknown, &pDID, NULL);
346     ok(hr == DIERR_DEVICENOTREG, "IDirectInput8_CreateDevice returned 0x%08x\n", hr);
347     ok(pDID == NULL, "Output interface pointer is %p\n", pDID);
348
349     hr = IDirectInput8_CreateDevice(pDI, &GUID_SysMouse, NULL, NULL);
350     ok(hr == E_POINTER, "IDirectInput8_CreateDevice returned 0x%08x\n", hr);
351
352     hr = IDirectInput8_CreateDevice(pDI, &GUID_SysMouse, &pDID, NULL);
353     ok(hr == DI_OK, "IDirectInput8_CreateDevice returned 0x%08x\n", hr);
354
355     IDirectInputDevice_Release(pDID);
356     IDirectInput8_Release(pDI);
357 }
358
359 struct enum_devices_test
360 {
361     unsigned int device_count;
362     BOOL return_value;
363 };
364
365 static BOOL CALLBACK enum_devices_callback(const DIDEVICEINSTANCEA *instance, void *context)
366 {
367     struct enum_devices_test *enum_test = context;
368
369     enum_test->device_count++;
370     return enum_test->return_value;
371 }
372
373 static void test_EnumDevices(void)
374 {
375     IDirectInput8A *pDI;
376     HRESULT hr;
377     struct enum_devices_test enum_test, enum_test_return;
378
379     hr = DirectInput8Create(hInstance, DIRECTINPUT_VERSION, &IID_IDirectInput8A, (void **)&pDI, NULL);
380     if (FAILED(hr))
381     {
382         win_skip("Failed to instantiate a IDirectInputA instance: 0x%08x\n", hr);
383         return;
384     }
385
386     hr = IDirectInput8_EnumDevices(pDI, 0, NULL, NULL, 0);
387     ok(hr == DIERR_INVALIDPARAM, "IDirectInput8_EnumDevices returned 0x%08x\n", hr);
388
389     hr = IDirectInput8_EnumDevices(pDI, 0, NULL, NULL, ~0u);
390     ok(hr == DIERR_INVALIDPARAM, "IDirectInput8_EnumDevices returned 0x%08x\n", hr);
391
392     /* Test crashes on Wine. */
393     if (0)
394     {
395         hr = IDirectInput8_EnumDevices(pDI, 0, enum_devices_callback, NULL, ~0u);
396         ok(hr == DIERR_INVALIDPARAM, "IDirectInput8_EnumDevices returned 0x%08x\n", hr);
397     }
398
399     hr = IDirectInput8_EnumDevices(pDI, 0xdeadbeef, NULL, NULL, 0);
400     ok(hr == DIERR_INVALIDPARAM, "IDirectInput8_EnumDevices returned 0x%08x\n", hr);
401
402     hr = IDirectInput8_EnumDevices(pDI, 0xdeadbeef, NULL, NULL, ~0u);
403     ok(hr == DIERR_INVALIDPARAM, "IDirectInput8_EnumDevices returned 0x%08x\n", hr);
404
405     hr = IDirectInput8_EnumDevices(pDI, 0xdeadbeef, enum_devices_callback, NULL, 0);
406     ok(hr == DIERR_INVALIDPARAM, "IDirectInput8_EnumDevices returned 0x%08x\n", hr);
407
408     hr = IDirectInput8_EnumDevices(pDI, 0xdeadbeef, enum_devices_callback, NULL, ~0u);
409     ok(hr == DIERR_INVALIDPARAM, "IDirectInput8_EnumDevices returned 0x%08x\n", hr);
410
411     enum_test.device_count = 0;
412     enum_test.return_value = DIENUM_CONTINUE;
413     hr = IDirectInput8_EnumDevices(pDI, 0, enum_devices_callback, &enum_test, 0);
414     ok(hr == DI_OK, "IDirectInput8_EnumDevices returned 0x%08x\n", hr);
415     ok(enum_test.device_count != 0, "Device count is %u\n", enum_test.device_count);
416
417     /* Enumeration only stops with an explicit DIENUM_STOP. */
418     enum_test_return.device_count = 0;
419     enum_test_return.return_value = 42;
420     hr = IDirectInput8_EnumDevices(pDI, 0, enum_devices_callback, &enum_test_return, 0);
421     ok(hr == DI_OK, "IDirectInput8_EnumDevices returned 0x%08x\n", hr);
422     ok(enum_test_return.device_count == enum_test.device_count,
423        "Device count is %u vs. %u\n", enum_test_return.device_count, enum_test.device_count);
424
425     enum_test.device_count = 0;
426     enum_test.return_value = DIENUM_STOP;
427     hr = IDirectInput8_EnumDevices(pDI, 0, enum_devices_callback, &enum_test, 0);
428     ok(hr == DI_OK, "IDirectInput8_EnumDevices returned 0x%08x\n", hr);
429     ok(enum_test.device_count == 1, "Device count is %u\n", enum_test.device_count);
430
431     IDirectInput8_Release(pDI);
432 }
433
434 struct enum_semantics_test
435 {
436     unsigned int device_count;
437     BOOL mouse;
438     BOOL keyboard;
439     LPDIACTIONFORMAT lpdiaf;
440     const char* username;
441 };
442
443 static DIACTION actionMapping[]=
444 {
445   /* axis */
446   { 0, 0x01008A01 /* DIAXIS_DRIVINGR_STEER */,      0, { "Steer" }   },
447   /* button */
448   { 1, 0x01000C01 /* DIBUTTON_DRIVINGR_SHIFTUP */,  0, { "Upshift" } },
449   /* keyboard key */
450   { 2, DIKEYBOARD_SPACE,                            0, { "Missile" } },
451   /* mouse button */
452   { 3, DIMOUSE_BUTTON0,                             0, { "Select" }  },
453   /* mouse axis */
454   { 4, DIMOUSE_YAXIS,                               0, { "Y Axis" }  }
455 };
456
457 static BOOL CALLBACK enum_semantics_callback(LPCDIDEVICEINSTANCE lpddi, IDirectInputDevice8A *lpdid, DWORD dwFlags, DWORD dwRemaining, void *context)
458 {
459     struct enum_semantics_test *data = context;
460
461     if (context == NULL) return DIENUM_STOP;
462
463     data->device_count++;
464
465     if (IsEqualGUID(&lpddi->guidInstance, &GUID_SysKeyboard)) data->keyboard = TRUE;
466
467     if (IsEqualGUID(&lpddi->guidInstance, &GUID_SysMouse)) data->mouse = TRUE;
468
469     return DIENUM_CONTINUE;
470 }
471
472 static BOOL CALLBACK set_action_map_callback(LPCDIDEVICEINSTANCE lpddi, IDirectInputDevice8A *lpdid, DWORD dwFlags, DWORD dwRemaining, void *context)
473 {
474     HRESULT hr;
475     struct enum_semantics_test *data = context;
476
477     /* Building and setting an action map */
478     /* It should not use any pre-stored mappings so we use DIDBAM_INITIALIZE */
479     hr = IDirectInputDevice8_BuildActionMap(lpdid, data->lpdiaf, NULL, DIDBAM_INITIALIZE);
480     ok (SUCCEEDED(hr), "BuildActionMap failed hr=%08x\n", hr);
481
482     hr = IDirectInputDevice8_SetActionMap(lpdid, data->lpdiaf, data->username, 0);
483     ok (SUCCEEDED(hr), "SetActionMap failed hr=%08x\n", hr);
484
485     return DIENUM_CONTINUE;
486 }
487
488 static void test_EnumDevicesBySemantics(void)
489 {
490     IDirectInput8A *pDI;
491     HRESULT hr;
492     DIACTIONFORMATA diaf;
493     const GUID ACTION_MAPPING_GUID = { 0x1, 0x2, 0x3, { 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb } };
494     struct enum_semantics_test data = { 0, FALSE, FALSE, &diaf, NULL };
495     int device_total = 0;
496
497     hr = DirectInput8Create(hInstance, DIRECTINPUT_VERSION, &IID_IDirectInput8A, (void **)&pDI, NULL);
498     if (FAILED(hr))
499     {
500         win_skip("Failed to instantiate a IDirectInputA instance: 0x%08x\n", hr);
501         return;
502     }
503
504     memset (&diaf, 0, sizeof(diaf));
505     diaf.dwSize = sizeof(diaf);
506     diaf.dwActionSize = sizeof(DIACTION);
507     diaf.dwNumActions = sizeof(actionMapping) / sizeof(actionMapping[0]);
508     diaf.dwDataSize = 4 * diaf.dwNumActions;
509     diaf.rgoAction = actionMapping;
510     diaf.guidActionMap = ACTION_MAPPING_GUID;
511     diaf.dwGenre = 0x01000000; /* DIVIRTUAL_DRIVING_RACE */
512     diaf.dwBufferSize = 32;
513
514     /* Test enumerating all attached and installed devices */
515     data.keyboard = FALSE;
516     data.mouse = FALSE;
517     data.device_count = 0;
518     hr = IDirectInput8_EnumDevicesBySemantics(pDI, NULL, &diaf, enum_semantics_callback, &data, DIEDBSFL_ATTACHEDONLY);
519     ok (data.device_count > 0, "EnumDevicesBySemantics did not call the callback hr=%08x\n", hr);
520     ok (data.keyboard, "EnumDevicesBySemantics should enumerate the keyboard\n");
521     ok (data.mouse, "EnumDevicesBySemantics should enumerate the mouse\n");
522
523     /* Enumerate Force feedback devices. We should get no mouse nor keyboard */
524     data.keyboard = FALSE;
525     data.mouse = FALSE;
526     hr = IDirectInput8_EnumDevicesBySemantics(pDI, NULL, &diaf, enum_semantics_callback, &data, DIEDBSFL_FORCEFEEDBACK);
527     ok (SUCCEEDED(hr), "EnumDevicesBySemantics failed hr=%08x\n", hr);
528     ok (!data.keyboard, "Keyboard should not be enumerated when asking for forcefeedback\n");
529     ok (!data.mouse, "Mouse should not be enumerated when asking for forcefeedback\n");
530
531     /* Enumerate available devices. That is devices not owned by any user.
532        Before setting the action map for all devices we still have them available. */
533     data.device_count = 0;
534     hr = IDirectInput8_EnumDevicesBySemantics(pDI, NULL, &diaf, enum_semantics_callback, &data, DIEDBSFL_AVAILABLEDEVICES);
535     ok (SUCCEEDED(hr), "EnumDevicesBySemantics failed hr=%08x\n", hr);
536     ok (data.device_count > 0, "There should be devices available before action mapping available=%d\n", data.device_count);
537
538     /* Keep the device total */
539     device_total = data.device_count;
540
541     /* This enumeration builds and sets the action map for all devices with a NULL username */
542     hr = IDirectInput8_EnumDevicesBySemantics(pDI, NULL, &diaf, set_action_map_callback, &data, DIEDBSFL_ATTACHEDONLY);
543     ok (SUCCEEDED(hr), "EnumDevicesBySemantics failed: hr=%08x\n", hr);
544
545     /* After a successful action mapping we should have no devices available */
546     data.device_count = 0;
547     hr = IDirectInput8_EnumDevicesBySemantics(pDI, NULL, &diaf, enum_semantics_callback, &data, DIEDBSFL_AVAILABLEDEVICES);
548     ok (SUCCEEDED(hr), "EnumDevicesBySemantics failed hr=%08x\n", hr);
549     todo_wine ok (data.device_count == 0, "No device should be available after action mapping available=%d\n", data.device_count);
550
551     /* Now we'll give all the devices to a specific user */
552     data.username = "Sh4d0w M4g3";
553     hr = IDirectInput8_EnumDevicesBySemantics(pDI, NULL, &diaf, set_action_map_callback, &data, DIEDBSFL_ATTACHEDONLY);
554     ok (SUCCEEDED(hr), "EnumDevicesBySemantics failed: hr=%08x\n", hr);
555
556     /* Testing with the default user, DIEDBSFL_THISUSER has no effect */
557     data.device_count = 0;
558     hr = IDirectInput8_EnumDevicesBySemantics(pDI, NULL, &diaf, enum_semantics_callback, &data, DIEDBSFL_THISUSER);
559     ok (SUCCEEDED(hr), "EnumDevicesBySemantics failed hr=%08x\n", hr);
560     ok (data.device_count == device_total, "THISUSER has no effect with NULL username owned=%d, expected=%d\n", data.device_count, device_total);
561
562     /* Using an empty user string is the same as passing NULL, DIEDBSFL_THISUSER has no effect */
563     data.device_count = 0;
564     hr = IDirectInput8_EnumDevicesBySemantics(pDI, "", &diaf, enum_semantics_callback, &data, DIEDBSFL_THISUSER);
565     ok (SUCCEEDED(hr), "EnumDevicesBySemantics failed hr=%08x\n", hr);
566     ok (data.device_count == device_total, "THISUSER has no effect with \"\" as username owned=%d, expected=%d\n", data.device_count, device_total);
567
568     /* Testing with a user with no ownership of the devices */
569     data.device_count = 0;
570     hr = IDirectInput8_EnumDevicesBySemantics(pDI, "Ninja Brian", &diaf, enum_semantics_callback, &data, DIEDBSFL_THISUSER);
571     ok (SUCCEEDED(hr), "EnumDevicesBySemantics failed hr=%08x\n", hr);
572     todo_wine ok (data.device_count == 0, "This user should own no devices owned=%d\n", data.device_count);
573
574     /* Sh4d0w M4g3 has ownership of all devices */
575     data.device_count = 0;
576     hr = IDirectInput8_EnumDevicesBySemantics(pDI, "Sh4d0w M4g3", &diaf, enum_semantics_callback, &data, DIEDBSFL_THISUSER);
577     ok (SUCCEEDED(hr), "EnumDevicesBySemantics failed hr=%08x\n", hr);
578     ok (data.device_count == device_total, "This user should own %d devices owned=%d\n", device_total, data.device_count);
579
580     /* The call fails with a zeroed GUID */
581     memset(&diaf.guidActionMap, 0, sizeof(GUID));
582     hr = IDirectInput8_EnumDevicesBySemantics(pDI, NULL, &diaf, enum_semantics_callback, NULL, 0);
583     todo_wine ok(FAILED(hr), "EnumDevicesBySemantics succeeded with invalid GUID hr=%08x\n", hr);
584
585     IDirectInput8_Release(pDI);
586 }
587
588 static void test_GetDeviceStatus(void)
589 {
590     IDirectInput8A *pDI;
591     HRESULT hr;
592
593     hr = DirectInput8Create(hInstance, DIRECTINPUT_VERSION, &IID_IDirectInput8A, (void **)&pDI, NULL);
594     if (FAILED(hr))
595     {
596         win_skip("Failed to instantiate a IDirectInputA instance: 0x%08x\n", hr);
597         return;
598     }
599
600     hr = IDirectInput8_GetDeviceStatus(pDI, NULL);
601     ok(hr == E_POINTER, "IDirectInput8_GetDeviceStatus returned 0x%08x\n", hr);
602
603     hr = IDirectInput8_GetDeviceStatus(pDI, &GUID_Unknown);
604     todo_wine
605     ok(hr == DIERR_DEVICENOTREG, "IDirectInput8_GetDeviceStatus returned 0x%08x\n", hr);
606
607     hr = IDirectInput8_GetDeviceStatus(pDI, &GUID_SysMouse);
608     ok(hr == DI_OK, "IDirectInput8_GetDeviceStatus returned 0x%08x\n", hr);
609
610     IDirectInput8_Release(pDI);
611 }
612
613 static void test_RunControlPanel(void)
614 {
615     IDirectInput8A *pDI;
616     HRESULT hr;
617
618     hr = DirectInput8Create(hInstance, DIRECTINPUT_VERSION, &IID_IDirectInput8A, (void **)&pDI, NULL);
619     if (FAILED(hr))
620     {
621         win_skip("Failed to instantiate a IDirectInputA instance: 0x%08x\n", hr);
622         return;
623     }
624
625     if (winetest_interactive)
626     {
627         hr = IDirectInput8_RunControlPanel(pDI, NULL, 0);
628         ok(hr == S_OK, "IDirectInput8_RunControlPanel returned 0x%08x\n", hr);
629
630         hr = IDirectInput8_RunControlPanel(pDI, GetDesktopWindow(), 0);
631         ok(hr == S_OK, "IDirectInput8_RunControlPanel returned 0x%08x\n", hr);
632     }
633
634     hr = IDirectInput8_RunControlPanel(pDI, NULL, ~0u);
635     ok(hr == DIERR_INVALIDPARAM, "IDirectInput8_RunControlPanel returned 0x%08x\n", hr);
636
637     hr = IDirectInput8_RunControlPanel(pDI, (HWND)0xdeadbeef, 0);
638     ok(hr == E_HANDLE, "IDirectInput8_RunControlPanel returned 0x%08x\n", hr);
639
640     hr = IDirectInput8_RunControlPanel(pDI, (HWND)0xdeadbeef, ~0u);
641     ok(hr == E_HANDLE, "IDirectInput8_RunControlPanel returned 0x%08x\n", hr);
642
643     IDirectInput8_Release(pDI);
644 }
645
646 static void test_Initialize(void)
647 {
648     IDirectInput8A *pDI;
649     HRESULT hr;
650
651     hr = DirectInput8Create(hInstance, DIRECTINPUT_VERSION, &IID_IDirectInput8A, (void **)&pDI, NULL);
652     if (FAILED(hr))
653     {
654         win_skip("Failed to instantiate a IDirectInputA instance: 0x%08x\n", hr);
655         return;
656     }
657
658     hr = IDirectInput8_Initialize(pDI, NULL, 0);
659     ok(hr == DIERR_INVALIDPARAM, "IDirectInput8_Initialize returned 0x%08x\n", hr);
660
661     hr = IDirectInput8_Initialize(pDI, NULL, DIRECTINPUT_VERSION);
662     ok(hr == DIERR_INVALIDPARAM, "IDirectInput8_Initialize returned 0x%08x\n", hr);
663
664     hr = IDirectInput8_Initialize(pDI, hInstance, 0);
665     ok(hr == DIERR_NOTINITIALIZED, "IDirectInput8_Initialize returned 0x%08x\n", hr);
666
667     /* Invalid DirectInput versions less than DIRECTINPUT_VERSION yield DIERR_BETADIRECTINPUTVERSION. */
668     hr = IDirectInput8_Initialize(pDI, hInstance, DIRECTINPUT_VERSION - 1);
669     ok(hr == DIERR_BETADIRECTINPUTVERSION, "IDirectInput8_Initialize returned 0x%08x\n", hr);
670
671     /* Invalid DirectInput versions greater than DIRECTINPUT_VERSION yield DIERR_BETADIRECTINPUTVERSION. */
672     hr = IDirectInput8_Initialize(pDI, hInstance, DIRECTINPUT_VERSION + 1);
673     ok(hr == DIERR_OLDDIRECTINPUTVERSION, "IDirectInput8_Initialize returned 0x%08x\n", hr);
674
675     hr = IDirectInput8_Initialize(pDI, hInstance, DIRECTINPUT_VERSION);
676     ok(hr == DI_OK, "IDirectInput8_Initialize returned 0x%08x\n", hr);
677
678     /* Parameters are still validated after successful initialization. */
679     hr = IDirectInput8_Initialize(pDI, hInstance, 0);
680     ok(hr == DIERR_NOTINITIALIZED, "IDirectInput8_Initialize returned 0x%08x\n", hr);
681
682     IDirectInput8_Release(pDI);
683 }
684
685 START_TEST(dinput)
686 {
687     hInstance = GetModuleHandleA(NULL);
688
689     CoInitialize(NULL);
690     test_preinitialization();
691     test_DirectInput8Create();
692     test_QueryInterface();
693     test_CreateDevice();
694     test_EnumDevices();
695     test_EnumDevicesBySemantics();
696     test_GetDeviceStatus();
697     test_RunControlPanel();
698     test_Initialize();
699     CoUninitialize();
700 }