[DINPUT_WINETEST] Sync with Wine Staging 3.3. CORE-14434
[reactos.git] / modules / rostests / winetests / dinput / 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., 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 <math.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27
28 #include "wine/test.h"
29 #include "windef.h"
30 #include "wingdi.h"
31 #include "dinput.h"
32
33 #define numObjects(x) (sizeof(x) / sizeof(x[0]))
34
35 typedef struct tagUserData {
36 IDirectInputA *pDI;
37 DWORD version;
38 } UserData;
39
40 static const DIOBJECTDATAFORMAT dfDIJoystickTest[] = {
41 { &GUID_XAxis,DIJOFS_X,DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0},
42 { &GUID_YAxis,DIJOFS_Y,DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0},
43 { &GUID_ZAxis,DIJOFS_Z,DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0},
44 { &GUID_RxAxis,DIJOFS_RX,DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0},
45 { &GUID_RyAxis,DIJOFS_RY,DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0},
46 { &GUID_RzAxis,DIJOFS_RZ,DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0},
47 { &GUID_Button,DIJOFS_BUTTON(0),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
48 { &GUID_Button,DIJOFS_BUTTON(1),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
49 { &GUID_Button,DIJOFS_BUTTON(2),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
50 { &GUID_Button,DIJOFS_BUTTON(3),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
51 { &GUID_Button,DIJOFS_BUTTON(4),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
52 { &GUID_Button,DIJOFS_BUTTON(5),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
53 { &GUID_Button,DIJOFS_BUTTON(6),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
54 { &GUID_Button,DIJOFS_BUTTON(7),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
55 { &GUID_Button,DIJOFS_BUTTON(8),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
56 { &GUID_Button,DIJOFS_BUTTON(9),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
57 { &GUID_Button,DIJOFS_BUTTON(10),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
58 };
59
60 static const DIDATAFORMAT c_dfDIJoystickTest = {
61 sizeof(DIDATAFORMAT),
62 sizeof(DIOBJECTDATAFORMAT),
63 DIDF_ABSAXIS,
64 sizeof(DIJOYSTATE2),
65 numObjects(dfDIJoystickTest),
66 (LPDIOBJECTDATAFORMAT)dfDIJoystickTest
67 };
68
69 static HWND get_hwnd(void)
70 {
71 HWND hwnd=GetForegroundWindow();
72 if (!hwnd)
73 hwnd=GetDesktopWindow();
74 return hwnd;
75 }
76
77 typedef struct tagJoystickInfo
78 {
79 IDirectInputDeviceA *pJoystick;
80 DWORD axis;
81 DWORD pov;
82 DWORD button;
83 LONG lMin, lMax;
84 DWORD dZone;
85 } JoystickInfo;
86
87 static int get_refcount(IUnknown *object)
88 {
89 IUnknown_AddRef( object );
90 return IUnknown_Release( object );
91 }
92
93 static BOOL CALLBACK EnumAxes(const DIDEVICEOBJECTINSTANCEA *pdidoi, void *pContext)
94 {
95 HRESULT hr;
96 JoystickInfo * info = pContext;
97
98 if (IsEqualIID(&pdidoi->guidType, &GUID_XAxis) ||
99 IsEqualIID(&pdidoi->guidType, &GUID_YAxis) ||
100 IsEqualIID(&pdidoi->guidType, &GUID_ZAxis) ||
101 IsEqualIID(&pdidoi->guidType, &GUID_RxAxis) ||
102 IsEqualIID(&pdidoi->guidType, &GUID_RyAxis) ||
103 IsEqualIID(&pdidoi->guidType, &GUID_RzAxis) ||
104 IsEqualIID(&pdidoi->guidType, &GUID_Slider))
105 {
106 DIPROPRANGE diprg;
107 DIPROPDWORD dipdw;
108
109 diprg.diph.dwSize = sizeof(DIPROPRANGE);
110 diprg.diph.dwHeaderSize = sizeof(DIPROPHEADER);
111 diprg.diph.dwHow = DIPH_BYID;
112 diprg.diph.dwObj = pdidoi->dwType;
113
114 dipdw.diph.dwSize = sizeof(dipdw);
115 dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
116 dipdw.diph.dwHow = DIPH_BYID;
117 dipdw.diph.dwObj = pdidoi->dwType;
118
119 hr = IDirectInputDevice_GetProperty(info->pJoystick, DIPROP_RANGE, &diprg.diph);
120 ok(SUCCEEDED(hr), "IDirectInputDevice_GetProperty() failed: %08x\n", hr);
121 ok(info->lMin == diprg.lMin && info->lMax == diprg.lMax, "Min/Max range invalid: "
122 "expected %d..%d got %d..%d\n", info->lMin, info->lMax, diprg.lMin, diprg.lMax);
123
124 diprg.lMin = -2000;
125 diprg.lMax = +2000;
126
127 hr = IDirectInputDevice_SetProperty(info->pJoystick, DIPROP_RANGE, NULL);
128 ok(hr==E_INVALIDARG,"IDirectInputDevice_SetProperty() should have returned "
129 "E_INVALIDARG, returned: %08x\n", hr);
130
131 hr = IDirectInputDevice_SetProperty(info->pJoystick, DIPROP_RANGE, &diprg.diph);
132 ok(hr==DI_OK,"IDirectInputDevice_SetProperty() failed: %08x\n", hr);
133
134 /* dead zone */
135 hr = IDirectInputDevice_GetProperty(info->pJoystick, DIPROP_DEADZONE, &dipdw.diph);
136 ok(SUCCEEDED(hr), "IDirectInputDevice_GetProperty() failed: %08x\n", hr);
137 ok(info->dZone == dipdw.dwData, "deadzone invalid: expected %d got %d\n",
138 info->dZone, dipdw.dwData);
139
140 dipdw.dwData = 123;
141
142 hr = IDirectInputDevice_SetProperty(info->pJoystick, DIPROP_DEADZONE, &dipdw.diph);
143 ok(hr==DI_OK,"IDirectInputDevice_SetProperty() failed: %08x\n", hr);
144
145 /* ensure DIDOI_ASPECTPOSITION is set for axes objects */
146 ok(pdidoi->dwFlags & DIDOI_ASPECTPOSITION, "Missing DIDOI_ASPECTPOSITION, flags are 0x%x\n",
147 pdidoi->dwFlags);
148
149 info->axis++;
150 } else if (IsEqualIID(&pdidoi->guidType, &GUID_POV))
151 info->pov++;
152 else if (IsEqualIID(&pdidoi->guidType, &GUID_Button))
153 info->button++;
154
155 return DIENUM_CONTINUE;
156 }
157
158 static const struct effect_id
159 {
160 const GUID *guid;
161 int dieft;
162 const char *name;
163 } effect_conversion[] = {
164 {&GUID_ConstantForce, DIEFT_CONSTANTFORCE, "Constant"},
165 {&GUID_RampForce, DIEFT_RAMPFORCE, "Ramp"},
166 {&GUID_Square, DIEFT_PERIODIC, "Square"},
167 {&GUID_Sine, DIEFT_PERIODIC, "Sine"},
168 {&GUID_Triangle, DIEFT_PERIODIC, "Triangle"},
169 {&GUID_SawtoothUp, DIEFT_PERIODIC, "Saw Tooth Up"},
170 {&GUID_SawtoothDown, DIEFT_PERIODIC, "Saw Tooth Down"},
171 {&GUID_Spring, DIEFT_CONDITION, "Spring"},
172 {&GUID_Damper, DIEFT_CONDITION, "Damper"},
173 {&GUID_Inertia, DIEFT_CONDITION, "Inertia"},
174 {&GUID_Friction, DIEFT_CONDITION, "Friction"},
175 {&GUID_CustomForce, DIEFT_CUSTOMFORCE, "Custom"}
176 };
177
178 static const struct effect_id* effect_from_guid(const GUID *guid)
179 {
180 unsigned int i;
181 for (i = 0; i < sizeof(effect_conversion) / sizeof(effect_conversion[0]); i++)
182 if (IsEqualGUID(guid, effect_conversion[i].guid))
183 return &effect_conversion[i];
184 return NULL;
185 }
186
187 struct effect_enum
188 {
189 DIEFFECT eff;
190 GUID guid;
191 int effect_count;
192 const char *effect_name;
193 };
194
195 /* The last enumerated effect will be used for force feedback testing */
196 static BOOL CALLBACK EnumEffects(const DIEFFECTINFOA *lpef, void *ref)
197 {
198 const struct effect_id *id = effect_from_guid(&lpef->guid);
199 static union
200 {
201 DICONSTANTFORCE constant;
202 DIPERIODIC periodic;
203 DIRAMPFORCE ramp;
204 DICONDITION condition[2];
205 } specific;
206 struct effect_enum *data = ref;
207 int type = DIDFT_GETTYPE(lpef->dwEffType);
208
209 /* Insanity check */
210 if (!id)
211 {
212 ok(0, "unsupported effect enumerated, GUID %s!\n", wine_dbgstr_guid(&lpef->guid));
213 return DIENUM_CONTINUE;
214 }
215 trace("controller supports '%s' effect\n", id->name);
216 ok(type == id->dieft, "Invalid effect type, expected 0x%x, got 0x%x\n",
217 id->dieft, lpef->dwEffType);
218
219 /* Can't use custom for test as we don't know the data format */
220 if (type == DIEFT_CUSTOMFORCE)
221 return DIENUM_CONTINUE;
222
223 data->effect_count++;
224 data->effect_name = id->name;
225 data->guid = *id->guid;
226
227 ZeroMemory(&specific, sizeof(specific));
228 switch (type)
229 {
230 case DIEFT_PERIODIC:
231 data->eff.cbTypeSpecificParams = sizeof(specific.periodic);
232 data->eff.lpvTypeSpecificParams = &specific.periodic;
233 specific.periodic.dwMagnitude = DI_FFNOMINALMAX / 2;
234 specific.periodic.dwPeriod = DI_SECONDS; /* 1 second */
235 break;
236 case DIEFT_CONSTANTFORCE:
237 data->eff.cbTypeSpecificParams = sizeof(specific.constant);
238 data->eff.lpvTypeSpecificParams = &specific.constant;
239 specific.constant.lMagnitude = DI_FFNOMINALMAX / 2;
240 break;
241 case DIEFT_RAMPFORCE:
242 data->eff.cbTypeSpecificParams = sizeof(specific.ramp);
243 data->eff.lpvTypeSpecificParams = &specific.ramp;
244 specific.ramp.lStart = -DI_FFNOMINALMAX / 2;
245 specific.ramp.lEnd = +DI_FFNOMINALMAX / 2;
246 break;
247 case DIEFT_CONDITION:
248 {
249 int i;
250 data->eff.cbTypeSpecificParams = sizeof(specific.condition);
251 data->eff.lpvTypeSpecificParams = specific.condition;
252 for (i = 0; i < 2; i++)
253 {
254 specific.condition[i].lNegativeCoefficient = -DI_FFNOMINALMAX / 2;
255 specific.condition[i].lPositiveCoefficient = +DI_FFNOMINALMAX / 2;
256 }
257 break;
258 }
259 }
260 return DIENUM_CONTINUE;
261 }
262
263 static const HRESULT SetCoop_null_window[16] = {
264 E_INVALIDARG, E_INVALIDARG, E_INVALIDARG, E_INVALIDARG,
265 E_INVALIDARG, E_HANDLE, E_HANDLE, E_INVALIDARG,
266 E_INVALIDARG, E_HANDLE, S_OK, E_INVALIDARG,
267 E_INVALIDARG, E_INVALIDARG, E_INVALIDARG, E_INVALIDARG};
268
269 static const HRESULT SetCoop_real_window[16] = {
270 E_INVALIDARG, E_INVALIDARG, E_INVALIDARG, E_INVALIDARG,
271 E_INVALIDARG, S_OK, S_OK, E_INVALIDARG,
272 E_INVALIDARG, S_OK, S_OK, E_INVALIDARG,
273 E_INVALIDARG, E_INVALIDARG, E_INVALIDARG, E_INVALIDARG};
274
275 static BOOL CALLBACK EnumJoysticks(const DIDEVICEINSTANCEA *lpddi, void *pvRef)
276 {
277 HRESULT hr;
278 UserData * data = pvRef;
279 IDirectInputDeviceA *pJoystick;
280 DIDATAFORMAT format;
281 DIDEVCAPS caps;
282 DIJOYSTATE2 js;
283 JoystickInfo info;
284 int i, count;
285 ULONG ref;
286 DIDEVICEINSTANCEA inst;
287 DIDEVICEINSTANCE_DX3A inst3;
288 DIPROPDWORD dipw;
289 DIPROPSTRING dps;
290 DIPROPGUIDANDPATH dpg;
291 WCHAR nameBuffer[MAX_PATH];
292 HWND hWnd = get_hwnd();
293 char oldstate[248], curstate[248];
294 DWORD axes[2] = {DIJOFS_X, DIJOFS_Y};
295 LONG direction[2] = {0, 0};
296 LPDIRECTINPUTEFFECT effect = NULL;
297 LONG cnt1, cnt2;
298 HWND real_hWnd;
299 HINSTANCE hInstance = GetModuleHandleW(NULL);
300 DIPROPDWORD dip_gain_set, dip_gain_get;
301 struct effect_enum effect_data;
302
303 ok(data->version > 0x0300, "Joysticks not supported in version 0x%04x\n", data->version);
304
305 hr = IDirectInput_CreateDevice(data->pDI, &lpddi->guidInstance, NULL, NULL);
306 ok(hr==E_POINTER,"IDirectInput_CreateDevice() should have returned "
307 "E_POINTER, returned: %08x\n", hr);
308
309 hr = IDirectInput_CreateDevice(data->pDI, NULL, &pJoystick, NULL);
310 ok(hr==E_POINTER,"IDirectInput_CreateDevice() should have returned "
311 "E_POINTER, returned: %08x\n", hr);
312
313 hr = IDirectInput_CreateDevice(data->pDI, NULL, NULL, NULL);
314 ok(hr==E_POINTER,"IDirectInput_CreateDevice() should have returned "
315 "E_POINTER, returned: %08x\n", hr);
316
317 hr = IDirectInput_CreateDevice(data->pDI, &lpddi->guidInstance,
318 &pJoystick, NULL);
319 ok(hr==DI_OK,"IDirectInput_CreateDevice() failed: %08x\n", hr);
320 if (hr!=DI_OK)
321 goto DONE;
322
323 trace("---- Controller Information ----\n"
324 "Product Name : %s\n"
325 "Instance Name : %s\n"
326 "devType : 0x%08x\n"
327 "GUID Product : %s\n"
328 "GUID Instance : %s\n"
329 "HID Page : 0x%04x\n"
330 "HID Usage : 0x%04x\n",
331 lpddi->tszProductName,
332 lpddi->tszInstanceName,
333 lpddi->dwDevType,
334 wine_dbgstr_guid(&lpddi->guidProduct),
335 wine_dbgstr_guid(&lpddi->guidInstance),
336 lpddi->wUsagePage,
337 lpddi->wUsage);
338
339 /* Check if this is a HID device */
340 if (lpddi->dwDevType & DIDEVTYPE_HID)
341 ok(lpddi->wUsagePage == 0x01 && (lpddi->wUsage == 0x04 || lpddi->wUsage == 0x05),
342 "Expected a game controller HID UsagePage and Usage, got page 0x%x usage 0x%x\n",
343 lpddi->wUsagePage, lpddi->wUsage);
344
345 /* Test for joystick ID property */
346 ZeroMemory(&dipw, sizeof(dipw));
347 dipw.diph.dwSize = sizeof(DIPROPDWORD);
348 dipw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
349 dipw.diph.dwObj = 0;
350 dipw.diph.dwHow = DIPH_DEVICE;
351
352 hr = IDirectInputDevice_GetProperty(pJoystick, DIPROP_JOYSTICKID, &dipw.diph);
353 ok(SUCCEEDED(hr), "IDirectInputDevice_GetProperty() for DIPROP_JOYSTICKID failed\n");
354
355 /* Test for INSTANCENAME property */
356 memset(&dps, 0, sizeof(dps));
357 dps.diph.dwSize = sizeof(DIPROPSTRING);
358 dps.diph.dwHeaderSize = sizeof(DIPROPHEADER);
359 dps.diph.dwHow = DIPH_DEVICE;
360
361 hr = IDirectInputDevice_GetProperty(pJoystick, DIPROP_INSTANCENAME, &dps.diph);
362 ok(SUCCEEDED(hr), "IDirectInput_GetProperty() for DIPROP_INSTANCENAME failed: %08x\n", hr);
363
364 /* Test if instance name is the same as present in DIDEVICEINSTANCE */
365 MultiByteToWideChar(CP_ACP, 0, lpddi->tszInstanceName, -1, nameBuffer, MAX_PATH);
366 ok(!lstrcmpW(nameBuffer, dps.wsz), "DIPROP_INSTANCENAME returned is wrong. Expected: %s Got: %s\n",
367 wine_dbgstr_w(nameBuffer), wine_dbgstr_w(dps.wsz));
368
369 hr = IDirectInputDevice_GetProperty(pJoystick, DIPROP_PRODUCTNAME, &dps.diph);
370 ok(SUCCEEDED(hr), "IDirectInput_GetProperty() for DIPROP_PRODUCTNAME failed: %08x\n", hr);
371
372 /* Test if product name is the same as present in DIDEVICEINSTANCE */
373 MultiByteToWideChar(CP_ACP, 0, lpddi->tszProductName, -1, nameBuffer, MAX_PATH);
374 ok(!lstrcmpW(nameBuffer, dps.wsz), "DIPROP_PRODUCTNAME returned is wrong. Expected: %s Got: %s\n",
375 wine_dbgstr_w(nameBuffer), wine_dbgstr_w(dps.wsz));
376
377 /* Test for GUIDPATH properties */
378 memset(&dpg, 0, sizeof(dpg));
379 dpg.diph.dwSize = sizeof(DIPROPGUIDANDPATH);
380 dpg.diph.dwHeaderSize = sizeof(DIPROPHEADER);
381 dpg.diph.dwHow = DIPH_DEVICE;
382
383 hr = IDirectInputDevice_GetProperty(pJoystick, DIPROP_GUIDANDPATH, &dpg.diph);
384 todo_wine ok(SUCCEEDED(hr), "IDirectInput_GetProperty() for DIPROP_GUIDANDPATH failed: %08x\n", hr);
385
386 hr = IDirectInputDevice_SetDataFormat(pJoystick, NULL);
387 ok(hr==E_POINTER,"IDirectInputDevice_SetDataFormat() should have returned "
388 "E_POINTER, returned: %08x\n", hr);
389
390 ZeroMemory(&format, sizeof(format));
391 hr = IDirectInputDevice_SetDataFormat(pJoystick, &format);
392 ok(hr==DIERR_INVALIDPARAM,"IDirectInputDevice_SetDataFormat() should have "
393 "returned DIERR_INVALIDPARAM, returned: %08x\n", hr);
394
395 /* try the default formats */
396 hr = IDirectInputDevice_SetDataFormat(pJoystick, &c_dfDIJoystick);
397 ok(hr==DI_OK,"IDirectInputDevice_SetDataFormat() failed: %08x\n", hr);
398
399 hr = IDirectInputDevice_SetDataFormat(pJoystick, &c_dfDIJoystick2);
400 ok(hr==DI_OK,"IDirectInputDevice_SetDataFormat() failed: %08x\n", hr);
401
402 /* try an alternate format */
403 hr = IDirectInputDevice_SetDataFormat(pJoystick, &c_dfDIJoystickTest);
404 ok(hr==DI_OK,"IDirectInputDevice_SetDataFormat() failed: %08x\n", hr);
405
406 hr = IDirectInputDevice_SetDataFormat(pJoystick, &c_dfDIJoystick2);
407 ok(hr==DI_OK,"IDirectInputDevice_SetDataFormat() failed: %08x\n", hr);
408 if (hr != DI_OK)
409 goto RELEASE;
410
411 for (i=0; i<16; i++)
412 {
413 hr = IDirectInputDevice_SetCooperativeLevel(pJoystick, NULL, i);
414 ok(hr == SetCoop_null_window[i], "SetCooperativeLevel(NULL, %d): %08x\n", i, hr);
415 }
416 for (i=0; i<16; i++)
417 {
418 hr = IDirectInputDevice_SetCooperativeLevel(pJoystick, hWnd, i);
419 ok(hr == SetCoop_real_window[i], "SetCooperativeLevel(hwnd, %d): %08x\n", i, hr);
420 }
421
422 hr = IDirectInputDevice_SetCooperativeLevel(pJoystick, hWnd,
423 DISCL_NONEXCLUSIVE | DISCL_BACKGROUND);
424 ok(hr==DI_OK,"IDirectInputDevice_SetCooperativeLevel() failed: %08x\n", hr);
425
426 /* get capabilities */
427 hr = IDirectInputDevice_GetCapabilities(pJoystick, NULL);
428 ok(hr==E_POINTER,"IDirectInputDevice_GetCapabilities() "
429 "should have returned E_POINTER, returned: %08x\n", hr);
430
431 ZeroMemory(&caps, sizeof(caps));
432 hr = IDirectInputDevice_GetCapabilities(pJoystick, &caps);
433 ok(hr==DIERR_INVALIDPARAM,"IDirectInputDevice_GetCapabilities() "
434 "should have returned DIERR_INVALIDPARAM, returned: %08x\n", hr);
435
436 caps.dwSize = sizeof(caps);
437 hr = IDirectInputDevice_GetCapabilities(pJoystick, &caps);
438 ok(hr==DI_OK,"IDirectInputDevice_GetCapabilities() failed: %08x\n", hr);
439
440 ZeroMemory(&info, sizeof(info));
441 info.pJoystick = pJoystick;
442
443 /* default min/max limits */
444 info.lMin = 0;
445 info.lMax = 0xffff;
446 /* enumerate objects */
447 hr = IDirectInputDevice_EnumObjects(pJoystick, EnumAxes, &info, DIDFT_ALL);
448 ok(hr==DI_OK,"IDirectInputDevice_EnumObjects() failed: %08x\n", hr);
449
450 ok(caps.dwAxes == info.axis, "Number of enumerated axes (%d) doesn't match capabilities (%d)\n", info.axis, caps.dwAxes);
451 ok(caps.dwButtons == info.button, "Number of enumerated buttons (%d) doesn't match capabilities (%d)\n", info.button, caps.dwButtons);
452 ok(caps.dwPOVs == info.pov, "Number of enumerated POVs (%d) doesn't match capabilities (%d)\n", info.pov, caps.dwPOVs);
453
454 /* Set format and check limits again */
455 hr = IDirectInputDevice_SetDataFormat(pJoystick, &c_dfDIJoystick2);
456 ok(hr==DI_OK,"IDirectInputDevice_SetDataFormat() failed: %08x\n", hr);
457 info.lMin = -2000;
458 info.lMax = +2000;
459 info.dZone= 123;
460 hr = IDirectInputDevice_EnumObjects(pJoystick, EnumAxes, &info, DIDFT_ALL);
461 ok(hr==DI_OK,"IDirectInputDevice_EnumObjects() failed: %08x\n", hr);
462
463 hr = IDirectInputDevice_GetDeviceInfo(pJoystick, 0);
464 ok(hr==E_POINTER, "IDirectInputDevice_GetDeviceInfo() "
465 "should have returned E_POINTER, returned: %08x\n", hr);
466
467 ZeroMemory(&inst, sizeof(inst));
468 ZeroMemory(&inst3, sizeof(inst3));
469
470 hr = IDirectInputDevice_GetDeviceInfo(pJoystick, &inst);
471 ok(hr==DIERR_INVALIDPARAM, "IDirectInputDevice_GetDeviceInfo() "
472 "should have returned DIERR_INVALIDPARAM, returned: %08x\n", hr);
473
474 inst.dwSize = sizeof(inst);
475 hr = IDirectInputDevice_GetDeviceInfo(pJoystick, &inst);
476 ok(hr==DI_OK,"IDirectInputDevice_GetDeviceInfo() failed: %08x\n", hr);
477
478 inst3.dwSize = sizeof(inst3);
479 hr = IDirectInputDevice_GetDeviceInfo(pJoystick, (DIDEVICEINSTANCEA*)&inst3);
480 ok(hr==DI_OK,"IDirectInputDevice_GetDeviceInfo() failed: %08x\n", hr);
481
482 hr = IDirectInputDevice_Unacquire(pJoystick);
483 ok(hr == S_FALSE, "IDirectInputDevice_Unacquire() should have returned S_FALSE, got: %08x\n", hr);
484
485 hr = IDirectInputDevice_Acquire(pJoystick);
486 ok(hr==DI_OK,"IDirectInputDevice_Acquire() failed: %08x\n", hr);
487 if (hr != DI_OK)
488 goto RELEASE;
489
490 hr = IDirectInputDevice_Acquire(pJoystick);
491 ok(hr == S_FALSE, "IDirectInputDevice_Acquire() should have returned S_FALSE, got: %08x\n", hr);
492
493 if (info.pov < 4)
494 {
495 hr = IDirectInputDevice_GetDeviceState(pJoystick, sizeof(DIJOYSTATE2), &js);
496 ok(hr == DI_OK, "IDirectInputDevice_GetDeviceState() failed: %08x\n", hr);
497 ok(js.rgdwPOV[3] == -1, "Default for unassigned POV should be -1 not: %d\n", js.rgdwPOV[3]);
498 }
499
500 trace("Testing force feedback\n");
501 ZeroMemory(&effect_data, sizeof(effect_data));
502 effect_data.eff.dwSize = sizeof(effect_data.eff);
503 effect_data.eff.dwFlags = DIEFF_CARTESIAN | DIEFF_OBJECTOFFSETS;
504 effect_data.eff.dwDuration = INFINITE;
505 effect_data.eff.dwGain = DI_FFNOMINALMAX;
506 effect_data.eff.dwTriggerButton = DIEB_NOTRIGGER;
507 effect_data.eff.cAxes = sizeof(axes) / sizeof(axes[0]);
508 effect_data.eff.rgdwAxes = axes;
509 effect_data.eff.rglDirection = direction;
510
511 /* Sending effects to joystick requires
512 * calling IDirectInputEffect_Initialize, which requires
513 * having exclusive access to the device, which requires
514 * - not having acquired the joystick when calling
515 * IDirectInputDevice_SetCooperativeLevel
516 * - a visible window
517 */
518 real_hWnd = CreateWindowExA(0, "EDIT", "Test text", 0, 10, 10, 300, 300, NULL, NULL,
519 hInstance, NULL);
520 ok(real_hWnd!=0,"CreateWindowExA failed: %p\n", real_hWnd);
521 ShowWindow(real_hWnd, SW_SHOW);
522 hr = IDirectInputDevice_Unacquire(pJoystick);
523 ok(hr==DI_OK,"IDirectInputDevice_Unacquire() failed: %08x\n", hr);
524 hr = IDirectInputDevice_SetCooperativeLevel(pJoystick, real_hWnd,
525 DISCL_EXCLUSIVE | DISCL_FOREGROUND);
526 ok(hr==DI_OK,"IDirectInputDevice_SetCooperativeLevel() failed: %08x\n", hr);
527 hr = IDirectInputDevice_Acquire(pJoystick);
528 ok(hr==DI_OK,"IDirectInputDevice_Acquire() failed: %08x\n", hr);
529
530 cnt1 = get_refcount((IUnknown*)pJoystick);
531
532 hr = IDirectInputDevice2_EnumEffects((IDirectInputDevice2A*)pJoystick, EnumEffects, &effect_data, DIEFT_ALL);
533 ok(hr==DI_OK,"IDirectInputDevice2_EnumEffects() failed: %08x\n", hr);
534
535 /* If the controller does not support ANY effect use the constant effect to make
536 * CreateEffect fail but with the unsupported reason instead of invalid parameters. */
537 if (!effect_data.effect_count)
538 {
539 static DICONSTANTFORCE constant;
540 effect_data.guid = GUID_ConstantForce;
541 effect_data.eff.cbTypeSpecificParams = sizeof(constant);
542 effect_data.eff.lpvTypeSpecificParams = &constant;
543 effect_data.effect_name = "Constant";
544 constant.lMagnitude = DI_FFNOMINALMAX / 2;
545
546 ok(!(caps.dwFlags & DIDC_FORCEFEEDBACK), "effect count is zero but controller supports force feedback?\n");
547 }
548
549 effect = (void *)0xdeadbeef;
550 hr = IDirectInputDevice2_CreateEffect((IDirectInputDevice2A*)pJoystick, &effect_data.guid,
551 &effect_data.eff, &effect, NULL);
552 if (caps.dwFlags & DIDC_FORCEFEEDBACK)
553 {
554 trace("force feedback supported with %d effects, using '%s' for test\n",
555 effect_data.effect_count, effect_data.effect_name);
556 ok(hr == DI_OK, "IDirectInputDevice_CreateEffect() failed: %08x\n", hr);
557 cnt2 = get_refcount((IUnknown*)pJoystick);
558 ok(cnt1 == cnt2, "Ref count is wrong %d != %d\n", cnt1, cnt2);
559
560 if (effect)
561 {
562 DWORD effect_status;
563 struct DIPROPDWORD diprop_word;
564 GUID guid = {0};
565
566 hr = IDirectInputEffect_Initialize(effect, hInstance, data->version,
567 &effect_data.guid);
568 ok(hr==DI_OK,"IDirectInputEffect_Initialize failed: %08x\n", hr);
569 hr = IDirectInputEffect_SetParameters(effect, &effect_data.eff, DIEP_AXES | DIEP_DIRECTION |
570 DIEP_TYPESPECIFICPARAMS);
571 ok(hr==DI_OK,"IDirectInputEffect_SetParameters failed: %08x\n", hr);
572 if (hr==DI_OK) {
573 /* Test that upload, unacquire, acquire still permits updating
574 * uploaded effect. */
575 hr = IDirectInputDevice_Unacquire(pJoystick);
576 ok(hr==DI_OK,"IDirectInputDevice_Unacquire() failed: %08x\n", hr);
577 hr = IDirectInputDevice_Acquire(pJoystick);
578 ok(hr==DI_OK,"IDirectInputDevice_Acquire() failed: %08x\n", hr);
579 hr = IDirectInputEffect_SetParameters(effect, &effect_data.eff, DIEP_GAIN);
580 ok(hr==DI_OK,"IDirectInputEffect_SetParameters failed: %08x\n", hr);
581 }
582
583 /* Check effect status.
584 * State: initially stopped
585 * start
586 * State: started
587 * unacquire, acquire, download
588 * State: stopped
589 * start
590 * State: started
591 *
592 * Shows that:
593 * - effects are stopped after Unacquire + Acquire
594 * - effects are preserved (Download + Start doesn't complain
595 * about incomplete effect)
596 */
597 hr = IDirectInputEffect_GetEffectStatus(effect, NULL);
598 ok(hr==E_POINTER,"IDirectInputEffect_GetEffectStatus() must fail with E_POINTER, got: %08x\n", hr);
599 effect_status = 0xdeadbeef;
600 hr = IDirectInputEffect_GetEffectStatus(effect, &effect_status);
601 ok(hr==DI_OK,"IDirectInputEffect_GetEffectStatus() failed: %08x\n", hr);
602 ok(effect_status==0,"IDirectInputEffect_GetEffectStatus() reported effect as started\n");
603 hr = IDirectInputEffect_SetParameters(effect, &effect_data.eff, DIEP_START);
604 ok(hr==DI_OK,"IDirectInputEffect_SetParameters failed: %08x\n", hr);
605 hr = IDirectInputEffect_GetEffectStatus(effect, &effect_status);
606 ok(hr==DI_OK,"IDirectInputEffect_GetEffectStatus() failed: %08x\n", hr);
607 todo_wine ok(effect_status!=0,"IDirectInputEffect_GetEffectStatus() reported effect as stopped\n");
608 hr = IDirectInputDevice_Unacquire(pJoystick);
609 ok(hr==DI_OK,"IDirectInputDevice_Unacquire() failed: %08x\n", hr);
610 hr = IDirectInputDevice_Acquire(pJoystick);
611 ok(hr==DI_OK,"IDirectInputDevice_Acquire() failed: %08x\n", hr);
612 hr = IDirectInputEffect_Download(effect);
613 ok(hr==DI_OK,"IDirectInputEffect_Download() failed: %08x\n", hr);
614 hr = IDirectInputEffect_GetEffectStatus(effect, &effect_status);
615 ok(hr==DI_OK,"IDirectInputEffect_GetEffectStatus() failed: %08x\n", hr);
616 ok(effect_status==0,"IDirectInputEffect_GetEffectStatus() reported effect as started\n");
617 hr = IDirectInputEffect_Start(effect, 1, 0);
618 ok(hr==DI_OK,"IDirectInputEffect_Start() failed: %08x\n", hr);
619 hr = IDirectInputEffect_GetEffectStatus(effect, &effect_status);
620 ok(hr==DI_OK,"IDirectInputEffect_GetEffectStatus() failed: %08x\n", hr);
621 Sleep(250); /* feel the magic */
622 todo_wine ok(effect_status!=0,"IDirectInputEffect_GetEffectStatus() reported effect as stopped\n");
623 hr = IDirectInputEffect_GetEffectGuid(effect, &guid);
624 ok(hr==DI_OK,"IDirectInputEffect_GetEffectGuid() failed: %08x\n", hr);
625 ok(IsEqualGUID(&effect_data.guid, &guid), "Wrong guid returned\n");
626
627 /* Check autocenter status
628 * State: initially stopped
629 * enable
630 * State: enabled
631 * acquire
632 * State: enabled
633 * unacquire
634 * State: enabled
635 *
636 * IDirectInputDevice2_SetProperty(DIPROP_AUTOCENTER) can only be
637 * executed when the device is released.
638 *
639 * If Executed interactively, user can feel that autocenter is
640 * only disabled when the joystick is acquired.
641 */
642 diprop_word.diph.dwSize = sizeof(diprop_word);
643 diprop_word.diph.dwHeaderSize = sizeof(diprop_word.diph);
644 diprop_word.diph.dwObj = 0;
645 diprop_word.diph.dwHow = DIPH_DEVICE;
646 hr = IDirectInputDevice_Unacquire(pJoystick);
647 ok(hr==DI_OK,"IDirectInputDevice_Unacquire() failed: %08x\n", hr);
648 hr = IDirectInputDevice2_GetProperty(pJoystick, DIPROP_AUTOCENTER, &diprop_word.diph);
649 ok(hr==DI_OK,"IDirectInputDevice2_GetProperty() failed: %08x\n", hr);
650 ok(diprop_word.dwData==DIPROPAUTOCENTER_ON,"IDirectInputDevice2_GetProperty() reported autocenter as disabled\n");
651 diprop_word.dwData = DIPROPAUTOCENTER_OFF;
652 hr = IDirectInputDevice2_SetProperty(pJoystick, DIPROP_AUTOCENTER, &diprop_word.diph);
653 ok(hr==DI_OK,"IDirectInputDevice2_SetProperty() failed: %08x\n", hr);
654 hr = IDirectInputDevice2_GetProperty(pJoystick, DIPROP_AUTOCENTER, &diprop_word.diph);
655 ok(hr==DI_OK,"IDirectInputDevice2_GetProperty() failed: %08x\n", hr);
656 ok(diprop_word.dwData==DIPROPAUTOCENTER_OFF,"IDirectInputDevice2_GetProperty() reported autocenter as enabled\n");
657 if (winetest_interactive) {
658 trace("Acquiring in 2s, autocenter will be disabled.\n");
659 Sleep(2000);
660 }
661 hr = IDirectInputDevice_Acquire(pJoystick);
662 ok(hr==DI_OK,"IDirectInputDevice_Acquire() failed: %08x\n", hr);
663 if (winetest_interactive)
664 trace("Acquired.\n");
665 hr = IDirectInputDevice2_GetProperty(pJoystick, DIPROP_AUTOCENTER, &diprop_word.diph);
666 ok(hr==DI_OK,"IDirectInputDevice2_GetProperty() failed: %08x\n", hr);
667 ok(diprop_word.dwData==DIPROPAUTOCENTER_OFF,"IDirectInputDevice2_GetProperty() reported autocenter as enabled\n");
668 if (winetest_interactive) {
669 trace("Releasing in 2s, autocenter will be re-enabled.\n");
670 Sleep(2000);
671 }
672 hr = IDirectInputDevice_Unacquire(pJoystick);
673 ok(hr==DI_OK,"IDirectInputDevice_Unacquire() failed: %08x\n", hr);
674 if (winetest_interactive)
675 trace("Released\n");
676 hr = IDirectInputDevice2_GetProperty(pJoystick, DIPROP_AUTOCENTER, &diprop_word.diph);
677 ok(hr==DI_OK,"IDirectInputDevice2_GetProperty() failed: %08x\n", hr);
678 ok(diprop_word.dwData==DIPROPAUTOCENTER_OFF,"IDirectInputDevice2_GetProperty() reported autocenter as enabled\n");
679 hr = IDirectInputDevice_Acquire(pJoystick);
680 ok(hr==DI_OK,"IDirectInputDevice_Acquire() failed: %08x\n", hr);
681 hr = IDirectInputDevice2_GetProperty(pJoystick, DIPROP_AUTOCENTER, &diprop_word.diph);
682 ok(hr==DI_OK,"IDirectInputDevice2_GetProperty() failed: %08x\n", hr);
683
684 /* Device gain (DIPROP_FFGAIN).
685 * From MSDN:
686 * 0..10000 range, otherwise DIERR_INVALIDPARAM.
687 * Can be changed even if device is acquired.
688 * Difference found by tests:
689 * <0 is refused, >10000 is accepted
690 */
691 dip_gain_set.diph.dwSize = sizeof(DIPROPDWORD);
692 dip_gain_set.diph.dwHeaderSize = sizeof(DIPROPHEADER);
693 dip_gain_set.diph.dwObj = 0;
694 dip_gain_set.diph.dwHow = DIPH_DEVICE;
695 dip_gain_get.diph.dwSize = sizeof(DIPROPDWORD);
696 dip_gain_get.diph.dwHeaderSize = sizeof(DIPROPHEADER);
697 dip_gain_get.diph.dwObj = 0;
698 dip_gain_get.diph.dwHow = DIPH_DEVICE;
699 dip_gain_get.dwData = 0;
700
701 /* Test device is acquisition (non)impact. */
702 hr = IDirectInputDevice_Unacquire(pJoystick);
703 ok(hr == DI_OK, "IDirectInputDevice_Unacquire() should have returned S_FALSE, got: %08x\n", hr);
704 dip_gain_set.dwData = 1;
705 hr = IDirectInputDevice_SetProperty(pJoystick, DIPROP_FFGAIN, &dip_gain_set.diph);
706 ok(hr==DI_OK, "IDirectInputDevice_SetProperty() failed: %08x\n", hr);
707 hr = IDirectInputDevice_GetProperty(pJoystick, DIPROP_FFGAIN, &dip_gain_get.diph);
708 ok(hr==DI_OK, "IDirectInputDevice_GetProperty() failed: %08x\n", hr);
709 ok(dip_gain_get.dwData==dip_gain_set.dwData, "Gain not updated: %i\n", dip_gain_get.dwData);
710 hr = IDirectInputDevice_Acquire(pJoystick);
711 ok(hr==DI_OK,"IDirectInputDevice_Acquire() failed: %08x\n", hr);
712 dip_gain_set.dwData = 2;
713 hr = IDirectInputDevice_SetProperty(pJoystick, DIPROP_FFGAIN, &dip_gain_set.diph);
714 ok(hr==DI_OK, "IDirectInputDevice_SetProperty() failed: %08x\n", hr);
715 hr = IDirectInputDevice_GetProperty(pJoystick, DIPROP_FFGAIN, &dip_gain_get.diph);
716 ok(hr==DI_OK, "IDirectInputDevice_GetProperty() failed: %08x\n", hr);
717 ok(dip_gain_get.dwData==dip_gain_set.dwData, "Gain not updated: %i\n", dip_gain_get.dwData);
718 /* Test range and internal clamping. */
719 dip_gain_set.dwData = -1;
720 hr = IDirectInputDevice_SetProperty(pJoystick, DIPROP_FFGAIN, &dip_gain_set.diph);
721 todo_wine ok(hr==DIERR_INVALIDPARAM, "IDirectInputDevice_SetProperty() should have returned %08x: %08x\n", DIERR_INVALIDPARAM, hr);
722 dip_gain_set.dwData = 0;
723 hr = IDirectInputDevice_SetProperty(pJoystick, DIPROP_FFGAIN, &dip_gain_set.diph);
724 ok(hr==DI_OK, "IDirectInputDevice_SetProperty() failed: %08x\n", hr);
725 hr = IDirectInputDevice_GetProperty(pJoystick, DIPROP_FFGAIN, &dip_gain_get.diph);
726 ok(hr==DI_OK, "IDirectInputDevice_GetProperty() failed: %08x\n", hr);
727 ok(dip_gain_get.dwData==dip_gain_set.dwData, "Gain not updated: %i\n", dip_gain_get.dwData);
728 dip_gain_set.dwData = 10000;
729 hr = IDirectInputDevice_SetProperty(pJoystick, DIPROP_FFGAIN, &dip_gain_set.diph);
730 ok(hr==DI_OK, "IDirectInputDevice_SetProperty() failed: %08x\n", hr);
731 hr = IDirectInputDevice_GetProperty(pJoystick, DIPROP_FFGAIN, &dip_gain_get.diph);
732 ok(hr==DI_OK, "IDirectInputDevice_GetProperty() failed: %08x\n", hr);
733 ok(dip_gain_get.dwData==dip_gain_set.dwData, "Gain not updated: %i\n", dip_gain_get.dwData);
734 /* WARNING: This call succeeds, on the contrary of what is stated on MSDN. */
735 dip_gain_set.dwData = 10001;
736 hr = IDirectInputDevice_SetProperty(pJoystick, DIPROP_FFGAIN, &dip_gain_set.diph);
737 ok(hr==DI_OK, "IDirectInputDevice_SetProperty() failed: %08x\n", hr);
738 hr = IDirectInputDevice_GetProperty(pJoystick, DIPROP_FFGAIN, &dip_gain_get.diph);
739 ok(hr==DI_OK, "IDirectInputDevice_GetProperty() failed: %08x\n", hr);
740 ok(dip_gain_get.dwData==dip_gain_set.dwData, "Gain not updated: %i\n", dip_gain_get.dwData);
741
742 /* Test SendForceFeedbackCommand
743 * DISFFC_STOPALL - Should stop effects only
744 * DISFFC_RESET - Should stop effects and unload them (NOT release them)
745 * Tests for game Odallus (bug 41623) */
746 hr = IDirectInputDevice2_SendForceFeedbackCommand((IDirectInputDevice2A*)pJoystick, 0);
747 ok(hr==DIERR_INVALIDPARAM, "IDirectInputDevice_SendForceFeedbackCommand() failed: %08x\n", hr);
748 hr = IDirectInputDevice2_SendForceFeedbackCommand((IDirectInputDevice2A*)pJoystick, 0xFF);
749 ok(hr==DIERR_INVALIDPARAM, "IDirectInputDevice_SendForceFeedbackCommand() failed: %08x\n", hr);
750
751 hr = IDirectInputEffect_Download(effect);
752 ok(hr==DI_OK,"IDirectInputEffect_Download() failed: %08x\n", hr);
753
754 /* Send STOPALL and prove that the effect can still be started */
755 hr = IDirectInputDevice2_SendForceFeedbackCommand((IDirectInputDevice2A*)pJoystick, DISFFC_STOPALL);
756 ok(hr==DI_OK, "IDirectInputDevice_SendForceFeedbackCommand() failed: %08x\n", hr);
757 hr = IDirectInputEffect_GetEffectStatus(effect, &effect_status);
758 ok(hr==DI_OK,"IDirectInputEffect_GetEffectStatus() failed: %08x\n", hr);
759 ok(effect_status==0,"IDirectInputEffect_GetEffectStatus() reported effect as started\n");
760 hr = IDirectInputEffect_Start(effect, 1, 0);
761 ok(hr==DI_OK,"IDirectInputEffect_Start() failed: %08x\n", hr);
762 hr = IDirectInputEffect_GetEffectGuid(effect, &guid);
763 ok(hr==DI_OK,"IDirectInputEffect_GetEffectGuid() failed: %08x\n", hr);
764 ok(IsEqualGUID(&effect_data.guid, &guid), "Wrong guid returned\n");
765
766 /* Send RESET and prove that we can still manipulate the effect, thus not released */
767 hr = IDirectInputDevice2_SendForceFeedbackCommand((IDirectInputDevice2A*)pJoystick, DISFFC_RESET);
768 ok(hr==DI_OK, "IDirectInputDevice_SendForceFeedbackCommand() failed: %08x\n", hr);
769 hr = IDirectInputEffect_GetEffectStatus(effect, &effect_status);
770 ok(hr==DIERR_NOTDOWNLOADED,"IDirectInputEffect_GetEffectStatus() failed: %08x\n", hr);
771 hr = IDirectInputEffect_Download(effect);
772 ok(hr==DI_OK,"IDirectInputEffect_Download() failed: %08x\n", hr);
773 hr = IDirectInputEffect_GetEffectStatus(effect, &effect_status);
774 ok(hr==DI_OK,"IDirectInputEffect_GetEffectStatus() failed: %08x\n", hr);
775 ok(effect_status==0,"IDirectInputEffect_GetEffectStatus() reported effect as started\n");
776 hr = IDirectInputEffect_Start(effect, 1, 0);
777 ok(hr==DI_OK,"IDirectInputEffect_Start() failed: %08x\n", hr);
778 hr = IDirectInputEffect_GetEffectGuid(effect, &guid);
779 ok(hr==DI_OK,"IDirectInputEffect_GetEffectGuid() failed: %08x\n", hr);
780 ok(IsEqualGUID(&effect_data.guid, &guid), "Wrong guid returned\n");
781
782 ref = IUnknown_Release(effect);
783 ok(ref == 0, "IDirectInputDevice_Release() reference count = %d\n", ref);
784 }
785 cnt1 = get_refcount((IUnknown*)pJoystick);
786 ok(cnt1 == cnt2, "Ref count is wrong %d != %d\n", cnt1, cnt2);
787 }
788 /* No force feedback support, CreateEffect is supposed to fail. Fairy Bloom Freesia
789 * calls CreateEffect without checking the DIDC_FORCEFEEDBACK. It expects the correct
790 * error return to determine if force feedback is unsupported. */
791 else
792 {
793 trace("No force feedback support\n");
794 ok(hr==DIERR_UNSUPPORTED, "IDirectInputDevice_CreateEffect() must fail with DIERR_UNSUPPORTED, got: %08x\n", hr);
795 ok(effect == NULL, "effect must be NULL, got %p\n", effect);
796 }
797
798 /* Before destroying the window, release joystick to revert to
799 * non-exclusive, background cooperative level. */
800 hr = IDirectInputDevice_Unacquire(pJoystick);
801 ok(hr==DI_OK,"IDirectInputDevice_Unacquire() failed: %08x\n", hr);
802 hr = IDirectInputDevice_SetCooperativeLevel(pJoystick, hWnd,
803 DISCL_NONEXCLUSIVE | DISCL_BACKGROUND);
804 ok(hr==DI_OK,"IDirectInputDevice_SetCooperativeLevel() failed: %08x\n", hr);
805 DestroyWindow (real_hWnd);
806 hr = IDirectInputDevice_Acquire(pJoystick);
807 ok(hr==DI_OK,"IDirectInputDevice_Acquire() failed: %08x\n", hr);
808
809 if (winetest_interactive) {
810 trace("You have 30 seconds to test all axes, sliders, POVs and buttons\n");
811 count = 300;
812 } else
813 count = 1;
814
815 trace("\n");
816 oldstate[0]='\0';
817 for (i = 0; i < count; i++) {
818 hr = IDirectInputDevice_GetDeviceState(pJoystick, sizeof(DIJOYSTATE2), &js);
819 ok(hr==DI_OK,"IDirectInputDevice_GetDeviceState() failed: %08x\n", hr);
820 if (hr != DI_OK)
821 break;
822 sprintf(curstate, "X%5d Y%5d Z%5d Rx%5d Ry%5d Rz%5d "
823 "S0%5d S1%5d POV0%5d POV1%5d POV2%5d POV3%5d "
824 "B %d %d %d %d %d %d %d %d %d %d %d %d\n",
825 js.lX, js.lY, js.lZ, js.lRx, js.lRy, js.lRz,
826 js.rglSlider[0], js.rglSlider[1],
827 js.rgdwPOV[0], js.rgdwPOV[1], js.rgdwPOV[2], js.rgdwPOV[3],
828 js.rgbButtons[0]>>7, js.rgbButtons[1]>>7, js.rgbButtons[2]>>7,
829 js.rgbButtons[3]>>7, js.rgbButtons[4]>>7, js.rgbButtons[5]>>7,
830 js.rgbButtons[6]>>7, js.rgbButtons[7]>>7, js.rgbButtons[8]>>7,
831 js.rgbButtons[9]>>7, js.rgbButtons[10]>>7, js.rgbButtons[11]>>7);
832 if (strcmp(oldstate, curstate) != 0)
833 {
834 trace("%s\n", curstate);
835 strcpy(oldstate, curstate);
836 }
837 Sleep(100);
838 }
839 trace("\n");
840
841 hr = IDirectInputDevice_Unacquire(pJoystick);
842 ok(hr==DI_OK,"IDirectInputDevice_Unacquire() failed: %08x\n", hr);
843
844 RELEASE:
845 ref = IDirectInputDevice_Release(pJoystick);
846 ok(ref==0,"IDirectInputDevice_Release() reference count = %d\n", ref);
847
848 DONE:
849 return DIENUM_CONTINUE;
850 }
851
852 static void joystick_tests(DWORD version)
853 {
854 HRESULT hr;
855 IDirectInputA *pDI;
856 ULONG ref;
857 HINSTANCE hInstance = GetModuleHandleW(NULL);
858
859 trace("-- Testing Direct Input Version 0x%04x --\n", version);
860 hr = DirectInputCreateA(hInstance, version, &pDI, NULL);
861 ok(hr==DI_OK||hr==DIERR_OLDDIRECTINPUTVERSION, "DirectInputCreateA() failed: %08x\n", hr);
862 if (hr==DI_OK && pDI!=0) {
863 UserData data;
864 data.pDI = pDI;
865 data.version = version;
866 hr = IDirectInput_EnumDevices(pDI, DIDEVTYPE_JOYSTICK, EnumJoysticks,
867 &data, DIEDFL_ALLDEVICES);
868 ok(hr==DI_OK,"IDirectInput_EnumDevices() failed: %08x\n", hr);
869 ref = IDirectInput_Release(pDI);
870 ok(ref==0,"IDirectInput_Release() reference count = %d\n", ref);
871 } else if (hr==DIERR_OLDDIRECTINPUTVERSION)
872 trace(" Version Not Supported\n");
873 }
874
875 START_TEST(joystick)
876 {
877 CoInitialize(NULL);
878
879 joystick_tests(0x0700);
880 joystick_tests(0x0500);
881 joystick_tests(0x0300);
882
883 CoUninitialize();
884 }