21 #include "../../SDL_internal.h"
23 #ifdef SDL_JOYSTICK_HIDAPI
31 #include "../SDL_sysjoystick.h"
36 #ifdef SDL_JOYSTICK_HIDAPI_XBOX360
39 #define SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT
44 #ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT
45 #include "../../core/windows/SDL_xinput.h"
48 #ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_GAMING_INPUT
49 #include "../../core/windows/SDL_windows.h"
51 #include "windows.gaming.input.h"
57 #ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT
61 #ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_GAMING_INPUT
63 __x_ABI_CWindows_CGaming_CInput_CIGamepadStatics *gamepad_statics;
64 __x_ABI_CWindows_CGaming_CInput_CIGamepad *gamepad;
65 struct __x_ABI_CWindows_CGaming_CInput_CGamepadVibration vibration;
67 } SDL_DriverXbox360_Context;
70 #ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT
71 static Uint8 xinput_slots;
74 HIDAPI_DriverXbox360_MarkXInputSlotUsed(
Uint8 xinput_slot)
76 if (xinput_slot != XUSER_INDEX_ANY) {
77 xinput_slots |= (0x01 << xinput_slot);
82 HIDAPI_DriverXbox360_MarkXInputSlotFree(
Uint8 xinput_slot)
84 if (xinput_slot != XUSER_INDEX_ANY) {
85 xinput_slots &= ~(0x01 << xinput_slot);
90 HIDAPI_DriverXbox360_MissingXInputSlot()
92 return xinput_slots != 0x0F;
96 HIDAPI_DriverXbox360_GuessXInputSlot(WORD wButtons)
102 if (!XINPUTGETSTATE) {
103 return XUSER_INDEX_ANY;
107 for (user_index = 0; user_index < XUSER_MAX_COUNT; ++user_index) {
108 XINPUT_STATE_EX xinput_state;
110 if (XINPUTGETSTATE(user_index, &xinput_state) == ERROR_SUCCESS) {
111 if (xinput_state.Gamepad.wButtons == wButtons) {
113 match_slot = (
Uint8)user_index;
117 if (match_count == 1) {
120 return XUSER_INDEX_ANY;
125 #ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_GAMING_INPUT
128 HIDAPI_DriverXbox360_InitWindowsGamingInput(SDL_DriverXbox360_Context *
ctx)
137 static const IID SDL_IID_IGamepadStatics = { 0x8BBCE529, 0xD49C, 0x39E9, { 0x95, 0x60, 0xE4, 0x7D, 0xDE, 0x96, 0xB7, 0xC8 } };
139 HMODULE hModule = LoadLibraryA(
"combase.dll");
140 if (hModule !=
NULL) {
141 typedef HRESULT (WINAPI *WindowsCreateString_t)(PCNZWCH sourceString, UINT32
length, HSTRING*
string);
142 typedef HRESULT (WINAPI *WindowsDeleteString_t)(HSTRING
string);
143 typedef HRESULT (WINAPI *RoGetActivationFactory_t)(HSTRING activatableClassId, REFIID iid,
void**
factory);
145 WindowsCreateString_t WindowsCreateStringFunc = (WindowsCreateString_t)GetProcAddress(hModule,
"WindowsCreateString");
146 WindowsDeleteString_t WindowsDeleteStringFunc = (WindowsDeleteString_t)GetProcAddress(hModule,
"WindowsDeleteString");
147 RoGetActivationFactory_t RoGetActivationFactoryFunc = (RoGetActivationFactory_t)GetProcAddress(hModule,
"RoGetActivationFactory");
148 if (WindowsCreateStringFunc && WindowsDeleteStringFunc && RoGetActivationFactoryFunc) {
149 LPTSTR pNamespace = L
"Windows.Gaming.Input.Gamepad";
150 HSTRING hNamespaceString;
152 hr = WindowsCreateStringFunc(pNamespace,
SDL_wcslen(pNamespace), &hNamespaceString);
154 RoGetActivationFactoryFunc(hNamespaceString, &SDL_IID_IGamepadStatics, &
ctx->gamepad_statics);
155 WindowsDeleteStringFunc(hNamespaceString);
158 FreeLibrary(hModule);
164 HIDAPI_DriverXbox360_GetGamepadButtonsForMatch(__x_ABI_CWindows_CGaming_CInput_CIGamepad *gamepad)
167 struct __x_ABI_CWindows_CGaming_CInput_CGamepadReading
state;
170 hr = __x_ABI_CWindows_CGaming_CInput_CIGamepad_GetCurrentReading(gamepad, &
state);
172 if (
state.Buttons & GamepadButtons_A) {
175 if (
state.Buttons & GamepadButtons_B) {
178 if (
state.Buttons & GamepadButtons_X) {
181 if (
state.Buttons & GamepadButtons_Y) {
189 HIDAPI_DriverXbox360_GuessGamepad(SDL_DriverXbox360_Context *
ctx,
Uint8 buttons)
192 __FIVectorView_1_Windows__CGaming__CInput__CGamepad *gamepads;
194 hr = __x_ABI_CWindows_CGaming_CInput_CIGamepadStatics_get_Gamepads(
ctx->gamepad_statics, &gamepads);
196 unsigned int i, num_gamepads;
198 hr = __FIVectorView_1_Windows__CGaming__CInput__CGamepad_get_Size(gamepads, &num_gamepads);
201 unsigned int match_slot;
204 for (
i = 0;
i < num_gamepads; ++
i) {
205 __x_ABI_CWindows_CGaming_CInput_CIGamepad *gamepad;
207 hr = __FIVectorView_1_Windows__CGaming__CInput__CGamepad_GetAt(gamepads,
i, &gamepad);
209 Uint8 gamepad_buttons = HIDAPI_DriverXbox360_GetGamepadButtonsForMatch(gamepad);
210 if (buttons == gamepad_buttons) {
214 __x_ABI_CWindows_CGaming_CInput_CIGamepad_Release(gamepad);
217 if (match_count == 1) {
218 hr = __FIVectorView_1_Windows__CGaming__CInput__CGamepad_GetAt(gamepads, match_slot, &
ctx->gamepad);
223 __FIVectorView_1_Windows__CGaming__CInput__CGamepad_Release(gamepads);
228 HIDAPI_DriverXbox360_QuitWindowsGamingInput(SDL_DriverXbox360_Context *
ctx)
230 if (
ctx->gamepad_statics) {
231 __x_ABI_CWindows_CGaming_CInput_CIGamepadStatics_Release(
ctx->gamepad_statics);
235 __x_ABI_CWindows_CGaming_CInput_CIGamepad_Release(
ctx->gamepad);
239 if (
ctx->coinitialized) {
247 #if defined(__MACOSX__)
249 IsBluetoothXboxOneController(
Uint16 vendor_id,
Uint16 product_id)
266 const int XB360W_IFACE_PROTOCOL = 129;
277 if (interface_number > 0) {
281 #if defined(__MACOSX__) || defined(__WIN32__)
286 #if defined(__MACOSX__)
293 if (IsBluetoothXboxOneController(vendor_id, product_id)) {
304 HIDAPI_DriverXbox360_GetDeviceName(
Uint16 vendor_id,
Uint16 product_id)
312 const Uint8 led_packet[] = { 0x01, 0x03,
mode };
314 if (
hid_write(dev, led_packet,
sizeof(led_packet)) !=
sizeof(led_packet)) {
321 HIDAPI_DriverXbox360_InitDevice(SDL_HIDAPI_Device *
device)
327 HIDAPI_DriverXbox360_GetDevicePlayerIndex(SDL_HIDAPI_Device *
device,
SDL_JoystickID instance_id)
333 HIDAPI_DriverXbox360_SetDevicePlayerIndex(SDL_HIDAPI_Device *
device,
SDL_JoystickID instance_id,
int player_index)
336 SetSlotLED(
device->dev, (player_index % 4));
341 HIDAPI_DriverXbox360_OpenJoystick(SDL_HIDAPI_Device *
device, SDL_Joystick *joystick)
343 SDL_DriverXbox360_Context *
ctx;
360 #ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT
362 if (
ctx->xinput_enabled && WIN_LoadXInputDLL() < 0) {
365 ctx->xinput_slot = XUSER_INDEX_ANY;
367 #ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_GAMING_INPUT
368 HIDAPI_DriverXbox360_InitWindowsGamingInput(
ctx);
373 if (player_index >= 0) {
374 SetSlotLED(
device->dev, (player_index % 4));
386 HIDAPI_DriverXbox360_RumbleJoystick(SDL_HIDAPI_Device *
device, SDL_Joystick *joystick,
Uint16 low_frequency_rumble,
Uint16 high_frequency_rumble)
388 #if defined(SDL_JOYSTICK_HIDAPI_WINDOWS_GAMING_INPUT) || defined(SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT)
389 SDL_DriverXbox360_Context *
ctx = (SDL_DriverXbox360_Context *)
device->context;
395 #ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_GAMING_INPUT
396 if (!rumbled &&
ctx->gamepad) {
401 hr = __x_ABI_CWindows_CGaming_CInput_CIGamepad_put_Vibration(
ctx->gamepad,
ctx->vibration);
408 #ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT
409 if (!rumbled &&
ctx->xinput_slot != XUSER_INDEX_ANY) {
410 XINPUT_VIBRATION XVibration;
412 if (!XINPUTSETSTATE) {
416 XVibration.wLeftMotorSpeed = low_frequency_rumble;
417 XVibration.wRightMotorSpeed = high_frequency_rumble;
418 if (XINPUTSETSTATE(
ctx->xinput_slot, &XVibration) == ERROR_SUCCESS) {
429 if (IsBluetoothXboxOneController(
device->vendor_id,
device->product_id)) {
430 Uint8 rumble_packet[] = { 0x03, 0x0F, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00 };
432 rumble_packet[4] = (low_frequency_rumble >> 8);
433 rumble_packet[5] = (high_frequency_rumble >> 8);
435 if (SDL_HIDAPI_SendRumble(
device, rumble_packet,
sizeof(rumble_packet)) !=
sizeof(rumble_packet)) {
442 Uint8 rumble_packet[] = {
'M',
'A',
'G',
'I',
'C',
'0', 0x00, 0x04, 0x00, 0x00 };
444 rumble_packet[6+2] = (low_frequency_rumble >> 8);
445 rumble_packet[6+3] = (high_frequency_rumble >> 8);
447 if (SDL_HIDAPI_SendRumble(
device, rumble_packet,
sizeof(rumble_packet)) !=
sizeof(rumble_packet)) {
452 Uint8 rumble_packet[] = { 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
454 rumble_packet[3] = (low_frequency_rumble >> 8);
455 rumble_packet[4] = (high_frequency_rumble >> 8);
457 if (SDL_HIDAPI_SendRumble(
device, rumble_packet,
sizeof(rumble_packet)) !=
sizeof(rumble_packet)) {
474 HIDAPI_DriverXbox360_HandleStatePacket(SDL_Joystick *joystick,
hid_device *dev, SDL_DriverXbox360_Context *
ctx,
Uint8 *
data,
int size)
479 if (
ctx->last_state[10] !=
data[10]) {
490 if (
ctx->last_state[11] !=
data[11]) {
499 switch (
data[11] & 0x3C) {
546 #ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_GAMING_INPUT
547 if (
ctx->gamepad_statics && !
ctx->gamepad) {
550 if (
data[10] & 0x01) {
553 if (
data[10] & 0x02) {
556 if (
data[10] & 0x04) {
559 if (
data[10] & 0x08) {
563 HIDAPI_DriverXbox360_GuessGamepad(
ctx, buttons);
569 struct __x_ABI_CWindows_CGaming_CInput_CGamepadReading
state;
571 hr = __x_ABI_CWindows_CGaming_CInput_CIGamepad_GetCurrentReading(
ctx->gamepad, &
state);
581 #ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT
582 if (
ctx->xinput_enabled) {
583 if (
ctx->xinput_slot == XUSER_INDEX_ANY && HIDAPI_DriverXbox360_MissingXInputSlot()) {
586 if (
data[10] & 0x01) {
587 wButtons |= XINPUT_GAMEPAD_A;
589 if (
data[10] & 0x02) {
590 wButtons |= XINPUT_GAMEPAD_B;
592 if (
data[10] & 0x04) {
593 wButtons |= XINPUT_GAMEPAD_X;
595 if (
data[10] & 0x08) {
596 wButtons |= XINPUT_GAMEPAD_Y;
599 Uint8 xinput_slot = HIDAPI_DriverXbox360_GuessXInputSlot(wButtons);
600 if (xinput_slot != XUSER_INDEX_ANY) {
601 HIDAPI_DriverXbox360_MarkXInputSlotUsed(xinput_slot);
602 ctx->xinput_slot = xinput_slot;
607 if (!has_trigger_data &&
ctx->xinput_slot != XUSER_INDEX_ANY) {
608 XINPUT_STATE_EX xinput_state;
610 if (XINPUTGETSTATE(
ctx->xinput_slot, &xinput_state) == ERROR_SUCCESS) {
620 if (!has_trigger_data) {
622 if (
data[9] < 0x80) {
625 }
else if (
data[9] > 0x80) {
639 HIDAPI_DriverXbox360_HandleStatePacket(SDL_Joystick *joystick,
hid_device *dev, SDL_DriverXbox360_Context *
ctx,
Uint8 *
data,
int size)
648 if (
ctx->last_state[2] !=
data[2]) {
659 if (
ctx->last_state[3] !=
data[3]) {
669 axis = ((int)
data[4] * 257) - 32768;
671 axis = ((int)
data[5] * 257) - 32768;
693 HIDAPI_DriverXbox360_UpdateDevice(SDL_HIDAPI_Device *
device)
695 SDL_DriverXbox360_Context *
ctx = (SDL_DriverXbox360_Context *)
device->context;
696 SDL_Joystick *joystick =
NULL;
719 HIDAPI_DriverXbox360_CloseJoystick(SDL_HIDAPI_Device *
device, SDL_Joystick *joystick)
721 #if defined(SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT) || defined(SDL_JOYSTICK_HIDAPI_WINDOWS_GAMING_INPUT)
722 SDL_DriverXbox360_Context *
ctx = (SDL_DriverXbox360_Context *)
device->context;
725 #ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT
726 if (
ctx->xinput_enabled) {
727 HIDAPI_DriverXbox360_MarkXInputSlotFree(
ctx->xinput_slot);
728 WIN_UnloadXInputDLL();
731 #ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_GAMING_INPUT
732 HIDAPI_DriverXbox360_QuitWindowsGamingInput(
ctx);
743 HIDAPI_DriverXbox360_FreeDevice(SDL_HIDAPI_Device *
device)
751 HIDAPI_DriverXbox360_IsSupportedDevice,
752 HIDAPI_DriverXbox360_GetDeviceName,
753 HIDAPI_DriverXbox360_InitDevice,
754 HIDAPI_DriverXbox360_GetDevicePlayerIndex,
755 HIDAPI_DriverXbox360_SetDevicePlayerIndex,
756 HIDAPI_DriverXbox360_UpdateDevice,
757 HIDAPI_DriverXbox360_OpenJoystick,
758 HIDAPI_DriverXbox360_RumbleJoystick,
759 HIDAPI_DriverXbox360_CloseJoystick,
760 HIDAPI_DriverXbox360_FreeDevice