2 * The Wine project - Xinput Joystick Library
3 * Copyright 2008 Andrew Fenn
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.
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.
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
27 #include "ddk/hidsdi.h"
28 #include "ddk/hidclass.h"
29 #include "wine/test.h"
31 static DWORD (WINAPI
*pXInputGetState
)(DWORD
, XINPUT_STATE
*);
32 static DWORD (WINAPI
*pXInputGetStateEx
)(DWORD
, XINPUT_STATE
*);
33 static DWORD (WINAPI
*pXInputGetCapabilities
)(DWORD
,DWORD
,XINPUT_CAPABILITIES
*);
34 static DWORD (WINAPI
*pXInputSetState
)(DWORD
, XINPUT_VIBRATION
*);
35 static void (WINAPI
*pXInputEnable
)(BOOL
);
36 static DWORD (WINAPI
*pXInputGetKeystroke
)(DWORD
, DWORD
, PXINPUT_KEYSTROKE
);
37 static DWORD (WINAPI
*pXInputGetDSoundAudioDeviceGuids
)(DWORD
, GUID
*, GUID
*);
38 static DWORD (WINAPI
*pXInputGetBatteryInformation
)(DWORD
, BYTE
, XINPUT_BATTERY_INFORMATION
*);
40 static void dump_gamepad(XINPUT_GAMEPAD
*data
)
42 trace("-- Gamepad Variables --\n");
43 trace("Gamepad.wButtons: %#x\n", data
->wButtons
);
44 trace("Gamepad.bLeftTrigger: %d\n", data
->bLeftTrigger
);
45 trace("Gamepad.bRightTrigger: %d\n", data
->bRightTrigger
);
46 trace("Gamepad.sThumbLX: %d\n", data
->sThumbLX
);
47 trace("Gamepad.sThumbLY: %d\n", data
->sThumbLY
);
48 trace("Gamepad.sThumbRX: %d\n", data
->sThumbRX
);
49 trace("Gamepad.sThumbRY: %d\n\n", data
->sThumbRY
);
52 static void test_set_state(void)
54 XINPUT_VIBRATION vibrator
;
58 for(controllerNum
= 0; controllerNum
< XUSER_MAX_COUNT
; controllerNum
++)
60 ZeroMemory(&vibrator
, sizeof(XINPUT_VIBRATION
));
62 vibrator
.wLeftMotorSpeed
= 32767;
63 vibrator
.wRightMotorSpeed
= 32767;
64 result
= pXInputSetState(controllerNum
, &vibrator
);
65 if (result
== ERROR_DEVICE_NOT_CONNECTED
) continue;
68 vibrator
.wLeftMotorSpeed
= 0;
69 vibrator
.wRightMotorSpeed
= 0;
70 result
= pXInputSetState(controllerNum
, &vibrator
);
71 ok(result
== ERROR_SUCCESS
, "XInputSetState returned %lu\n", result
);
73 /* Disabling XInput here, queueing a vibration and then re-enabling XInput
74 * is used to prove that vibrations are auto enabled when resuming XInput.
75 * If XInputEnable(1) is removed below the vibration will never play. */
76 if (pXInputEnable
) pXInputEnable(0);
79 vibrator
.wLeftMotorSpeed
= 65535;
80 vibrator
.wRightMotorSpeed
= 65535;
81 result
= pXInputSetState(controllerNum
, &vibrator
);
82 ok(result
== ERROR_SUCCESS
, "XInputSetState returned %lu\n", result
);
84 if (pXInputEnable
) pXInputEnable(1);
87 vibrator
.wLeftMotorSpeed
= 0;
88 vibrator
.wRightMotorSpeed
= 0;
89 result
= pXInputSetState(controllerNum
, &vibrator
);
90 ok(result
== ERROR_SUCCESS
, "XInputSetState returned %lu\n", result
);
93 result
= pXInputSetState(XUSER_MAX_COUNT
+1, &vibrator
);
94 ok(result
== ERROR_BAD_ARGUMENTS
, "XInputSetState returned %lu\n", result
);
97 static void test_get_state(void)
100 DWORD controllerNum
, i
, result
, good
= XUSER_MAX_COUNT
;
102 for (i
= 0; i
< (pXInputGetStateEx
? 2 : 1); i
++)
104 for (controllerNum
= 0; controllerNum
< XUSER_MAX_COUNT
; controllerNum
++)
106 ZeroMemory(&state
, sizeof(state
));
109 result
= pXInputGetState(controllerNum
, &state
);
111 result
= pXInputGetStateEx(controllerNum
, &state
);
112 ok(result
== ERROR_SUCCESS
|| result
== ERROR_DEVICE_NOT_CONNECTED
,
113 "%s returned %lu\n", i
== 0 ? "XInputGetState" : "XInputGetStateEx", result
);
115 if (ERROR_DEVICE_NOT_CONNECTED
== result
)
117 skip("Controller %lu is not connected\n", controllerNum
);
121 trace("-- Results for controller %lu --\n", controllerNum
);
124 good
= controllerNum
;
125 trace("XInputGetState: %lu\n", result
);
128 trace("XInputGetStateEx: %lu\n", result
);
129 trace("State->dwPacketNumber: %lu\n", state
.dwPacketNumber
);
130 dump_gamepad(&state
.Gamepad
);
134 result
= pXInputGetState(0, NULL
);
135 ok(result
== ERROR_BAD_ARGUMENTS
, "XInputGetState returned %lu\n", result
);
137 result
= pXInputGetState(XUSER_MAX_COUNT
, &state
);
138 ok(result
== ERROR_BAD_ARGUMENTS
, "XInputGetState returned %lu\n", result
);
140 result
= pXInputGetState(XUSER_MAX_COUNT
+1, &state
);
141 ok(result
== ERROR_BAD_ARGUMENTS
, "XInputGetState returned %lu\n", result
);
142 if (pXInputGetStateEx
)
144 result
= pXInputGetStateEx(XUSER_MAX_COUNT
, &state
);
145 ok(result
== ERROR_BAD_ARGUMENTS
, "XInputGetState returned %lu\n", result
);
147 result
= pXInputGetStateEx(XUSER_MAX_COUNT
+1, &state
);
148 ok(result
== ERROR_BAD_ARGUMENTS
, "XInputGetState returned %lu\n", result
);
151 if (winetest_interactive
&& good
< XUSER_MAX_COUNT
)
153 DWORD now
= GetTickCount(), packet
= 0;
154 XINPUT_GAMEPAD
*game
= &state
.Gamepad
;
156 trace("You have 20 seconds to test the joystick freely\n");
160 pXInputGetState(good
, &state
);
161 if (state
.dwPacketNumber
== packet
)
164 packet
= state
.dwPacketNumber
;
165 trace("Buttons 0x%04X Triggers %3d/%3d LT %6d/%6d RT %6d/%6d\n",
166 game
->wButtons
, game
->bLeftTrigger
, game
->bRightTrigger
,
167 game
->sThumbLX
, game
->sThumbLY
, game
->sThumbRX
, game
->sThumbRY
);
169 while(GetTickCount() - now
< 20000);
170 trace("Test over...\n");
174 static void test_get_keystroke(void)
176 XINPUT_KEYSTROKE keystroke
;
180 for(controllerNum
= 0; controllerNum
< XUSER_MAX_COUNT
; controllerNum
++)
182 ZeroMemory(&keystroke
, sizeof(XINPUT_KEYSTROKE
));
184 result
= pXInputGetKeystroke(controllerNum
, XINPUT_FLAG_GAMEPAD
, &keystroke
);
185 ok(result
== ERROR_EMPTY
|| result
== ERROR_SUCCESS
|| result
== ERROR_DEVICE_NOT_CONNECTED
,
186 "XInputGetKeystroke returned %lu\n", result
);
188 if (ERROR_DEVICE_NOT_CONNECTED
== result
)
190 skip("Controller %lu is not connected\n", controllerNum
);
194 ZeroMemory(&keystroke
, sizeof(XINPUT_KEYSTROKE
));
195 result
= pXInputGetKeystroke(XUSER_MAX_COUNT
+1, XINPUT_FLAG_GAMEPAD
, &keystroke
);
196 ok(result
== ERROR_BAD_ARGUMENTS
, "XInputGetKeystroke returned %lu\n", result
);
199 static void test_get_capabilities(void)
201 XINPUT_CAPABILITIES capabilities
;
205 for(controllerNum
= 0; controllerNum
< XUSER_MAX_COUNT
; controllerNum
++)
207 ZeroMemory(&capabilities
, sizeof(XINPUT_CAPABILITIES
));
209 result
= pXInputGetCapabilities(controllerNum
, XINPUT_FLAG_GAMEPAD
, &capabilities
);
210 ok(result
== ERROR_SUCCESS
|| result
== ERROR_DEVICE_NOT_CONNECTED
, "XInputGetCapabilities returned %lu\n", result
);
212 if (ERROR_DEVICE_NOT_CONNECTED
== result
)
214 skip("Controller %lu is not connected\n", controllerNum
);
218 /* Important to show that the results changed between 1.3 and 1.4 XInput version */
219 dump_gamepad(&capabilities
.Gamepad
);
222 ZeroMemory(&capabilities
, sizeof(XINPUT_CAPABILITIES
));
223 result
= pXInputGetCapabilities(XUSER_MAX_COUNT
+1, XINPUT_FLAG_GAMEPAD
, &capabilities
);
224 ok(result
== ERROR_BAD_ARGUMENTS
, "XInputGetCapabilities returned %lu\n", result
);
227 static void test_get_dsoundaudiodevice(void)
231 GUID soundRender
, soundCapture
;
232 GUID testGuid
= {0xFFFFFFFF, 0xFFFF, 0xFFFF, {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}};
233 GUID emptyGuid
= {0x0, 0x0, 0x0, {0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0}};
235 for(controllerNum
= 0; controllerNum
< XUSER_MAX_COUNT
; controllerNum
++)
237 soundRender
= soundCapture
= testGuid
;
238 result
= pXInputGetDSoundAudioDeviceGuids(controllerNum
, &soundRender
, &soundCapture
);
239 ok(result
== ERROR_SUCCESS
|| result
== ERROR_DEVICE_NOT_CONNECTED
, "XInputGetDSoundAudioDeviceGuids returned %lu\n", result
);
241 if (ERROR_DEVICE_NOT_CONNECTED
== result
)
243 skip("Controller %lu is not connected\n", controllerNum
);
247 if (!IsEqualGUID(&soundRender
, &emptyGuid
))
248 ok(!IsEqualGUID(&soundRender
, &testGuid
), "Broken GUID returned for sound render device\n");
250 trace("Headset phone not attached\n");
252 if (!IsEqualGUID(&soundCapture
, &emptyGuid
))
253 ok(!IsEqualGUID(&soundCapture
, &testGuid
), "Broken GUID returned for sound capture device\n");
255 trace("Headset microphone not attached\n");
258 result
= pXInputGetDSoundAudioDeviceGuids(XUSER_MAX_COUNT
+1, &soundRender
, &soundCapture
);
259 ok(result
== ERROR_BAD_ARGUMENTS
, "XInputGetDSoundAudioDeviceGuids returned %lu\n", result
);
262 static void test_get_batteryinformation(void)
266 XINPUT_BATTERY_INFORMATION batteryInfo
;
268 for(controllerNum
= 0; controllerNum
< XUSER_MAX_COUNT
; controllerNum
++)
270 ZeroMemory(&batteryInfo
, sizeof(XINPUT_BATTERY_INFORMATION
));
272 result
= pXInputGetBatteryInformation(controllerNum
, BATTERY_DEVTYPE_GAMEPAD
, &batteryInfo
);
273 ok(result
== ERROR_SUCCESS
|| result
== ERROR_DEVICE_NOT_CONNECTED
, "XInputGetBatteryInformation returned %lu\n", result
);
275 if (ERROR_DEVICE_NOT_CONNECTED
== result
)
277 ok(batteryInfo
.BatteryLevel
== BATTERY_TYPE_DISCONNECTED
, "Failed to report device as being disconnected.\n");
278 skip("Controller %lu is not connected\n", controllerNum
);
282 result
= pXInputGetBatteryInformation(XUSER_MAX_COUNT
+1, BATTERY_DEVTYPE_GAMEPAD
, &batteryInfo
);
283 ok(result
== ERROR_BAD_ARGUMENTS
, "XInputGetBatteryInformation returned %lu\n", result
);
286 #define check_member_(file, line, val, exp, fmt, member) \
287 ok_(file, line)((val).member == (exp).member, \
288 "got " #member " " fmt ", expected " fmt "\n", \
289 (val).member, (exp).member)
290 #define check_member(val, exp, fmt, member) check_member_(__FILE__, __LINE__, val, exp, fmt, member)
292 static void check_hid_caps(DWORD index
, HANDLE device
, PHIDP_PREPARSED_DATA preparsed
,
293 HIDD_ATTRIBUTES
*attrs
, HIDP_CAPS
*hid_caps
)
295 const HIDP_CAPS expect_hid_caps
=
297 .Usage
= HID_USAGE_GENERIC_GAMEPAD
,
298 .UsagePage
= HID_USAGE_PAGE_GENERIC
,
299 .InputReportByteLength
=
300 attrs
->VendorID
== 0x045e && attrs
->ProductID
== 0x02ff ? 16 :
302 .OutputReportByteLength
= 0,
303 .FeatureReportByteLength
= 0,
304 .NumberLinkCollectionNodes
= 4,
305 .NumberInputButtonCaps
= 1,
306 .NumberInputValueCaps
= 6,
307 .NumberInputDataIndices
=
308 attrs
->VendorID
== 0x045e && attrs
->ProductID
== 0x02ff ? 22 :
310 .NumberFeatureButtonCaps
= 0,
311 .NumberFeatureValueCaps
= 0,
312 .NumberFeatureDataIndices
= 0,
314 const HIDP_BUTTON_CAPS expect_button_caps
[] =
317 .UsagePage
= HID_USAGE_PAGE_BUTTON
,
319 .LinkUsage
= HID_USAGE_GENERIC_GAMEPAD
,
320 .LinkUsagePage
= HID_USAGE_PAGE_GENERIC
,
323 .Range
.UsageMin
= 0x01,
325 attrs
->VendorID
== 0x045e && attrs
->ProductID
== 0x02ff ? 0x10 :
327 .Range
.DataIndexMin
= 5,
328 .Range
.DataIndexMax
=
329 attrs
->VendorID
== 0x045e && attrs
->ProductID
== 0x02ff ? 20 :
333 const HIDP_VALUE_CAPS expect_value_caps
[] =
336 .UsagePage
= HID_USAGE_PAGE_GENERIC
,
338 .LinkUsagePage
= HID_USAGE_PAGE_GENERIC
,
345 .NotRange
.Usage
= HID_USAGE_GENERIC_Y
,
346 .NotRange
.DataIndex
= 0,
349 .UsagePage
= HID_USAGE_PAGE_GENERIC
,
351 .LinkUsagePage
= HID_USAGE_PAGE_GENERIC
,
358 .NotRange
.Usage
= HID_USAGE_GENERIC_X
,
359 .NotRange
.DataIndex
= 1,
362 .UsagePage
= HID_USAGE_PAGE_GENERIC
,
364 .LinkUsagePage
= HID_USAGE_PAGE_GENERIC
,
371 .NotRange
.Usage
= HID_USAGE_GENERIC_RY
,
372 .NotRange
.DataIndex
= 2,
375 .UsagePage
= HID_USAGE_PAGE_GENERIC
,
377 .LinkUsagePage
= HID_USAGE_PAGE_GENERIC
,
384 .NotRange
.Usage
= HID_USAGE_GENERIC_RX
,
385 .NotRange
.DataIndex
= 3,
388 .UsagePage
= HID_USAGE_PAGE_GENERIC
,
390 .LinkUsagePage
= HID_USAGE_PAGE_GENERIC
,
397 .NotRange
.Usage
= HID_USAGE_GENERIC_Z
,
398 .NotRange
.DataIndex
= 4,
401 .UsagePage
= HID_USAGE_PAGE_GENERIC
,
403 .LinkUsagePage
= HID_USAGE_PAGE_GENERIC
,
404 .LinkUsage
= HID_USAGE_GENERIC_GAMEPAD
,
412 .PhysicalMin
= 0x0000,
413 .PhysicalMax
= 0x103b,
414 .NotRange
.Usage
= HID_USAGE_GENERIC_HATSWITCH
,
415 .NotRange
.DataIndex
=
416 attrs
->VendorID
== 0x045e && attrs
->ProductID
== 0x02ff ? 21 :
420 static const HIDP_LINK_COLLECTION_NODE expect_collections
[] =
423 .LinkUsage
= HID_USAGE_GENERIC_GAMEPAD
,
424 .LinkUsagePage
= HID_USAGE_PAGE_GENERIC
,
426 .NumberOfChildren
= 3,
429 { .LinkUsagePage
= HID_USAGE_PAGE_GENERIC
, .NextSibling
= 0, },
430 { .LinkUsagePage
= HID_USAGE_PAGE_GENERIC
, .NextSibling
= 1, },
431 { .LinkUsagePage
= HID_USAGE_PAGE_GENERIC
, .NextSibling
= 2, },
434 HIDP_LINK_COLLECTION_NODE collections
[16];
435 HIDP_BUTTON_CAPS button_caps
[16];
436 HIDP_VALUE_CAPS value_caps
[16];
437 XINPUT_STATE last_state
, state
;
438 XINPUT_CAPABILITIES xi_caps
;
439 char buffer
[200] = {0};
448 res
= pXInputGetCapabilities(index
, 0, &xi_caps
);
449 ok(res
== ERROR_SUCCESS
, "XInputGetCapabilities %lu returned %lu\n", index
, res
);
451 res
= pXInputGetState(index
, &state
);
452 ok(res
== ERROR_SUCCESS
, "XInputGetState %lu returned %lu\n", index
, res
);
454 ok(hid_caps
->UsagePage
== HID_USAGE_PAGE_GENERIC
, "unexpected usage page %04x\n", hid_caps
->UsagePage
);
455 ok(hid_caps
->Usage
== HID_USAGE_GENERIC_GAMEPAD
, "unexpected usage %04x\n", hid_caps
->Usage
);
457 check_member(*hid_caps
, expect_hid_caps
, "%04x", Usage
);
458 check_member(*hid_caps
, expect_hid_caps
, "%04x", UsagePage
);
459 check_member(*hid_caps
, expect_hid_caps
, "%d", InputReportByteLength
);
460 check_member(*hid_caps
, expect_hid_caps
, "%d", OutputReportByteLength
);
461 check_member(*hid_caps
, expect_hid_caps
, "%d", FeatureReportByteLength
);
462 check_member(*hid_caps
, expect_hid_caps
, "%d", NumberLinkCollectionNodes
);
463 check_member(*hid_caps
, expect_hid_caps
, "%d", NumberInputButtonCaps
);
464 check_member(*hid_caps
, expect_hid_caps
, "%d", NumberInputValueCaps
);
465 check_member(*hid_caps
, expect_hid_caps
, "%d", NumberInputDataIndices
);
466 check_member(*hid_caps
, expect_hid_caps
, "%d", NumberOutputButtonCaps
);
467 check_member(*hid_caps
, expect_hid_caps
, "%d", NumberOutputValueCaps
);
468 check_member(*hid_caps
, expect_hid_caps
, "%d", NumberOutputDataIndices
);
469 check_member(*hid_caps
, expect_hid_caps
, "%d", NumberFeatureButtonCaps
);
470 check_member(*hid_caps
, expect_hid_caps
, "%d", NumberFeatureValueCaps
);
471 check_member(*hid_caps
, expect_hid_caps
, "%d", NumberFeatureDataIndices
);
473 length
= hid_caps
->NumberLinkCollectionNodes
;
474 status
= HidP_GetLinkCollectionNodes(collections
, &length
, preparsed
);
475 ok(status
== HIDP_STATUS_SUCCESS
, "HidP_GetLinkCollectionNodes returned %#lx\n", status
);
476 ok(length
== ARRAY_SIZE(expect_collections
), "got %lu collections\n", length
);
478 for (i
= 0; i
< min(length
, ARRAY_SIZE(expect_collections
)); ++i
)
480 winetest_push_context("collections[%d]", i
);
481 check_member(collections
[i
], expect_collections
[i
], "%04x", LinkUsage
);
482 check_member(collections
[i
], expect_collections
[i
], "%04x", LinkUsagePage
);
483 check_member(collections
[i
], expect_collections
[i
], "%d", Parent
);
484 check_member(collections
[i
], expect_collections
[i
], "%d", NumberOfChildren
);
485 check_member(collections
[i
], expect_collections
[i
], "%d", NextSibling
);
486 check_member(collections
[i
], expect_collections
[i
], "%d", FirstChild
);
487 check_member(collections
[i
], expect_collections
[i
], "%d", CollectionType
);
488 check_member(collections
[i
], expect_collections
[i
], "%d", IsAlias
);
489 winetest_pop_context();
492 count
= hid_caps
->NumberInputButtonCaps
;
493 status
= HidP_GetButtonCaps(HidP_Input
, button_caps
, &count
, preparsed
);
494 ok(status
== HIDP_STATUS_SUCCESS
, "HidP_GetButtonCaps returned %#lx\n", status
);
495 ok(count
== ARRAY_SIZE(expect_button_caps
), "got %d button caps\n", count
);
497 for (i
= 0; i
< ARRAY_SIZE(expect_button_caps
); ++i
)
499 winetest_push_context("button_caps[%d]", i
);
500 check_member(button_caps
[i
], expect_button_caps
[i
], "%04x", UsagePage
);
501 check_member(button_caps
[i
], expect_button_caps
[i
], "%d", ReportID
);
502 check_member(button_caps
[i
], expect_button_caps
[i
], "%d", IsAlias
);
503 check_member(button_caps
[i
], expect_button_caps
[i
], "%d", BitField
);
504 check_member(button_caps
[i
], expect_button_caps
[i
], "%d", LinkCollection
);
505 check_member(button_caps
[i
], expect_button_caps
[i
], "%04x", LinkUsage
);
506 check_member(button_caps
[i
], expect_button_caps
[i
], "%04x", LinkUsagePage
);
507 check_member(button_caps
[i
], expect_button_caps
[i
], "%d", IsRange
);
508 check_member(button_caps
[i
], expect_button_caps
[i
], "%d", IsStringRange
);
509 check_member(button_caps
[i
], expect_button_caps
[i
], "%d", IsDesignatorRange
);
510 check_member(button_caps
[i
], expect_button_caps
[i
], "%d", IsAbsolute
);
512 if (!button_caps
[i
].IsRange
&& !expect_button_caps
[i
].IsRange
)
514 check_member(button_caps
[i
], expect_button_caps
[i
], "%04x", NotRange
.Usage
);
515 check_member(button_caps
[i
], expect_button_caps
[i
], "%d", NotRange
.DataIndex
);
517 else if (button_caps
[i
].IsRange
&& expect_button_caps
[i
].IsRange
)
519 check_member(button_caps
[i
], expect_button_caps
[i
], "%04x", Range
.UsageMin
);
520 check_member(button_caps
[i
], expect_button_caps
[i
], "%04x", Range
.UsageMax
);
521 check_member(button_caps
[i
], expect_button_caps
[i
], "%d", Range
.DataIndexMin
);
522 check_member(button_caps
[i
], expect_button_caps
[i
], "%d", Range
.DataIndexMax
);
525 if (!button_caps
[i
].IsRange
&& !expect_button_caps
[i
].IsRange
)
526 check_member(button_caps
[i
], expect_button_caps
[i
], "%d", NotRange
.StringIndex
);
527 else if (button_caps
[i
].IsStringRange
&& expect_button_caps
[i
].IsStringRange
)
529 check_member(button_caps
[i
], expect_button_caps
[i
], "%d", Range
.StringMin
);
530 check_member(button_caps
[i
], expect_button_caps
[i
], "%d", Range
.StringMax
);
533 if (!button_caps
[i
].IsDesignatorRange
&& !expect_button_caps
[i
].IsDesignatorRange
)
534 check_member(button_caps
[i
], expect_button_caps
[i
], "%d", NotRange
.DesignatorIndex
);
535 else if (button_caps
[i
].IsDesignatorRange
&& expect_button_caps
[i
].IsDesignatorRange
)
537 check_member(button_caps
[i
], expect_button_caps
[i
], "%d", Range
.DesignatorMin
);
538 check_member(button_caps
[i
], expect_button_caps
[i
], "%d", Range
.DesignatorMax
);
540 winetest_pop_context();
543 count
= hid_caps
->NumberInputValueCaps
;
544 status
= HidP_GetValueCaps(HidP_Input
, value_caps
, &count
, preparsed
);
545 ok(status
== HIDP_STATUS_SUCCESS
, "HidP_GetValueCaps returned %#lx\n", status
);
546 ok(count
== ARRAY_SIZE(expect_value_caps
), "got %d value caps\n", count
);
548 for (i
= 0; i
< min(count
, ARRAY_SIZE(expect_value_caps
)); ++i
)
550 winetest_push_context("value_caps[%d]", i
);
551 check_member(value_caps
[i
], expect_value_caps
[i
], "%04x", UsagePage
);
552 check_member(value_caps
[i
], expect_value_caps
[i
], "%d", ReportID
);
553 check_member(value_caps
[i
], expect_value_caps
[i
], "%d", IsAlias
);
554 check_member(value_caps
[i
], expect_value_caps
[i
], "%d", BitField
);
555 check_member(value_caps
[i
], expect_value_caps
[i
], "%d", LinkCollection
);
556 check_member(value_caps
[i
], expect_value_caps
[i
], "%d", LinkUsage
);
557 check_member(value_caps
[i
], expect_value_caps
[i
], "%d", LinkUsagePage
);
558 check_member(value_caps
[i
], expect_value_caps
[i
], "%d", IsRange
);
559 check_member(value_caps
[i
], expect_value_caps
[i
], "%d", IsStringRange
);
560 check_member(value_caps
[i
], expect_value_caps
[i
], "%d", IsDesignatorRange
);
561 check_member(value_caps
[i
], expect_value_caps
[i
], "%d", IsAbsolute
);
563 check_member(value_caps
[i
], expect_value_caps
[i
], "%d", HasNull
);
564 check_member(value_caps
[i
], expect_value_caps
[i
], "%d", BitSize
);
565 check_member(value_caps
[i
], expect_value_caps
[i
], "%d", ReportCount
);
566 check_member(value_caps
[i
], expect_value_caps
[i
], "%#lx", UnitsExp
);
567 check_member(value_caps
[i
], expect_value_caps
[i
], "%#lx", Units
);
568 check_member(value_caps
[i
], expect_value_caps
[i
], "%+ld", LogicalMin
);
569 check_member(value_caps
[i
], expect_value_caps
[i
], "%+ld", LogicalMax
);
570 check_member(value_caps
[i
], expect_value_caps
[i
], "%+ld", PhysicalMin
);
571 check_member(value_caps
[i
], expect_value_caps
[i
], "%+ld", PhysicalMax
);
573 if (!value_caps
[i
].IsRange
&& !expect_value_caps
[i
].IsRange
)
575 check_member(value_caps
[i
], expect_value_caps
[i
], "%04x", NotRange
.Usage
);
576 check_member(value_caps
[i
], expect_value_caps
[i
], "%d", NotRange
.DataIndex
);
578 else if (value_caps
[i
].IsRange
&& expect_value_caps
[i
].IsRange
)
580 check_member(value_caps
[i
], expect_value_caps
[i
], "%04x", Range
.UsageMin
);
581 check_member(value_caps
[i
], expect_value_caps
[i
], "%04x", Range
.UsageMax
);
582 check_member(value_caps
[i
], expect_value_caps
[i
], "%d", Range
.DataIndexMin
);
583 check_member(value_caps
[i
], expect_value_caps
[i
], "%d", Range
.DataIndexMax
);
586 if (!value_caps
[i
].IsRange
&& !expect_value_caps
[i
].IsRange
)
587 check_member(value_caps
[i
], expect_value_caps
[i
], "%d", NotRange
.StringIndex
);
588 else if (value_caps
[i
].IsStringRange
&& expect_value_caps
[i
].IsStringRange
)
590 check_member(value_caps
[i
], expect_value_caps
[i
], "%d", Range
.StringMin
);
591 check_member(value_caps
[i
], expect_value_caps
[i
], "%d", Range
.StringMax
);
594 if (!value_caps
[i
].IsDesignatorRange
&& !expect_value_caps
[i
].IsDesignatorRange
)
595 check_member(value_caps
[i
], expect_value_caps
[i
], "%d", NotRange
.DesignatorIndex
);
596 else if (value_caps
[i
].IsDesignatorRange
&& expect_value_caps
[i
].IsDesignatorRange
)
598 check_member(value_caps
[i
], expect_value_caps
[i
], "%d", Range
.DesignatorMin
);
599 check_member(value_caps
[i
], expect_value_caps
[i
], "%d", Range
.DesignatorMax
);
601 winetest_pop_context();
604 status
= HidP_InitializeReportForID(HidP_Input
, 0, preparsed
, buffer
, hid_caps
->InputReportByteLength
);
605 ok(status
== HIDP_STATUS_SUCCESS
, "HidP_InitializeReportForID returned %#lx\n", status
);
607 SetLastError(0xdeadbeef);
608 memset(buffer
, 0, sizeof(buffer
));
609 ret
= HidD_GetInputReport(device
, buffer
, hid_caps
->InputReportByteLength
);
610 ok(!ret
, "HidD_GetInputReport succeeded\n");
611 ok(GetLastError() == ERROR_INVALID_PARAMETER
, "HidD_GetInputReport returned error %lu\n", GetLastError());
613 if (!winetest_interactive
) skip("skipping interactive tests\n");
614 /* ReadFile on Xbox One For Windows controller seems to never succeed */
615 else if (attrs
->VendorID
== 0x045e && attrs
->ProductID
== 0x02ff) skip("skipping interactive tests (Xbox One For Windows)\n");
618 res
= pXInputGetState(index
, &last_state
);
619 ok(res
== ERROR_SUCCESS
, "XInputGetState returned %#lx\n", res
);
621 trace("press A button on gamepad %lu\n", index
);
626 res
= pXInputGetState(index
, &state
);
627 ok(res
== ERROR_SUCCESS
, "XInputGetState returned %#lx\n", res
);
628 } while (res
== ERROR_SUCCESS
&& state
.dwPacketNumber
== last_state
.dwPacketNumber
);
629 ok(state
.Gamepad
.wButtons
& XINPUT_GAMEPAD_A
, "unexpected button state %#x\n", state
.Gamepad
.wButtons
);
631 /* now read as many reports from the device to get a consistent final state */
632 for (i
= 0; i
< (state
.dwPacketNumber
- last_state
.dwPacketNumber
); ++i
)
634 SetLastError(0xdeadbeef);
635 memset(buffer
, 0, sizeof(buffer
));
636 length
= hid_caps
->InputReportByteLength
;
637 ret
= ReadFile(device
, buffer
, hid_caps
->InputReportByteLength
, &length
, NULL
);
638 ok(ret
, "ReadFile failed, last error %lu\n", GetLastError());
639 ok(length
== hid_caps
->InputReportByteLength
, "ReadFile returned length %lu\n", length
);
643 length
= ARRAY_SIZE(usages
);
644 status
= HidP_GetUsages(HidP_Input
, HID_USAGE_PAGE_BUTTON
, 0, usages
, &length
, preparsed
, buffer
, hid_caps
->InputReportByteLength
);
645 ok(status
== HIDP_STATUS_SUCCESS
, "HidP_GetUsages returned %#lx\n", status
);
646 ok(length
== 1, "got length %lu\n", length
);
647 ok(usages
[0] == 1, "got usages[0] %u\n", usages
[0]);
649 trace("release A on gamepad %lu\n", index
);
654 res
= pXInputGetState(index
, &state
);
655 ok(res
== ERROR_SUCCESS
, "XInputGetState returned %#lx\n", res
);
656 } while (res
== ERROR_SUCCESS
&& state
.dwPacketNumber
== last_state
.dwPacketNumber
);
657 ok(!state
.Gamepad
.wButtons
, "unexpected button state %#x\n", state
.Gamepad
.wButtons
);
659 /* now read as many reports from the device to get a consistent final state */
660 for (i
= 0; i
< (state
.dwPacketNumber
- last_state
.dwPacketNumber
); ++i
)
662 SetLastError(0xdeadbeef);
663 memset(buffer
, 0, sizeof(buffer
));
664 length
= hid_caps
->InputReportByteLength
;
665 ret
= ReadFile(device
, buffer
, hid_caps
->InputReportByteLength
, &length
, NULL
);
666 ok(ret
, "ReadFile failed, last error %lu\n", GetLastError());
667 ok(length
== hid_caps
->InputReportByteLength
, "ReadFile returned length %lu\n", length
);
671 length
= ARRAY_SIZE(usages
);
672 status
= HidP_GetUsages(HidP_Input
, HID_USAGE_PAGE_BUTTON
, 0, usages
, &length
, preparsed
, buffer
, hid_caps
->InputReportByteLength
);
673 ok(status
== HIDP_STATUS_SUCCESS
, "HidP_GetUsages returned %#lx\n", status
);
674 ok(length
== 0, "got length %lu\n", length
);
676 trace("press both LT and RT on gamepad %lu\n", index
);
683 res
= pXInputGetState(index
, &state
);
684 ok(res
== ERROR_SUCCESS
, "XInputGetState returned %#lx\n", res
);
685 } while (res
== ERROR_SUCCESS
&& state
.dwPacketNumber
== last_state
.dwPacketNumber
);
687 /* now read as many reports from the device to get a consistent final state */
688 for (i
= 0; i
< (state
.dwPacketNumber
- last_state
.dwPacketNumber
); ++i
)
690 SetLastError(0xdeadbeef);
691 memset(buffer
, 0, sizeof(buffer
));
692 length
= hid_caps
->InputReportByteLength
;
693 ret
= ReadFile(device
, buffer
, hid_caps
->InputReportByteLength
, &length
, NULL
);
694 ok(ret
, "ReadFile failed, last error %lu\n", GetLastError());
695 ok(length
== hid_caps
->InputReportByteLength
, "ReadFile returned length %lu\n", length
);
700 status
= HidP_GetUsageValue(HidP_Input
, HID_USAGE_PAGE_GENERIC
, 0, HID_USAGE_GENERIC_X
, &value
, preparsed
, buffer
, hid_caps
->InputReportByteLength
);
701 ok(status
== HIDP_STATUS_SUCCESS
, "HidP_GetUsageValue returned %#lx\n", status
);
702 ok(value
== state
.Gamepad
.sThumbLX
+ 32768, "got LX value %lu\n", value
);
704 status
= HidP_GetUsageValue(HidP_Input
, HID_USAGE_PAGE_GENERIC
, 0, HID_USAGE_GENERIC_Y
, &value
, preparsed
, buffer
, hid_caps
->InputReportByteLength
);
705 ok(status
== HIDP_STATUS_SUCCESS
, "HidP_GetUsageValue returned %#lx\n", status
);
706 ok(value
== 32767 - state
.Gamepad
.sThumbLY
, "got LY value %lu\n", value
);
708 status
= HidP_GetUsageValue(HidP_Input
, HID_USAGE_PAGE_GENERIC
, 0, HID_USAGE_GENERIC_RX
, &value
, preparsed
, buffer
, hid_caps
->InputReportByteLength
);
709 ok(status
== HIDP_STATUS_SUCCESS
, "HidP_GetUsageValue returned %#lx\n", status
);
710 ok(value
== state
.Gamepad
.sThumbRX
+ 32768, "got LX value %lu\n", value
);
712 status
= HidP_GetUsageValue(HidP_Input
, HID_USAGE_PAGE_GENERIC
, 0, HID_USAGE_GENERIC_RY
, &value
, preparsed
, buffer
, hid_caps
->InputReportByteLength
);
713 ok(status
== HIDP_STATUS_SUCCESS
, "HidP_GetUsageValue returned %#lx\n", status
);
714 ok(value
== 32767 - state
.Gamepad
.sThumbRY
, "got LY value %lu\n", value
);
716 status
= HidP_GetUsageValue(HidP_Input
, HID_USAGE_PAGE_GENERIC
, 0, HID_USAGE_GENERIC_Z
, &value
, preparsed
, buffer
, hid_caps
->InputReportByteLength
);
717 ok(status
== HIDP_STATUS_SUCCESS
, "HidP_GetUsageValue returned %#lx\n", status
);
718 ok(value
== 32768 + (state
.Gamepad
.bLeftTrigger
- state
.Gamepad
.bRightTrigger
) * 128, "got Z value %lu (RT %d, LT %d)\n",
719 value
, state
.Gamepad
.bRightTrigger
, state
.Gamepad
.bLeftTrigger
);
721 status
= HidP_GetUsageValue(HidP_Input
, HID_USAGE_PAGE_GENERIC
, 0, HID_USAGE_GENERIC_RZ
, &value
, preparsed
, buffer
, hid_caps
->InputReportByteLength
);
722 ok(status
== HIDP_STATUS_USAGE_NOT_FOUND
, "HidP_GetUsageValue returned %#lx\n", status
);
723 } while (ret
&& (state
.Gamepad
.bRightTrigger
!= 255 || state
.Gamepad
.bLeftTrigger
!= 255));
727 static BOOL
try_open_hid_device(const WCHAR
*path
, HANDLE
*device
, PHIDP_PREPARSED_DATA
*preparsed
,
728 HIDD_ATTRIBUTES
*attrs
, HIDP_CAPS
*caps
)
730 PHIDP_PREPARSED_DATA preparsed_data
= NULL
;
733 device_file
= CreateFileW(path
, FILE_READ_ACCESS
| FILE_WRITE_ACCESS
, FILE_SHARE_READ
| FILE_SHARE_WRITE
,
734 NULL
, OPEN_EXISTING
, 0, NULL
);
735 if (device_file
== INVALID_HANDLE_VALUE
) return FALSE
;
737 if (!HidD_GetPreparsedData(device_file
, &preparsed_data
)) goto failed
;
738 if (!HidD_GetAttributes(device_file
, attrs
)) goto failed
;
739 if (HidP_GetCaps(preparsed_data
, caps
) != HIDP_STATUS_SUCCESS
) goto failed
;
741 *device
= device_file
;
742 *preparsed
= preparsed_data
;
746 CloseHandle(device_file
);
747 HidD_FreePreparsedData(preparsed_data
);
751 static void test_hid_reports(void)
753 static const WCHAR prefix
[] = L
"\\\\?\\HID#VID_0000&PID_0000";
754 char buffer
[sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W
) + MAX_PATH
* sizeof(WCHAR
)];
755 SP_DEVICE_INTERFACE_DETAIL_DATA_W
*detail
= (void *)buffer
;
756 SP_DEVICE_INTERFACE_DATA iface
= {sizeof(iface
)};
757 SP_DEVINFO_DATA devinfo
= {sizeof(devinfo
)};
758 PHIDP_PREPARSED_DATA preparsed
;
759 HIDD_ATTRIBUTES attrs
;
763 UINT32 i
= 0, cnt
= 0;
766 HidD_GetHidGuid(&hid
);
768 set
= SetupDiGetClassDevsW(&hid
, NULL
, NULL
, DIGCF_DEVICEINTERFACE
);
769 ok(set
!= INVALID_HANDLE_VALUE
, "SetupDiGetClassDevsW failed, error %lu\n", GetLastError());
771 while (SetupDiEnumDeviceInterfaces(set
, NULL
, &hid
, i
++, &iface
))
773 detail
->cbSize
= sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W
);
774 if (!SetupDiGetDeviceInterfaceDetailW(set
, &iface
, detail
, sizeof(buffer
), NULL
, &devinfo
))
777 if (!try_open_hid_device(detail
->DevicePath
, &device
, &preparsed
, &attrs
, &caps
))
780 if (wcslen(detail
->DevicePath
) <= wcslen(prefix
) ||
781 wcsnicmp(detail
->DevicePath
+ wcslen(prefix
), L
"&IG_", 4 ))
784 trace("found xinput HID device %s\n", wine_dbgstr_w(detail
->DevicePath
));
785 check_hid_caps(cnt
++, device
, preparsed
, &attrs
, &caps
);
788 HidD_FreePreparsedData(preparsed
);
791 SetupDiDestroyDeviceInfoList(set
);
801 { "xinput1_1.dll", 1 },
802 { "xinput1_2.dll", 2 },
803 { "xinput1_3.dll", 3 },
804 { "xinput1_4.dll", 4 },
805 { "xinput9_1_0.dll", 0 } /* legacy for XP/Vista */
808 void *pXInputGetStateEx_Ordinal
;
811 for (i
= 0; i
< ARRAY_SIZE(libs
); i
++)
813 hXinput
= LoadLibraryA( libs
[i
].name
);
817 win_skip("Could not load %s\n", libs
[i
].name
);
820 trace("Testing %s\n", libs
[i
].name
);
822 pXInputEnable
= (void*)GetProcAddress(hXinput
, "XInputEnable");
823 pXInputSetState
= (void*)GetProcAddress(hXinput
, "XInputSetState");
824 pXInputGetState
= (void*)GetProcAddress(hXinput
, "XInputGetState");
825 pXInputGetStateEx
= (void*)GetProcAddress(hXinput
, "XInputGetStateEx"); /* Win >= 8 */
826 pXInputGetStateEx_Ordinal
= (void*)GetProcAddress(hXinput
, (LPCSTR
) 100);
827 pXInputGetKeystroke
= (void*)GetProcAddress(hXinput
, "XInputGetKeystroke");
828 pXInputGetCapabilities
= (void*)GetProcAddress(hXinput
, "XInputGetCapabilities");
829 pXInputGetDSoundAudioDeviceGuids
= (void*)GetProcAddress(hXinput
, "XInputGetDSoundAudioDeviceGuids");
830 pXInputGetBatteryInformation
= (void*)GetProcAddress(hXinput
, "XInputGetBatteryInformation");
832 /* XInputGetStateEx may not be present by name, use ordinal in this case */
833 if (!pXInputGetStateEx
)
834 pXInputGetStateEx
= pXInputGetStateEx_Ordinal
;
839 test_get_capabilities();
841 if (libs
[i
].version
!= 4)
842 test_get_dsoundaudiodevice();
844 ok(!pXInputGetDSoundAudioDeviceGuids
, "XInputGetDSoundAudioDeviceGuids exists in %s\n", libs
[i
].name
);
846 if (libs
[i
].version
> 2)
848 test_get_keystroke();
849 test_get_batteryinformation();
850 ok(pXInputGetStateEx
!= NULL
, "XInputGetStateEx not found in %s\n", libs
[i
].name
);
854 ok(!pXInputGetKeystroke
, "XInputGetKeystroke exists in %s\n", libs
[i
].name
);
855 ok(!pXInputGetStateEx
, "XInputGetStateEx exists in %s\n", libs
[i
].name
);
856 ok(!pXInputGetBatteryInformation
, "XInputGetBatteryInformation exists in %s\n", libs
[i
].name
);
857 if (libs
[i
].version
== 0)
858 ok(!pXInputEnable
, "XInputEnable exists in %s\n", libs
[i
].name
);
861 FreeLibrary(hXinput
);