87f992978269fff3faad6350ad26edc8b8e05bad
[reactos.git] / modules / rostests / winetests / xinput1_3 / xinput.c
1 /*
2 * The Wine project - Xinput Joystick Library
3 * Copyright 2008 Andrew Fenn
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
18 */
19
20 #include <windows.h>
21 #include <stdio.h>
22
23 #include "xinput.h"
24 #include "wine/test.h"
25
26 static DWORD (WINAPI *pXInputGetState)(DWORD, XINPUT_STATE*);
27 static DWORD (WINAPI *pXInputGetStateEx)(DWORD, XINPUT_STATE_EX*);
28 static DWORD (WINAPI *pXInputGetCapabilities)(DWORD,DWORD,XINPUT_CAPABILITIES*);
29 static DWORD (WINAPI *pXInputSetState)(DWORD, XINPUT_VIBRATION*);
30 static void (WINAPI *pXInputEnable)(BOOL);
31 static DWORD (WINAPI *pXInputGetKeystroke)(DWORD, DWORD, PXINPUT_KEYSTROKE);
32 static DWORD (WINAPI *pXInputGetDSoundAudioDeviceGuids)(DWORD, GUID*, GUID*);
33 static DWORD (WINAPI *pXInputGetBatteryInformation)(DWORD, BYTE, XINPUT_BATTERY_INFORMATION*);
34
35 static void dump_gamepad(XINPUT_GAMEPAD *data)
36 {
37 trace("-- Gamepad Variables --\n");
38 trace("Gamepad.wButtons: %#x\n", data->wButtons);
39 trace("Gamepad.bLeftTrigger: %d\n", data->bLeftTrigger);
40 trace("Gamepad.bRightTrigger: %d\n", data->bRightTrigger);
41 trace("Gamepad.sThumbLX: %d\n", data->sThumbLX);
42 trace("Gamepad.sThumbLY: %d\n", data->sThumbLY);
43 trace("Gamepad.sThumbRX: %d\n", data->sThumbRX);
44 trace("Gamepad.sThumbRY: %d\n\n", data->sThumbRY);
45 }
46
47 static void test_set_state(void)
48 {
49 XINPUT_VIBRATION vibrator;
50 DWORD controllerNum;
51 DWORD result;
52
53 for(controllerNum = 0; controllerNum < XUSER_MAX_COUNT; controllerNum++)
54 {
55 ZeroMemory(&vibrator, sizeof(XINPUT_VIBRATION));
56
57 vibrator.wLeftMotorSpeed = 32767;
58 vibrator.wRightMotorSpeed = 32767;
59 result = pXInputSetState(controllerNum, &vibrator);
60 if (result == ERROR_DEVICE_NOT_CONNECTED) continue;
61
62 Sleep(250);
63 vibrator.wLeftMotorSpeed = 0;
64 vibrator.wRightMotorSpeed = 0;
65 result = pXInputSetState(controllerNum, &vibrator);
66 ok(result == ERROR_SUCCESS, "XInputSetState failed with (%d)\n", result);
67
68 /* Disabling XInput here, queueing a vibration and then re-enabling XInput
69 * is used to prove that vibrations are auto enabled when resuming XInput.
70 * If XInputEnable(1) is removed below the vibration will never play. */
71 if (pXInputEnable) pXInputEnable(0);
72
73 Sleep(250);
74 vibrator.wLeftMotorSpeed = 65535;
75 vibrator.wRightMotorSpeed = 65535;
76 result = pXInputSetState(controllerNum, &vibrator);
77 ok(result == ERROR_SUCCESS, "XInputSetState failed with (%d)\n", result);
78
79 if (pXInputEnable) pXInputEnable(1);
80 Sleep(250);
81
82 vibrator.wLeftMotorSpeed = 0;
83 vibrator.wRightMotorSpeed = 0;
84 result = pXInputSetState(controllerNum, &vibrator);
85 ok(result == ERROR_SUCCESS, "XInputSetState failed with (%d)\n", result);
86 }
87
88 result = pXInputSetState(XUSER_MAX_COUNT+1, &vibrator);
89 ok(result == ERROR_BAD_ARGUMENTS, "XInputSetState returned (%d)\n", result);
90 }
91
92 static void test_get_state(void)
93 {
94 union
95 {
96 XINPUT_STATE state;
97 XINPUT_STATE_EX state_ex;
98 } xinput;
99 DWORD controllerNum, i, result, good = XUSER_MAX_COUNT;
100
101 for (i = 0; i < (pXInputGetStateEx ? 2 : 1); i++)
102 {
103 for (controllerNum = 0; controllerNum < XUSER_MAX_COUNT; controllerNum++)
104 {
105 ZeroMemory(&xinput, sizeof(xinput));
106
107 if (i == 0)
108 result = pXInputGetState(controllerNum, &xinput.state);
109 else
110 result = pXInputGetStateEx(controllerNum, &xinput.state_ex);
111 ok(result == ERROR_SUCCESS || result == ERROR_DEVICE_NOT_CONNECTED,
112 "%s failed with (%d)\n", i == 0 ? "XInputGetState" : "XInputGetStateEx", result);
113
114 if (ERROR_DEVICE_NOT_CONNECTED == result)
115 {
116 skip("Controller %d is not connected\n", controllerNum);
117 continue;
118 }
119
120 trace("-- Results for controller %d --\n", controllerNum);
121 if (i == 0)
122 {
123 good = controllerNum;
124 trace("XInputGetState: %d\n", result);
125 }
126 else
127 trace("XInputGetStateEx: %d\n", result);
128 trace("State->dwPacketNumber: %d\n", xinput.state.dwPacketNumber);
129 dump_gamepad(&xinput.state.Gamepad);
130 }
131 }
132
133 result = pXInputGetState(XUSER_MAX_COUNT, &xinput.state);
134 ok(result == ERROR_BAD_ARGUMENTS, "XInputGetState returned (%d)\n", result);
135
136 result = pXInputGetState(XUSER_MAX_COUNT+1, &xinput.state);
137 ok(result == ERROR_BAD_ARGUMENTS, "XInputGetState returned (%d)\n", result);
138 if (pXInputGetStateEx)
139 {
140 result = pXInputGetStateEx(XUSER_MAX_COUNT, &xinput.state_ex);
141 ok(result == ERROR_BAD_ARGUMENTS, "XInputGetState returned (%d)\n", result);
142
143 result = pXInputGetStateEx(XUSER_MAX_COUNT+1, &xinput.state_ex);
144 ok(result == ERROR_BAD_ARGUMENTS, "XInputGetState returned (%d)\n", result);
145 }
146
147 if (winetest_interactive && good < XUSER_MAX_COUNT)
148 {
149 DWORD now = GetTickCount(), packet = 0;
150 XINPUT_GAMEPAD *game = &xinput.state.Gamepad;
151
152 trace("You have 20 seconds to test the joystick freely\n");
153 do
154 {
155 Sleep(100);
156 pXInputGetState(good, &xinput.state);
157 if (xinput.state.dwPacketNumber == packet)
158 continue;
159
160 packet = xinput.state.dwPacketNumber;
161 trace("Buttons 0x%04X Triggers %3d/%3d LT %6d/%6d RT %6d/%6d\n",
162 game->wButtons, game->bLeftTrigger, game->bRightTrigger,
163 game->sThumbLX, game->sThumbLY, game->sThumbRX, game->sThumbRY);
164 }
165 while(GetTickCount() - now < 20000);
166 trace("Test over...\n");
167 }
168 }
169
170 static void test_get_keystroke(void)
171 {
172 XINPUT_KEYSTROKE keystroke;
173 DWORD controllerNum;
174 DWORD result;
175
176 for(controllerNum = 0; controllerNum < XUSER_MAX_COUNT; controllerNum++)
177 {
178 ZeroMemory(&keystroke, sizeof(XINPUT_KEYSTROKE));
179
180 result = pXInputGetKeystroke(controllerNum, XINPUT_FLAG_GAMEPAD, &keystroke);
181 ok(result == ERROR_EMPTY || result == ERROR_SUCCESS || result == ERROR_DEVICE_NOT_CONNECTED,
182 "XInputGetKeystroke failed with (%d)\n", result);
183
184 if (ERROR_DEVICE_NOT_CONNECTED == result)
185 {
186 skip("Controller %d is not connected\n", controllerNum);
187 }
188 }
189
190 ZeroMemory(&keystroke, sizeof(XINPUT_KEYSTROKE));
191 result = pXInputGetKeystroke(XUSER_MAX_COUNT+1, XINPUT_FLAG_GAMEPAD, &keystroke);
192 ok(result == ERROR_BAD_ARGUMENTS, "XInputGetKeystroke returned (%d)\n", result);
193 }
194
195 static void test_get_capabilities(void)
196 {
197 XINPUT_CAPABILITIES capabilities;
198 DWORD controllerNum;
199 DWORD result;
200
201 for(controllerNum = 0; controllerNum < XUSER_MAX_COUNT; controllerNum++)
202 {
203 ZeroMemory(&capabilities, sizeof(XINPUT_CAPABILITIES));
204
205 result = pXInputGetCapabilities(controllerNum, XINPUT_FLAG_GAMEPAD, &capabilities);
206 ok(result == ERROR_SUCCESS || result == ERROR_DEVICE_NOT_CONNECTED, "XInputGetCapabilities failed with (%d)\n", result);
207
208 if (ERROR_DEVICE_NOT_CONNECTED == result)
209 {
210 skip("Controller %d is not connected\n", controllerNum);
211 continue;
212 }
213
214 /* Important to show that the results changed between 1.3 and 1.4 XInput version */
215 dump_gamepad(&capabilities.Gamepad);
216 }
217
218 ZeroMemory(&capabilities, sizeof(XINPUT_CAPABILITIES));
219 result = pXInputGetCapabilities(XUSER_MAX_COUNT+1, XINPUT_FLAG_GAMEPAD, &capabilities);
220 ok(result == ERROR_BAD_ARGUMENTS, "XInputGetCapabilities returned (%d)\n", result);
221 }
222
223 static void test_get_dsoundaudiodevice(void)
224 {
225 DWORD controllerNum;
226 DWORD result;
227 GUID soundRender, soundCapture;
228 GUID testGuid = {0xFFFFFFFF, 0xFFFF, 0xFFFF, {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}};
229 GUID emptyGuid = {0x0, 0x0, 0x0, {0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0}};
230
231 for(controllerNum = 0; controllerNum < XUSER_MAX_COUNT; controllerNum++)
232 {
233 soundRender = soundCapture = testGuid;
234 result = pXInputGetDSoundAudioDeviceGuids(controllerNum, &soundRender, &soundCapture);
235 ok(result == ERROR_SUCCESS || result == ERROR_DEVICE_NOT_CONNECTED, "XInputGetDSoundAudioDeviceGuids failed with (%d)\n", result);
236
237 if (ERROR_DEVICE_NOT_CONNECTED == result)
238 {
239 skip("Controller %d is not connected\n", controllerNum);
240 continue;
241 }
242
243 if (!IsEqualGUID(&soundRender, &emptyGuid))
244 ok(!IsEqualGUID(&soundRender, &testGuid), "Broken GUID returned for sound render device\n");
245 else
246 trace("Headset phone not attached\n");
247
248 if (!IsEqualGUID(&soundCapture, &emptyGuid))
249 ok(!IsEqualGUID(&soundCapture, &testGuid), "Broken GUID returned for sound capture device\n");
250 else
251 trace("Headset microphone not attached\n");
252 }
253
254 result = pXInputGetDSoundAudioDeviceGuids(XUSER_MAX_COUNT+1, &soundRender, &soundCapture);
255 ok(result == ERROR_BAD_ARGUMENTS, "XInputGetDSoundAudioDeviceGuids returned (%d)\n", result);
256 }
257
258 static void test_get_batteryinformation(void)
259 {
260 DWORD controllerNum;
261 DWORD result;
262 XINPUT_BATTERY_INFORMATION batteryInfo;
263
264 for(controllerNum = 0; controllerNum < XUSER_MAX_COUNT; controllerNum++)
265 {
266 ZeroMemory(&batteryInfo, sizeof(XINPUT_BATTERY_INFORMATION));
267
268 result = pXInputGetBatteryInformation(controllerNum, BATTERY_DEVTYPE_GAMEPAD, &batteryInfo);
269 ok(result == ERROR_SUCCESS || result == ERROR_DEVICE_NOT_CONNECTED, "XInputGetBatteryInformation failed with (%d)\n", result);
270
271 if (ERROR_DEVICE_NOT_CONNECTED == result)
272 {
273 ok(batteryInfo.BatteryLevel == BATTERY_TYPE_DISCONNECTED, "Failed to report device as being disconnected.\n");
274 skip("Controller %d is not connected\n", controllerNum);
275 }
276 }
277
278 result = pXInputGetBatteryInformation(XUSER_MAX_COUNT+1, BATTERY_DEVTYPE_GAMEPAD, &batteryInfo);
279 ok(result == ERROR_BAD_ARGUMENTS, "XInputGetBatteryInformation returned (%d)\n", result);
280 }
281
282 START_TEST(xinput)
283 {
284 struct
285 {
286 const char *name;
287 int version;
288 } libs[] = {
289 { "xinput1_1.dll", 1 },
290 { "xinput1_2.dll", 2 },
291 { "xinput1_3.dll", 3 },
292 { "xinput1_4.dll", 4 },
293 { "xinput9_1_0.dll", 0 } /* legacy for XP/Vista */
294 };
295 HMODULE hXinput;
296 void *pXInputGetStateEx_Ordinal;
297 int i;
298
299 for (i = 0; i < sizeof(libs) / sizeof(libs[0]); i++)
300 {
301 hXinput = LoadLibraryA( libs[i].name );
302
303 if (!hXinput)
304 {
305 win_skip("Could not load %s\n", libs[i].name);
306 continue;
307 }
308 trace("Testing %s\n", libs[i].name);
309
310 pXInputEnable = (void*)GetProcAddress(hXinput, "XInputEnable");
311 pXInputSetState = (void*)GetProcAddress(hXinput, "XInputSetState");
312 pXInputGetState = (void*)GetProcAddress(hXinput, "XInputGetState");
313 pXInputGetStateEx = (void*)GetProcAddress(hXinput, "XInputGetStateEx"); /* Win >= 8 */
314 pXInputGetStateEx_Ordinal = (void*)GetProcAddress(hXinput, (LPCSTR) 100);
315 pXInputGetKeystroke = (void*)GetProcAddress(hXinput, "XInputGetKeystroke");
316 pXInputGetCapabilities = (void*)GetProcAddress(hXinput, "XInputGetCapabilities");
317 pXInputGetDSoundAudioDeviceGuids = (void*)GetProcAddress(hXinput, "XInputGetDSoundAudioDeviceGuids");
318 pXInputGetBatteryInformation = (void*)GetProcAddress(hXinput, "XInputGetBatteryInformation");
319
320 /* XInputGetStateEx may not be present by name, use ordinal in this case */
321 if (!pXInputGetStateEx)
322 pXInputGetStateEx = pXInputGetStateEx_Ordinal;
323
324 test_set_state();
325 test_get_state();
326 test_get_capabilities();
327
328 if (libs[i].version != 4)
329 test_get_dsoundaudiodevice();
330 else
331 ok(!pXInputGetDSoundAudioDeviceGuids, "XInputGetDSoundAudioDeviceGuids exists in %s\n", libs[i].name);
332
333 if (libs[i].version > 2)
334 {
335 test_get_keystroke();
336 test_get_batteryinformation();
337 ok(pXInputGetStateEx != NULL, "XInputGetStateEx not found in %s\n", libs[i].name);
338 }
339 else
340 {
341 ok(!pXInputGetKeystroke, "XInputGetKeystroke exists in %s\n", libs[i].name);
342 ok(!pXInputGetStateEx, "XInputGetStateEx exists in %s\n", libs[i].name);
343 ok(!pXInputGetBatteryInformation, "XInputGetBatteryInformation exists in %s\n", libs[i].name);
344 if (libs[i].version == 0)
345 ok(!pXInputEnable, "XInputEnable exists in %s\n", libs[i].name);
346 }
347
348 FreeLibrary(hXinput);
349 }
350 }