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