21 #include "../../SDL_internal.h"
23 #ifdef SDL_JOYSTICK_HIDAPI
31 #include "../SDL_sysjoystick.h"
35 #ifdef SDL_JOYSTICK_HIDAPI_XBOX360
38 #define SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT
43 #ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT
44 #include "../../core/windows/SDL_xinput.h"
47 #ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_GAMING_INPUT
48 #include "../../core/windows/SDL_windows.h"
50 #include "windows.gaming.input.h"
53 #define USB_PACKET_LENGTH 64
57 Uint8 last_state[USB_PACKET_LENGTH];
59 #ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT
63 #ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_GAMING_INPUT
65 __x_ABI_CWindows_CGaming_CInput_CIGamepadStatics *gamepad_statics;
66 __x_ABI_CWindows_CGaming_CInput_CIGamepad *gamepad;
67 struct __x_ABI_CWindows_CGaming_CInput_CGamepadVibration vibration;
69 } SDL_DriverXbox360_Context;
72 #ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT
73 static Uint8 xinput_slots;
76 HIDAPI_DriverXbox360_MarkXInputSlotUsed(
Uint8 xinput_slot)
78 if (xinput_slot != XUSER_INDEX_ANY) {
79 xinput_slots |= (0x01 << xinput_slot);
84 HIDAPI_DriverXbox360_MarkXInputSlotFree(
Uint8 xinput_slot)
86 if (xinput_slot != XUSER_INDEX_ANY) {
87 xinput_slots &= ~(0x01 << xinput_slot);
92 HIDAPI_DriverXbox360_MissingXInputSlot()
94 return xinput_slots != 0x0F;
98 HIDAPI_DriverXbox360_GuessXInputSlot(WORD wButtons)
104 if (!XINPUTGETSTATE) {
105 return XUSER_INDEX_ANY;
109 for (user_index = 0; user_index < XUSER_MAX_COUNT; ++user_index) {
110 XINPUT_STATE_EX xinput_state;
112 if (XINPUTGETSTATE(user_index, &xinput_state) == ERROR_SUCCESS) {
113 if (xinput_state.Gamepad.wButtons == wButtons) {
115 match_slot = (
Uint8)user_index;
119 if (match_count == 1) {
122 return XUSER_INDEX_ANY;
127 #ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_GAMING_INPUT
130 HIDAPI_DriverXbox360_InitWindowsGamingInput(SDL_DriverXbox360_Context *
ctx)
139 static const IID SDL_IID_IGamepadStatics = { 0x8BBCE529, 0xD49C, 0x39E9, { 0x95, 0x60, 0xE4, 0x7D, 0xDE, 0x96, 0xB7, 0xC8 } };
141 HMODULE hModule = LoadLibraryA(
"combase.dll");
142 if (hModule !=
NULL) {
143 typedef HRESULT (WINAPI *WindowsCreateString_t)(PCNZWCH sourceString, UINT32
length, HSTRING*
string);
144 typedef HRESULT (WINAPI *WindowsDeleteString_t)(HSTRING
string);
145 typedef HRESULT (WINAPI *RoGetActivationFactory_t)(HSTRING activatableClassId, REFIID iid,
void**
factory);
147 WindowsCreateString_t WindowsCreateStringFunc = (WindowsCreateString_t)GetProcAddress(hModule,
"WindowsCreateString");
148 WindowsDeleteString_t WindowsDeleteStringFunc = (WindowsDeleteString_t)GetProcAddress(hModule,
"WindowsDeleteString");
149 RoGetActivationFactory_t RoGetActivationFactoryFunc = (RoGetActivationFactory_t)GetProcAddress(hModule,
"RoGetActivationFactory");
150 if (WindowsCreateStringFunc && WindowsDeleteStringFunc && RoGetActivationFactoryFunc) {
151 LPTSTR pNamespace = L
"Windows.Gaming.Input.Gamepad";
152 HSTRING hNamespaceString;
154 hr = WindowsCreateStringFunc(pNamespace,
SDL_wcslen(pNamespace), &hNamespaceString);
156 RoGetActivationFactoryFunc(hNamespaceString, &SDL_IID_IGamepadStatics, &
ctx->gamepad_statics);
157 WindowsDeleteStringFunc(hNamespaceString);
160 FreeLibrary(hModule);
166 HIDAPI_DriverXbox360_GetGamepadButtonsForMatch(__x_ABI_CWindows_CGaming_CInput_CIGamepad *gamepad)
169 struct __x_ABI_CWindows_CGaming_CInput_CGamepadReading
state;
172 hr = __x_ABI_CWindows_CGaming_CInput_CIGamepad_GetCurrentReading(gamepad, &
state);
174 if (
state.Buttons & GamepadButtons_A) {
177 if (
state.Buttons & GamepadButtons_B) {
180 if (
state.Buttons & GamepadButtons_X) {
183 if (
state.Buttons & GamepadButtons_Y) {
191 HIDAPI_DriverXbox360_GuessGamepad(SDL_DriverXbox360_Context *
ctx,
Uint8 buttons)
194 __FIVectorView_1_Windows__CGaming__CInput__CGamepad *gamepads;
196 hr = __x_ABI_CWindows_CGaming_CInput_CIGamepadStatics_get_Gamepads(
ctx->gamepad_statics, &gamepads);
198 unsigned int i, num_gamepads;
200 hr = __FIVectorView_1_Windows__CGaming__CInput__CGamepad_get_Size(gamepads, &num_gamepads);
203 unsigned int match_slot;
206 for (
i = 0;
i < num_gamepads; ++
i) {
207 __x_ABI_CWindows_CGaming_CInput_CIGamepad *gamepad;
209 hr = __FIVectorView_1_Windows__CGaming__CInput__CGamepad_GetAt(gamepads,
i, &gamepad);
211 Uint8 gamepad_buttons = HIDAPI_DriverXbox360_GetGamepadButtonsForMatch(gamepad);
212 if (buttons == gamepad_buttons) {
216 __x_ABI_CWindows_CGaming_CInput_CIGamepad_Release(gamepad);
219 if (match_count == 1) {
220 hr = __FIVectorView_1_Windows__CGaming__CInput__CGamepad_GetAt(gamepads, match_slot, &
ctx->gamepad);
225 __FIVectorView_1_Windows__CGaming__CInput__CGamepad_Release(gamepads);
230 HIDAPI_DriverXbox360_QuitWindowsGamingInput(SDL_DriverXbox360_Context *
ctx)
232 if (
ctx->gamepad_statics) {
233 __x_ABI_CWindows_CGaming_CInput_CIGamepadStatics_Release(
ctx->gamepad_statics);
237 __x_ABI_CWindows_CGaming_CInput_CIGamepad_Release(
ctx->gamepad);
241 if (
ctx->coinitialized) {
250 HIDAPI_DriverXbox360_IsSupportedDevice(
Uint16 vendor_id,
Uint16 product_id,
Uint16 version,
int interface_number)
252 #if defined(__MACOSX__) || defined(__WIN32__)
253 if (vendor_id == 0x045e && product_id == 0x028e && version == 1) {
264 HIDAPI_DriverXbox360_GetDeviceName(
Uint16 vendor_id,
Uint16 product_id)
271 const Uint8 led_packet[] = { 0x01, 0x03, (2 + slot) };
273 if (
hid_write(dev, led_packet,
sizeof(led_packet)) !=
sizeof(led_packet)) {
282 SDL_DriverXbox360_Context *
ctx;
289 #ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT
291 if (
ctx->xinput_enabled && WIN_LoadXInputDLL() < 0) {
294 ctx->xinput_slot = XUSER_INDEX_ANY;
296 #ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_GAMING_INPUT
297 HIDAPI_DriverXbox360_InitWindowsGamingInput(
ctx);
302 SetSlotLED(dev, (joystick->instance_id % 4));
315 SDL_DriverXbox360_Context *
ctx = (SDL_DriverXbox360_Context *)
context;
320 #ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_GAMING_INPUT
321 if (!rumbled &&
ctx->gamepad) {
326 hr = __x_ABI_CWindows_CGaming_CInput_CIGamepad_put_Vibration(
ctx->gamepad,
ctx->vibration);
333 #ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT
334 if (!rumbled &&
ctx->xinput_slot != XUSER_INDEX_ANY) {
335 XINPUT_VIBRATION XVibration;
337 if (!XINPUTSETSTATE) {
341 XVibration.wLeftMotorSpeed = low_frequency_rumble;
342 XVibration.wRightMotorSpeed = high_frequency_rumble;
343 if (XINPUTSETSTATE(
ctx->xinput_slot, &XVibration) == ERROR_SUCCESS) {
357 Uint8 rumble_packet[] = {
'M',
'A',
'G',
'I',
'C',
'0', 0x00, 0x04, 0x00, 0x00 };
359 rumble_packet[6+2] = (low_frequency_rumble >> 8);
360 rumble_packet[6+3] = (high_frequency_rumble >> 8);
362 Uint8 rumble_packet[] = { 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
364 rumble_packet[3] = (low_frequency_rumble >> 8);
365 rumble_packet[4] = (high_frequency_rumble >> 8);
368 if (
hid_write(dev, rumble_packet,
sizeof(rumble_packet)) !=
sizeof(rumble_packet)) {
373 if ((low_frequency_rumble || high_frequency_rumble) && duration_ms) {
376 ctx->rumble_expiration = 0;
389 HIDAPI_DriverXbox360_HandleStatePacket(SDL_Joystick *joystick,
hid_device *dev, SDL_DriverXbox360_Context *
ctx,
Uint8 *
data,
int size)
394 if (
ctx->last_state[10] !=
data[10]) {
405 if (
ctx->last_state[11] !=
data[11]) {
414 switch (
data[11] & 0x3C) {
461 #ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_GAMING_INPUT
462 if (
ctx->gamepad_statics && !
ctx->gamepad) {
465 if (
data[10] & 0x01) {
468 if (
data[10] & 0x02) {
471 if (
data[10] & 0x04) {
474 if (
data[10] & 0x08) {
478 HIDAPI_DriverXbox360_GuessGamepad(
ctx, buttons);
484 struct __x_ABI_CWindows_CGaming_CInput_CGamepadReading
state;
486 hr = __x_ABI_CWindows_CGaming_CInput_CIGamepad_GetCurrentReading(
ctx->gamepad, &
state);
496 #ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT
497 if (
ctx->xinput_enabled) {
498 if (
ctx->xinput_slot == XUSER_INDEX_ANY && HIDAPI_DriverXbox360_MissingXInputSlot()) {
501 if (
data[10] & 0x01) {
502 wButtons |= XINPUT_GAMEPAD_A;
504 if (
data[10] & 0x02) {
505 wButtons |= XINPUT_GAMEPAD_B;
507 if (
data[10] & 0x04) {
508 wButtons |= XINPUT_GAMEPAD_X;
510 if (
data[10] & 0x08) {
511 wButtons |= XINPUT_GAMEPAD_Y;
514 Uint8 xinput_slot = HIDAPI_DriverXbox360_GuessXInputSlot(wButtons);
515 if (xinput_slot != XUSER_INDEX_ANY) {
516 HIDAPI_DriverXbox360_MarkXInputSlotUsed(xinput_slot);
517 ctx->xinput_slot = xinput_slot;
522 if (!has_trigger_data &&
ctx->xinput_slot != XUSER_INDEX_ANY) {
523 XINPUT_STATE_EX xinput_state;
525 if (XINPUTGETSTATE(
ctx->xinput_slot, &xinput_state) == ERROR_SUCCESS) {
535 if (!has_trigger_data) {
537 if (
data[9] < 0x80) {
540 }
else if (
data[9] > 0x80) {
554 HIDAPI_DriverXbox360_HandleStatePacket(SDL_Joystick *joystick,
hid_device *dev, SDL_DriverXbox360_Context *
ctx,
Uint8 *
data,
int size)
563 if (
ctx->last_state[2] !=
data[2]) {
574 if (
ctx->last_state[3] !=
data[3]) {
584 axis = ((int)
data[4] * 257) - 32768;
586 axis = ((int)
data[5] * 257) - 32768;
609 HIDAPI_DriverXboxOneS_HandleStatePacket(SDL_Joystick *joystick,
hid_device *dev, SDL_DriverXbox360_Context *
ctx,
Uint8 *
data,
int size)
613 if (
ctx->last_state[14] !=
data[14]) {
622 if (
ctx->last_state[15] !=
data[15]) {
628 if (
ctx->last_state[16] !=
data[16]) {
632 if (
ctx->last_state[13] !=
data[13]) {
701 HIDAPI_DriverXboxOneS_HandleGuidePacket(SDL_Joystick *joystick,
hid_device *dev, SDL_DriverXbox360_Context *
ctx,
Uint8 *
data,
int size)
708 HIDAPI_DriverXbox360_Update(SDL_Joystick *joystick,
hid_device *dev,
void *
context)
710 SDL_DriverXbox360_Context *
ctx = (SDL_DriverXbox360_Context *)
context;
716 HIDAPI_DriverXbox360_HandleStatePacket(joystick, dev,
ctx,
data,
size);
720 HIDAPI_DriverXbox360_HandleStatePacket(joystick, dev,
ctx,
data,
size);
724 HIDAPI_DriverXboxOneS_HandleStatePacket(joystick, dev,
ctx,
data,
size);
727 HIDAPI_DriverXboxOneS_HandleGuidePacket(joystick, dev,
ctx,
data,
size);
731 #ifdef DEBUG_JOYSTICK
732 SDL_Log(
"Unknown Xbox 360 packet, size = %d\n",
size);
733 SDL_Log(
"%.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x\n",
742 if (
ctx->rumble_expiration) {
745 HIDAPI_DriverXbox360_Rumble(joystick, dev,
context, 0, 0, 0);
753 HIDAPI_DriverXbox360_Quit(SDL_Joystick *joystick,
hid_device *dev,
void *
context)
755 #if defined(SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT) || defined(SDL_JOYSTICK_HIDAPI_WINDOWS_GAMING_INPUT)
756 SDL_DriverXbox360_Context *
ctx = (SDL_DriverXbox360_Context *)
context;
759 #ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT
760 if (
ctx->xinput_enabled) {
761 HIDAPI_DriverXbox360_MarkXInputSlotFree(
ctx->xinput_slot);
762 WIN_UnloadXInputDLL();
765 #ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_GAMING_INPUT
766 HIDAPI_DriverXbox360_InitWindowsGamingInput(
ctx);
775 HIDAPI_DriverXbox360_IsSupportedDevice,
776 HIDAPI_DriverXbox360_GetDeviceName,
777 HIDAPI_DriverXbox360_Init,
778 HIDAPI_DriverXbox360_Rumble,
779 HIDAPI_DriverXbox360_Update,
780 HIDAPI_DriverXbox360_Quit