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