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);
234 ctx->gamepad_statics =
NULL;
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) {
257 if (vendor_id == 0x045e && product_id == 0x02e0) {
268 HIDAPI_DriverXbox360_GetDeviceName(
Uint16 vendor_id,
Uint16 product_id)
275 const Uint8 led_packet[] = { 0x01, 0x03, (2 + slot) };
277 if (
hid_write(dev, led_packet,
sizeof(led_packet)) !=
sizeof(led_packet)) {
286 SDL_DriverXbox360_Context *
ctx;
288 ctx = (SDL_DriverXbox360_Context *)
SDL_calloc(1,
sizeof(*ctx));
293 #ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT 295 if (ctx->xinput_enabled && WIN_LoadXInputDLL() < 0) {
298 ctx->xinput_slot = XUSER_INDEX_ANY;
300 #ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_GAMING_INPUT 301 HIDAPI_DriverXbox360_InitWindowsGamingInput(ctx);
306 SetSlotLED(dev, (joystick->instance_id % 4));
317 HIDAPI_DriverXbox360_Rumble(SDL_Joystick *joystick,
hid_device *dev,
void *context,
Uint16 low_frequency_rumble,
Uint16 high_frequency_rumble,
Uint32 duration_ms)
319 SDL_DriverXbox360_Context *ctx = (SDL_DriverXbox360_Context *)context;
324 #ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_GAMING_INPUT 325 if (!rumbled && ctx->gamepad) {
328 ctx->vibration.LeftMotor = (DOUBLE)low_frequency_rumble /
SDL_MAX_UINT16;
329 ctx->vibration.RightMotor = (DOUBLE)high_frequency_rumble /
SDL_MAX_UINT16;
330 hr = __x_ABI_CWindows_CGaming_CInput_CIGamepad_put_Vibration(ctx->gamepad, ctx->vibration);
337 #ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT 338 if (!rumbled && ctx->xinput_slot != XUSER_INDEX_ANY) {
339 XINPUT_VIBRATION XVibration;
341 if (!XINPUTSETSTATE) {
345 XVibration.wLeftMotorSpeed = low_frequency_rumble;
346 XVibration.wRightMotorSpeed = high_frequency_rumble;
347 if (XINPUTSETSTATE(ctx->xinput_slot, &XVibration) == ERROR_SUCCESS) {
361 Uint8 rumble_packet[] = {
'M',
'A',
'G',
'I',
'C',
'0', 0x00, 0x04, 0x00, 0x00 };
363 rumble_packet[6+2] = (low_frequency_rumble >> 8);
364 rumble_packet[6+3] = (high_frequency_rumble >> 8);
366 Uint8 rumble_packet[] = { 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
368 rumble_packet[3] = (low_frequency_rumble >> 8);
369 rumble_packet[4] = (high_frequency_rumble >> 8);
372 if (
hid_write(dev, rumble_packet,
sizeof(rumble_packet)) !=
sizeof(rumble_packet)) {
377 if ((low_frequency_rumble || high_frequency_rumble) && duration_ms) {
380 ctx->rumble_expiration = 0;
393 HIDAPI_DriverXbox360_HandleStatePacket(SDL_Joystick *joystick,
hid_device *dev, SDL_DriverXbox360_Context *ctx,
Uint8 *
data,
int size)
398 if (ctx->last_state[10] != data[10]) {
409 if (ctx->last_state[11] != data[11]) {
418 switch (data[11] & 0x3C) {
456 axis = (int)*(
Uint16*)(&data[0]) - 0x8000;
458 axis = (int)*(
Uint16*)(&data[2]) - 0x8000;
460 axis = (int)*(
Uint16*)(&data[4]) - 0x8000;
462 axis = (int)*(
Uint16*)(&data[6]) - 0x8000;
465 #ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_GAMING_INPUT 466 if (ctx->gamepad_statics && !ctx->gamepad) {
469 if (data[10] & 0x01) {
472 if (data[10] & 0x02) {
475 if (data[10] & 0x04) {
478 if (data[10] & 0x08) {
482 HIDAPI_DriverXbox360_GuessGamepad(ctx, buttons);
488 struct __x_ABI_CWindows_CGaming_CInput_CGamepadReading
state;
490 hr = __x_ABI_CWindows_CGaming_CInput_CIGamepad_GetCurrentReading(ctx->gamepad, &
state);
500 #ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT 501 if (ctx->xinput_enabled) {
502 if (ctx->xinput_slot == XUSER_INDEX_ANY && HIDAPI_DriverXbox360_MissingXInputSlot()) {
505 if (data[10] & 0x01) {
506 wButtons |= XINPUT_GAMEPAD_A;
508 if (data[10] & 0x02) {
509 wButtons |= XINPUT_GAMEPAD_B;
511 if (data[10] & 0x04) {
512 wButtons |= XINPUT_GAMEPAD_X;
514 if (data[10] & 0x08) {
515 wButtons |= XINPUT_GAMEPAD_Y;
518 Uint8 xinput_slot = HIDAPI_DriverXbox360_GuessXInputSlot(wButtons);
519 if (xinput_slot != XUSER_INDEX_ANY) {
520 HIDAPI_DriverXbox360_MarkXInputSlotUsed(xinput_slot);
521 ctx->xinput_slot = xinput_slot;
526 if (!has_trigger_data && ctx->xinput_slot != XUSER_INDEX_ANY) {
527 XINPUT_STATE_EX xinput_state;
529 if (XINPUTGETSTATE(ctx->xinput_slot, &xinput_state) == ERROR_SUCCESS) {
539 if (!has_trigger_data) {
540 axis = (data[9] * 257) - 32768;
541 if (data[9] < 0x80) {
542 axis = -axis * 2 - 32769;
544 }
else if (data[9] > 0x80) {
545 axis = axis * 2 - 32767;
558 HIDAPI_DriverXbox360_HandleStatePacket(SDL_Joystick *joystick,
hid_device *dev, SDL_DriverXbox360_Context *ctx,
Uint8 *data,
int size)
567 if (ctx->last_state[2] != data[2]) {
578 if (ctx->last_state[3] != data[3]) {
588 axis = ((int)data[4] * 257) - 32768;
590 axis = ((int)data[5] * 257) - 32768;
592 axis = *(
Sint16*)(&data[6]);
594 axis = *(
Sint16*)(&data[8]);
599 axis = *(
Sint16*)(&data[10]);
601 axis = *(
Sint16*)(&data[12]);
613 HIDAPI_DriverXboxOneS_HandleStatePacket(SDL_Joystick *joystick,
hid_device *dev, SDL_DriverXbox360_Context *ctx,
Uint8 *data,
int size)
617 if (ctx->last_state[14] != data[14]) {
626 if (ctx->last_state[15] != data[15]) {
632 if (ctx->last_state[16] != data[16]) {
636 if (ctx->last_state[13] != data[13]) {
680 axis = (int)*(
Uint16*)(&data[1]) - 0x8000;
682 axis = (int)*(
Uint16*)(&data[3]) - 0x8000;
684 axis = (int)*(
Uint16*)(&data[5]) - 0x8000;
686 axis = (int)*(
Uint16*)(&data[7]) - 0x8000;
689 axis = ((int)*(
Sint16*)(&data[9]) * 64) - 32768;
695 axis = ((int)*(
Sint16*)(&data[11]) * 64) - 32768;
705 HIDAPI_DriverXboxOneS_HandleGuidePacket(SDL_Joystick *joystick,
hid_device *dev, SDL_DriverXbox360_Context *ctx,
Uint8 *data,
int size)
712 HIDAPI_DriverXbox360_Update(SDL_Joystick *joystick,
hid_device *dev,
void *context)
714 SDL_DriverXbox360_Context *ctx = (SDL_DriverXbox360_Context *)context;
715 Uint8 data[USB_PACKET_LENGTH];
720 HIDAPI_DriverXbox360_HandleStatePacket(joystick, dev, ctx, data, size);
724 HIDAPI_DriverXbox360_HandleStatePacket(joystick, dev, ctx, data, size);
728 HIDAPI_DriverXboxOneS_HandleStatePacket(joystick, dev, ctx, data, size);
731 HIDAPI_DriverXboxOneS_HandleGuidePacket(joystick, dev, ctx, data, size);
735 #ifdef DEBUG_JOYSTICK 736 SDL_Log(
"Unknown Xbox 360 packet, size = %d\n", size);
737 SDL_Log(
"%.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x\n",
738 data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7],
739 data[8], data[9], data[10], data[11], data[12], data[13], data[14], data[15], data[16]);
746 if (ctx->rumble_expiration) {
749 HIDAPI_DriverXbox360_Rumble(joystick, dev, context, 0, 0, 0);
757 HIDAPI_DriverXbox360_Quit(SDL_Joystick *joystick,
hid_device *dev,
void *context)
759 #if defined(SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT) || defined(SDL_JOYSTICK_HIDAPI_WINDOWS_GAMING_INPUT) 760 SDL_DriverXbox360_Context *ctx = (SDL_DriverXbox360_Context *)context;
763 #ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT 764 if (ctx->xinput_enabled) {
765 HIDAPI_DriverXbox360_MarkXInputSlotFree(ctx->xinput_slot);
766 WIN_UnloadXInputDLL();
769 #ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_GAMING_INPUT 770 HIDAPI_DriverXbox360_InitWindowsGamingInput(ctx);
779 HIDAPI_DriverXbox360_IsSupportedDevice,
780 HIDAPI_DriverXbox360_GetDeviceName,
781 HIDAPI_DriverXbox360_Init,
782 HIDAPI_DriverXbox360_Rumble,
783 HIDAPI_DriverXbox360_Update,
784 HIDAPI_DriverXbox360_Quit
GLsizei const GLchar *const * string
static screen_context_t context
int SDL_PrivateJoystickButton(SDL_Joystick *joystick, Uint8 button, Uint8 state)
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
int HID_API_EXPORT HID_API_CALL hid_write(hid_device *device, const unsigned char *data, size_t length)
Write an Output report to a HID device.
SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverXbox360
int SDL_PrivateJoystickAxis(SDL_Joystick *joystick, Uint8 axis, Sint16 value)
SDL_bool SDL_IsJoystickXboxOne(Uint16 vendor, Uint16 product)
#define SDL_GetHintBoolean
#define SDL_HINT_XINPUT_ENABLED
A variable that lets you disable the detection and use of Xinput gamepad devices. ...
int HID_API_EXPORT HID_API_CALL hid_read_timeout(hid_device *device, unsigned char *data, size_t length, int milliseconds)
Read an Input report from a HID device with timeout.
const char * HIDAPI_XboxControllerName(Uint16 vendor_id, Uint16 product_id)
#define SDL_HINT_JOYSTICK_HIDAPI_XBOX
A variable controlling whether the HIDAPI driver for XBox controllers should be used.
Uint32 SDL_GetTicks(void)
Get the number of milliseconds since the SDL library initialization.
HRESULT WIN_CoInitialize(void)
struct hid_device_ hid_device
return Display return Display Bool Bool int int int return Display XEvent Bool(*) XPointer return Display return Display Drawable _Xconst char unsigned int unsigned int return Display Pixmap Pixmap XColor XColor unsigned int unsigned int return Display _Xconst char char int char return Display Visual unsigned int int int char unsigned int unsigned int in i)
#define SDL_OutOfMemory()
void WIN_CoUninitialize(void)
static NativeWindowFactory * factory
#define SDL_MAX_UINT16
An unsigned 16-bit integer type.
SDL_bool SDL_IsJoystickXbox360(Uint16 vendor, Uint16 product)
GLuint GLsizei GLsizei * length
#define SDL_TICKS_PASSED(A, B)
Compare SDL ticks values, and return true if A has passed B.
#define SDL_Unsupported()