Added dinput tests.
[wine] / dlls / dinput / tests / joystick.c
1 /*
2  * Copyright (c) 2004-2005 Robert Reif
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17  */
18
19 #define STRICT
20 #define DIRECTINPUT_VERSION 0x0700
21
22 #define NONAMELESSSTRUCT
23 #define NONAMELESSUNION
24 #include <windows.h>
25
26 #include <math.h>
27 #include <stdlib.h>
28
29 #include "wine/test.h"
30 #include "windef.h"
31 #include "wingdi.h"
32 #include "dinput.h"
33 #include "dxerr8.h"
34 #include "dinput_test.h"
35
36 #define numObjects(x) (sizeof(x) / sizeof(x[0]))
37
38 static const DIOBJECTDATAFORMAT dfDIJoystickTest[] = {
39   { &GUID_XAxis,DIJOFS_X,DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0},
40   { &GUID_YAxis,DIJOFS_Y,DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0},
41   { &GUID_ZAxis,DIJOFS_Z,DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0},
42   { &GUID_RxAxis,DIJOFS_RX,DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0},
43   { &GUID_RyAxis,DIJOFS_RY,DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0},
44   { &GUID_RzAxis,DIJOFS_RZ,DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0},
45   { &GUID_Button,DIJOFS_BUTTON(0),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
46   { &GUID_Button,DIJOFS_BUTTON(1),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
47   { &GUID_Button,DIJOFS_BUTTON(2),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
48   { &GUID_Button,DIJOFS_BUTTON(3),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
49   { &GUID_Button,DIJOFS_BUTTON(4),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
50   { &GUID_Button,DIJOFS_BUTTON(5),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
51   { &GUID_Button,DIJOFS_BUTTON(6),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
52   { &GUID_Button,DIJOFS_BUTTON(7),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
53   { &GUID_Button,DIJOFS_BUTTON(8),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
54   { &GUID_Button,DIJOFS_BUTTON(9),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
55   { &GUID_Button,DIJOFS_BUTTON(10),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
56 };
57
58 static const DIDATAFORMAT c_dfDIJoystickTest = {
59     sizeof(DIDATAFORMAT),
60     sizeof(DIOBJECTDATAFORMAT),
61     DIDF_ABSAXIS,
62     sizeof(DIJOYSTATE2),
63     numObjects(dfDIJoystickTest),
64     (LPDIOBJECTDATAFORMAT)dfDIJoystickTest
65 };
66
67 HWND get_hwnd()
68 {
69     HWND hwnd=GetForegroundWindow();
70     if (!hwnd)
71         hwnd=GetDesktopWindow();
72     return hwnd;
73 }
74
75 typedef struct tagJoystickInfo
76 {
77     LPDIRECTINPUTDEVICE pJoystick;
78     int axis;
79     int pov;
80     int button;
81 } JoystickInfo;
82
83 static BOOL CALLBACK EnumAxes(
84     const DIDEVICEOBJECTINSTANCE* pdidoi,
85     VOID* pContext)
86 {
87     HRESULT hr;
88     JoystickInfo * info = (JoystickInfo *)pContext;
89
90     if (IsEqualIID(&pdidoi->guidType, &GUID_XAxis) ||
91         IsEqualIID(&pdidoi->guidType, &GUID_YAxis) ||
92         IsEqualIID(&pdidoi->guidType, &GUID_ZAxis) ||
93         IsEqualIID(&pdidoi->guidType, &GUID_RxAxis) ||
94         IsEqualIID(&pdidoi->guidType, &GUID_RyAxis) ||
95         IsEqualIID(&pdidoi->guidType, &GUID_RzAxis) ||
96         IsEqualIID(&pdidoi->guidType, &GUID_Slider)) {
97         DIPROPRANGE diprg;
98         diprg.diph.dwSize       = sizeof(DIPROPRANGE);
99         diprg.diph.dwHeaderSize = sizeof(DIPROPHEADER);
100         diprg.diph.dwHow        = DIPH_BYID;
101         diprg.diph.dwObj        = pdidoi->dwType;
102         diprg.lMin              = -1000;
103         diprg.lMax              = +1000;
104
105         hr = IDirectInputDevice_SetProperty(info->pJoystick, DIPROP_RANGE, NULL);
106         ok(hr==E_POINTER,"IDirectInputDevice_SetProperty() should have returned "
107            "E_POINTER, returned: %s\n", DXGetErrorString8(hr));
108
109         hr = IDirectInputDevice_SetProperty(info->pJoystick, DIPROP_RANGE, &diprg.diph);
110         ok(hr==DI_OK,"IDirectInputDevice_SetProperty() failed: %s\n", DXGetErrorString8(hr));
111
112         info->axis++;
113     } else if (IsEqualIID(&pdidoi->guidType, &GUID_POV))
114         info->pov++;
115     else if (IsEqualIID(&pdidoi->guidType, &GUID_Button))
116         info->button++;
117
118     return DIENUM_CONTINUE;
119 }
120
121 static BOOL CALLBACK EnumJoysticks(
122     LPCDIDEVICEINSTANCE lpddi,
123     LPVOID pvRef)
124 {
125     HRESULT hr;
126     LPDIRECTINPUT pDI = (LPDIRECTINPUT)pvRef;
127     LPDIRECTINPUTDEVICE pJoystick;
128     DIDATAFORMAT format;
129     DIDEVCAPS caps;
130     DIJOYSTATE2 js;
131     JoystickInfo info;
132     int i, count;
133     ULONG ref;
134
135     hr = IDirectInput_CreateDevice(pDI, &lpddi->guidInstance, NULL, NULL);
136     ok(hr==E_POINTER,"IDirectInput_CreateDevice() should have returned "
137        "E_POINTER, returned: %s\n", DXGetErrorString8(hr));
138
139     hr = IDirectInput_CreateDevice(pDI, NULL, &pJoystick, NULL);
140     ok(hr==E_POINTER,"IDirectInput_CreateDevice() should have returned "
141        "E_POINTER, returned: %s\n", DXGetErrorString8(hr));
142
143     hr = IDirectInput_CreateDevice(pDI, NULL, NULL, NULL);
144     ok(hr==E_POINTER,"IDirectInput_CreateDevice() should have returned "
145        "E_POINTER, returned: %s\n", DXGetErrorString8(hr));
146
147     hr = IDirectInput_CreateDevice(pDI, &lpddi->guidInstance, &pJoystick, NULL);
148     ok(hr==DI_OK,"IDirectInput_CreateDevice() failed: %s\n",
149        DXGetErrorString8(hr));
150     if (hr!=DI_OK)
151         goto DONE;
152
153     trace("---- %s ----\n", lpddi->tszProductName);
154
155     hr = IDirectInputDevice_SetDataFormat(pJoystick, NULL);
156     ok(hr==E_POINTER,"IDirectInputDevice_SetDataFormat() should have returned "
157        "E_POINTER, returned: %s\n", DXGetErrorString8(hr));
158
159     ZeroMemory(&format, sizeof(format));
160     hr = IDirectInputDevice_SetDataFormat(pJoystick, &format);
161     ok(hr==DIERR_INVALIDPARAM,"IDirectInputDevice_SetDataFormat() should have "
162        "returned DIERR_INVALIDPARAM, returned: %s\n", DXGetErrorString8(hr));
163
164     /* try the default formats */
165     hr = IDirectInputDevice_SetDataFormat(pJoystick, &c_dfDIJoystick);
166     ok(hr==DI_OK,"IDirectInputDevice_SetDataFormat() failed: %s\n",
167        DXGetErrorString8(hr));
168
169     hr = IDirectInputDevice_SetDataFormat(pJoystick, &c_dfDIJoystick2);
170     ok(hr==DI_OK,"IDirectInputDevice_SetDataFormat() failed: %s\n",
171        DXGetErrorString8(hr));
172
173     /* try an alternate format */
174     hr = IDirectInputDevice_SetDataFormat(pJoystick, &c_dfDIJoystickTest);
175     ok(hr==DI_OK,"IDirectInputDevice_SetDataFormat() failed: %s\n",
176        DXGetErrorString8(hr));
177
178     hr = IDirectInputDevice_SetDataFormat(pJoystick, &c_dfDIJoystick2);
179     ok(hr==DI_OK,"IDirectInputDevice_SetDataFormat() failed: %s\n",
180        DXGetErrorString8(hr));
181     if (hr != DI_OK)
182         goto RELEASE;
183
184     hr = IDirectInputDevice_SetCooperativeLevel(pJoystick, get_hwnd(),
185                                                 DISCL_EXCLUSIVE | DISCL_FOREGROUND);
186     ok(hr==DI_OK,"IDirectInputDevice_SetCooperativeLevel() failed: %s\n",
187        DXGetErrorString8(hr));
188
189     /* get capabilities */
190     hr = IDirectInputDevice_GetCapabilities(pJoystick, NULL);
191     ok(hr==E_POINTER,"IDirectInputDevice_GetCapabilities() "
192        "should have returned E_POINTER, returned: %s\n",
193        DXGetErrorString8(hr));
194
195     ZeroMemory(&caps, sizeof(caps));
196     hr = IDirectInputDevice_GetCapabilities(pJoystick, &caps);
197     ok(hr==DIERR_INVALIDPARAM,"IDirectInputDevice_GetCapabilities() "
198        "should have returned DIERR_INVALIDPARAM, returned: %s\n",
199        DXGetErrorString8(hr));
200
201     caps.dwSize = sizeof(caps);
202     hr = IDirectInputDevice_GetCapabilities(pJoystick, &caps);
203     ok(hr==DI_OK,"IDirectInputDevice_GetCapabilities() failed: %s\n",
204        DXGetErrorString8(hr));
205
206     ZeroMemory(&info, sizeof(info));
207     info.pJoystick = pJoystick;
208
209     /* enumerate objects */
210     hr = IDirectInputDevice_EnumObjects(pJoystick,  EnumAxes, (VOID*)&info, DIDFT_ALL);
211     ok(hr==DI_OK,"IDirectInputDevice_EnumObjects() failed: %s\n",
212        DXGetErrorString8(hr));
213
214     ok(caps.dwAxes == info.axis, "Number of enumerated axes doesn't match capabilities\n");
215     ok(caps.dwButtons == info.button, "Number of enumerated buttons doesn't match capabilities\n");
216     ok(caps.dwPOVs == info.pov, "Number of enumerated buttons doesn't match capabilities\n");
217
218     hr = IDirectInputDevice_Acquire(pJoystick);
219     ok(hr==DI_OK,"IDirectInputDevice_Acquire() failed: %s\n",
220        DXGetErrorString8(hr));
221     if (hr != DI_OK)
222         goto RELEASE;
223
224     if (winetest_interactive) {
225         trace("You have 30 seconds to test all axes, sliders, POVs and buttons\n");
226         count = 300;
227     } else
228         count = 1;
229
230     trace("\n");
231     for (i = 0; i < count; i++) {
232         hr = IDirectInputDevice_GetDeviceState(pJoystick, sizeof(DIJOYSTATE2), &js);
233         ok(hr==DI_OK,"IDirectInputDevice_GetDeviceState() failed: %s\n",
234            DXGetErrorString8(hr));
235         if (hr != DI_OK)
236             break;
237         trace("X%5ld Y%5ld Z%5ld Rx%5ld Ry%5ld Rz%5ld "
238               "S0%5ld S1%5ld POV0%5ld POV1%5ld POV2%5ld POV3%5ld "
239               "B %d %d %d %d %d %d %d %d %d %d %d %d\r",
240               js.lX, js.lY, js.lZ, js.lRx, js.lRy, js.lRz,
241               js.rglSlider[0], js.rglSlider[1],
242               js.rgdwPOV[0], js.rgdwPOV[1], js.rgdwPOV[2], js.rgdwPOV[3],
243               js.rgbButtons[0]>>7, js.rgbButtons[1]>>7, js.rgbButtons[2]>>7,
244               js.rgbButtons[3]>>7, js.rgbButtons[4]>>7, js.rgbButtons[5]>>7,
245               js.rgbButtons[6]>>7, js.rgbButtons[7]>>7, js.rgbButtons[8]>>7,
246               js.rgbButtons[9]>>7, js.rgbButtons[10]>>7, js.rgbButtons[11]>>7);
247         Sleep(100);
248     }
249     trace("\n");
250
251     hr = IDirectInputDevice_Unacquire(pJoystick);
252     ok(hr==DI_OK,"IDirectInputDevice_Unacquire() failed: %s\n",
253        DXGetErrorString8(hr));
254
255 RELEASE:
256     ref = IDirectInputDevice_Release(pJoystick);
257     ok(ref==0,"IDirectInputDevice_Release() reference count = %ld\n", ref);
258
259 DONE:
260     return DIENUM_CONTINUE;
261 }
262
263 static void joystick_tests()
264 {
265     HRESULT hr;
266     LPDIRECTINPUT pDI;
267     ULONG ref;
268
269     hr = DirectInputCreate(GetModuleHandle(NULL), DIRECTINPUT_VERSION, &pDI, NULL);
270     ok(hr==DI_OK, "DirectInputCreate() failed: %s\n", DXGetErrorString8(hr));
271     if (hr!=DI_OK)
272         return;
273
274     hr = IDirectInput_EnumDevices(pDI, DIDEVTYPE_JOYSTICK, EnumJoysticks, pDI, DIEDFL_ALLDEVICES);
275     ok(hr==DI_OK,"IDirectInput_EnumDevices() failed: %s\n", DXGetErrorString8(hr));
276
277     ref = IDirectInput_Release(pDI);
278     ok(ref==0,"IDirectInput_Release() reference count = %ld\n", ref);
279 }
280
281 START_TEST(joystick)
282 {
283     CoInitialize(NULL);
284
285     trace("DLL Version: %s\n", get_file_version("dinput.dll"));
286
287     joystick_tests();
288
289     CoUninitialize();
290 }