From 30f41c02aec763d32e62351452da9ef582bc3472 Mon Sep 17 00:00:00 2001 From: 3gg <3gg@shellblade.net> Date: Fri, 6 Mar 2026 13:30:59 -0800 Subject: Move contrib libraries to contrib repo --- .../src/joystick/windows/SDL_dinputjoystick.c | 1210 ----------- .../src/joystick/windows/SDL_dinputjoystick_c.h | 40 - .../src/joystick/windows/SDL_rawinputjoystick.c | 2238 -------------------- .../src/joystick/windows/SDL_rawinputjoystick_c.h | 32 - .../joystick/windows/SDL_windows_gaming_input.c | 1039 --------- .../src/joystick/windows/SDL_windowsjoystick.c | 693 ------ .../src/joystick/windows/SDL_windowsjoystick_c.h | 103 - .../src/joystick/windows/SDL_xinputjoystick.c | 473 ----- .../src/joystick/windows/SDL_xinputjoystick_c.h | 44 - 9 files changed, 5872 deletions(-) delete mode 100644 contrib/SDL-3.2.8/src/joystick/windows/SDL_dinputjoystick.c delete mode 100644 contrib/SDL-3.2.8/src/joystick/windows/SDL_dinputjoystick_c.h delete mode 100644 contrib/SDL-3.2.8/src/joystick/windows/SDL_rawinputjoystick.c delete mode 100644 contrib/SDL-3.2.8/src/joystick/windows/SDL_rawinputjoystick_c.h delete mode 100644 contrib/SDL-3.2.8/src/joystick/windows/SDL_windows_gaming_input.c delete mode 100644 contrib/SDL-3.2.8/src/joystick/windows/SDL_windowsjoystick.c delete mode 100644 contrib/SDL-3.2.8/src/joystick/windows/SDL_windowsjoystick_c.h delete mode 100644 contrib/SDL-3.2.8/src/joystick/windows/SDL_xinputjoystick.c delete mode 100644 contrib/SDL-3.2.8/src/joystick/windows/SDL_xinputjoystick_c.h (limited to 'contrib/SDL-3.2.8/src/joystick/windows') diff --git a/contrib/SDL-3.2.8/src/joystick/windows/SDL_dinputjoystick.c b/contrib/SDL-3.2.8/src/joystick/windows/SDL_dinputjoystick.c deleted file mode 100644 index b00218d..0000000 --- a/contrib/SDL-3.2.8/src/joystick/windows/SDL_dinputjoystick.c +++ /dev/null @@ -1,1210 +0,0 @@ -/* - Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. -*/ -#include "SDL_internal.h" - -#include "../SDL_sysjoystick.h" - -#ifdef SDL_JOYSTICK_DINPUT - -#include "SDL_windowsjoystick_c.h" -#include "SDL_dinputjoystick_c.h" -#include "SDL_rawinputjoystick_c.h" -#include "SDL_xinputjoystick_c.h" -#include "../hidapi/SDL_hidapijoystick_c.h" - -#ifndef DIDFT_OPTIONAL -#define DIDFT_OPTIONAL 0x80000000 -#endif - -#define INPUT_QSIZE 128 // Buffer up to 128 input messages -#define JOY_AXIS_THRESHOLD (((SDL_JOYSTICK_AXIS_MAX) - (SDL_JOYSTICK_AXIS_MIN)) / 100) // 1% motion - -#define CONVERT_MAGNITUDE(x) (((x)*10000) / 0x7FFF) - -// external variables referenced. -#ifdef SDL_VIDEO_DRIVER_WINDOWS -extern HWND SDL_HelperWindow; -#else -static const HWND SDL_HelperWindow = NULL; -#endif - -// local variables -static bool coinitialized = false; -static LPDIRECTINPUT8 dinput = NULL; - -// Taken from Wine - Thanks! -static DIOBJECTDATAFORMAT dfDIJoystick2[] = { - { &GUID_XAxis, DIJOFS_X, DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, DIDOI_ASPECTPOSITION }, - { &GUID_YAxis, DIJOFS_Y, DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, DIDOI_ASPECTPOSITION }, - { &GUID_ZAxis, DIJOFS_Z, DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, DIDOI_ASPECTPOSITION }, - { &GUID_RxAxis, DIJOFS_RX, DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, DIDOI_ASPECTPOSITION }, - { &GUID_RyAxis, DIJOFS_RY, DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, DIDOI_ASPECTPOSITION }, - { &GUID_RzAxis, DIJOFS_RZ, DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, DIDOI_ASPECTPOSITION }, - { &GUID_Slider, DIJOFS_SLIDER(0), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, DIDOI_ASPECTPOSITION }, - { &GUID_Slider, DIJOFS_SLIDER(1), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, DIDOI_ASPECTPOSITION }, - { &GUID_POV, DIJOFS_POV(0), DIDFT_OPTIONAL | DIDFT_POV | DIDFT_ANYINSTANCE, 0 }, - { &GUID_POV, DIJOFS_POV(1), DIDFT_OPTIONAL | DIDFT_POV | DIDFT_ANYINSTANCE, 0 }, - { &GUID_POV, DIJOFS_POV(2), DIDFT_OPTIONAL | DIDFT_POV | DIDFT_ANYINSTANCE, 0 }, - { &GUID_POV, DIJOFS_POV(3), DIDFT_OPTIONAL | DIDFT_POV | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(0), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(1), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(2), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(3), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(4), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(5), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(6), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(7), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(8), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(9), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(10), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(11), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(12), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(13), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(14), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(15), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(16), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(17), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(18), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(19), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(20), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(21), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(22), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(23), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(24), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(25), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(26), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(27), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(28), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(29), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(30), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(31), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(32), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(33), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(34), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(35), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(36), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(37), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(38), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(39), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(40), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(41), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(42), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(43), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(44), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(45), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(46), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(47), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(48), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(49), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(50), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(51), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(52), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(53), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(54), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(55), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(56), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(57), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(58), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(59), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(60), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(61), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(62), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(63), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(64), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(65), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(66), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(67), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(68), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(69), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(70), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(71), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(72), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(73), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(74), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(75), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(76), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(77), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(78), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(79), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(80), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(81), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(82), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(83), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(84), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(85), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(86), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(87), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(88), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(89), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(90), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(91), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(92), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(93), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(94), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(95), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(96), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(97), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(98), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(99), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(100), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(101), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(102), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(103), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(104), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(105), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(106), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(107), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(108), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(109), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(110), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(111), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(112), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(113), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(114), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(115), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(116), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(117), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(118), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(119), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(120), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(121), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(122), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(123), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(124), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(125), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(126), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { NULL, DIJOFS_BUTTON(127), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, - { &GUID_XAxis, FIELD_OFFSET(DIJOYSTATE2, lVX), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, DIDOI_ASPECTVELOCITY }, - { &GUID_YAxis, FIELD_OFFSET(DIJOYSTATE2, lVY), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, DIDOI_ASPECTVELOCITY }, - { &GUID_ZAxis, FIELD_OFFSET(DIJOYSTATE2, lVZ), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, DIDOI_ASPECTVELOCITY }, - { &GUID_RxAxis, FIELD_OFFSET(DIJOYSTATE2, lVRx), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, DIDOI_ASPECTVELOCITY }, - { &GUID_RyAxis, FIELD_OFFSET(DIJOYSTATE2, lVRy), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, DIDOI_ASPECTVELOCITY }, - { &GUID_RzAxis, FIELD_OFFSET(DIJOYSTATE2, lVRz), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, DIDOI_ASPECTVELOCITY }, - // note: dwOfs value matches Windows - { &GUID_Slider, DIJOFS_SLIDER(0), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, DIDOI_ASPECTVELOCITY }, - { &GUID_Slider, DIJOFS_SLIDER(1), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, DIDOI_ASPECTVELOCITY }, - { &GUID_XAxis, FIELD_OFFSET(DIJOYSTATE2, lAX), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, DIDOI_ASPECTACCEL }, - { &GUID_YAxis, FIELD_OFFSET(DIJOYSTATE2, lAY), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, DIDOI_ASPECTACCEL }, - { &GUID_ZAxis, FIELD_OFFSET(DIJOYSTATE2, lAZ), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, DIDOI_ASPECTACCEL }, - { &GUID_RxAxis, FIELD_OFFSET(DIJOYSTATE2, lARx), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, DIDOI_ASPECTACCEL }, - { &GUID_RyAxis, FIELD_OFFSET(DIJOYSTATE2, lARy), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, DIDOI_ASPECTACCEL }, - { &GUID_RzAxis, FIELD_OFFSET(DIJOYSTATE2, lARz), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, DIDOI_ASPECTACCEL }, - // note: dwOfs value matches Windows - { &GUID_Slider, DIJOFS_SLIDER(0), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, DIDOI_ASPECTACCEL }, - { &GUID_Slider, DIJOFS_SLIDER(1), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, DIDOI_ASPECTACCEL }, - { &GUID_XAxis, FIELD_OFFSET(DIJOYSTATE2, lFX), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, DIDOI_ASPECTFORCE }, - { &GUID_YAxis, FIELD_OFFSET(DIJOYSTATE2, lFY), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, DIDOI_ASPECTFORCE }, - { &GUID_ZAxis, FIELD_OFFSET(DIJOYSTATE2, lFZ), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, DIDOI_ASPECTFORCE }, - { &GUID_RxAxis, FIELD_OFFSET(DIJOYSTATE2, lFRx), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, DIDOI_ASPECTFORCE }, - { &GUID_RyAxis, FIELD_OFFSET(DIJOYSTATE2, lFRy), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, DIDOI_ASPECTFORCE }, - { &GUID_RzAxis, FIELD_OFFSET(DIJOYSTATE2, lFRz), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, DIDOI_ASPECTFORCE }, - // note: dwOfs value matches Windows - { &GUID_Slider, DIJOFS_SLIDER(0), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, DIDOI_ASPECTFORCE }, - { &GUID_Slider, DIJOFS_SLIDER(1), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, DIDOI_ASPECTFORCE }, -}; - -const DIDATAFORMAT SDL_c_dfDIJoystick2 = { - sizeof(DIDATAFORMAT), - sizeof(DIOBJECTDATAFORMAT), - DIDF_ABSAXIS, - sizeof(DIJOYSTATE2), - SDL_arraysize(dfDIJoystick2), - dfDIJoystick2 -}; - -// Convert a DirectInput return code to a text message -static bool SetDIerror(const char *function, HRESULT code) -{ - return SDL_SetError("%s() DirectX error 0x%8.8lx", function, code); -} - -static bool SDL_IsXInputDevice(Uint16 vendor_id, Uint16 product_id, const char *hidPath) -{ -#if defined(SDL_JOYSTICK_XINPUT) || defined(SDL_JOYSTICK_RAWINPUT) - SDL_GamepadType type; - - // XInput and RawInput backends will pick up XInput-compatible devices - if (!SDL_XINPUT_Enabled() -#ifdef SDL_JOYSTICK_RAWINPUT - && !RAWINPUT_IsEnabled() -#endif - ) { - return false; - } - - // If device path contains "IG_" then its an XInput device - // See: https://docs.microsoft.com/windows/win32/xinput/xinput-and-directinput - if (SDL_strstr(hidPath, "IG_") != NULL) { - return true; - } - - type = SDL_GetGamepadTypeFromVIDPID(vendor_id, product_id, NULL, false); - if (type == SDL_GAMEPAD_TYPE_XBOX360 || - type == SDL_GAMEPAD_TYPE_XBOXONE || - (vendor_id == USB_VENDOR_VALVE && product_id == USB_PRODUCT_STEAM_VIRTUAL_GAMEPAD)) { - return true; - } -#endif // SDL_JOYSTICK_XINPUT || SDL_JOYSTICK_RAWINPUT - - return false; -} - -static bool QueryDeviceName(LPDIRECTINPUTDEVICE8 device, Uint16 vendor_id, Uint16 product_id, char **manufacturer_string, char **product_string) -{ - DIPROPSTRING dipstr; - - if (!device || !manufacturer_string || !product_string) { - return false; - } - -#ifdef SDL_JOYSTICK_HIDAPI - *manufacturer_string = HIDAPI_GetDeviceManufacturerName(vendor_id, product_id); - *product_string = HIDAPI_GetDeviceProductName(vendor_id, product_id); - if (*product_string) { - return true; - } -#endif - - dipstr.diph.dwSize = sizeof(dipstr); - dipstr.diph.dwHeaderSize = sizeof(dipstr.diph); - dipstr.diph.dwObj = 0; - dipstr.diph.dwHow = DIPH_DEVICE; - - if (FAILED(IDirectInputDevice8_GetProperty(device, DIPROP_PRODUCTNAME, &dipstr.diph))) { - return false; - } - - *manufacturer_string = NULL; - *product_string = WIN_StringToUTF8(dipstr.wsz); - - return true; -} - -static bool QueryDevicePath(LPDIRECTINPUTDEVICE8 device, char **device_path) -{ - DIPROPGUIDANDPATH dippath; - - if (!device || !device_path) { - return false; - } - - dippath.diph.dwSize = sizeof(dippath); - dippath.diph.dwHeaderSize = sizeof(dippath.diph); - dippath.diph.dwObj = 0; - dippath.diph.dwHow = DIPH_DEVICE; - - if (FAILED(IDirectInputDevice8_GetProperty(device, DIPROP_GUIDANDPATH, &dippath.diph))) { - return false; - } - - *device_path = WIN_StringToUTF8W(dippath.wszPath); - - // Normalize path to upper case. - SDL_strupr(*device_path); - - return true; -} - -static bool QueryDeviceInfo(LPDIRECTINPUTDEVICE8 device, Uint16 *vendor_id, Uint16 *product_id) -{ - DIPROPDWORD dipdw; - - if (!device || !vendor_id || !product_id) { - return false; - } - - dipdw.diph.dwSize = sizeof(dipdw); - dipdw.diph.dwHeaderSize = sizeof(dipdw.diph); - dipdw.diph.dwObj = 0; - dipdw.diph.dwHow = DIPH_DEVICE; - dipdw.dwData = 0; - - if (FAILED(IDirectInputDevice8_GetProperty(device, DIPROP_VIDPID, &dipdw.diph))) { - return false; - } - - *vendor_id = LOWORD(dipdw.dwData); - *product_id = HIWORD(dipdw.dwData); - - return true; -} - -void FreeRumbleEffectData(DIEFFECT *effect) -{ - if (!effect) { - return; - } - SDL_free(effect->rgdwAxes); - SDL_free(effect->rglDirection); - SDL_free(effect->lpvTypeSpecificParams); - SDL_free(effect); -} - -DIEFFECT *CreateRumbleEffectData(Sint16 magnitude) -{ - DIEFFECT *effect; - DIPERIODIC *periodic; - - // Create the effect - effect = (DIEFFECT *)SDL_calloc(1, sizeof(*effect)); - if (!effect) { - return NULL; - } - effect->dwSize = sizeof(*effect); - effect->dwGain = 10000; - effect->dwFlags = DIEFF_OBJECTOFFSETS; - effect->dwDuration = SDL_MAX_RUMBLE_DURATION_MS * 1000; // In microseconds. - effect->dwTriggerButton = DIEB_NOTRIGGER; - - effect->cAxes = 2; - effect->rgdwAxes = (DWORD *)SDL_calloc(effect->cAxes, sizeof(DWORD)); - if (!effect->rgdwAxes) { - FreeRumbleEffectData(effect); - return NULL; - } - - effect->rglDirection = (LONG *)SDL_calloc(effect->cAxes, sizeof(LONG)); - if (!effect->rglDirection) { - FreeRumbleEffectData(effect); - return NULL; - } - effect->dwFlags |= DIEFF_CARTESIAN; - - periodic = (DIPERIODIC *)SDL_calloc(1, sizeof(*periodic)); - if (!periodic) { - FreeRumbleEffectData(effect); - return NULL; - } - periodic->dwMagnitude = CONVERT_MAGNITUDE(magnitude); - periodic->dwPeriod = 1000000; - - effect->cbTypeSpecificParams = sizeof(*periodic); - effect->lpvTypeSpecificParams = periodic; - - return effect; -} - -bool SDL_DINPUT_JoystickInit(void) -{ - HRESULT result; - HINSTANCE instance; - - if (!SDL_GetHintBoolean(SDL_HINT_JOYSTICK_DIRECTINPUT, true)) { - // In some environments, IDirectInput8_Initialize / _EnumDevices can take a minute even with no controllers. - dinput = NULL; - return true; - } - - result = WIN_CoInitialize(); - if (FAILED(result)) { - return SetDIerror("CoInitialize", result); - } - - coinitialized = true; - - result = CoCreateInstance(&CLSID_DirectInput8, NULL, CLSCTX_INPROC_SERVER, - &IID_IDirectInput8, (LPVOID *)&dinput); - - if (FAILED(result)) { - return SetDIerror("CoCreateInstance", result); - } - - // Because we used CoCreateInstance, we need to Initialize it, first. - instance = GetModuleHandle(NULL); - if (!instance) { - IDirectInput8_Release(dinput); - dinput = NULL; - return SDL_SetError("GetModuleHandle() failed with error code %lu.", GetLastError()); - } - result = IDirectInput8_Initialize(dinput, instance, DIRECTINPUT_VERSION); - - if (FAILED(result)) { - IDirectInput8_Release(dinput); - dinput = NULL; - return SetDIerror("IDirectInput::Initialize", result); - } - return true; -} - -static int GetSteamVirtualGamepadSlot(Uint16 vendor_id, Uint16 product_id, const char *device_path) -{ - int slot = -1; - - if (vendor_id == USB_VENDOR_VALVE && - product_id == USB_PRODUCT_STEAM_VIRTUAL_GAMEPAD) { - (void)SDL_sscanf(device_path, "\\\\?\\HID#VID_28DE&PID_11FF&IG_0%d", &slot); - } - return slot; -} - -// helper function for direct input, gets called for each connected joystick -static BOOL CALLBACK EnumJoystickDetectCallback(LPCDIDEVICEINSTANCE pDeviceInstance, LPVOID pContext) -{ -#define CHECK(expression) \ - { \ - if (!(expression)) \ - goto err; \ - } - JoyStick_DeviceData *pNewJoystick = NULL; - JoyStick_DeviceData *pPrevJoystick = NULL; - Uint16 vendor = 0; - Uint16 product = 0; - Uint16 version = 0; - char *hidPath = NULL; - char *manufacturer_string = NULL; - char *product_string = NULL; - LPDIRECTINPUTDEVICE8 device = NULL; - - // We are only supporting HID devices. - CHECK(pDeviceInstance->dwDevType & DIDEVTYPE_HID); - - CHECK(SUCCEEDED(IDirectInput8_CreateDevice(dinput, &pDeviceInstance->guidInstance, &device, NULL))); - CHECK(QueryDevicePath(device, &hidPath)); - CHECK(QueryDeviceInfo(device, &vendor, &product)); - CHECK(QueryDeviceName(device, vendor, product, &manufacturer_string, &product_string)); - - CHECK(!SDL_IsXInputDevice(vendor, product, hidPath)); - CHECK(!SDL_ShouldIgnoreJoystick(vendor, product, version, product_string)); - CHECK(!SDL_JoystickHandledByAnotherDriver(&SDL_WINDOWS_JoystickDriver, vendor, product, version, product_string)); - - pNewJoystick = *(JoyStick_DeviceData **)pContext; - while (pNewJoystick) { - // update GUIDs of joysticks with matching paths, in case they're not open yet - if (SDL_strcmp(pNewJoystick->path, hidPath) == 0) { - // if we are replacing the front of the list then update it - if (pNewJoystick == *(JoyStick_DeviceData **)pContext) { - *(JoyStick_DeviceData **)pContext = pNewJoystick->pNext; - } else if (pPrevJoystick) { - pPrevJoystick->pNext = pNewJoystick->pNext; - } - - // Update with new guid/etc, if it has changed - SDL_memcpy(&pNewJoystick->dxdevice, pDeviceInstance, sizeof(DIDEVICEINSTANCE)); - - pNewJoystick->pNext = SYS_Joystick; - SYS_Joystick = pNewJoystick; - - pNewJoystick = NULL; - CHECK(FALSE); - } - - pPrevJoystick = pNewJoystick; - pNewJoystick = pNewJoystick->pNext; - } - - pNewJoystick = (JoyStick_DeviceData *)SDL_calloc(1, sizeof(JoyStick_DeviceData)); - CHECK(pNewJoystick); - - pNewJoystick->steam_virtual_gamepad_slot = GetSteamVirtualGamepadSlot(vendor, product, hidPath); - SDL_strlcpy(pNewJoystick->path, hidPath, SDL_arraysize(pNewJoystick->path)); - SDL_memcpy(&pNewJoystick->dxdevice, pDeviceInstance, sizeof(DIDEVICEINSTANCE)); - - pNewJoystick->joystickname = SDL_CreateJoystickName(vendor, product, manufacturer_string, product_string); - CHECK(pNewJoystick->joystickname); - - if (vendor && product) { - pNewJoystick->guid = SDL_CreateJoystickGUID(SDL_HARDWARE_BUS_USB, vendor, product, version, manufacturer_string, product_string, 0, 0); - } else { - pNewJoystick->guid = SDL_CreateJoystickGUID(SDL_HARDWARE_BUS_BLUETOOTH, vendor, product, version, manufacturer_string, product_string, 0, 0); - } - - WINDOWS_AddJoystickDevice(pNewJoystick); - pNewJoystick = NULL; - -err: - if (pNewJoystick) { - SDL_free(pNewJoystick->joystickname); - SDL_free(pNewJoystick); - } - - SDL_free(hidPath); - SDL_free(manufacturer_string); - SDL_free(product_string); - - if (device) { - IDirectInputDevice8_Release(device); - } - - return DIENUM_CONTINUE; // get next device, please -#undef CHECK -} - -void SDL_DINPUT_JoystickDetect(JoyStick_DeviceData **pContext) -{ - if (!dinput) { - return; - } - - IDirectInput8_EnumDevices(dinput, DI8DEVCLASS_GAMECTRL, EnumJoystickDetectCallback, pContext, DIEDFL_ATTACHEDONLY); -} - -// helper function for direct input, gets called for each connected joystick -typedef struct -{ - Uint16 vendor; - Uint16 product; - bool present; -} Joystick_PresentData; - -static BOOL CALLBACK EnumJoystickPresentCallback(LPCDIDEVICEINSTANCE pDeviceInstance, LPVOID pContext) -{ -#define CHECK(expression) \ - { \ - if (!(expression)) \ - goto err; \ - } - Joystick_PresentData *pData = (Joystick_PresentData *)pContext; - Uint16 vendor = 0; - Uint16 product = 0; - LPDIRECTINPUTDEVICE8 device = NULL; - BOOL result = DIENUM_CONTINUE; - - // We are only supporting HID devices. - CHECK(pDeviceInstance->dwDevType & DIDEVTYPE_HID); - - CHECK(SUCCEEDED(IDirectInput8_CreateDevice(dinput, &pDeviceInstance->guidInstance, &device, NULL))); - CHECK(QueryDeviceInfo(device, &vendor, &product)); - - if (vendor == pData->vendor && product == pData->product) { - pData->present = true; - result = DIENUM_STOP; // found it - } - -err: - if (device) { - IDirectInputDevice8_Release(device); - } - - return result; -#undef CHECK -} - -bool SDL_DINPUT_JoystickPresent(Uint16 vendor_id, Uint16 product_id, Uint16 version_number) -{ - Joystick_PresentData data; - - if (!dinput) { - return false; - } - - data.vendor = vendor_id; - data.product = product_id; - data.present = false; - IDirectInput8_EnumDevices(dinput, DI8DEVCLASS_GAMECTRL, EnumJoystickPresentCallback, &data, DIEDFL_ATTACHEDONLY); - return data.present; -} - -static BOOL CALLBACK EnumDevObjectsCallback(LPCDIDEVICEOBJECTINSTANCE pDeviceObject, LPVOID pContext) -{ - SDL_Joystick *joystick = (SDL_Joystick *)pContext; - HRESULT result; - input_t *in = &joystick->hwdata->Inputs[joystick->hwdata->NumInputs]; - - if (pDeviceObject->dwType & DIDFT_BUTTON) { - in->type = BUTTON; - in->num = (Uint8)joystick->nbuttons; - in->ofs = DIJOFS_BUTTON(in->num); - joystick->nbuttons++; - } else if (pDeviceObject->dwType & DIDFT_POV) { - in->type = HAT; - in->num = (Uint8)joystick->nhats; - in->ofs = DIJOFS_POV(in->num); - joystick->nhats++; - } else if (pDeviceObject->dwType & DIDFT_AXIS) { - DIPROPRANGE diprg; - DIPROPDWORD dilong; - - in->type = AXIS; - in->num = (Uint8)joystick->naxes; - if (SDL_memcmp(&pDeviceObject->guidType, &GUID_XAxis, sizeof(pDeviceObject->guidType)) == 0) { - in->ofs = DIJOFS_X; - } else if (SDL_memcmp(&pDeviceObject->guidType, &GUID_YAxis, sizeof(pDeviceObject->guidType)) == 0) { - in->ofs = DIJOFS_Y; - } else if (SDL_memcmp(&pDeviceObject->guidType, &GUID_ZAxis, sizeof(pDeviceObject->guidType)) == 0) { - in->ofs = DIJOFS_Z; - } else if (SDL_memcmp(&pDeviceObject->guidType, &GUID_RxAxis, sizeof(pDeviceObject->guidType)) == 0) { - in->ofs = DIJOFS_RX; - } else if (SDL_memcmp(&pDeviceObject->guidType, &GUID_RyAxis, sizeof(pDeviceObject->guidType)) == 0) { - in->ofs = DIJOFS_RY; - } else if (SDL_memcmp(&pDeviceObject->guidType, &GUID_RzAxis, sizeof(pDeviceObject->guidType)) == 0) { - in->ofs = DIJOFS_RZ; - } else if (SDL_memcmp(&pDeviceObject->guidType, &GUID_Slider, sizeof(pDeviceObject->guidType)) == 0) { - in->ofs = DIJOFS_SLIDER(joystick->hwdata->NumSliders); - ++joystick->hwdata->NumSliders; - } else { - return DIENUM_CONTINUE; // not an axis we can grok - } - - diprg.diph.dwSize = sizeof(diprg); - diprg.diph.dwHeaderSize = sizeof(diprg.diph); - diprg.diph.dwObj = pDeviceObject->dwType; - diprg.diph.dwHow = DIPH_BYID; - diprg.lMin = SDL_JOYSTICK_AXIS_MIN; - diprg.lMax = SDL_JOYSTICK_AXIS_MAX; - - result = - IDirectInputDevice8_SetProperty(joystick->hwdata->InputDevice, - DIPROP_RANGE, &diprg.diph); - if (FAILED(result)) { - return DIENUM_CONTINUE; // don't use this axis - } - - // Set dead zone to 0. - dilong.diph.dwSize = sizeof(dilong); - dilong.diph.dwHeaderSize = sizeof(dilong.diph); - dilong.diph.dwObj = pDeviceObject->dwType; - dilong.diph.dwHow = DIPH_BYID; - dilong.dwData = 0; - result = - IDirectInputDevice8_SetProperty(joystick->hwdata->InputDevice, - DIPROP_DEADZONE, &dilong.diph); - if (FAILED(result)) { - return DIENUM_CONTINUE; // don't use this axis - } - - joystick->naxes++; - } else { - // not supported at this time - return DIENUM_CONTINUE; - } - - joystick->hwdata->NumInputs++; - - if (joystick->hwdata->NumInputs == MAX_INPUTS) { - return DIENUM_STOP; // too many - } - - return DIENUM_CONTINUE; -} - -/* Sort using the data offset into the DInput struct. - * This gives a reasonable ordering for the inputs. - */ -static int SDLCALL SortDevFunc(const void *a, const void *b) -{ - const input_t *inputA = (const input_t *)a; - const input_t *inputB = (const input_t *)b; - - if (inputA->ofs < inputB->ofs) { - return -1; - } - if (inputA->ofs > inputB->ofs) { - return 1; - } - return 0; -} - -// Sort the input objects and recalculate the indices for each input. -static void SortDevObjects(SDL_Joystick *joystick) -{ - input_t *inputs = joystick->hwdata->Inputs; - Uint8 nButtons = 0; - Uint8 nHats = 0; - Uint8 nAxis = 0; - int n; - - SDL_qsort(inputs, joystick->hwdata->NumInputs, sizeof(input_t), SortDevFunc); - - for (n = 0; n < joystick->hwdata->NumInputs; n++) { - switch (inputs[n].type) { - case BUTTON: - inputs[n].num = nButtons; - nButtons++; - break; - - case HAT: - inputs[n].num = nHats; - nHats++; - break; - - case AXIS: - inputs[n].num = nAxis; - nAxis++; - break; - } - } -} - -bool SDL_DINPUT_JoystickOpen(SDL_Joystick *joystick, JoyStick_DeviceData *joystickdevice) -{ - HRESULT result; - DIPROPDWORD dipdw; - - joystick->hwdata->buffered = true; - joystick->hwdata->Capabilities.dwSize = sizeof(DIDEVCAPS); - - SDL_zero(dipdw); - dipdw.diph.dwSize = sizeof(DIPROPDWORD); - dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER); - - result = - IDirectInput8_CreateDevice(dinput, - &joystickdevice->dxdevice.guidInstance, - &joystick->hwdata->InputDevice, - NULL); - if (FAILED(result)) { - return SetDIerror("IDirectInput::CreateDevice", result); - } - - /* Acquire shared access. Exclusive access is required for forces, - * though. */ - result = - IDirectInputDevice8_SetCooperativeLevel(joystick->hwdata->InputDevice, SDL_HelperWindow, - DISCL_EXCLUSIVE | - DISCL_BACKGROUND); - if (FAILED(result)) { - return SetDIerror("IDirectInputDevice8::SetCooperativeLevel", result); - } - - // Use the extended data structure: DIJOYSTATE2. - result = - IDirectInputDevice8_SetDataFormat(joystick->hwdata->InputDevice, - &SDL_c_dfDIJoystick2); - if (FAILED(result)) { - return SetDIerror("IDirectInputDevice8::SetDataFormat", result); - } - - // Get device capabilities - result = - IDirectInputDevice8_GetCapabilities(joystick->hwdata->InputDevice, - &joystick->hwdata->Capabilities); - if (FAILED(result)) { - return SetDIerror("IDirectInputDevice8::GetCapabilities", result); - } - - // Force capable? - if (joystick->hwdata->Capabilities.dwFlags & DIDC_FORCEFEEDBACK) { - result = IDirectInputDevice8_Acquire(joystick->hwdata->InputDevice); - if (FAILED(result)) { - return SetDIerror("IDirectInputDevice8::Acquire", result); - } - - // reset all actuators. - result = - IDirectInputDevice8_SendForceFeedbackCommand(joystick->hwdata->InputDevice, - DISFFC_RESET); - - /* Not necessarily supported, ignore if not supported. - if (FAILED(result)) { - return SetDIerror("IDirectInputDevice8::SendForceFeedbackCommand", result); - } - */ - - result = IDirectInputDevice8_Unacquire(joystick->hwdata->InputDevice); - - if (FAILED(result)) { - return SetDIerror("IDirectInputDevice8::Unacquire", result); - } - - /* Turn on auto-centering for a ForceFeedback device (until told - * otherwise). */ - dipdw.diph.dwObj = 0; - dipdw.diph.dwHow = DIPH_DEVICE; - dipdw.dwData = DIPROPAUTOCENTER_ON; - - result = - IDirectInputDevice8_SetProperty(joystick->hwdata->InputDevice, - DIPROP_AUTOCENTER, &dipdw.diph); - - /* Not necessarily supported, ignore if not supported. - if (FAILED(result)) { - return SetDIerror("IDirectInputDevice8::SetProperty", result); - } - */ - - SDL_SetBooleanProperty(SDL_GetJoystickProperties(joystick), SDL_PROP_JOYSTICK_CAP_RUMBLE_BOOLEAN, true); - } - - // What buttons and axes does it have? - IDirectInputDevice8_EnumObjects(joystick->hwdata->InputDevice, - EnumDevObjectsCallback, joystick, - DIDFT_BUTTON | DIDFT_AXIS | DIDFT_POV); - - /* Reorder the input objects. Some devices do not report the X axis as - * the first axis, for example. */ - SortDevObjects(joystick); - - dipdw.diph.dwObj = 0; - dipdw.diph.dwHow = DIPH_DEVICE; - dipdw.dwData = INPUT_QSIZE; - - // Set the buffer size - result = - IDirectInputDevice8_SetProperty(joystick->hwdata->InputDevice, - DIPROP_BUFFERSIZE, &dipdw.diph); - - if (result == DI_POLLEDDEVICE) { - /* This device doesn't support buffering, so we're forced - * to use less reliable polling. */ - joystick->hwdata->buffered = false; - } else if (FAILED(result)) { - return SetDIerror("IDirectInputDevice8::SetProperty", result); - } - joystick->hwdata->first_update = true; - - // Poll and wait for initial device state to be populated - result = IDirectInputDevice8_Poll(joystick->hwdata->InputDevice); - if (result == DIERR_INPUTLOST || result == DIERR_NOTACQUIRED) { - IDirectInputDevice8_Acquire(joystick->hwdata->InputDevice); - IDirectInputDevice8_Poll(joystick->hwdata->InputDevice); - } - SDL_Delay(50); - - return true; -} - -static bool SDL_DINPUT_JoystickInitRumble(SDL_Joystick *joystick, Sint16 magnitude) -{ - HRESULT result; - - // Reset and then enable actuators - result = IDirectInputDevice8_SendForceFeedbackCommand(joystick->hwdata->InputDevice, DISFFC_RESET); - if (result == DIERR_INPUTLOST || result == DIERR_NOTEXCLUSIVEACQUIRED) { - result = IDirectInputDevice8_Acquire(joystick->hwdata->InputDevice); - if (SUCCEEDED(result)) { - result = IDirectInputDevice8_SendForceFeedbackCommand(joystick->hwdata->InputDevice, DISFFC_RESET); - } - } - if (FAILED(result)) { - return SetDIerror("IDirectInputDevice8::SendForceFeedbackCommand(DISFFC_RESET)", result); - } - - result = IDirectInputDevice8_SendForceFeedbackCommand(joystick->hwdata->InputDevice, DISFFC_SETACTUATORSON); - if (FAILED(result)) { - return SetDIerror("IDirectInputDevice8::SendForceFeedbackCommand(DISFFC_SETACTUATORSON)", result); - } - - // Create the effect - joystick->hwdata->ffeffect = CreateRumbleEffectData(magnitude); - if (!joystick->hwdata->ffeffect) { - return false; - } - - result = IDirectInputDevice8_CreateEffect(joystick->hwdata->InputDevice, &GUID_Sine, - joystick->hwdata->ffeffect, &joystick->hwdata->ffeffect_ref, NULL); - if (FAILED(result)) { - return SetDIerror("IDirectInputDevice8::CreateEffect", result); - } - return true; -} - -bool SDL_DINPUT_JoystickRumble(SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble) -{ - HRESULT result; - - // Scale and average the two rumble strengths - Sint16 magnitude = (Sint16)(((low_frequency_rumble / 2) + (high_frequency_rumble / 2)) / 2); - - if (!(joystick->hwdata->Capabilities.dwFlags & DIDC_FORCEFEEDBACK)) { - return SDL_Unsupported(); - } - - if (joystick->hwdata->ff_initialized) { - DIPERIODIC *periodic = ((DIPERIODIC *)joystick->hwdata->ffeffect->lpvTypeSpecificParams); - periodic->dwMagnitude = CONVERT_MAGNITUDE(magnitude); - - result = IDirectInputEffect_SetParameters(joystick->hwdata->ffeffect_ref, joystick->hwdata->ffeffect, (DIEP_DURATION | DIEP_TYPESPECIFICPARAMS)); - if (result == DIERR_INPUTLOST) { - result = IDirectInputDevice8_Acquire(joystick->hwdata->InputDevice); - if (SUCCEEDED(result)) { - result = IDirectInputEffect_SetParameters(joystick->hwdata->ffeffect_ref, joystick->hwdata->ffeffect, (DIEP_DURATION | DIEP_TYPESPECIFICPARAMS)); - } - } - if (FAILED(result)) { - return SetDIerror("IDirectInputDevice8::SetParameters", result); - } - } else { - if (!SDL_DINPUT_JoystickInitRumble(joystick, magnitude)) { - return false; - } - joystick->hwdata->ff_initialized = true; - } - - result = IDirectInputEffect_Start(joystick->hwdata->ffeffect_ref, 1, 0); - if (result == DIERR_INPUTLOST || result == DIERR_NOTEXCLUSIVEACQUIRED) { - result = IDirectInputDevice8_Acquire(joystick->hwdata->InputDevice); - if (SUCCEEDED(result)) { - result = IDirectInputEffect_Start(joystick->hwdata->ffeffect_ref, 1, 0); - } - } - if (FAILED(result)) { - return SetDIerror("IDirectInputDevice8::Start", result); - } - return true; -} - -static Uint8 TranslatePOV(DWORD value) -{ - const Uint8 HAT_VALS[] = { - SDL_HAT_UP, - SDL_HAT_UP | SDL_HAT_RIGHT, - SDL_HAT_RIGHT, - SDL_HAT_DOWN | SDL_HAT_RIGHT, - SDL_HAT_DOWN, - SDL_HAT_DOWN | SDL_HAT_LEFT, - SDL_HAT_LEFT, - SDL_HAT_UP | SDL_HAT_LEFT - }; - - if (LOWORD(value) == 0xFFFF) { - return SDL_HAT_CENTERED; - } - - // Round the value up: - value += 4500 / 2; - value %= 36000; - value /= 4500; - - if (value >= 8) { - return SDL_HAT_CENTERED; // shouldn't happen - } - - return HAT_VALS[value]; -} - -/* Function to update the state of a joystick - called as a device poll. - * This function shouldn't update the joystick structure directly, - * but instead should call SDL_PrivateJoystick*() to deliver events - * and update joystick device state. - */ -static void UpdateDINPUTJoystickState_Polled(SDL_Joystick *joystick) -{ - DIJOYSTATE2 state; - HRESULT result; - int i; - Uint64 timestamp = SDL_GetTicksNS(); - - result = - IDirectInputDevice8_GetDeviceState(joystick->hwdata->InputDevice, - sizeof(DIJOYSTATE2), &state); - if (result == DIERR_INPUTLOST || result == DIERR_NOTACQUIRED) { - IDirectInputDevice8_Acquire(joystick->hwdata->InputDevice); - result = - IDirectInputDevice8_GetDeviceState(joystick->hwdata->InputDevice, - sizeof(DIJOYSTATE2), &state); - } - - if (result != DI_OK) { - return; - } - - // Set each known axis, button and POV. - for (i = 0; i < joystick->hwdata->NumInputs; ++i) { - const input_t *in = &joystick->hwdata->Inputs[i]; - - switch (in->type) { - case AXIS: - switch (in->ofs) { - case DIJOFS_X: - SDL_SendJoystickAxis(timestamp, joystick, in->num, (Sint16)state.lX); - break; - case DIJOFS_Y: - SDL_SendJoystickAxis(timestamp, joystick, in->num, (Sint16)state.lY); - break; - case DIJOFS_Z: - SDL_SendJoystickAxis(timestamp, joystick, in->num, (Sint16)state.lZ); - break; - case DIJOFS_RX: - SDL_SendJoystickAxis(timestamp, joystick, in->num, (Sint16)state.lRx); - break; - case DIJOFS_RY: - SDL_SendJoystickAxis(timestamp, joystick, in->num, (Sint16)state.lRy); - break; - case DIJOFS_RZ: - SDL_SendJoystickAxis(timestamp, joystick, in->num, (Sint16)state.lRz); - break; - case DIJOFS_SLIDER(0): - SDL_SendJoystickAxis(timestamp, joystick, in->num, (Sint16)state.rglSlider[0]); - break; - case DIJOFS_SLIDER(1): - SDL_SendJoystickAxis(timestamp, joystick, in->num, (Sint16)state.rglSlider[1]); - break; - } - break; - - case BUTTON: - SDL_SendJoystickButton(timestamp, joystick, in->num, - (state.rgbButtons[in->ofs - DIJOFS_BUTTON0] != 0)); - break; - case HAT: - { - Uint8 pos = TranslatePOV(state.rgdwPOV[in->ofs - DIJOFS_POV(0)]); - SDL_SendJoystickHat(timestamp, joystick, in->num, pos); - break; - } - } - } -} - -static void UpdateDINPUTJoystickState_Buffered(SDL_Joystick *joystick) -{ - int i; - HRESULT result; - DWORD numevents; - DIDEVICEOBJECTDATA evtbuf[INPUT_QSIZE]; - Uint64 timestamp = SDL_GetTicksNS(); - - numevents = INPUT_QSIZE; - result = - IDirectInputDevice8_GetDeviceData(joystick->hwdata->InputDevice, - sizeof(DIDEVICEOBJECTDATA), evtbuf, - &numevents, 0); - if (result == DIERR_INPUTLOST || result == DIERR_NOTACQUIRED) { - IDirectInputDevice8_Acquire(joystick->hwdata->InputDevice); - result = - IDirectInputDevice8_GetDeviceData(joystick->hwdata->InputDevice, - sizeof(DIDEVICEOBJECTDATA), - evtbuf, &numevents, 0); - } - - // Handle the events or punt - if (FAILED(result)) { - return; - } - - for (i = 0; i < (int)numevents; ++i) { - int j; - - for (j = 0; j < joystick->hwdata->NumInputs; ++j) { - const input_t *in = &joystick->hwdata->Inputs[j]; - - if (evtbuf[i].dwOfs != in->ofs) { - continue; - } - - switch (in->type) { - case AXIS: - SDL_SendJoystickAxis(timestamp, joystick, in->num, (Sint16)evtbuf[i].dwData); - break; - case BUTTON: - SDL_SendJoystickButton(timestamp, joystick, in->num, - (evtbuf[i].dwData != 0)); - break; - case HAT: - { - Uint8 pos = TranslatePOV(evtbuf[i].dwData); - SDL_SendJoystickHat(timestamp, joystick, in->num, pos); - } break; - } - } - } - - if (result == DI_BUFFEROVERFLOW) { - /* Our buffer wasn't big enough to hold all the queued events, - * so poll the device to make sure we have the complete state. - */ - UpdateDINPUTJoystickState_Polled(joystick); - } -} - -void SDL_DINPUT_JoystickUpdate(SDL_Joystick *joystick) -{ - HRESULT result; - - result = IDirectInputDevice8_Poll(joystick->hwdata->InputDevice); - if (result == DIERR_INPUTLOST || result == DIERR_NOTACQUIRED) { - IDirectInputDevice8_Acquire(joystick->hwdata->InputDevice); - IDirectInputDevice8_Poll(joystick->hwdata->InputDevice); - } - - if (joystick->hwdata->first_update) { - // Poll to get the initial state of the joystick - UpdateDINPUTJoystickState_Polled(joystick); - joystick->hwdata->first_update = false; - return; - } - - if (joystick->hwdata->buffered ) { - UpdateDINPUTJoystickState_Buffered(joystick); - } else { - UpdateDINPUTJoystickState_Polled(joystick); - } -} - -void SDL_DINPUT_JoystickClose(SDL_Joystick *joystick) -{ - if (joystick->hwdata->ffeffect_ref) { - IDirectInputEffect_Unload(joystick->hwdata->ffeffect_ref); - joystick->hwdata->ffeffect_ref = NULL; - } - if (joystick->hwdata->ffeffect) { - FreeRumbleEffectData(joystick->hwdata->ffeffect); - joystick->hwdata->ffeffect = NULL; - } - IDirectInputDevice8_Unacquire(joystick->hwdata->InputDevice); - IDirectInputDevice8_Release(joystick->hwdata->InputDevice); - joystick->hwdata->ff_initialized = false; -} - -void SDL_DINPUT_JoystickQuit(void) -{ - if (dinput != NULL) { - IDirectInput8_Release(dinput); - dinput = NULL; - } - - if (coinitialized) { - WIN_CoUninitialize(); - coinitialized = false; - } -} - -#else // !SDL_JOYSTICK_DINPUT - -typedef struct JoyStick_DeviceData JoyStick_DeviceData; - -bool SDL_DINPUT_JoystickInit(void) -{ - return true; -} - -void SDL_DINPUT_JoystickDetect(JoyStick_DeviceData **pContext) -{ -} - -bool SDL_DINPUT_JoystickPresent(Uint16 vendor, Uint16 product, Uint16 version) -{ - return false; -} - -bool SDL_DINPUT_JoystickOpen(SDL_Joystick *joystick, JoyStick_DeviceData *joystickdevice) -{ - return SDL_Unsupported(); -} - -bool SDL_DINPUT_JoystickRumble(SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble) -{ - return SDL_Unsupported(); -} - -void SDL_DINPUT_JoystickUpdate(SDL_Joystick *joystick) -{ -} - -void SDL_DINPUT_JoystickClose(SDL_Joystick *joystick) -{ -} - -void SDL_DINPUT_JoystickQuit(void) -{ -} - -#endif // SDL_JOYSTICK_DINPUT diff --git a/contrib/SDL-3.2.8/src/joystick/windows/SDL_dinputjoystick_c.h b/contrib/SDL-3.2.8/src/joystick/windows/SDL_dinputjoystick_c.h deleted file mode 100644 index 0643ce1..0000000 --- a/contrib/SDL-3.2.8/src/joystick/windows/SDL_dinputjoystick_c.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. -*/ -#include "SDL_internal.h" - -// Set up for C function definitions, even when using C++ -#ifdef __cplusplus -extern "C" { -#endif - -extern bool SDL_DINPUT_JoystickInit(void); -extern void SDL_DINPUT_JoystickDetect(JoyStick_DeviceData **pContext); -extern bool SDL_DINPUT_JoystickPresent(Uint16 vendor, Uint16 product, Uint16 version); -extern bool SDL_DINPUT_JoystickOpen(SDL_Joystick *joystick, JoyStick_DeviceData *joystickdevice); -extern bool SDL_DINPUT_JoystickRumble(SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble); -extern void SDL_DINPUT_JoystickUpdate(SDL_Joystick *joystick); -extern void SDL_DINPUT_JoystickClose(SDL_Joystick *joystick); -extern void SDL_DINPUT_JoystickQuit(void); - -// Ends C function definitions when using C++ -#ifdef __cplusplus -} -#endif diff --git a/contrib/SDL-3.2.8/src/joystick/windows/SDL_rawinputjoystick.c b/contrib/SDL-3.2.8/src/joystick/windows/SDL_rawinputjoystick.c deleted file mode 100644 index d5166de..0000000 --- a/contrib/SDL-3.2.8/src/joystick/windows/SDL_rawinputjoystick.c +++ /dev/null @@ -1,2238 +0,0 @@ -/* - Simple DirectMedia Layer - Copyright (C) 2025 Sam Lantinga - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - -*/ -/* - RAWINPUT Joystick API for better handling XInput-capable devices on Windows. - - XInput is limited to 4 devices. - Windows.Gaming.Input does not get inputs from XBox One controllers when not in the foreground. - DirectInput does not get inputs from XBox One controllers when not in the foreground, nor rumble or accurate triggers. - RawInput does not get rumble or accurate triggers. - - So, combine them as best we can! -*/ -#include "SDL_internal.h" - -#ifdef SDL_JOYSTICK_RAWINPUT - -#include "../usb_ids.h" -#include "../SDL_sysjoystick.h" -#include "../../core/windows/SDL_windows.h" -#include "../../core/windows/SDL_hid.h" -#include "../hidapi/SDL_hidapijoystick_c.h" - -/* SDL_JOYSTICK_RAWINPUT_XINPUT is disabled because using XInput at the same time as - raw input will turn off the Xbox Series X controller when it is connected via the - Xbox One Wireless Adapter. - */ -#ifdef HAVE_XINPUT_H -#define SDL_JOYSTICK_RAWINPUT_XINPUT -#endif -#ifdef HAVE_WINDOWS_GAMING_INPUT_H -#define SDL_JOYSTICK_RAWINPUT_WGI -#endif - -#ifdef SDL_JOYSTICK_RAWINPUT_XINPUT -#include "../../core/windows/SDL_xinput.h" -#endif - -#ifdef SDL_JOYSTICK_RAWINPUT_WGI -#include "../../core/windows/SDL_windows.h" -typedef struct WindowsGamingInputGamepadState WindowsGamingInputGamepadState; -#define GamepadButtons_GUIDE 0x40000000 -#define COBJMACROS -#include "windows.gaming.input.h" -#include -#endif - -#if defined(SDL_JOYSTICK_RAWINPUT_XINPUT) || defined(SDL_JOYSTICK_RAWINPUT_WGI) -#define SDL_JOYSTICK_RAWINPUT_MATCHING -#define SDL_JOYSTICK_RAWINPUT_MATCH_AXES -#define SDL_JOYSTICK_RAWINPUT_MATCH_TRIGGERS -#ifdef SDL_JOYSTICK_RAWINPUT_MATCH_TRIGGERS -#define SDL_JOYSTICK_RAWINPUT_MATCH_COUNT 6 // stick + trigger axes -#else -#define SDL_JOYSTICK_RAWINPUT_MATCH_COUNT 4 // stick axes -#endif -#endif - -#if 0 -#define DEBUG_RAWINPUT -#endif - -#ifndef RIDEV_EXINPUTSINK -#define RIDEV_EXINPUTSINK 0x00001000 -#define RIDEV_DEVNOTIFY 0x00002000 -#endif - -#ifndef WM_INPUT_DEVICE_CHANGE -#define WM_INPUT_DEVICE_CHANGE 0x00FE -#endif -#ifndef WM_INPUT -#define WM_INPUT 0x00FF -#endif -#ifndef GIDC_ARRIVAL -#define GIDC_ARRIVAL 1 -#define GIDC_REMOVAL 2 -#endif - -extern void WINDOWS_RAWINPUTEnabledChanged(void); -extern void WINDOWS_JoystickDetect(void); - -static bool SDL_RAWINPUT_inited = false; -static bool SDL_RAWINPUT_remote_desktop = false; -static int SDL_RAWINPUT_numjoysticks = 0; - -static void RAWINPUT_JoystickClose(SDL_Joystick *joystick); - -typedef struct SDL_RAWINPUT_Device -{ - SDL_AtomicInt refcount; - char *name; - char *path; - Uint16 vendor_id; - Uint16 product_id; - Uint16 version; - SDL_GUID guid; - bool is_xinput; - bool is_xboxone; - int steam_virtual_gamepad_slot; - PHIDP_PREPARSED_DATA preparsed_data; - - HANDLE hDevice; - SDL_Joystick *joystick; - SDL_JoystickID joystick_id; - - struct SDL_RAWINPUT_Device *next; -} SDL_RAWINPUT_Device; - -struct joystick_hwdata -{ - bool is_xinput; - bool is_xboxone; - PHIDP_PREPARSED_DATA preparsed_data; - ULONG max_data_length; - HIDP_DATA *data; - USHORT *button_indices; - USHORT *axis_indices; - USHORT *hat_indices; - bool guide_hack; - bool trigger_hack; - USHORT trigger_hack_index; - -#ifdef SDL_JOYSTICK_RAWINPUT_MATCHING - Uint64 match_state; // Lowest 16 bits for button states, higher 24 for 6 4bit axes - Uint64 last_state_packet; -#endif - -#ifdef SDL_JOYSTICK_RAWINPUT_XINPUT - bool xinput_enabled; - bool xinput_correlated; - Uint8 xinput_correlation_id; - Uint8 xinput_correlation_count; - Uint8 xinput_uncorrelate_count; - Uint8 xinput_slot; -#endif - -#ifdef SDL_JOYSTICK_RAWINPUT_WGI - bool wgi_correlated; - Uint8 wgi_correlation_id; - Uint8 wgi_correlation_count; - Uint8 wgi_uncorrelate_count; - WindowsGamingInputGamepadState *wgi_slot; -#endif - - SDL_RAWINPUT_Device *device; -}; -typedef struct joystick_hwdata RAWINPUT_DeviceContext; - -SDL_RAWINPUT_Device *SDL_RAWINPUT_devices; - -static const Uint16 subscribed_devices[] = { - USB_USAGE_GENERIC_GAMEPAD, - /* Don't need Joystick for any devices we're handling here (XInput-capable) - USB_USAGE_GENERIC_JOYSTICK, - USB_USAGE_GENERIC_MULTIAXISCONTROLLER, - */ -}; - -#ifdef SDL_JOYSTICK_RAWINPUT_MATCHING - -static struct -{ - Uint64 last_state_packet; - SDL_Joystick *joystick; - SDL_Joystick *last_joystick; -} guide_button_candidate; - -typedef struct WindowsMatchState -{ -#ifdef SDL_JOYSTICK_RAWINPUT_MATCH_AXES - SHORT match_axes[SDL_JOYSTICK_RAWINPUT_MATCH_COUNT]; -#endif -#ifdef SDL_JOYSTICK_RAWINPUT_XINPUT - WORD xinput_buttons; -#endif -#ifdef SDL_JOYSTICK_RAWINPUT_WGI - Uint32 wgi_buttons; -#endif - bool any_data; -} WindowsMatchState; - -static void RAWINPUT_FillMatchState(WindowsMatchState *state, Uint64 match_state) -{ -#ifdef SDL_JOYSTICK_RAWINPUT_MATCH_AXES - int ii; -#endif - - bool any_axes_data = false; -#ifdef SDL_JOYSTICK_RAWINPUT_MATCH_AXES - /* SHORT state->match_axes[4] = { - (match_state & 0x000F0000) >> 4, - (match_state & 0x00F00000) >> 8, - (match_state & 0x0F000000) >> 12, - (match_state & 0xF0000000) >> 16, - }; */ - for (ii = 0; ii < 4; ii++) { - state->match_axes[ii] = (SHORT)((match_state & (0x000F0000ull << (ii * 4))) >> (4 + ii * 4)); - any_axes_data |= ((Uint32)(state->match_axes[ii] + 0x1000) > 0x2000); // match_state bit is not 0xF, 0x1, or 0x2 - } -#endif // SDL_JOYSTICK_RAWINPUT_MATCH_AXES -#ifdef SDL_JOYSTICK_RAWINPUT_MATCH_TRIGGERS - for (; ii < SDL_JOYSTICK_RAWINPUT_MATCH_COUNT; ii++) { - state->match_axes[ii] = (SHORT)((match_state & (0x000F0000ull << (ii * 4))) >> (4 + ii * 4)); - any_axes_data |= (state->match_axes[ii] != SDL_MIN_SINT16); - } -#endif // SDL_JOYSTICK_RAWINPUT_MATCH_TRIGGERS - - state->any_data = any_axes_data; - -#ifdef SDL_JOYSTICK_RAWINPUT_XINPUT - // Match axes by checking if the distance between the high 4 bits of axis and the 4 bits from match_state is 1 or less -#define XInputAxesMatch(gamepad) ( \ - (Uint32)(gamepad.sThumbLX - state->match_axes[0] + 0x1000) <= 0x2fff && \ - (Uint32)(~gamepad.sThumbLY - state->match_axes[1] + 0x1000) <= 0x2fff && \ - (Uint32)(gamepad.sThumbRX - state->match_axes[2] + 0x1000) <= 0x2fff && \ - (Uint32)(~gamepad.sThumbRY - state->match_axes[3] + 0x1000) <= 0x2fff) - /* Explicit -#define XInputAxesMatch(gamepad) (\ - SDL_abs((Sint8)((gamepad.sThumbLX & 0xF000) >> 8) - ((match_state & 0x000F0000) >> 12)) <= 0x10 && \ - SDL_abs((Sint8)((~gamepad.sThumbLY & 0xF000) >> 8) - ((match_state & 0x00F00000) >> 16)) <= 0x10 && \ - SDL_abs((Sint8)((gamepad.sThumbRX & 0xF000) >> 8) - ((match_state & 0x0F000000) >> 20)) <= 0x10 && \ - SDL_abs((Sint8)((~gamepad.sThumbRY & 0xF000) >> 8) - ((match_state & 0xF0000000) >> 24)) <= 0x10) */ - - // Can only match trigger values if a single trigger has a value. -#define XInputTriggersMatch(gamepad) ( \ - ((state->match_axes[4] == SDL_MIN_SINT16) && (state->match_axes[5] == SDL_MIN_SINT16)) || \ - ((gamepad.bLeftTrigger != 0) && (gamepad.bRightTrigger != 0)) || \ - ((Uint32)((((int)gamepad.bLeftTrigger * 257) - 32768) - state->match_axes[4]) <= 0x2fff) || \ - ((Uint32)((((int)gamepad.bRightTrigger * 257) - 32768) - state->match_axes[5]) <= 0x2fff)) - - state->xinput_buttons = - // Bitwise map .RLDUWVQTS.KYXBA -> YXBA..WVQTKSRLDU - (WORD)(match_state << 12 | (match_state & 0x0780) >> 1 | (match_state & 0x0010) << 1 | (match_state & 0x0040) >> 2 | (match_state & 0x7800) >> 11); - /* Explicit - ((match_state & (1<xinput_buttons) { - state->any_data = true; - } -#endif - -#ifdef SDL_JOYSTICK_RAWINPUT_WGI - // Match axes by checking if the distance between the high 4 bits of axis and the 4 bits from match_state is 1 or less -#define WindowsGamingInputAxesMatch(gamepad) ( \ - (Uint16)(((Sint16)(gamepad.LeftThumbstickX * SDL_MAX_SINT16) & 0xF000) - state->match_axes[0] + 0x1000) <= 0x2fff && \ - (Uint16)((~(Sint16)(gamepad.LeftThumbstickY * SDL_MAX_SINT16) & 0xF000) - state->match_axes[1] + 0x1000) <= 0x2fff && \ - (Uint16)(((Sint16)(gamepad.RightThumbstickX * SDL_MAX_SINT16) & 0xF000) - state->match_axes[2] + 0x1000) <= 0x2fff && \ - (Uint16)((~(Sint16)(gamepad.RightThumbstickY * SDL_MAX_SINT16) & 0xF000) - state->match_axes[3] + 0x1000) <= 0x2fff) - -#define WindowsGamingInputTriggersMatch(gamepad) ( \ - ((state->match_axes[4] == SDL_MIN_SINT16) && (state->match_axes[5] == SDL_MIN_SINT16)) || \ - ((gamepad.LeftTrigger == 0.0f) && (gamepad.RightTrigger == 0.0f)) || \ - ((Uint16)((((int)(gamepad.LeftTrigger * SDL_MAX_UINT16)) - 32768) - state->match_axes[4]) <= 0x2fff) || \ - ((Uint16)((((int)(gamepad.RightTrigger * SDL_MAX_UINT16)) - 32768) - state->match_axes[5]) <= 0x2fff)) - - state->wgi_buttons = - // Bitwise map .RLD UWVQ TS.K YXBA -> ..QT WVRL DUYX BAKS - // RStick/LStick (QT) RShould/LShould (WV) DPad R/L/D/U YXBA bac(K) (S)tart - (match_state & 0x0180) << 5 | (match_state & 0x0600) << 1 | (match_state & 0x7800) >> 5 | (match_state & 0x000F) << 2 | (match_state & 0x0010) >> 3 | (match_state & 0x0040) >> 6; - /* Explicit - ((match_state & (1<wgi_buttons) { - state->any_data = true; - } -#endif -} - -#endif // SDL_JOYSTICK_RAWINPUT_MATCHING - -#ifdef SDL_JOYSTICK_RAWINPUT_XINPUT - -static struct -{ - XINPUT_STATE state; - XINPUT_BATTERY_INFORMATION_EX battery; - bool connected; // Currently has an active XInput device - bool used; // Is currently mapped to an SDL device - Uint8 correlation_id; -} xinput_state[XUSER_MAX_COUNT]; -static bool xinput_device_change = true; -static bool xinput_state_dirty = true; - -static void RAWINPUT_UpdateXInput(void) -{ - DWORD user_index; - if (xinput_device_change) { - for (user_index = 0; user_index < XUSER_MAX_COUNT; user_index++) { - XINPUT_CAPABILITIES capabilities; - xinput_state[user_index].connected = (XINPUTGETCAPABILITIES(user_index, XINPUT_FLAG_GAMEPAD, &capabilities) == ERROR_SUCCESS); - } - xinput_device_change = false; - xinput_state_dirty = true; - } - if (xinput_state_dirty) { - xinput_state_dirty = false; - for (user_index = 0; user_index < SDL_arraysize(xinput_state); ++user_index) { - if (xinput_state[user_index].connected) { - if (XINPUTGETSTATE(user_index, &xinput_state[user_index].state) != ERROR_SUCCESS) { - xinput_state[user_index].connected = false; - } - xinput_state[user_index].battery.BatteryType = BATTERY_TYPE_UNKNOWN; - if (XINPUTGETBATTERYINFORMATION) { - XINPUTGETBATTERYINFORMATION(user_index, BATTERY_DEVTYPE_GAMEPAD, &xinput_state[user_index].battery); - } - } - } - } -} - -static void RAWINPUT_MarkXInputSlotUsed(Uint8 xinput_slot) -{ - if (xinput_slot != XUSER_INDEX_ANY) { - xinput_state[xinput_slot].used = true; - } -} - -static void RAWINPUT_MarkXInputSlotFree(Uint8 xinput_slot) -{ - if (xinput_slot != XUSER_INDEX_ANY) { - xinput_state[xinput_slot].used = false; - } -} -static bool RAWINPUT_MissingXInputSlot(void) -{ - int ii; - for (ii = 0; ii < SDL_arraysize(xinput_state); ii++) { - if (xinput_state[ii].connected && !xinput_state[ii].used) { - return true; - } - } - return false; -} - -static bool RAWINPUT_XInputSlotMatches(const WindowsMatchState *state, Uint8 slot_idx) -{ - if (xinput_state[slot_idx].connected) { - WORD xinput_buttons = xinput_state[slot_idx].state.Gamepad.wButtons; - if ((xinput_buttons & ~XINPUT_GAMEPAD_GUIDE) == state->xinput_buttons -#ifdef SDL_JOYSTICK_RAWINPUT_MATCH_AXES - && XInputAxesMatch(xinput_state[slot_idx].state.Gamepad) -#endif -#ifdef SDL_JOYSTICK_RAWINPUT_MATCH_TRIGGERS - && XInputTriggersMatch(xinput_state[slot_idx].state.Gamepad) -#endif - ) { - return true; - } - } - return false; -} - -static bool RAWINPUT_GuessXInputSlot(const WindowsMatchState *state, Uint8 *correlation_id, Uint8 *slot_idx) -{ - Uint8 user_index; - int match_count; - - /* If there is only one available slot, let's use that - * That will be right most of the time, and uncorrelation will fix any bad guesses - */ - match_count = 0; - for (user_index = 0; user_index < XUSER_MAX_COUNT; ++user_index) { - if (xinput_state[user_index].connected && !xinput_state[user_index].used) { - *slot_idx = user_index; - ++match_count; - } - } - if (match_count == 1) { - *correlation_id = ++xinput_state[*slot_idx].correlation_id; - return true; - } - - *slot_idx = 0; - - match_count = 0; - for (user_index = 0; user_index < XUSER_MAX_COUNT; ++user_index) { - if (!xinput_state[user_index].used && RAWINPUT_XInputSlotMatches(state, user_index)) { - ++match_count; - *slot_idx = user_index; - // Incrementing correlation_id for any match, as negative evidence for others being correlated - *correlation_id = ++xinput_state[user_index].correlation_id; - } - } - /* Only return a match if we match exactly one, and we have some non-zero data (buttons or axes) that matched. - Note that we're still invalidating *other* potential correlations if we have more than one match or we have no - data. */ - if (match_count == 1 && state->any_data) { - return true; - } - return false; -} - -#endif // SDL_JOYSTICK_RAWINPUT_XINPUT - -#ifdef SDL_JOYSTICK_RAWINPUT_WGI - -typedef struct WindowsGamingInputGamepadState -{ - __x_ABI_CWindows_CGaming_CInput_CIGamepad *gamepad; - struct __x_ABI_CWindows_CGaming_CInput_CGamepadReading state; - RAWINPUT_DeviceContext *correlated_context; - bool used; // Is currently mapped to an SDL device - bool connected; // Just used during update to track disconnected - Uint8 correlation_id; - struct __x_ABI_CWindows_CGaming_CInput_CGamepadVibration vibration; -} WindowsGamingInputGamepadState; - -static struct -{ - WindowsGamingInputGamepadState **per_gamepad; - int per_gamepad_count; - bool initialized; - bool dirty; - bool need_device_list_update; - int ref_count; - __x_ABI_CWindows_CGaming_CInput_CIGamepadStatics *gamepad_statics; - EventRegistrationToken gamepad_added_token; - EventRegistrationToken gamepad_removed_token; -} wgi_state; - -typedef struct GamepadDelegate -{ - __FIEventHandler_1_Windows__CGaming__CInput__CGamepad iface; - SDL_AtomicInt refcount; -} GamepadDelegate; - -static const IID IID_IEventHandler_Gamepad = { 0x8a7639ee, 0x624a, 0x501a, { 0xbb, 0x53, 0x56, 0x2d, 0x1e, 0xc1, 0x1b, 0x52 } }; - -static HRESULT STDMETHODCALLTYPE IEventHandler_CGamepadVtbl_QueryInterface(__FIEventHandler_1_Windows__CGaming__CInput__CGamepad *This, REFIID riid, void **ppvObject) -{ - if (!ppvObject) { - return E_INVALIDARG; - } - - *ppvObject = NULL; - if (WIN_IsEqualIID(riid, &IID_IUnknown) || WIN_IsEqualIID(riid, &IID_IAgileObject) || WIN_IsEqualIID(riid, &IID_IEventHandler_Gamepad)) { - *ppvObject = This; - __FIEventHandler_1_Windows__CGaming__CInput__CGamepad_AddRef(This); - return S_OK; - } else if (WIN_IsEqualIID(riid, &IID_IMarshal)) { - // This seems complicated. Let's hope it doesn't happen. - return E_OUTOFMEMORY; - } else { - return E_NOINTERFACE; - } -} - -static ULONG STDMETHODCALLTYPE IEventHandler_CGamepadVtbl_AddRef(__FIEventHandler_1_Windows__CGaming__CInput__CGamepad *This) -{ - GamepadDelegate *self = (GamepadDelegate *)This; - return SDL_AddAtomicInt(&self->refcount, 1) + 1UL; -} - -static ULONG STDMETHODCALLTYPE IEventHandler_CGamepadVtbl_Release(__FIEventHandler_1_Windows__CGaming__CInput__CGamepad *This) -{ - GamepadDelegate *self = (GamepadDelegate *)This; - int rc = SDL_AddAtomicInt(&self->refcount, -1) - 1; - // Should never free the static delegate objects - SDL_assert(rc > 0); - return rc; -} - -static HRESULT STDMETHODCALLTYPE IEventHandler_CGamepadVtbl_InvokeAdded(__FIEventHandler_1_Windows__CGaming__CInput__CGamepad *This, IInspectable *sender, __x_ABI_CWindows_CGaming_CInput_CIGamepad *e) -{ - wgi_state.need_device_list_update = true; - return S_OK; -} - -static HRESULT STDMETHODCALLTYPE IEventHandler_CGamepadVtbl_InvokeRemoved(__FIEventHandler_1_Windows__CGaming__CInput__CGamepad *This, IInspectable *sender, __x_ABI_CWindows_CGaming_CInput_CIGamepad *e) -{ - wgi_state.need_device_list_update = true; - return S_OK; -} - -#ifdef _MSC_VER -#pragma warning(push) -#pragma warning(disable : 4028) // formal parameter 3 different from declaration, when using older buggy WGI headers -#pragma warning(disable : 4113) // X differs in parameter lists from Y, when using older buggy WGI headers -#endif - -static __FIEventHandler_1_Windows__CGaming__CInput__CGamepadVtbl gamepad_added_vtbl = { - IEventHandler_CGamepadVtbl_QueryInterface, - IEventHandler_CGamepadVtbl_AddRef, - IEventHandler_CGamepadVtbl_Release, - IEventHandler_CGamepadVtbl_InvokeAdded -}; -static GamepadDelegate gamepad_added = { - { &gamepad_added_vtbl }, - { 1 } -}; - -static __FIEventHandler_1_Windows__CGaming__CInput__CGamepadVtbl gamepad_removed_vtbl = { - IEventHandler_CGamepadVtbl_QueryInterface, - IEventHandler_CGamepadVtbl_AddRef, - IEventHandler_CGamepadVtbl_Release, - IEventHandler_CGamepadVtbl_InvokeRemoved -}; -static GamepadDelegate gamepad_removed = { - { &gamepad_removed_vtbl }, - { 1 } -}; - -#ifdef _MSC_VER -#pragma warning(pop) -#endif - -static void RAWINPUT_MarkWindowsGamingInputSlotUsed(WindowsGamingInputGamepadState *wgi_slot, RAWINPUT_DeviceContext *ctx) -{ - wgi_slot->used = true; - wgi_slot->correlated_context = ctx; -} - -static void RAWINPUT_MarkWindowsGamingInputSlotFree(WindowsGamingInputGamepadState *wgi_slot) -{ - wgi_slot->used = false; - wgi_slot->correlated_context = NULL; -} - -static bool RAWINPUT_MissingWindowsGamingInputSlot(void) -{ - int ii; - for (ii = 0; ii < wgi_state.per_gamepad_count; ii++) { - if (!wgi_state.per_gamepad[ii]->used) { - return true; - } - } - return false; -} - -static bool RAWINPUT_UpdateWindowsGamingInput(void) -{ - int ii; - if (!wgi_state.gamepad_statics) { - return true; - } - - if (!wgi_state.dirty) { - return true; - } - - wgi_state.dirty = false; - - if (wgi_state.need_device_list_update) { - HRESULT hr; - __FIVectorView_1_Windows__CGaming__CInput__CGamepad *gamepads; - wgi_state.need_device_list_update = false; - for (ii = 0; ii < wgi_state.per_gamepad_count; ii++) { - wgi_state.per_gamepad[ii]->connected = false; - } - - hr = __x_ABI_CWindows_CGaming_CInput_CIGamepadStatics_get_Gamepads(wgi_state.gamepad_statics, &gamepads); - if (SUCCEEDED(hr)) { - unsigned int num_gamepads; - - hr = __FIVectorView_1_Windows__CGaming__CInput__CGamepad_get_Size(gamepads, &num_gamepads); - if (SUCCEEDED(hr)) { - unsigned int i; - for (i = 0; i < num_gamepads; ++i) { - __x_ABI_CWindows_CGaming_CInput_CIGamepad *gamepad; - - hr = __FIVectorView_1_Windows__CGaming__CInput__CGamepad_GetAt(gamepads, i, &gamepad); - if (SUCCEEDED(hr)) { - bool found = false; - int jj; - for (jj = 0; jj < wgi_state.per_gamepad_count; jj++) { - if (wgi_state.per_gamepad[jj]->gamepad == gamepad) { - found = true; - wgi_state.per_gamepad[jj]->connected = true; - break; - } - } - if (!found) { - // New device, add it - WindowsGamingInputGamepadState *gamepad_state; - WindowsGamingInputGamepadState **new_per_gamepad; - gamepad_state = SDL_calloc(1, sizeof(*gamepad_state)); - if (!gamepad_state) { - return false; - } - new_per_gamepad = SDL_realloc(wgi_state.per_gamepad, sizeof(wgi_state.per_gamepad[0]) * (wgi_state.per_gamepad_count + 1)); - if (!new_per_gamepad) { - SDL_free(gamepad_state); - return false; - } - wgi_state.per_gamepad = new_per_gamepad; - wgi_state.per_gamepad_count++; - wgi_state.per_gamepad[wgi_state.per_gamepad_count - 1] = gamepad_state; - gamepad_state->gamepad = gamepad; - gamepad_state->connected = true; - } else { - // Already tracked - __x_ABI_CWindows_CGaming_CInput_CIGamepad_Release(gamepad); - } - } - } - for (ii = wgi_state.per_gamepad_count - 1; ii >= 0; ii--) { - WindowsGamingInputGamepadState *gamepad_state = wgi_state.per_gamepad[ii]; - if (!gamepad_state->connected) { - // Device missing, must be disconnected - if (gamepad_state->correlated_context) { - gamepad_state->correlated_context->wgi_correlated = false; - gamepad_state->correlated_context->wgi_slot = NULL; - } - __x_ABI_CWindows_CGaming_CInput_CIGamepad_Release(gamepad_state->gamepad); - SDL_free(gamepad_state); - wgi_state.per_gamepad[ii] = wgi_state.per_gamepad[wgi_state.per_gamepad_count - 1]; - --wgi_state.per_gamepad_count; - } - } - } - __FIVectorView_1_Windows__CGaming__CInput__CGamepad_Release(gamepads); - } - } // need_device_list_update - - for (ii = 0; ii < wgi_state.per_gamepad_count; ii++) { - HRESULT hr = __x_ABI_CWindows_CGaming_CInput_CIGamepad_GetCurrentReading(wgi_state.per_gamepad[ii]->gamepad, &wgi_state.per_gamepad[ii]->state); - if (!SUCCEEDED(hr)) { - wgi_state.per_gamepad[ii]->connected = false; // Not used by anything, currently - } - } - return true; -} -static void RAWINPUT_InitWindowsGamingInput(RAWINPUT_DeviceContext *ctx) -{ - if (!SDL_GetHintBoolean(SDL_HINT_JOYSTICK_WGI, true)) { - return; - } - - wgi_state.ref_count++; - if (!wgi_state.initialized) { - static const IID SDL_IID_IGamepadStatics = { 0x8BBCE529, 0xD49C, 0x39E9, { 0x95, 0x60, 0xE4, 0x7D, 0xDE, 0x96, 0xB7, 0xC8 } }; - HRESULT hr; - - if (FAILED(WIN_RoInitialize())) { - return; - } - wgi_state.initialized = true; - wgi_state.dirty = true; - - { - typedef HRESULT(WINAPI * WindowsCreateStringReference_t)(PCWSTR sourceString, UINT32 length, HSTRING_HEADER * hstringHeader, HSTRING * string); - typedef HRESULT(WINAPI * RoGetActivationFactory_t)(HSTRING activatableClassId, REFIID iid, void **factory); - - WindowsCreateStringReference_t WindowsCreateStringReferenceFunc = (WindowsCreateStringReference_t)WIN_LoadComBaseFunction("WindowsCreateStringReference"); - RoGetActivationFactory_t RoGetActivationFactoryFunc = (RoGetActivationFactory_t)WIN_LoadComBaseFunction("RoGetActivationFactory"); - if (WindowsCreateStringReferenceFunc && RoGetActivationFactoryFunc) { - PCWSTR pNamespace = L"Windows.Gaming.Input.Gamepad"; - HSTRING_HEADER hNamespaceStringHeader; - HSTRING hNamespaceString; - - hr = WindowsCreateStringReferenceFunc(pNamespace, (UINT32)SDL_wcslen(pNamespace), &hNamespaceStringHeader, &hNamespaceString); - if (SUCCEEDED(hr)) { - RoGetActivationFactoryFunc(hNamespaceString, &SDL_IID_IGamepadStatics, (void **)&wgi_state.gamepad_statics); - } - - if (wgi_state.gamepad_statics) { - wgi_state.need_device_list_update = true; - - hr = __x_ABI_CWindows_CGaming_CInput_CIGamepadStatics_add_GamepadAdded(wgi_state.gamepad_statics, &gamepad_added.iface, &wgi_state.gamepad_added_token); - if (!SUCCEEDED(hr)) { - SDL_SetError("add_GamepadAdded() failed: 0x%lx", hr); - } - - hr = __x_ABI_CWindows_CGaming_CInput_CIGamepadStatics_add_GamepadRemoved(wgi_state.gamepad_statics, &gamepad_removed.iface, &wgi_state.gamepad_removed_token); - if (!SUCCEEDED(hr)) { - SDL_SetError("add_GamepadRemoved() failed: 0x%lx", hr); - } - } - } - } - } -} - -static bool RAWINPUT_WindowsGamingInputSlotMatches(const WindowsMatchState *state, WindowsGamingInputGamepadState *slot, bool xinput_correlated) -{ - Uint32 wgi_buttons = slot->state.Buttons; - if ((wgi_buttons & 0x3FFF) == state->wgi_buttons -#ifdef SDL_JOYSTICK_RAWINPUT_MATCH_AXES - && WindowsGamingInputAxesMatch(slot->state) -#endif -#ifdef SDL_JOYSTICK_RAWINPUT_MATCH_TRIGGERS - // Don't try to match WGI triggers if getting values from XInput - && (xinput_correlated || WindowsGamingInputTriggersMatch(slot->state)) -#endif - ) { - return true; - } - return false; -} - -static bool RAWINPUT_GuessWindowsGamingInputSlot(const WindowsMatchState *state, Uint8 *correlation_id, WindowsGamingInputGamepadState **slot, bool xinput_correlated) -{ - int match_count, user_index; - WindowsGamingInputGamepadState *gamepad_state = NULL; - - /* If there is only one available slot, let's use that - * That will be right most of the time, and uncorrelation will fix any bad guesses - */ - match_count = 0; - for (user_index = 0; user_index < wgi_state.per_gamepad_count; ++user_index) { - gamepad_state = wgi_state.per_gamepad[user_index]; - if (gamepad_state->connected && !gamepad_state->used) { - *slot = gamepad_state; - ++match_count; - } - } - if (match_count == 1) { - *correlation_id = ++gamepad_state->correlation_id; - return true; - } - - match_count = 0; - for (user_index = 0; user_index < wgi_state.per_gamepad_count; ++user_index) { - gamepad_state = wgi_state.per_gamepad[user_index]; - if (RAWINPUT_WindowsGamingInputSlotMatches(state, gamepad_state, xinput_correlated)) { - ++match_count; - *slot = gamepad_state; - // Incrementing correlation_id for any match, as negative evidence for others being correlated - *correlation_id = ++gamepad_state->correlation_id; - } - } - /* Only return a match if we match exactly one, and we have some non-zero data (buttons or axes) that matched. - Note that we're still invalidating *other* potential correlations if we have more than one match or we have no - data. */ - if (match_count == 1 && state->any_data) { - return true; - } - return false; -} - -static void RAWINPUT_QuitWindowsGamingInput(RAWINPUT_DeviceContext *ctx) -{ - --wgi_state.ref_count; - if (!wgi_state.ref_count && wgi_state.initialized) { - int ii; - for (ii = 0; ii < wgi_state.per_gamepad_count; ii++) { - __x_ABI_CWindows_CGaming_CInput_CIGamepad_Release(wgi_state.per_gamepad[ii]->gamepad); - } - if (wgi_state.per_gamepad) { - SDL_free(wgi_state.per_gamepad); - wgi_state.per_gamepad = NULL; - } - wgi_state.per_gamepad_count = 0; - if (wgi_state.gamepad_statics) { - __x_ABI_CWindows_CGaming_CInput_CIGamepadStatics_remove_GamepadAdded(wgi_state.gamepad_statics, wgi_state.gamepad_added_token); - __x_ABI_CWindows_CGaming_CInput_CIGamepadStatics_remove_GamepadRemoved(wgi_state.gamepad_statics, wgi_state.gamepad_removed_token); - __x_ABI_CWindows_CGaming_CInput_CIGamepadStatics_Release(wgi_state.gamepad_statics); - wgi_state.gamepad_statics = NULL; - } - WIN_RoUninitialize(); - wgi_state.initialized = false; - } -} - -#endif // SDL_JOYSTICK_RAWINPUT_WGI - -static SDL_RAWINPUT_Device *RAWINPUT_AcquireDevice(SDL_RAWINPUT_Device *device) -{ - SDL_AtomicIncRef(&device->refcount); - return device; -} - -static void RAWINPUT_ReleaseDevice(SDL_RAWINPUT_Device *device) -{ -#ifdef SDL_JOYSTICK_RAWINPUT_XINPUT - if (device->joystick) { - RAWINPUT_DeviceContext *ctx = device->joystick->hwdata; - - if (ctx->xinput_enabled && ctx->xinput_correlated) { - RAWINPUT_MarkXInputSlotFree(ctx->xinput_slot); - ctx->xinput_correlated = false; - } - } -#endif // SDL_JOYSTICK_RAWINPUT_XINPUT - - if (SDL_AtomicDecRef(&device->refcount)) { - SDL_free(device->preparsed_data); - SDL_free(device->name); - SDL_free(device->path); - SDL_free(device); - } -} - -static SDL_RAWINPUT_Device *RAWINPUT_DeviceFromHandle(HANDLE hDevice) -{ - SDL_RAWINPUT_Device *curr; - - for (curr = SDL_RAWINPUT_devices; curr; curr = curr->next) { - if (curr->hDevice == hDevice) { - return curr; - } - } - return NULL; -} - -static int GetSteamVirtualGamepadSlot(Uint16 vendor_id, Uint16 product_id, const char *device_path) -{ - int slot = -1; - - // The format for the raw input device path is documented here: - // https://partner.steamgames.com/doc/features/steam_controller/steam_input_gamepad_emulation_bestpractices - if (vendor_id == USB_VENDOR_VALVE && - product_id == USB_PRODUCT_STEAM_VIRTUAL_GAMEPAD) { - (void)SDL_sscanf(device_path, "\\\\.\\pipe\\HID#VID_045E&PID_028E&IG_00#%*X&%*X&%*X#%d#%*u", &slot); - } - return slot; -} - -static void RAWINPUT_AddDevice(HANDLE hDevice) -{ -#define CHECK(expression) \ - { \ - if (!(expression)) \ - goto err; \ - } - SDL_RAWINPUT_Device *device = NULL; - SDL_RAWINPUT_Device *curr, *last; - RID_DEVICE_INFO rdi; - UINT size; - char dev_name[MAX_PATH] = { 0 }; - HANDLE hFile = INVALID_HANDLE_VALUE; - - // Make sure we're not trying to add the same device twice - if (RAWINPUT_DeviceFromHandle(hDevice)) { - return; - } - - // Figure out what kind of device it is - size = sizeof(rdi); - SDL_zero(rdi); - CHECK(GetRawInputDeviceInfoA(hDevice, RIDI_DEVICEINFO, &rdi, &size) != (UINT)-1); - CHECK(rdi.dwType == RIM_TYPEHID); - - // Get the device "name" (HID Path) - size = SDL_arraysize(dev_name); - CHECK(GetRawInputDeviceInfoA(hDevice, RIDI_DEVICENAME, dev_name, &size) != (UINT)-1); - // Only take XInput-capable devices - CHECK(SDL_strstr(dev_name, "IG_") != NULL); - CHECK(!SDL_ShouldIgnoreJoystick((Uint16)rdi.hid.dwVendorId, (Uint16)rdi.hid.dwProductId, (Uint16)rdi.hid.dwVersionNumber, "")); - CHECK(!SDL_JoystickHandledByAnotherDriver(&SDL_RAWINPUT_JoystickDriver, (Uint16)rdi.hid.dwVendorId, (Uint16)rdi.hid.dwProductId, (Uint16)rdi.hid.dwVersionNumber, "")); - - device = (SDL_RAWINPUT_Device *)SDL_calloc(1, sizeof(SDL_RAWINPUT_Device)); - CHECK(device); - device->hDevice = hDevice; - device->vendor_id = (Uint16)rdi.hid.dwVendorId; - device->product_id = (Uint16)rdi.hid.dwProductId; - device->version = (Uint16)rdi.hid.dwVersionNumber; - device->is_xinput = true; - device->is_xboxone = SDL_IsJoystickXboxOne(device->vendor_id, device->product_id); - device->steam_virtual_gamepad_slot = GetSteamVirtualGamepadSlot(device->vendor_id, device->product_id, dev_name); - - // Get HID Top-Level Collection Preparsed Data - size = 0; - CHECK(GetRawInputDeviceInfoA(hDevice, RIDI_PREPARSEDDATA, NULL, &size) != (UINT)-1); - device->preparsed_data = (PHIDP_PREPARSED_DATA)SDL_calloc(size, sizeof(BYTE)); - CHECK(device->preparsed_data); - CHECK(GetRawInputDeviceInfoA(hDevice, RIDI_PREPARSEDDATA, device->preparsed_data, &size) != (UINT)-1); - - hFile = CreateFileA(dev_name, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); - CHECK(hFile != INVALID_HANDLE_VALUE); - - { - char *manufacturer_string = NULL; - char *product_string = NULL; - WCHAR string[128]; - - if (SDL_HidD_GetManufacturerString(hFile, string, sizeof(string))) { - manufacturer_string = WIN_StringToUTF8W(string); - } - if (SDL_HidD_GetProductString(hFile, string, sizeof(string))) { - product_string = WIN_StringToUTF8W(string); - } - - device->name = SDL_CreateJoystickName(device->vendor_id, device->product_id, manufacturer_string, product_string); - device->guid = SDL_CreateJoystickGUID(SDL_HARDWARE_BUS_USB, device->vendor_id, device->product_id, device->version, manufacturer_string, product_string, 'r', 0); - - if (manufacturer_string) { - SDL_free(manufacturer_string); - } - if (product_string) { - SDL_free(product_string); - } - } - - device->path = SDL_strdup(dev_name); - - CloseHandle(hFile); - hFile = INVALID_HANDLE_VALUE; - - device->joystick_id = SDL_GetNextObjectID(); - -#ifdef DEBUG_RAWINPUT - SDL_Log("Adding RAWINPUT device '%s' VID 0x%.4x, PID 0x%.4x, version %d, handle 0x%.8x", device->name, device->vendor_id, device->product_id, device->version, device->hDevice); -#endif - - // Add it to the list - RAWINPUT_AcquireDevice(device); - for (curr = SDL_RAWINPUT_devices, last = NULL; curr; last = curr, curr = curr->next) { - } - if (last) { - last->next = device; - } else { - SDL_RAWINPUT_devices = device; - } - - ++SDL_RAWINPUT_numjoysticks; - - SDL_PrivateJoystickAdded(device->joystick_id); - - return; - -err: - if (hFile != INVALID_HANDLE_VALUE) { - CloseHandle(hFile); - } - if (device) { - if (device->name) { - SDL_free(device->name); - } - if (device->path) { - SDL_free(device->path); - } - SDL_free(device); - } -#undef CHECK -} - -static void RAWINPUT_DelDevice(SDL_RAWINPUT_Device *device, bool send_event) -{ - SDL_RAWINPUT_Device *curr, *last; - for (curr = SDL_RAWINPUT_devices, last = NULL; curr; last = curr, curr = curr->next) { - if (curr == device) { - if (last) { - last->next = curr->next; - } else { - SDL_RAWINPUT_devices = curr->next; - } - --SDL_RAWINPUT_numjoysticks; - - SDL_PrivateJoystickRemoved(device->joystick_id); - -#ifdef DEBUG_RAWINPUT - SDL_Log("Removing RAWINPUT device '%s' VID 0x%.4x, PID 0x%.4x, version %d, handle %p", device->name, device->vendor_id, device->product_id, device->version, device->hDevice); -#endif - RAWINPUT_ReleaseDevice(device); - return; - } - } -} - -static void RAWINPUT_DetectDevices(void) -{ - UINT device_count = 0; - - if ((GetRawInputDeviceList(NULL, &device_count, sizeof(RAWINPUTDEVICELIST)) != -1) && device_count > 0) { - PRAWINPUTDEVICELIST devices = NULL; - UINT i; - - devices = (PRAWINPUTDEVICELIST)SDL_malloc(sizeof(RAWINPUTDEVICELIST) * device_count); - if (devices) { - device_count = GetRawInputDeviceList(devices, &device_count, sizeof(RAWINPUTDEVICELIST)); - if (device_count != (UINT)-1) { - for (i = 0; i < device_count; ++i) { - RAWINPUT_AddDevice(devices[i].hDevice); - } - } - SDL_free(devices); - } - } -} - -static void RAWINPUT_RemoveDevices(void) -{ - while (SDL_RAWINPUT_devices) { - RAWINPUT_DelDevice(SDL_RAWINPUT_devices, false); - } - SDL_assert(SDL_RAWINPUT_numjoysticks == 0); -} - -static bool RAWINPUT_JoystickInit(void) -{ - SDL_assert(!SDL_RAWINPUT_inited); - - if (!SDL_GetHintBoolean(SDL_HINT_JOYSTICK_RAWINPUT, true)) { - return true; - } - - if (!WIN_IsWindowsVistaOrGreater()) { - // According to bug 6400, this doesn't work on Windows XP - return false; - } - - if (!WIN_LoadHIDDLL()) { - return false; - } - - SDL_RAWINPUT_inited = true; - - RAWINPUT_DetectDevices(); - - return true; -} - -static int RAWINPUT_JoystickGetCount(void) -{ - return SDL_RAWINPUT_numjoysticks; -} - -bool RAWINPUT_IsEnabled(void) -{ - return SDL_RAWINPUT_inited && !SDL_RAWINPUT_remote_desktop; -} - -static void RAWINPUT_PostUpdate(void) -{ -#ifdef SDL_JOYSTICK_RAWINPUT_MATCHING - bool unmapped_guide_pressed = false; - -#ifdef SDL_JOYSTICK_RAWINPUT_WGI - if (!wgi_state.dirty) { - int ii; - for (ii = 0; ii < wgi_state.per_gamepad_count; ii++) { - WindowsGamingInputGamepadState *gamepad_state = wgi_state.per_gamepad[ii]; - if (!gamepad_state->used && (gamepad_state->state.Buttons & GamepadButtons_GUIDE)) { - unmapped_guide_pressed = true; - break; - } - } - } - wgi_state.dirty = true; -#endif - -#ifdef SDL_JOYSTICK_RAWINPUT_XINPUT - if (!xinput_state_dirty) { - int ii; - for (ii = 0; ii < SDL_arraysize(xinput_state); ii++) { - if (xinput_state[ii].connected && !xinput_state[ii].used && (xinput_state[ii].state.Gamepad.wButtons & XINPUT_GAMEPAD_GUIDE)) { - unmapped_guide_pressed = true; - break; - } - } - } - xinput_state_dirty = true; -#endif - - if (unmapped_guide_pressed) { - if (guide_button_candidate.joystick && !guide_button_candidate.last_joystick) { - SDL_Joystick *joystick = guide_button_candidate.joystick; - RAWINPUT_DeviceContext *ctx = joystick->hwdata; - if (ctx->guide_hack) { - int guide_button = joystick->nbuttons - 1; - - SDL_SendJoystickButton(SDL_GetTicksNS(), guide_button_candidate.joystick, (Uint8)guide_button, true); - } - guide_button_candidate.last_joystick = guide_button_candidate.joystick; - } - } else if (guide_button_candidate.last_joystick) { - SDL_Joystick *joystick = guide_button_candidate.last_joystick; - RAWINPUT_DeviceContext *ctx = joystick->hwdata; - if (ctx->guide_hack) { - int guide_button = joystick->nbuttons - 1; - - SDL_SendJoystickButton(SDL_GetTicksNS(), joystick, (Uint8)guide_button, false); - } - guide_button_candidate.last_joystick = NULL; - } - guide_button_candidate.joystick = NULL; - -#endif // SDL_JOYSTICK_RAWINPUT_MATCHING -} - -static void RAWINPUT_JoystickDetect(void) -{ - bool remote_desktop; - - if (!SDL_RAWINPUT_inited) { - return; - } - - remote_desktop = GetSystemMetrics(SM_REMOTESESSION) ? true : false; - if (remote_desktop != SDL_RAWINPUT_remote_desktop) { - SDL_RAWINPUT_remote_desktop = remote_desktop; - - WINDOWS_RAWINPUTEnabledChanged(); - - if (remote_desktop) { - RAWINPUT_RemoveDevices(); - WINDOWS_JoystickDetect(); - } else { - WINDOWS_JoystickDetect(); - RAWINPUT_DetectDevices(); - } - } - RAWINPUT_PostUpdate(); -} - -static bool RAWINPUT_JoystickIsDevicePresent(Uint16 vendor_id, Uint16 product_id, Uint16 version, const char *name) -{ - SDL_RAWINPUT_Device *device; - - // If we're being asked about a device, that means another API just detected one, so rescan -#ifdef SDL_JOYSTICK_RAWINPUT_XINPUT - xinput_device_change = true; -#endif - - device = SDL_RAWINPUT_devices; - while (device) { - if (vendor_id == device->vendor_id && product_id == device->product_id) { - return true; - } - - /* The Xbox 360 wireless controller shows up as product 0 in WGI. - Try to match it to a Raw Input device via name or known product ID. */ - if (vendor_id == device->vendor_id && product_id == 0 && - ((name && SDL_strstr(device->name, name) != NULL) || - (device->vendor_id == USB_VENDOR_MICROSOFT && - device->product_id == USB_PRODUCT_XBOX360_XUSB_CONTROLLER))) { - return true; - } - - // The Xbox One controller shows up as a hardcoded raw input VID/PID - if (name && SDL_strcmp(name, "Xbox One Game Controller") == 0 && - device->vendor_id == USB_VENDOR_MICROSOFT && - device->product_id == USB_PRODUCT_XBOX_ONE_XBOXGIP_CONTROLLER) { - return true; - } - - device = device->next; - } - return false; -} - -static SDL_RAWINPUT_Device *RAWINPUT_GetDeviceByIndex(int device_index) -{ - SDL_RAWINPUT_Device *device = SDL_RAWINPUT_devices; - while (device) { - if (device_index == 0) { - break; - } - --device_index; - device = device->next; - } - return device; -} - -static const char *RAWINPUT_JoystickGetDeviceName(int device_index) -{ - return RAWINPUT_GetDeviceByIndex(device_index)->name; -} - -static const char *RAWINPUT_JoystickGetDevicePath(int device_index) -{ - return RAWINPUT_GetDeviceByIndex(device_index)->path; -} - -static int RAWINPUT_JoystickGetDeviceSteamVirtualGamepadSlot(int device_index) -{ - return RAWINPUT_GetDeviceByIndex(device_index)->steam_virtual_gamepad_slot; -} - -static int RAWINPUT_JoystickGetDevicePlayerIndex(int device_index) -{ - return false; -} - -static void RAWINPUT_JoystickSetDevicePlayerIndex(int device_index, int player_index) -{ -} - -static SDL_GUID RAWINPUT_JoystickGetDeviceGUID(int device_index) -{ - return RAWINPUT_GetDeviceByIndex(device_index)->guid; -} - -static SDL_JoystickID RAWINPUT_JoystickGetDeviceInstanceID(int device_index) -{ - return RAWINPUT_GetDeviceByIndex(device_index)->joystick_id; -} - -static int SDLCALL RAWINPUT_SortValueCaps(const void *A, const void *B) -{ - HIDP_VALUE_CAPS *capsA = (HIDP_VALUE_CAPS *)A; - HIDP_VALUE_CAPS *capsB = (HIDP_VALUE_CAPS *)B; - - // Sort by Usage for single values, or UsageMax for range of values - return (int)capsA->NotRange.Usage - capsB->NotRange.Usage; -} - -static bool RAWINPUT_JoystickOpen(SDL_Joystick *joystick, int device_index) -{ - SDL_RAWINPUT_Device *device = RAWINPUT_GetDeviceByIndex(device_index); - RAWINPUT_DeviceContext *ctx; - HIDP_CAPS caps; - HIDP_BUTTON_CAPS *button_caps; - HIDP_VALUE_CAPS *value_caps; - ULONG i; - - ctx = (RAWINPUT_DeviceContext *)SDL_calloc(1, sizeof(RAWINPUT_DeviceContext)); - if (!ctx) { - return false; - } - joystick->hwdata = ctx; - - ctx->device = RAWINPUT_AcquireDevice(device); - device->joystick = joystick; - - if (device->is_xinput) { - // We'll try to get guide button and trigger axes from XInput -#ifdef SDL_JOYSTICK_RAWINPUT_XINPUT - xinput_device_change = true; - ctx->xinput_enabled = SDL_GetHintBoolean(SDL_HINT_JOYSTICK_RAWINPUT_CORRELATE_XINPUT, true); - if (ctx->xinput_enabled && (!WIN_LoadXInputDLL() || !XINPUTGETSTATE)) { - ctx->xinput_enabled = false; - } - ctx->xinput_slot = XUSER_INDEX_ANY; -#endif -#ifdef SDL_JOYSTICK_RAWINPUT_WGI - RAWINPUT_InitWindowsGamingInput(ctx); -#endif - } - - ctx->is_xinput = device->is_xinput; - ctx->is_xboxone = device->is_xboxone; -#ifdef SDL_JOYSTICK_RAWINPUT_MATCHING - ctx->match_state = 0x0000008800000000ULL; // Trigger axes at rest -#endif - ctx->preparsed_data = device->preparsed_data; - ctx->max_data_length = SDL_HidP_MaxDataListLength(HidP_Input, ctx->preparsed_data); - ctx->data = (HIDP_DATA *)SDL_malloc(ctx->max_data_length * sizeof(*ctx->data)); - if (!ctx->data) { - RAWINPUT_JoystickClose(joystick); - return false; - } - - if (SDL_HidP_GetCaps(ctx->preparsed_data, &caps) != HIDP_STATUS_SUCCESS) { - RAWINPUT_JoystickClose(joystick); - return SDL_SetError("Couldn't get device capabilities"); - } - - button_caps = SDL_stack_alloc(HIDP_BUTTON_CAPS, caps.NumberInputButtonCaps); - if (SDL_HidP_GetButtonCaps(HidP_Input, button_caps, &caps.NumberInputButtonCaps, ctx->preparsed_data) != HIDP_STATUS_SUCCESS) { - RAWINPUT_JoystickClose(joystick); - return SDL_SetError("Couldn't get device button capabilities"); - } - - value_caps = SDL_stack_alloc(HIDP_VALUE_CAPS, caps.NumberInputValueCaps); - if (SDL_HidP_GetValueCaps(HidP_Input, value_caps, &caps.NumberInputValueCaps, ctx->preparsed_data) != HIDP_STATUS_SUCCESS) { - RAWINPUT_JoystickClose(joystick); - SDL_stack_free(button_caps); - return SDL_SetError("Couldn't get device value capabilities"); - } - - // Sort the axes by usage, so X comes before Y, etc. - SDL_qsort(value_caps, caps.NumberInputValueCaps, sizeof(*value_caps), RAWINPUT_SortValueCaps); - - for (i = 0; i < caps.NumberInputButtonCaps; ++i) { - HIDP_BUTTON_CAPS *cap = &button_caps[i]; - - if (cap->UsagePage == USB_USAGEPAGE_BUTTON) { - int count; - - if (cap->IsRange) { - count = 1 + (cap->Range.DataIndexMax - cap->Range.DataIndexMin); - } else { - count = 1; - } - - joystick->nbuttons += count; - } - } - - if (joystick->nbuttons > 0) { - int button_index = 0; - - ctx->button_indices = (USHORT *)SDL_malloc(joystick->nbuttons * sizeof(*ctx->button_indices)); - if (!ctx->button_indices) { - RAWINPUT_JoystickClose(joystick); - SDL_stack_free(value_caps); - SDL_stack_free(button_caps); - return false; - } - - for (i = 0; i < caps.NumberInputButtonCaps; ++i) { - HIDP_BUTTON_CAPS *cap = &button_caps[i]; - - if (cap->UsagePage == USB_USAGEPAGE_BUTTON) { - if (cap->IsRange) { - int j, count = 1 + (cap->Range.DataIndexMax - cap->Range.DataIndexMin); - - for (j = 0; j < count; ++j) { - ctx->button_indices[button_index++] = (USHORT)(cap->Range.DataIndexMin + j); - } - } else { - ctx->button_indices[button_index++] = cap->NotRange.DataIndex; - } - } - } - } - if (ctx->is_xinput && joystick->nbuttons == 10) { - ctx->guide_hack = true; - joystick->nbuttons += 1; - } - - SDL_stack_free(button_caps); - - for (i = 0; i < caps.NumberInputValueCaps; ++i) { - HIDP_VALUE_CAPS *cap = &value_caps[i]; - - if (cap->IsRange) { - continue; - } - - if (ctx->trigger_hack && cap->NotRange.Usage == USB_USAGE_GENERIC_Z) { - continue; - } - - if (cap->NotRange.Usage == USB_USAGE_GENERIC_HAT) { - joystick->nhats += 1; - continue; - } - - if (ctx->is_xinput && cap->NotRange.Usage == USB_USAGE_GENERIC_Z) { - continue; - } - - joystick->naxes += 1; - } - - if (joystick->naxes > 0) { - int axis_index = 0; - - ctx->axis_indices = (USHORT *)SDL_malloc(joystick->naxes * sizeof(*ctx->axis_indices)); - if (!ctx->axis_indices) { - RAWINPUT_JoystickClose(joystick); - SDL_stack_free(value_caps); - return false; - } - - for (i = 0; i < caps.NumberInputValueCaps; ++i) { - HIDP_VALUE_CAPS *cap = &value_caps[i]; - - if (cap->IsRange) { - continue; - } - - if (cap->NotRange.Usage == USB_USAGE_GENERIC_HAT) { - continue; - } - - if (ctx->is_xinput && cap->NotRange.Usage == USB_USAGE_GENERIC_Z) { - ctx->trigger_hack = true; - ctx->trigger_hack_index = cap->NotRange.DataIndex; - continue; - } - - ctx->axis_indices[axis_index++] = cap->NotRange.DataIndex; - } - } - if (ctx->trigger_hack) { - joystick->naxes += 2; - } - - if (joystick->nhats > 0) { - int hat_index = 0; - - ctx->hat_indices = (USHORT *)SDL_malloc(joystick->nhats * sizeof(*ctx->hat_indices)); - if (!ctx->hat_indices) { - RAWINPUT_JoystickClose(joystick); - SDL_stack_free(value_caps); - return false; - } - - for (i = 0; i < caps.NumberInputValueCaps; ++i) { - HIDP_VALUE_CAPS *cap = &value_caps[i]; - - if (cap->IsRange) { - continue; - } - - if (cap->NotRange.Usage != USB_USAGE_GENERIC_HAT) { - continue; - } - - ctx->hat_indices[hat_index++] = cap->NotRange.DataIndex; - } - } - - SDL_stack_free(value_caps); - -#ifdef SDL_JOYSTICK_RAWINPUT_XINPUT - if (ctx->is_xinput) { - SDL_SetBooleanProperty(SDL_GetJoystickProperties(joystick), SDL_PROP_JOYSTICK_CAP_RUMBLE_BOOLEAN, true); - } -#endif -#ifdef SDL_JOYSTICK_RAWINPUT_WGI - if (ctx->is_xinput) { - SDL_SetBooleanProperty(SDL_GetJoystickProperties(joystick), SDL_PROP_JOYSTICK_CAP_RUMBLE_BOOLEAN, true); - - if (ctx->is_xboxone) { - SDL_SetBooleanProperty(SDL_GetJoystickProperties(joystick), SDL_PROP_JOYSTICK_CAP_TRIGGER_RUMBLE_BOOLEAN, true); - } - } -#endif - - return true; -} - -static bool RAWINPUT_JoystickRumble(SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble) -{ -#if defined(SDL_JOYSTICK_RAWINPUT_WGI) || defined(SDL_JOYSTICK_RAWINPUT_XINPUT) - RAWINPUT_DeviceContext *ctx = joystick->hwdata; -#endif - bool rumbled = false; - -#ifdef SDL_JOYSTICK_RAWINPUT_XINPUT - // Prefer XInput over WGI because it allows rumble in the background - if (!rumbled && ctx->xinput_correlated) { - XINPUT_VIBRATION XVibration; - - if (!XINPUTSETSTATE) { - return SDL_Unsupported(); - } - - XVibration.wLeftMotorSpeed = low_frequency_rumble; - XVibration.wRightMotorSpeed = high_frequency_rumble; - if (XINPUTSETSTATE(ctx->xinput_slot, &XVibration) == ERROR_SUCCESS) { - rumbled = true; - } else { - return SDL_SetError("XInputSetState() failed"); - } - } -#endif // SDL_JOYSTICK_RAWINPUT_XINPUT - -#ifdef SDL_JOYSTICK_RAWINPUT_WGI - if (!rumbled && ctx->wgi_correlated) { - WindowsGamingInputGamepadState *gamepad_state = ctx->wgi_slot; - HRESULT hr; - gamepad_state->vibration.LeftMotor = (DOUBLE)low_frequency_rumble / SDL_MAX_UINT16; - gamepad_state->vibration.RightMotor = (DOUBLE)high_frequency_rumble / SDL_MAX_UINT16; - hr = __x_ABI_CWindows_CGaming_CInput_CIGamepad_put_Vibration(gamepad_state->gamepad, gamepad_state->vibration); - if (SUCCEEDED(hr)) { - rumbled = true; - } - } -#endif - - if (!rumbled) { -#if defined(SDL_JOYSTICK_RAWINPUT_WGI) || defined(SDL_JOYSTICK_RAWINPUT_XINPUT) - return SDL_SetError("Controller isn't correlated yet, try hitting a button first"); -#else - return SDL_Unsupported(); -#endif - } - return true; -} - -static bool RAWINPUT_JoystickRumbleTriggers(SDL_Joystick *joystick, Uint16 left_rumble, Uint16 right_rumble) -{ -#ifdef SDL_JOYSTICK_RAWINPUT_WGI - RAWINPUT_DeviceContext *ctx = joystick->hwdata; - - if (ctx->wgi_correlated) { - WindowsGamingInputGamepadState *gamepad_state = ctx->wgi_slot; - HRESULT hr; - gamepad_state->vibration.LeftTrigger = (DOUBLE)left_rumble / SDL_MAX_UINT16; - gamepad_state->vibration.RightTrigger = (DOUBLE)right_rumble / SDL_MAX_UINT16; - hr = __x_ABI_CWindows_CGaming_CInput_CIGamepad_put_Vibration(gamepad_state->gamepad, gamepad_state->vibration); - if (!SUCCEEDED(hr)) { - return SDL_SetError("Setting vibration failed: 0x%lx", hr); - } - return true; - } else { - return SDL_SetError("Controller isn't correlated yet, try hitting a button first"); - } -#else - return SDL_Unsupported(); -#endif -} - -static bool RAWINPUT_JoystickSetLED(SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue) -{ - return SDL_Unsupported(); -} - -static bool RAWINPUT_JoystickSendEffect(SDL_Joystick *joystick, const void *data, int size) -{ - return SDL_Unsupported(); -} - -static bool RAWINPUT_JoystickSetSensorsEnabled(SDL_Joystick *joystick, bool enabled) -{ - return SDL_Unsupported(); -} - -static HIDP_DATA *GetData(USHORT index, HIDP_DATA *data, ULONG length) -{ - ULONG i; - - // Check to see if the data is at the expected offset - if (index < length && data[index].DataIndex == index) { - return &data[index]; - } - - // Loop through the data to find it - for (i = 0; i < length; ++i) { - if (data[i].DataIndex == index) { - return &data[i]; - } - } - return NULL; -} - -/* This is the packet format for Xbox 360 and Xbox One controllers on Windows, - however with this interface there is no rumble support, no guide button, - and the left and right triggers are tied together as a single axis. - - We use XInput and Windows.Gaming.Input to make up for these shortcomings. - */ -static void RAWINPUT_HandleStatePacket(SDL_Joystick *joystick, Uint8 *data, int size) -{ - RAWINPUT_DeviceContext *ctx = joystick->hwdata; -#ifdef SDL_JOYSTICK_RAWINPUT_MATCHING - // Map new buttons and axes into game controller controls - static const int button_map[] = { - SDL_GAMEPAD_BUTTON_SOUTH, - SDL_GAMEPAD_BUTTON_EAST, - SDL_GAMEPAD_BUTTON_WEST, - SDL_GAMEPAD_BUTTON_NORTH, - SDL_GAMEPAD_BUTTON_LEFT_SHOULDER, - SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER, - SDL_GAMEPAD_BUTTON_BACK, - SDL_GAMEPAD_BUTTON_START, - SDL_GAMEPAD_BUTTON_LEFT_STICK, - SDL_GAMEPAD_BUTTON_RIGHT_STICK - }; -#define HAT_MASK ((1 << SDL_GAMEPAD_BUTTON_DPAD_UP) | (1 << SDL_GAMEPAD_BUTTON_DPAD_DOWN) | (1 << SDL_GAMEPAD_BUTTON_DPAD_LEFT) | (1 << SDL_GAMEPAD_BUTTON_DPAD_RIGHT)) - static const int hat_map[] = { - 0, - (1 << SDL_GAMEPAD_BUTTON_DPAD_UP), - (1 << SDL_GAMEPAD_BUTTON_DPAD_UP) | (1 << SDL_GAMEPAD_BUTTON_DPAD_RIGHT), - (1 << SDL_GAMEPAD_BUTTON_DPAD_RIGHT), - (1 << SDL_GAMEPAD_BUTTON_DPAD_DOWN) | (1 << SDL_GAMEPAD_BUTTON_DPAD_RIGHT), - (1 << SDL_GAMEPAD_BUTTON_DPAD_DOWN), - (1 << SDL_GAMEPAD_BUTTON_DPAD_DOWN) | (1 << SDL_GAMEPAD_BUTTON_DPAD_LEFT), - (1 << SDL_GAMEPAD_BUTTON_DPAD_LEFT), - (1 << SDL_GAMEPAD_BUTTON_DPAD_UP) | (1 << SDL_GAMEPAD_BUTTON_DPAD_LEFT), - 0, - }; - Uint64 match_state = ctx->match_state; - // Update match_state with button bit, then fall through -#define SDL_SendJoystickButton(timestamp, joystick, button, down) \ - if (button < SDL_arraysize(button_map)) { \ - Uint64 button_bit = 1ull << button_map[button]; \ - match_state = (match_state & ~button_bit) | (button_bit * (down)); \ - } \ - SDL_SendJoystickButton(timestamp, joystick, button, down) -#ifdef SDL_JOYSTICK_RAWINPUT_MATCH_AXES - // Grab high 4 bits of value, then fall through -#define AddAxisToMatchState(axis, value) \ - { \ - match_state = (match_state & ~(0xFull << (4 * axis + 16))) | ((value)&0xF000ull) << (4 * axis + 4); \ - } -#define SDL_SendJoystickAxis(timestamp, joystick, axis, value) \ - if (axis < 4) \ - AddAxisToMatchState(axis, value); \ - SDL_SendJoystickAxis(timestamp, joystick, axis, value) -#endif -#endif // SDL_JOYSTICK_RAWINPUT_MATCHING - - ULONG data_length = ctx->max_data_length; - int i; - int nbuttons = joystick->nbuttons - (ctx->guide_hack * 1); - int naxes = joystick->naxes - (ctx->trigger_hack * 2); - int nhats = joystick->nhats; - Uint32 button_mask = 0; - Uint64 timestamp = SDL_GetTicksNS(); - - if (SDL_HidP_GetData(HidP_Input, ctx->data, &data_length, ctx->preparsed_data, (PCHAR)data, size) != HIDP_STATUS_SUCCESS) { - return; - } - - for (i = 0; i < nbuttons; ++i) { - HIDP_DATA *item = GetData(ctx->button_indices[i], ctx->data, data_length); - if (item && item->On) { - button_mask |= (1 << i); - } - } - for (i = 0; i < nbuttons; ++i) { - SDL_SendJoystickButton(timestamp, joystick, (Uint8)i, ((button_mask & (1 << i)) != 0)); - } - - for (i = 0; i < naxes; ++i) { - HIDP_DATA *item = GetData(ctx->axis_indices[i], ctx->data, data_length); - if (item) { - Sint16 axis = (int)(Uint16)item->RawValue - 0x8000; - SDL_SendJoystickAxis(timestamp, joystick, (Uint8)i, axis); - } - } - - for (i = 0; i < nhats; ++i) { - HIDP_DATA *item = GetData(ctx->hat_indices[i], ctx->data, data_length); - if (item) { - Uint8 hat = SDL_HAT_CENTERED; - const Uint8 hat_states[] = { - SDL_HAT_CENTERED, - SDL_HAT_UP, - SDL_HAT_UP | SDL_HAT_RIGHT, - SDL_HAT_RIGHT, - SDL_HAT_DOWN | SDL_HAT_RIGHT, - SDL_HAT_DOWN, - SDL_HAT_DOWN | SDL_HAT_LEFT, - SDL_HAT_LEFT, - SDL_HAT_UP | SDL_HAT_LEFT, - SDL_HAT_CENTERED, - }; - ULONG state = item->RawValue; - - if (state < SDL_arraysize(hat_states)) { -#ifdef SDL_JOYSTICK_RAWINPUT_MATCHING - match_state = (match_state & ~HAT_MASK) | hat_map[state]; -#endif - hat = hat_states[state]; - } - SDL_SendJoystickHat(timestamp, joystick, (Uint8)i, hat); - } - } - -#ifdef SDL_SendJoystickButton -#undef SDL_SendJoystickButton -#endif -#ifdef SDL_SendJoystickAxis -#undef SDL_SendJoystickAxis -#endif - -#ifdef SDL_JOYSTICK_RAWINPUT_MATCH_TRIGGERS -#define AddTriggerToMatchState(axis, value) \ - { \ - int match_axis = axis + SDL_JOYSTICK_RAWINPUT_MATCH_COUNT - joystick->naxes; \ - AddAxisToMatchState(match_axis, value); \ - } -#endif // SDL_JOYSTICK_RAWINPUT_MATCH_TRIGGERS - - if (ctx->trigger_hack) { - bool has_trigger_data = false; - int left_trigger = joystick->naxes - 2; - int right_trigger = joystick->naxes - 1; - -#ifdef SDL_JOYSTICK_RAWINPUT_XINPUT - // Prefer XInput over WindowsGamingInput, it continues to provide data in the background - if (!has_trigger_data && ctx->xinput_enabled && ctx->xinput_correlated) { - has_trigger_data = true; - } -#endif // SDL_JOYSTICK_RAWINPUT_XINPUT - -#ifdef SDL_JOYSTICK_RAWINPUT_WGI - if (!has_trigger_data && ctx->wgi_correlated) { - has_trigger_data = true; - } -#endif // SDL_JOYSTICK_RAWINPUT_WGI - -#ifndef SDL_JOYSTICK_RAWINPUT_MATCH_TRIGGERS - if (!has_trigger_data) -#endif - { - HIDP_DATA *item = GetData(ctx->trigger_hack_index, ctx->data, data_length); - if (item) { - Sint16 value = (int)(Uint16)item->RawValue - 0x8000; - Sint16 left_value = (value > 0) ? (value * 2 - 32767) : SDL_MIN_SINT16; - Sint16 right_value = (value < 0) ? (-value * 2 - 32769) : SDL_MIN_SINT16; - -#ifdef SDL_JOYSTICK_RAWINPUT_MATCH_TRIGGERS - AddTriggerToMatchState(left_trigger, left_value); - AddTriggerToMatchState(right_trigger, right_value); - if (!has_trigger_data) -#endif // SDL_JOYSTICK_RAWINPUT_MATCH_TRIGGERS - { - SDL_SendJoystickAxis(timestamp, joystick, (Uint8)left_trigger, left_value); - SDL_SendJoystickAxis(timestamp, joystick, (Uint8)right_trigger, right_value); - } - } - } - } - -#ifdef AddAxisToMatchState -#undef AddAxisToMatchState -#endif -#ifdef AddTriggerToMatchState -#undef AddTriggerToMatchState -#endif - -#ifdef SDL_JOYSTICK_RAWINPUT_MATCHING - if (ctx->is_xinput) { - ctx->match_state = match_state; - ctx->last_state_packet = SDL_GetTicks(); - } -#endif -} - -static void RAWINPUT_UpdateOtherAPIs(SDL_Joystick *joystick) -{ -#ifdef SDL_JOYSTICK_RAWINPUT_MATCHING - RAWINPUT_DeviceContext *ctx = joystick->hwdata; - bool has_trigger_data = false; - bool correlated = false; - WindowsMatchState match_state_xinput; - int guide_button = joystick->nbuttons - 1; - int left_trigger = joystick->naxes - 2; - int right_trigger = joystick->naxes - 1; -#ifdef SDL_JOYSTICK_RAWINPUT_WGI - bool xinput_correlated; -#endif - - RAWINPUT_FillMatchState(&match_state_xinput, ctx->match_state); - -#ifdef SDL_JOYSTICK_RAWINPUT_WGI -#ifdef SDL_JOYSTICK_RAWINPUT_XINPUT - xinput_correlated = ctx->xinput_correlated; -#else - xinput_correlated = false; -#endif - // Parallel logic to WINDOWS_XINPUT below - RAWINPUT_UpdateWindowsGamingInput(); - if (ctx->wgi_correlated && - !joystick->low_frequency_rumble && !joystick->high_frequency_rumble && - !joystick->left_trigger_rumble && !joystick->right_trigger_rumble) { - // We have been previously correlated, ensure we are still matching, see comments in XINPUT section - if (RAWINPUT_WindowsGamingInputSlotMatches(&match_state_xinput, ctx->wgi_slot, xinput_correlated)) { - ctx->wgi_uncorrelate_count = 0; - } else { - ++ctx->wgi_uncorrelate_count; - /* Only un-correlate if this is consistent over multiple Update() calls - the timing of polling/event - pumping can easily cause this to uncorrelate for a frame. 2 seemed reliable in my testing, but - let's set it to 5 to be safe. An incorrect un-correlation will simply result in lower precision - triggers for a frame. */ - if (ctx->wgi_uncorrelate_count >= 5) { -#ifdef DEBUG_RAWINPUT - SDL_Log("UN-Correlated joystick %d to WindowsGamingInput device #%d", joystick->instance_id, ctx->wgi_slot); -#endif - RAWINPUT_MarkWindowsGamingInputSlotFree(ctx->wgi_slot); - ctx->wgi_correlated = false; - ctx->wgi_correlation_count = 0; - // Force release of Guide button, it can't possibly be down on this device now. - /* It gets left down if we were actually correlated incorrectly and it was released on the WindowsGamingInput - device but we didn't get a state packet. */ - if (ctx->guide_hack) { - SDL_SendJoystickButton(0, joystick, (Uint8)guide_button, false); - } - } - } - } - if (!ctx->wgi_correlated) { - Uint8 new_correlation_count = 0; - if (RAWINPUT_MissingWindowsGamingInputSlot()) { - Uint8 correlation_id = 0; - WindowsGamingInputGamepadState *slot_idx = NULL; - if (RAWINPUT_GuessWindowsGamingInputSlot(&match_state_xinput, &correlation_id, &slot_idx, xinput_correlated)) { - // we match exactly one WindowsGamingInput device - /* Probably can do without wgi_correlation_count, just check and clear wgi_slot to NULL, unless we need - even more frames to be sure. */ - if (ctx->wgi_correlation_count && ctx->wgi_slot == slot_idx) { - // was correlated previously, and still the same device - if (ctx->wgi_correlation_id + 1 == correlation_id) { - // no one else was correlated in the meantime - new_correlation_count = ctx->wgi_correlation_count + 1; - if (new_correlation_count == 2) { - // correlation stayed steady and uncontested across multiple frames, guaranteed match - ctx->wgi_correlated = true; -#ifdef DEBUG_RAWINPUT - SDL_Log("Correlated joystick %d to WindowsGamingInput device #%d", joystick->instance_id, slot_idx); -#endif - correlated = true; - RAWINPUT_MarkWindowsGamingInputSlotUsed(ctx->wgi_slot, ctx); - // If the generalized Guide button was using us, it doesn't need to anymore - if (guide_button_candidate.joystick == joystick) { - guide_button_candidate.joystick = NULL; - } - if (guide_button_candidate.last_joystick == joystick) { - guide_button_candidate.last_joystick = NULL; - } - } - } else { - // someone else also possibly correlated to this device, start over - new_correlation_count = 1; - } - } else { - // new possible correlation - new_correlation_count = 1; - ctx->wgi_slot = slot_idx; - } - ctx->wgi_correlation_id = correlation_id; - } else { - // Match multiple WindowsGamingInput devices, or none (possibly due to no buttons pressed) - } - } - ctx->wgi_correlation_count = new_correlation_count; - } else { - correlated = true; - } -#endif // SDL_JOYSTICK_RAWINPUT_WGI - -#ifdef SDL_JOYSTICK_RAWINPUT_XINPUT - // Parallel logic to WINDOWS_GAMING_INPUT above - if (ctx->xinput_enabled) { - RAWINPUT_UpdateXInput(); - if (ctx->xinput_correlated && - !joystick->low_frequency_rumble && !joystick->high_frequency_rumble) { - // We have been previously correlated, ensure we are still matching - /* This is required to deal with two (mostly) un-preventable mis-correlation situations: - A) Since the HID data stream does not provide an initial state (but polling XInput does), if we open - 5 controllers (#1-4 XInput mapped, #5 is not), and controller 1 had the A button down (and we don't - know), and the user presses A on controller #5, we'll see exactly 1 controller with A down (#5) and - exactly 1 XInput device with A down (#1), and incorrectly correlate. This code will then un-correlate - when A is released from either controller #1 or #5. - B) Since the app may not open all controllers, we could have a similar situation where only controller #5 - is opened, and the user holds A on controllers #1 and #5 simultaneously - again we see only 1 controller - with A down and 1 XInput device with A down, and incorrectly correlate. This should be very unusual - (only when apps do not open all controllers, yet are listening to Guide button presses, yet - for some reason want to ignore guide button presses on the un-opened controllers, yet users are - pressing buttons on the unopened controllers), and will resolve itself when either button is released - and we un-correlate. We could prevent this by processing the state packets for *all* controllers, - even un-opened ones, as that would allow more precise correlation. - */ - if (RAWINPUT_XInputSlotMatches(&match_state_xinput, ctx->xinput_slot)) { - ctx->xinput_uncorrelate_count = 0; - } else { - ++ctx->xinput_uncorrelate_count; - /* Only un-correlate if this is consistent over multiple Update() calls - the timing of polling/event - pumping can easily cause this to uncorrelate for a frame. 2 seemed reliable in my testing, but - let's set it to 5 to be safe. An incorrect un-correlation will simply result in lower precision - triggers for a frame. */ - if (ctx->xinput_uncorrelate_count >= 5) { -#ifdef DEBUG_RAWINPUT - SDL_Log("UN-Correlated joystick %d to XInput device #%d", joystick->instance_id, ctx->xinput_slot); -#endif - RAWINPUT_MarkXInputSlotFree(ctx->xinput_slot); - ctx->xinput_correlated = false; - ctx->xinput_correlation_count = 0; - // Force release of Guide button, it can't possibly be down on this device now. - /* It gets left down if we were actually correlated incorrectly and it was released on the XInput - device but we didn't get a state packet. */ - if (ctx->guide_hack) { - SDL_SendJoystickButton(0, joystick, (Uint8)guide_button, false); - } - } - } - } - if (!ctx->xinput_correlated) { - Uint8 new_correlation_count = 0; - if (RAWINPUT_MissingXInputSlot()) { - Uint8 correlation_id = 0; - Uint8 slot_idx = 0; - if (RAWINPUT_GuessXInputSlot(&match_state_xinput, &correlation_id, &slot_idx)) { - // we match exactly one XInput device - /* Probably can do without xinput_correlation_count, just check and clear xinput_slot to ANY, unless - we need even more frames to be sure */ - if (ctx->xinput_correlation_count && ctx->xinput_slot == slot_idx) { - // was correlated previously, and still the same device - if (ctx->xinput_correlation_id + 1 == correlation_id) { - // no one else was correlated in the meantime - new_correlation_count = ctx->xinput_correlation_count + 1; - if (new_correlation_count == 2) { - // correlation stayed steady and uncontested across multiple frames, guaranteed match - ctx->xinput_correlated = true; -#ifdef DEBUG_RAWINPUT - SDL_Log("Correlated joystick %d to XInput device #%d", joystick->instance_id, slot_idx); -#endif - correlated = true; - RAWINPUT_MarkXInputSlotUsed(ctx->xinput_slot); - // If the generalized Guide button was using us, it doesn't need to anymore - if (guide_button_candidate.joystick == joystick) { - guide_button_candidate.joystick = NULL; - } - if (guide_button_candidate.last_joystick == joystick) { - guide_button_candidate.last_joystick = NULL; - } - } - } else { - // someone else also possibly correlated to this device, start over - new_correlation_count = 1; - } - } else { - // new possible correlation - new_correlation_count = 1; - ctx->xinput_slot = slot_idx; - } - ctx->xinput_correlation_id = correlation_id; - } else { - // Match multiple XInput devices, or none (possibly due to no buttons pressed) - } - } - ctx->xinput_correlation_count = new_correlation_count; - } else { - correlated = true; - } - } -#endif // SDL_JOYSTICK_RAWINPUT_XINPUT - - // Poll for trigger data once (not per-state-packet) -#ifdef SDL_JOYSTICK_RAWINPUT_XINPUT - // Prefer XInput over WindowsGamingInput, it continues to provide data in the background - if (!has_trigger_data && ctx->xinput_enabled && ctx->xinput_correlated) { - RAWINPUT_UpdateXInput(); - if (xinput_state[ctx->xinput_slot].connected) { - XINPUT_BATTERY_INFORMATION_EX *battery_info = &xinput_state[ctx->xinput_slot].battery; - Uint64 timestamp; - - if (ctx->guide_hack || ctx->trigger_hack) { - timestamp = SDL_GetTicksNS(); - } else { - // timestamp won't be used - timestamp = 0; - } - - if (ctx->guide_hack) { - bool down = ((xinput_state[ctx->xinput_slot].state.Gamepad.wButtons & XINPUT_GAMEPAD_GUIDE) != 0); - SDL_SendJoystickButton(timestamp, joystick, (Uint8)guide_button, down); - } - if (ctx->trigger_hack) { - SDL_SendJoystickAxis(timestamp, joystick, (Uint8)left_trigger, ((int)xinput_state[ctx->xinput_slot].state.Gamepad.bLeftTrigger * 257) - 32768); - SDL_SendJoystickAxis(timestamp, joystick, (Uint8)right_trigger, ((int)xinput_state[ctx->xinput_slot].state.Gamepad.bRightTrigger * 257) - 32768); - } - has_trigger_data = true; - - SDL_PowerState state; - int percent; - switch (battery_info->BatteryType) { - case BATTERY_TYPE_WIRED: - state = SDL_POWERSTATE_CHARGING; - break; - case BATTERY_TYPE_UNKNOWN: - case BATTERY_TYPE_DISCONNECTED: - state = SDL_POWERSTATE_UNKNOWN; - break; - default: - state = SDL_POWERSTATE_ON_BATTERY; - break; - } - switch (battery_info->BatteryLevel) { - case BATTERY_LEVEL_EMPTY: - percent = 10; - break; - case BATTERY_LEVEL_LOW: - percent = 40; - break; - case BATTERY_LEVEL_MEDIUM: - percent = 70; - break; - default: - case BATTERY_LEVEL_FULL: - percent = 100; - break; - } - SDL_SendJoystickPowerInfo(joystick, state, percent); - } - } -#endif // SDL_JOYSTICK_RAWINPUT_XINPUT - -#ifdef SDL_JOYSTICK_RAWINPUT_WGI - if (!has_trigger_data && ctx->wgi_correlated) { - RAWINPUT_UpdateWindowsGamingInput(); // May detect disconnect / cause uncorrelation - if (ctx->wgi_correlated) { // Still connected - struct __x_ABI_CWindows_CGaming_CInput_CGamepadReading *state = &ctx->wgi_slot->state; - Uint64 timestamp; - - if (ctx->guide_hack || ctx->trigger_hack) { - timestamp = SDL_GetTicksNS(); - } else { - // timestamp won't be used - timestamp = 0; - } - - if (ctx->guide_hack) { - bool down = ((state->Buttons & GamepadButtons_GUIDE) != 0); - SDL_SendJoystickButton(timestamp, joystick, (Uint8)guide_button, down); - } - if (ctx->trigger_hack) { - SDL_SendJoystickAxis(timestamp, joystick, (Uint8)left_trigger, (Sint16)(((int)(state->LeftTrigger * SDL_MAX_UINT16)) - 32768)); - SDL_SendJoystickAxis(timestamp, joystick, (Uint8)right_trigger, (Sint16)(((int)(state->RightTrigger * SDL_MAX_UINT16)) - 32768)); - } - has_trigger_data = true; - } - } -#endif // SDL_JOYSTICK_RAWINPUT_WGI - - if (!correlated) { - if (!guide_button_candidate.joystick || - (ctx->last_state_packet && (!guide_button_candidate.last_state_packet || - ctx->last_state_packet >= guide_button_candidate.last_state_packet))) { - guide_button_candidate.joystick = joystick; - guide_button_candidate.last_state_packet = ctx->last_state_packet; - } - } -#endif // SDL_JOYSTICK_RAWINPUT_MATCHING -} - -static void RAWINPUT_JoystickUpdate(SDL_Joystick *joystick) -{ - RAWINPUT_UpdateOtherAPIs(joystick); -} - -static void RAWINPUT_JoystickClose(SDL_Joystick *joystick) -{ - RAWINPUT_DeviceContext *ctx = joystick->hwdata; - -#ifdef SDL_JOYSTICK_RAWINPUT_MATCHING - if (guide_button_candidate.joystick == joystick) { - guide_button_candidate.joystick = NULL; - } - if (guide_button_candidate.last_joystick == joystick) { - guide_button_candidate.last_joystick = NULL; - } -#endif - - if (ctx) { - SDL_RAWINPUT_Device *device; - -#ifdef SDL_JOYSTICK_RAWINPUT_XINPUT - xinput_device_change = true; - if (ctx->xinput_enabled) { - if (ctx->xinput_correlated) { - RAWINPUT_MarkXInputSlotFree(ctx->xinput_slot); - } - WIN_UnloadXInputDLL(); - } -#endif -#ifdef SDL_JOYSTICK_RAWINPUT_WGI - RAWINPUT_QuitWindowsGamingInput(ctx); -#endif - - device = ctx->device; - if (device) { - SDL_assert(device->joystick == joystick); - device->joystick = NULL; - RAWINPUT_ReleaseDevice(device); - } - - SDL_free(ctx->data); - SDL_free(ctx->button_indices); - SDL_free(ctx->axis_indices); - SDL_free(ctx->hat_indices); - SDL_free(ctx); - joystick->hwdata = NULL; - } -} - -bool RAWINPUT_RegisterNotifications(HWND hWnd) -{ - int i; - RAWINPUTDEVICE rid[SDL_arraysize(subscribed_devices)]; - - if (!SDL_RAWINPUT_inited) { - return true; - } - - for (i = 0; i < SDL_arraysize(subscribed_devices); i++) { - rid[i].usUsagePage = USB_USAGEPAGE_GENERIC_DESKTOP; - rid[i].usUsage = subscribed_devices[i]; - rid[i].dwFlags = RIDEV_DEVNOTIFY | RIDEV_INPUTSINK; // Receive messages when in background, including device add/remove - rid[i].hwndTarget = hWnd; - } - - if (!RegisterRawInputDevices(rid, SDL_arraysize(rid), sizeof(RAWINPUTDEVICE))) { - return SDL_SetError("Couldn't register for raw input events"); - } - return true; -} - -bool RAWINPUT_UnregisterNotifications(void) -{ - int i; - RAWINPUTDEVICE rid[SDL_arraysize(subscribed_devices)]; - - if (!SDL_RAWINPUT_inited) { - return true; - } - - for (i = 0; i < SDL_arraysize(subscribed_devices); i++) { - rid[i].usUsagePage = USB_USAGEPAGE_GENERIC_DESKTOP; - rid[i].usUsage = subscribed_devices[i]; - rid[i].dwFlags = RIDEV_REMOVE; - rid[i].hwndTarget = NULL; - } - - if (!RegisterRawInputDevices(rid, SDL_arraysize(rid), sizeof(RAWINPUTDEVICE))) { - return SDL_SetError("Couldn't unregister for raw input events"); - } - return true; -} - -LRESULT CALLBACK -RAWINPUT_WindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) -{ - LRESULT result = -1; - - if (SDL_RAWINPUT_inited) { - SDL_LockJoysticks(); - - switch (msg) { - case WM_INPUT_DEVICE_CHANGE: - { - HANDLE hDevice = (HANDLE)lParam; - switch (wParam) { - case GIDC_ARRIVAL: - RAWINPUT_AddDevice(hDevice); - break; - case GIDC_REMOVAL: - { - SDL_RAWINPUT_Device *device; - device = RAWINPUT_DeviceFromHandle(hDevice); - if (device) { - RAWINPUT_DelDevice(device, true); - } - break; - } - default: - break; - } - } - result = 0; - break; - - case WM_INPUT: - { - Uint8 data[sizeof(RAWINPUTHEADER) + sizeof(RAWHID) + USB_PACKET_LENGTH]; - UINT buffer_size = SDL_arraysize(data); - - if ((int)GetRawInputData((HRAWINPUT)lParam, RID_INPUT, data, &buffer_size, sizeof(RAWINPUTHEADER)) > 0) { - PRAWINPUT raw_input = (PRAWINPUT)data; - SDL_RAWINPUT_Device *device = RAWINPUT_DeviceFromHandle(raw_input->header.hDevice); - if (device) { - SDL_Joystick *joystick = device->joystick; - if (joystick) { - RAWINPUT_HandleStatePacket(joystick, raw_input->data.hid.bRawData, raw_input->data.hid.dwSizeHid); - } - } - } - } - result = 0; - break; - } - - SDL_UnlockJoysticks(); - } - - if (result >= 0) { - return result; - } - return CallWindowProc(DefWindowProc, hWnd, msg, wParam, lParam); -} - -static void RAWINPUT_JoystickQuit(void) -{ - if (!SDL_RAWINPUT_inited) { - return; - } - - RAWINPUT_RemoveDevices(); - - WIN_UnloadHIDDLL(); - - SDL_RAWINPUT_inited = false; -} - -static bool RAWINPUT_JoystickGetGamepadMapping(int device_index, SDL_GamepadMapping *out) -{ - return false; -} - -SDL_JoystickDriver SDL_RAWINPUT_JoystickDriver = { - RAWINPUT_JoystickInit, - RAWINPUT_JoystickGetCount, - RAWINPUT_JoystickDetect, - RAWINPUT_JoystickIsDevicePresent, - RAWINPUT_JoystickGetDeviceName, - RAWINPUT_JoystickGetDevicePath, - RAWINPUT_JoystickGetDeviceSteamVirtualGamepadSlot, - RAWINPUT_JoystickGetDevicePlayerIndex, - RAWINPUT_JoystickSetDevicePlayerIndex, - RAWINPUT_JoystickGetDeviceGUID, - RAWINPUT_JoystickGetDeviceInstanceID, - RAWINPUT_JoystickOpen, - RAWINPUT_JoystickRumble, - RAWINPUT_JoystickRumbleTriggers, - RAWINPUT_JoystickSetLED, - RAWINPUT_JoystickSendEffect, - RAWINPUT_JoystickSetSensorsEnabled, - RAWINPUT_JoystickUpdate, - RAWINPUT_JoystickClose, - RAWINPUT_JoystickQuit, - RAWINPUT_JoystickGetGamepadMapping -}; - -#endif // SDL_JOYSTICK_RAWINPUT diff --git a/contrib/SDL-3.2.8/src/joystick/windows/SDL_rawinputjoystick_c.h b/contrib/SDL-3.2.8/src/joystick/windows/SDL_rawinputjoystick_c.h deleted file mode 100644 index b67544b..0000000 --- a/contrib/SDL-3.2.8/src/joystick/windows/SDL_rawinputjoystick_c.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. -*/ -#include "SDL_internal.h" -#include "../../core/windows/SDL_windows.h" - -// Return true if the RawInput driver is enabled -extern bool RAWINPUT_IsEnabled(void); - -// Registers for input events -extern int RAWINPUT_RegisterNotifications(HWND hWnd); -extern int RAWINPUT_UnregisterNotifications(void); - -// Returns 0 if message was handled -extern LRESULT CALLBACK RAWINPUT_WindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); diff --git a/contrib/SDL-3.2.8/src/joystick/windows/SDL_windows_gaming_input.c b/contrib/SDL-3.2.8/src/joystick/windows/SDL_windows_gaming_input.c deleted file mode 100644 index dbc5658..0000000 --- a/contrib/SDL-3.2.8/src/joystick/windows/SDL_windows_gaming_input.c +++ /dev/null @@ -1,1039 +0,0 @@ -/* - Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. -*/ -#include "SDL_internal.h" - -#ifdef SDL_JOYSTICK_WGI - -#include "../SDL_sysjoystick.h" -#include "../hidapi/SDL_hidapijoystick_c.h" -#include "SDL_rawinputjoystick_c.h" - -#include "../../core/windows/SDL_windows.h" -#define COBJMACROS -#include "windows.gaming.input.h" -#include -#include -#include -#include - -#ifdef ____FIReference_1_INT32_INTERFACE_DEFINED__ -// MinGW-64 uses __FIReference_1_INT32 instead of Microsoft's __FIReference_1_int -#define __FIReference_1_int __FIReference_1_INT32 -#define __FIReference_1_int_get_Value __FIReference_1_INT32_get_Value -#define __FIReference_1_int_Release __FIReference_1_INT32_Release -#endif - -struct joystick_hwdata -{ - __x_ABI_CWindows_CGaming_CInput_CIRawGameController *controller; - __x_ABI_CWindows_CGaming_CInput_CIGameController *game_controller; - __x_ABI_CWindows_CGaming_CInput_CIGameControllerBatteryInfo *battery; - __x_ABI_CWindows_CGaming_CInput_CIGamepad *gamepad; - __x_ABI_CWindows_CGaming_CInput_CGamepadVibration vibration; - UINT64 timestamp; -}; - -typedef struct WindowsGamingInputControllerState -{ - SDL_JoystickID instance_id; - __x_ABI_CWindows_CGaming_CInput_CIRawGameController *controller; - char *name; - SDL_GUID guid; - SDL_JoystickType type; - int steam_virtual_gamepad_slot; -} WindowsGamingInputControllerState; - -typedef HRESULT(WINAPI *CoIncrementMTAUsage_t)(CO_MTA_USAGE_COOKIE *pCookie); -typedef HRESULT(WINAPI *RoGetActivationFactory_t)(HSTRING activatableClassId, REFIID iid, void **factory); -typedef HRESULT(WINAPI *WindowsCreateStringReference_t)(PCWSTR sourceString, UINT32 length, HSTRING_HEADER *hstringHeader, HSTRING *string); -typedef HRESULT(WINAPI *WindowsDeleteString_t)(HSTRING string); -typedef PCWSTR(WINAPI *WindowsGetStringRawBuffer_t)(HSTRING string, UINT32 *length); - -static struct -{ - CoIncrementMTAUsage_t CoIncrementMTAUsage; - RoGetActivationFactory_t RoGetActivationFactory; - WindowsCreateStringReference_t WindowsCreateStringReference; - WindowsDeleteString_t WindowsDeleteString; - WindowsGetStringRawBuffer_t WindowsGetStringRawBuffer; - __x_ABI_CWindows_CGaming_CInput_CIRawGameControllerStatics *controller_statics; - __x_ABI_CWindows_CGaming_CInput_CIArcadeStickStatics *arcade_stick_statics; - __x_ABI_CWindows_CGaming_CInput_CIArcadeStickStatics2 *arcade_stick_statics2; - __x_ABI_CWindows_CGaming_CInput_CIFlightStickStatics *flight_stick_statics; - __x_ABI_CWindows_CGaming_CInput_CIGamepadStatics *gamepad_statics; - __x_ABI_CWindows_CGaming_CInput_CIGamepadStatics2 *gamepad_statics2; - __x_ABI_CWindows_CGaming_CInput_CIRacingWheelStatics *racing_wheel_statics; - __x_ABI_CWindows_CGaming_CInput_CIRacingWheelStatics2 *racing_wheel_statics2; - EventRegistrationToken controller_added_token; - EventRegistrationToken controller_removed_token; - int controller_count; - WindowsGamingInputControllerState *controllers; -} wgi; - -// WinRT headers in official Windows SDK contain only declarations, and we have to define these GUIDs ourselves. -// https://stackoverflow.com/a/55605485/1795050 -DEFINE_GUID(IID___FIEventHandler_1_Windows__CGaming__CInput__CRawGameController, 0x00621c22, 0x42e8, 0x529f, 0x92, 0x70, 0x83, 0x6b, 0x32, 0x93, 0x1d, 0x72); -DEFINE_GUID(IID___x_ABI_CWindows_CGaming_CInput_CIArcadeStickStatics, 0x5c37b8c8, 0x37b1, 0x4ad8, 0x94, 0x58, 0x20, 0x0f, 0x1a, 0x30, 0x01, 0x8e); -DEFINE_GUID(IID___x_ABI_CWindows_CGaming_CInput_CIArcadeStickStatics2, 0x52b5d744, 0xbb86, 0x445a, 0xb5, 0x9c, 0x59, 0x6f, 0x0e, 0x2a, 0x49, 0xdf); -DEFINE_GUID(IID___x_ABI_CWindows_CGaming_CInput_CIFlightStickStatics, 0x5514924a, 0xfecc, 0x435e, 0x83, 0xdc, 0x5c, 0xec, 0x8a, 0x18, 0xa5, 0x20); -DEFINE_GUID(IID___x_ABI_CWindows_CGaming_CInput_CIGameController, 0x1baf6522, 0x5f64, 0x42c5, 0x82, 0x67, 0xb9, 0xfe, 0x22, 0x15, 0xbf, 0xbd); -DEFINE_GUID(IID___x_ABI_CWindows_CGaming_CInput_CIGameControllerBatteryInfo, 0xdcecc681, 0x3963, 0x4da6, 0x95, 0x5d, 0x55, 0x3f, 0x3b, 0x6f, 0x61, 0x61); -DEFINE_GUID(IID___x_ABI_CWindows_CGaming_CInput_CIGamepadStatics, 0x8bbce529, 0xd49c, 0x39e9, 0x95, 0x60, 0xe4, 0x7d, 0xde, 0x96, 0xb7, 0xc8); -DEFINE_GUID(IID___x_ABI_CWindows_CGaming_CInput_CIGamepadStatics2, 0x42676dc5, 0x0856, 0x47c4, 0x92, 0x13, 0xb3, 0x95, 0x50, 0x4c, 0x3a, 0x3c); -DEFINE_GUID(IID___x_ABI_CWindows_CGaming_CInput_CIRacingWheelStatics, 0x3ac12cd5, 0x581b, 0x4936, 0x9f, 0x94, 0x69, 0xf1, 0xe6, 0x51, 0x4c, 0x7d); -DEFINE_GUID(IID___x_ABI_CWindows_CGaming_CInput_CIRacingWheelStatics2, 0xe666bcaa, 0xedfd, 0x4323, 0xa9, 0xf6, 0x3c, 0x38, 0x40, 0x48, 0xd1, 0xed); -DEFINE_GUID(IID___x_ABI_CWindows_CGaming_CInput_CIRawGameController, 0x7cad6d91, 0xa7e1, 0x4f71, 0x9a, 0x78, 0x33, 0xe9, 0xc5, 0xdf, 0xea, 0x62); -DEFINE_GUID(IID___x_ABI_CWindows_CGaming_CInput_CIRawGameController2, 0x43c0c035, 0xbb73, 0x4756, 0xa7, 0x87, 0x3e, 0xd6, 0xbe, 0xa6, 0x17, 0xbd); -DEFINE_GUID(IID___x_ABI_CWindows_CGaming_CInput_CIRawGameControllerStatics, 0xeb8d0792, 0xe95a, 0x4b19, 0xaf, 0xc7, 0x0a, 0x59, 0xf8, 0xbf, 0x75, 0x9e); - -extern bool SDL_XINPUT_Enabled(void); - - -static bool SDL_IsXInputDevice(Uint16 vendor, Uint16 product, const char *name) -{ -#if defined(SDL_JOYSTICK_XINPUT) || defined(SDL_JOYSTICK_RAWINPUT) - PRAWINPUTDEVICELIST raw_devices = NULL; - UINT i, raw_device_count = 0; - LONG vidpid = MAKELONG(vendor, product); - - // XInput and RawInput backends will pick up XInput-compatible devices - if (!SDL_XINPUT_Enabled() -#ifdef SDL_JOYSTICK_RAWINPUT - && !RAWINPUT_IsEnabled() -#endif - ) { - return false; - } - - // Sometimes we'll get a Windows.Gaming.Input callback before the raw input device is even in the list, - // so try to do some checks up front to catch these cases. - if (SDL_IsJoystickXboxOne(vendor, product) || - (name && SDL_strncmp(name, "Xbox ", 5) == 0)) { - return true; - } - - // Go through RAWINPUT (WinXP and later) to find HID devices. - if ((GetRawInputDeviceList(NULL, &raw_device_count, sizeof(RAWINPUTDEVICELIST)) == -1) || (!raw_device_count)) { - return false; // oh well. - } - - raw_devices = (PRAWINPUTDEVICELIST)SDL_malloc(sizeof(RAWINPUTDEVICELIST) * raw_device_count); - if (!raw_devices) { - return false; - } - - raw_device_count = GetRawInputDeviceList(raw_devices, &raw_device_count, sizeof(RAWINPUTDEVICELIST)); - if (raw_device_count == (UINT)-1) { - SDL_free(raw_devices); - raw_devices = NULL; - return false; // oh well. - } - - for (i = 0; i < raw_device_count; i++) { - RID_DEVICE_INFO rdi; - char devName[MAX_PATH] = { 0 }; - UINT rdiSize = sizeof(rdi); - UINT nameSize = SDL_arraysize(devName); - DEVINST devNode; - char devVidPidString[32]; - int j; - - rdi.cbSize = sizeof(rdi); - - if ((raw_devices[i].dwType != RIM_TYPEHID) || - (GetRawInputDeviceInfoA(raw_devices[i].hDevice, RIDI_DEVICEINFO, &rdi, &rdiSize) == ((UINT)-1)) || - (GetRawInputDeviceInfoA(raw_devices[i].hDevice, RIDI_DEVICENAME, devName, &nameSize) == ((UINT)-1)) || - (SDL_strstr(devName, "IG_") == NULL)) { - // Skip non-XInput devices - continue; - } - - // First check for a simple VID/PID match. This will work for Xbox 360 controllers. - if (MAKELONG(rdi.hid.dwVendorId, rdi.hid.dwProductId) == vidpid) { - SDL_free(raw_devices); - return true; - } - - /* For Xbox One controllers, Microsoft doesn't propagate the VID/PID down to the HID stack. - * We'll have to walk the device tree upwards searching for a match for our VID/PID. */ - - // Make sure the device interface string is something we know how to parse - // Example: \\?\HID#VID_045E&PID_02FF&IG_00#9&2c203035&2&0000#{4d1e55b2-f16f-11cf-88cb-001111000030} - if ((SDL_strstr(devName, "\\\\?\\") != devName) || (SDL_strstr(devName, "#{") == NULL)) { - continue; - } - - // Unescape the backslashes in the string and terminate before the GUID portion - for (j = 0; devName[j] != '\0'; j++) { - if (devName[j] == '#') { - if (devName[j + 1] == '{') { - devName[j] = '\0'; - break; - } else { - devName[j] = '\\'; - } - } - } - - /* We'll be left with a string like this: \\?\HID\VID_045E&PID_02FF&IG_00\9&2c203035&2&0000 - * Simply skip the \\?\ prefix and we'll have a properly formed device instance ID */ - if (CM_Locate_DevNodeA(&devNode, &devName[4], CM_LOCATE_DEVNODE_NORMAL) != CR_SUCCESS) { - continue; - } - - (void)SDL_snprintf(devVidPidString, sizeof(devVidPidString), "VID_%04X&PID_%04X", vendor, product); - - while (CM_Get_Parent(&devNode, devNode, 0) == CR_SUCCESS) { - char deviceId[MAX_DEVICE_ID_LEN]; - - if ((CM_Get_Device_IDA(devNode, deviceId, SDL_arraysize(deviceId), 0) == CR_SUCCESS) && - (SDL_strstr(deviceId, devVidPidString) != NULL)) { - // The VID/PID matched a parent device - SDL_free(raw_devices); - return true; - } - } - } - - SDL_free(raw_devices); -#endif // SDL_JOYSTICK_XINPUT || SDL_JOYSTICK_RAWINPUT - - return false; -} - -static void WGI_LoadRawGameControllerStatics(void) -{ - HRESULT hr; - HSTRING_HEADER class_name_header; - HSTRING class_name; - - hr = wgi.WindowsCreateStringReference(RuntimeClass_Windows_Gaming_Input_RawGameController, (UINT32)SDL_wcslen(RuntimeClass_Windows_Gaming_Input_RawGameController), &class_name_header, &class_name); - if (SUCCEEDED(hr)) { - hr = wgi.RoGetActivationFactory(class_name, &IID___x_ABI_CWindows_CGaming_CInput_CIRawGameControllerStatics, (void **)&wgi.controller_statics); - if (!SUCCEEDED(hr)) { - WIN_SetErrorFromHRESULT("Couldn't find Windows.Gaming.Input.IRawGameControllerStatics", hr); - } - } -} - -static void WGI_LoadOtherControllerStatics(void) -{ - HRESULT hr; - HSTRING_HEADER class_name_header; - HSTRING class_name; - - if (!wgi.arcade_stick_statics) { - hr = wgi.WindowsCreateStringReference(RuntimeClass_Windows_Gaming_Input_ArcadeStick, (UINT32)SDL_wcslen(RuntimeClass_Windows_Gaming_Input_ArcadeStick), &class_name_header, &class_name); - if (SUCCEEDED(hr)) { - hr = wgi.RoGetActivationFactory(class_name, &IID___x_ABI_CWindows_CGaming_CInput_CIArcadeStickStatics, (void **)&wgi.arcade_stick_statics); - if (SUCCEEDED(hr)) { - __x_ABI_CWindows_CGaming_CInput_CIArcadeStickStatics_QueryInterface(wgi.arcade_stick_statics, &IID___x_ABI_CWindows_CGaming_CInput_CIArcadeStickStatics2, (void **)&wgi.arcade_stick_statics2); - } else { - WIN_SetErrorFromHRESULT("Couldn't find Windows.Gaming.Input.IArcadeStickStatics", hr); - } - } - } - - if (!wgi.flight_stick_statics) { - hr = wgi.WindowsCreateStringReference(RuntimeClass_Windows_Gaming_Input_FlightStick, (UINT32)SDL_wcslen(RuntimeClass_Windows_Gaming_Input_FlightStick), &class_name_header, &class_name); - if (SUCCEEDED(hr)) { - hr = wgi.RoGetActivationFactory(class_name, &IID___x_ABI_CWindows_CGaming_CInput_CIFlightStickStatics, (void **)&wgi.flight_stick_statics); - if (!SUCCEEDED(hr)) { - WIN_SetErrorFromHRESULT("Couldn't find Windows.Gaming.Input.IFlightStickStatics", hr); - } - } - } - - if (!wgi.gamepad_statics) { - hr = wgi.WindowsCreateStringReference(RuntimeClass_Windows_Gaming_Input_Gamepad, (UINT32)SDL_wcslen(RuntimeClass_Windows_Gaming_Input_Gamepad), &class_name_header, &class_name); - if (SUCCEEDED(hr)) { - hr = wgi.RoGetActivationFactory(class_name, &IID___x_ABI_CWindows_CGaming_CInput_CIGamepadStatics, (void **)&wgi.gamepad_statics); - if (SUCCEEDED(hr)) { - __x_ABI_CWindows_CGaming_CInput_CIGamepadStatics_QueryInterface(wgi.gamepad_statics, &IID___x_ABI_CWindows_CGaming_CInput_CIGamepadStatics2, (void **)&wgi.gamepad_statics2); - } else { - WIN_SetErrorFromHRESULT("Couldn't find Windows.Gaming.Input.IGamepadStatics", hr); - } - } - } - - if (!wgi.racing_wheel_statics) { - hr = wgi.WindowsCreateStringReference(RuntimeClass_Windows_Gaming_Input_RacingWheel, (UINT32)SDL_wcslen(RuntimeClass_Windows_Gaming_Input_RacingWheel), &class_name_header, &class_name); - if (SUCCEEDED(hr)) { - hr = wgi.RoGetActivationFactory(class_name, &IID___x_ABI_CWindows_CGaming_CInput_CIRacingWheelStatics, (void **)&wgi.racing_wheel_statics); - if (SUCCEEDED(hr)) { - __x_ABI_CWindows_CGaming_CInput_CIRacingWheelStatics_QueryInterface(wgi.racing_wheel_statics, &IID___x_ABI_CWindows_CGaming_CInput_CIRacingWheelStatics2, (void **)&wgi.racing_wheel_statics2); - } else { - WIN_SetErrorFromHRESULT("Couldn't find Windows.Gaming.Input.IRacingWheelStatics", hr); - } - } - } -} - -static SDL_JoystickType GetGameControllerType(__x_ABI_CWindows_CGaming_CInput_CIGameController *game_controller) -{ - __x_ABI_CWindows_CGaming_CInput_CIArcadeStick *arcade_stick = NULL; - __x_ABI_CWindows_CGaming_CInput_CIFlightStick *flight_stick = NULL; - __x_ABI_CWindows_CGaming_CInput_CIGamepad *gamepad = NULL; - __x_ABI_CWindows_CGaming_CInput_CIRacingWheel *racing_wheel = NULL; - - /* Wait to initialize these interfaces until we need them. - * Initializing the gamepad interface will switch Bluetooth PS4 controllers into enhanced mode, breaking DirectInput - */ - WGI_LoadOtherControllerStatics(); - - if (wgi.gamepad_statics2 && SUCCEEDED(__x_ABI_CWindows_CGaming_CInput_CIGamepadStatics2_FromGameController(wgi.gamepad_statics2, game_controller, &gamepad)) && gamepad) { - __x_ABI_CWindows_CGaming_CInput_CIGamepad_Release(gamepad); - return SDL_JOYSTICK_TYPE_GAMEPAD; - } - - if (wgi.arcade_stick_statics2 && SUCCEEDED(__x_ABI_CWindows_CGaming_CInput_CIArcadeStickStatics2_FromGameController(wgi.arcade_stick_statics2, game_controller, &arcade_stick)) && arcade_stick) { - __x_ABI_CWindows_CGaming_CInput_CIArcadeStick_Release(arcade_stick); - return SDL_JOYSTICK_TYPE_ARCADE_STICK; - } - - if (wgi.flight_stick_statics && SUCCEEDED(__x_ABI_CWindows_CGaming_CInput_CIFlightStickStatics_FromGameController(wgi.flight_stick_statics, game_controller, &flight_stick)) && flight_stick) { - __x_ABI_CWindows_CGaming_CInput_CIFlightStick_Release(flight_stick); - return SDL_JOYSTICK_TYPE_FLIGHT_STICK; - } - - if (wgi.racing_wheel_statics2 && SUCCEEDED(__x_ABI_CWindows_CGaming_CInput_CIRacingWheelStatics2_FromGameController(wgi.racing_wheel_statics2, game_controller, &racing_wheel)) && racing_wheel) { - __x_ABI_CWindows_CGaming_CInput_CIRacingWheel_Release(racing_wheel); - return SDL_JOYSTICK_TYPE_WHEEL; - } - - return SDL_JOYSTICK_TYPE_UNKNOWN; -} - -typedef struct RawGameControllerDelegate -{ - __FIEventHandler_1_Windows__CGaming__CInput__CRawGameController iface; - SDL_AtomicInt refcount; -} RawGameControllerDelegate; - -static HRESULT STDMETHODCALLTYPE IEventHandler_CRawGameControllerVtbl_QueryInterface(__FIEventHandler_1_Windows__CGaming__CInput__CRawGameController *This, REFIID riid, void **ppvObject) -{ - if (!ppvObject) { - return E_INVALIDARG; - } - - *ppvObject = NULL; - if (WIN_IsEqualIID(riid, &IID_IUnknown) || WIN_IsEqualIID(riid, &IID_IAgileObject) || WIN_IsEqualIID(riid, &IID___FIEventHandler_1_Windows__CGaming__CInput__CRawGameController)) { - *ppvObject = This; - __FIEventHandler_1_Windows__CGaming__CInput__CRawGameController_AddRef(This); - return S_OK; - } else if (WIN_IsEqualIID(riid, &IID_IMarshal)) { - // This seems complicated. Let's hope it doesn't happen. - return E_OUTOFMEMORY; - } else { - return E_NOINTERFACE; - } -} - -static ULONG STDMETHODCALLTYPE IEventHandler_CRawGameControllerVtbl_AddRef(__FIEventHandler_1_Windows__CGaming__CInput__CRawGameController *This) -{ - RawGameControllerDelegate *self = (RawGameControllerDelegate *)This; - return SDL_AddAtomicInt(&self->refcount, 1) + 1UL; -} - -static ULONG STDMETHODCALLTYPE IEventHandler_CRawGameControllerVtbl_Release(__FIEventHandler_1_Windows__CGaming__CInput__CRawGameController *This) -{ - RawGameControllerDelegate *self = (RawGameControllerDelegate *)This; - int rc = SDL_AddAtomicInt(&self->refcount, -1) - 1; - // Should never free the static delegate objects - SDL_assert(rc > 0); - return rc; -} - -static int GetSteamVirtualGamepadSlot(__x_ABI_CWindows_CGaming_CInput_CIRawGameController *controller, Uint16 vendor_id, Uint16 product_id) -{ - int slot = -1; - - if (vendor_id == USB_VENDOR_VALVE && - product_id == USB_PRODUCT_STEAM_VIRTUAL_GAMEPAD) { - __x_ABI_CWindows_CGaming_CInput_CIRawGameController2 *controller2 = NULL; - HRESULT hr = __x_ABI_CWindows_CGaming_CInput_CIRawGameController_QueryInterface(controller, &IID___x_ABI_CWindows_CGaming_CInput_CIRawGameController2, (void **)&controller2); - if (SUCCEEDED(hr)) { - HSTRING hString; - hr = __x_ABI_CWindows_CGaming_CInput_CIRawGameController2_get_NonRoamableId(controller2, &hString); - if (SUCCEEDED(hr)) { - PCWSTR string = wgi.WindowsGetStringRawBuffer(hString, NULL); - if (string) { - char *id = WIN_StringToUTF8W(string); - if (id) { - (void)SDL_sscanf(id, "{wgi/nrid/:steam-%*X&%*X&%*X#%d#%*u}", &slot); - SDL_free(id); - } - } - wgi.WindowsDeleteString(hString); - } - __x_ABI_CWindows_CGaming_CInput_CIRawGameController2_Release(controller2); - } - } - return slot; -} - -static HRESULT STDMETHODCALLTYPE IEventHandler_CRawGameControllerVtbl_InvokeAdded(__FIEventHandler_1_Windows__CGaming__CInput__CRawGameController *This, IInspectable *sender, __x_ABI_CWindows_CGaming_CInput_CIRawGameController *e) -{ - HRESULT hr; - __x_ABI_CWindows_CGaming_CInput_CIRawGameController *controller = NULL; - - SDL_LockJoysticks(); - - // We can get delayed calls to InvokeAdded() after WGI_JoystickQuit() - if (SDL_JoysticksQuitting() || !SDL_JoysticksInitialized()) { - SDL_UnlockJoysticks(); - return S_OK; - } - - hr = __x_ABI_CWindows_CGaming_CInput_CIRawGameController_QueryInterface(e, &IID___x_ABI_CWindows_CGaming_CInput_CIRawGameController, (void **)&controller); - if (SUCCEEDED(hr)) { - char *name = NULL; - Uint16 bus = SDL_HARDWARE_BUS_USB; - Uint16 vendor = 0; - Uint16 product = 0; - Uint16 version = 0; - SDL_JoystickType type = SDL_JOYSTICK_TYPE_UNKNOWN; - __x_ABI_CWindows_CGaming_CInput_CIRawGameController2 *controller2 = NULL; - __x_ABI_CWindows_CGaming_CInput_CIGameController *game_controller = NULL; - bool ignore_joystick = false; - - __x_ABI_CWindows_CGaming_CInput_CIRawGameController_get_HardwareVendorId(controller, &vendor); - __x_ABI_CWindows_CGaming_CInput_CIRawGameController_get_HardwareProductId(controller, &product); - - hr = __x_ABI_CWindows_CGaming_CInput_CIRawGameController_QueryInterface(controller, &IID___x_ABI_CWindows_CGaming_CInput_CIGameController, (void **)&game_controller); - if (SUCCEEDED(hr)) { - boolean wireless = 0; - hr = __x_ABI_CWindows_CGaming_CInput_CIGameController_get_IsWireless(game_controller, &wireless); - if (SUCCEEDED(hr) && wireless) { - bus = SDL_HARDWARE_BUS_BLUETOOTH; - - // Fixup for Wireless Xbox 360 Controller - if (product == 0) { - vendor = USB_VENDOR_MICROSOFT; - product = USB_PRODUCT_XBOX360_XUSB_CONTROLLER; - } - } - - __x_ABI_CWindows_CGaming_CInput_CIGameController_Release(game_controller); - } - - hr = __x_ABI_CWindows_CGaming_CInput_CIRawGameController_QueryInterface(controller, &IID___x_ABI_CWindows_CGaming_CInput_CIRawGameController2, (void **)&controller2); - if (SUCCEEDED(hr)) { - HSTRING hString; - hr = __x_ABI_CWindows_CGaming_CInput_CIRawGameController2_get_DisplayName(controller2, &hString); - if (SUCCEEDED(hr)) { - PCWSTR string = wgi.WindowsGetStringRawBuffer(hString, NULL); - if (string) { - name = WIN_StringToUTF8W(string); - } - wgi.WindowsDeleteString(hString); - } - __x_ABI_CWindows_CGaming_CInput_CIRawGameController2_Release(controller2); - } - if (!name) { - name = SDL_strdup(""); - } - - if (!ignore_joystick && SDL_ShouldIgnoreJoystick(vendor, product, version, name)) { - ignore_joystick = true; - } - - if (!ignore_joystick && SDL_JoystickHandledByAnotherDriver(&SDL_WGI_JoystickDriver, vendor, product, version, name)) { - ignore_joystick = true; - } - - if (!ignore_joystick && SDL_IsXInputDevice(vendor, product, name)) { - // This hasn't been detected by the RAWINPUT driver yet, but it will be picked up later. - ignore_joystick = true; - } - - if (!ignore_joystick) { - // New device, add it - WindowsGamingInputControllerState *controllers = SDL_realloc(wgi.controllers, sizeof(wgi.controllers[0]) * (wgi.controller_count + 1)); - if (controllers) { - WindowsGamingInputControllerState *state = &controllers[wgi.controller_count]; - SDL_JoystickID joystickID = SDL_GetNextObjectID(); - - if (game_controller) { - type = GetGameControllerType(game_controller); - } - - SDL_zerop(state); - state->instance_id = joystickID; - state->controller = controller; - state->name = name; - state->guid = SDL_CreateJoystickGUID(bus, vendor, product, version, NULL, name, 'w', (Uint8)type); - state->type = type; - state->steam_virtual_gamepad_slot = GetSteamVirtualGamepadSlot(controller, vendor, product); - - __x_ABI_CWindows_CGaming_CInput_CIRawGameController_AddRef(controller); - - ++wgi.controller_count; - wgi.controllers = controllers; - - SDL_PrivateJoystickAdded(joystickID); - } else { - SDL_free(name); - } - } else { - SDL_free(name); - } - - __x_ABI_CWindows_CGaming_CInput_CIRawGameController_Release(controller); - } - - SDL_UnlockJoysticks(); - - return S_OK; -} - -static HRESULT STDMETHODCALLTYPE IEventHandler_CRawGameControllerVtbl_InvokeRemoved(__FIEventHandler_1_Windows__CGaming__CInput__CRawGameController *This, IInspectable *sender, __x_ABI_CWindows_CGaming_CInput_CIRawGameController *e) -{ - HRESULT hr; - __x_ABI_CWindows_CGaming_CInput_CIRawGameController *controller = NULL; - - SDL_LockJoysticks(); - - // Can we get delayed calls to InvokeRemoved() after WGI_JoystickQuit()? - if (!SDL_JoysticksInitialized()) { - SDL_UnlockJoysticks(); - return S_OK; - } - - hr = __x_ABI_CWindows_CGaming_CInput_CIRawGameController_QueryInterface(e, &IID___x_ABI_CWindows_CGaming_CInput_CIRawGameController, (void **)&controller); - if (SUCCEEDED(hr)) { - int i; - - for (i = 0; i < wgi.controller_count; i++) { - if (wgi.controllers[i].controller == controller) { - WindowsGamingInputControllerState *state = &wgi.controllers[i]; - SDL_JoystickID joystickID = state->instance_id; - - __x_ABI_CWindows_CGaming_CInput_CIRawGameController_Release(state->controller); - - SDL_free(state->name); - - --wgi.controller_count; - if (i < wgi.controller_count) { - SDL_memmove(&wgi.controllers[i], &wgi.controllers[i + 1], (wgi.controller_count - i) * sizeof(wgi.controllers[i])); - } - - SDL_PrivateJoystickRemoved(joystickID); - break; - } - } - - __x_ABI_CWindows_CGaming_CInput_CIRawGameController_Release(controller); - } - - SDL_UnlockJoysticks(); - - return S_OK; -} - -#ifdef _MSC_VER -#pragma warning(push) -#pragma warning(disable : 4028) // formal parameter 3 different from declaration, when using older buggy WGI headers -#pragma warning(disable : 4113) // formal parameter 3 different from declaration (a more specific warning added in VS 2022), when using older buggy WGI headers -#endif - -static __FIEventHandler_1_Windows__CGaming__CInput__CRawGameControllerVtbl controller_added_vtbl = { - IEventHandler_CRawGameControllerVtbl_QueryInterface, - IEventHandler_CRawGameControllerVtbl_AddRef, - IEventHandler_CRawGameControllerVtbl_Release, - IEventHandler_CRawGameControllerVtbl_InvokeAdded -}; -static RawGameControllerDelegate controller_added = { - { &controller_added_vtbl }, - { 1 } -}; - -static __FIEventHandler_1_Windows__CGaming__CInput__CRawGameControllerVtbl controller_removed_vtbl = { - IEventHandler_CRawGameControllerVtbl_QueryInterface, - IEventHandler_CRawGameControllerVtbl_AddRef, - IEventHandler_CRawGameControllerVtbl_Release, - IEventHandler_CRawGameControllerVtbl_InvokeRemoved -}; -static RawGameControllerDelegate controller_removed = { - { &controller_removed_vtbl }, - { 1 } -}; - -#ifdef _MSC_VER -#pragma warning(pop) -#endif - -static bool WGI_JoystickInit(void) -{ - HRESULT hr; - - if (!SDL_GetHintBoolean(SDL_HINT_JOYSTICK_WGI, true)) { - return true; - } - - if (FAILED(WIN_RoInitialize())) { - return SDL_SetError("RoInitialize() failed"); - } - -#define RESOLVE(x) wgi.x = (x##_t)WIN_LoadComBaseFunction(#x); if (!wgi.x) return WIN_SetError("GetProcAddress failed for " #x); - RESOLVE(CoIncrementMTAUsage); - RESOLVE(RoGetActivationFactory); - RESOLVE(WindowsCreateStringReference); - RESOLVE(WindowsDeleteString); - RESOLVE(WindowsGetStringRawBuffer); -#undef RESOLVE - - { - /* There seems to be a bug in Windows where a dependency of WGI can be unloaded from memory prior to WGI itself. - * This results in Windows_Gaming_Input!GameController::~GameController() invoking an unloaded DLL and crashing. - * As a workaround, we will keep a reference to the MTA to prevent COM from unloading DLLs later. - * See https://github.com/libsdl-org/SDL/issues/5552 for more details. - */ - static CO_MTA_USAGE_COOKIE cookie = NULL; - if (!cookie) { - hr = wgi.CoIncrementMTAUsage(&cookie); - if (FAILED(hr)) { - return WIN_SetErrorFromHRESULT("CoIncrementMTAUsage() failed", hr); - } - } - } - - WGI_LoadRawGameControllerStatics(); - - if (wgi.controller_statics) { - __FIVectorView_1_Windows__CGaming__CInput__CRawGameController *controllers; - - hr = __x_ABI_CWindows_CGaming_CInput_CIRawGameControllerStatics_add_RawGameControllerAdded(wgi.controller_statics, &controller_added.iface, &wgi.controller_added_token); - if (!SUCCEEDED(hr)) { - WIN_SetErrorFromHRESULT("Windows.Gaming.Input.IRawGameControllerStatics.add_RawGameControllerAdded failed", hr); - } - - hr = __x_ABI_CWindows_CGaming_CInput_CIRawGameControllerStatics_add_RawGameControllerRemoved(wgi.controller_statics, &controller_removed.iface, &wgi.controller_removed_token); - if (!SUCCEEDED(hr)) { - WIN_SetErrorFromHRESULT("Windows.Gaming.Input.IRawGameControllerStatics.add_RawGameControllerRemoved failed", hr); - } - - hr = __x_ABI_CWindows_CGaming_CInput_CIRawGameControllerStatics_get_RawGameControllers(wgi.controller_statics, &controllers); - if (SUCCEEDED(hr)) { - unsigned i, count = 0; - - hr = __FIVectorView_1_Windows__CGaming__CInput__CRawGameController_get_Size(controllers, &count); - if (SUCCEEDED(hr)) { - for (i = 0; i < count; ++i) { - __x_ABI_CWindows_CGaming_CInput_CIRawGameController *controller = NULL; - - hr = __FIVectorView_1_Windows__CGaming__CInput__CRawGameController_GetAt(controllers, i, &controller); - if (SUCCEEDED(hr) && controller) { - IEventHandler_CRawGameControllerVtbl_InvokeAdded(&controller_added.iface, NULL, controller); - __x_ABI_CWindows_CGaming_CInput_CIRawGameController_Release(controller); - } - } - } - - __FIVectorView_1_Windows__CGaming__CInput__CRawGameController_Release(controllers); - } - } - - return true; -} - -static int WGI_JoystickGetCount(void) -{ - return wgi.controller_count; -} - -static void WGI_JoystickDetect(void) -{ -} - -static bool WGI_JoystickIsDevicePresent(Uint16 vendor_id, Uint16 product_id, Uint16 version, const char *name) -{ - // We don't override any other drivers - return false; -} - -static const char *WGI_JoystickGetDeviceName(int device_index) -{ - return wgi.controllers[device_index].name; -} - -static const char *WGI_JoystickGetDevicePath(int device_index) -{ - return NULL; -} - -static int WGI_JoystickGetDeviceSteamVirtualGamepadSlot(int device_index) -{ - return wgi.controllers[device_index].steam_virtual_gamepad_slot; -} - -static int WGI_JoystickGetDevicePlayerIndex(int device_index) -{ - return false; -} - -static void WGI_JoystickSetDevicePlayerIndex(int device_index, int player_index) -{ -} - -static SDL_GUID WGI_JoystickGetDeviceGUID(int device_index) -{ - return wgi.controllers[device_index].guid; -} - -static SDL_JoystickID WGI_JoystickGetDeviceInstanceID(int device_index) -{ - return wgi.controllers[device_index].instance_id; -} - -static bool WGI_JoystickOpen(SDL_Joystick *joystick, int device_index) -{ - WindowsGamingInputControllerState *state = &wgi.controllers[device_index]; - struct joystick_hwdata *hwdata; - boolean wireless = false; - - hwdata = (struct joystick_hwdata *)SDL_calloc(1, sizeof(*hwdata)); - if (!hwdata) { - return false; - } - joystick->hwdata = hwdata; - - hwdata->controller = state->controller; - __x_ABI_CWindows_CGaming_CInput_CIRawGameController_AddRef(hwdata->controller); - __x_ABI_CWindows_CGaming_CInput_CIRawGameController_QueryInterface(hwdata->controller, &IID___x_ABI_CWindows_CGaming_CInput_CIGameController, (void **)&hwdata->game_controller); - __x_ABI_CWindows_CGaming_CInput_CIRawGameController_QueryInterface(hwdata->controller, &IID___x_ABI_CWindows_CGaming_CInput_CIGameControllerBatteryInfo, (void **)&hwdata->battery); - - if (wgi.gamepad_statics2) { - __x_ABI_CWindows_CGaming_CInput_CIGamepadStatics2_FromGameController(wgi.gamepad_statics2, hwdata->game_controller, &hwdata->gamepad); - } - - if (hwdata->game_controller) { - __x_ABI_CWindows_CGaming_CInput_CIGameController_get_IsWireless(hwdata->game_controller, &wireless); - } - - // Initialize the joystick capabilities - if (wireless) { - joystick->connection_state = SDL_JOYSTICK_CONNECTION_WIRELESS; - } else { - joystick->connection_state = SDL_JOYSTICK_CONNECTION_WIRED; - } - __x_ABI_CWindows_CGaming_CInput_CIRawGameController_get_ButtonCount(hwdata->controller, &joystick->nbuttons); - __x_ABI_CWindows_CGaming_CInput_CIRawGameController_get_AxisCount(hwdata->controller, &joystick->naxes); - __x_ABI_CWindows_CGaming_CInput_CIRawGameController_get_SwitchCount(hwdata->controller, &joystick->nhats); - - if (hwdata->gamepad) { - // FIXME: Can WGI even tell us if trigger rumble is supported? - SDL_SetBooleanProperty(SDL_GetJoystickProperties(joystick), SDL_PROP_JOYSTICK_CAP_RUMBLE_BOOLEAN, true); - SDL_SetBooleanProperty(SDL_GetJoystickProperties(joystick), SDL_PROP_JOYSTICK_CAP_TRIGGER_RUMBLE_BOOLEAN, true); - } - return true; -} - -static bool WGI_JoystickRumble(SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble) -{ - struct joystick_hwdata *hwdata = joystick->hwdata; - - if (hwdata->gamepad) { - HRESULT hr; - - // Note: reusing partially filled vibration data struct - hwdata->vibration.LeftMotor = (DOUBLE)low_frequency_rumble / SDL_MAX_UINT16; - hwdata->vibration.RightMotor = (DOUBLE)high_frequency_rumble / SDL_MAX_UINT16; - hr = __x_ABI_CWindows_CGaming_CInput_CIGamepad_put_Vibration(hwdata->gamepad, hwdata->vibration); - if (SUCCEEDED(hr)) { - return true; - } else { - return WIN_SetErrorFromHRESULT("Windows.Gaming.Input.IGamepad.put_Vibration failed", hr); - } - } else { - return SDL_Unsupported(); - } -} - -static bool WGI_JoystickRumbleTriggers(SDL_Joystick *joystick, Uint16 left_rumble, Uint16 right_rumble) -{ - struct joystick_hwdata *hwdata = joystick->hwdata; - - if (hwdata->gamepad) { - HRESULT hr; - - // Note: reusing partially filled vibration data struct - hwdata->vibration.LeftTrigger = (DOUBLE)left_rumble / SDL_MAX_UINT16; - hwdata->vibration.RightTrigger = (DOUBLE)right_rumble / SDL_MAX_UINT16; - hr = __x_ABI_CWindows_CGaming_CInput_CIGamepad_put_Vibration(hwdata->gamepad, hwdata->vibration); - if (SUCCEEDED(hr)) { - return true; - } else { - return WIN_SetErrorFromHRESULT("Windows.Gaming.Input.IGamepad.put_Vibration failed", hr); - } - } else { - return SDL_Unsupported(); - } -} - -static bool WGI_JoystickSetLED(SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue) -{ - return SDL_Unsupported(); -} - -static bool WGI_JoystickSendEffect(SDL_Joystick *joystick, const void *data, int size) -{ - return SDL_Unsupported(); -} - -static bool WGI_JoystickSetSensorsEnabled(SDL_Joystick *joystick, bool enabled) -{ - return SDL_Unsupported(); -} - -static Uint8 ConvertHatValue(__x_ABI_CWindows_CGaming_CInput_CGameControllerSwitchPosition value) -{ - switch (value) { - case GameControllerSwitchPosition_Up: - return SDL_HAT_UP; - case GameControllerSwitchPosition_UpRight: - return SDL_HAT_RIGHTUP; - case GameControllerSwitchPosition_Right: - return SDL_HAT_RIGHT; - case GameControllerSwitchPosition_DownRight: - return SDL_HAT_RIGHTDOWN; - case GameControllerSwitchPosition_Down: - return SDL_HAT_DOWN; - case GameControllerSwitchPosition_DownLeft: - return SDL_HAT_LEFTDOWN; - case GameControllerSwitchPosition_Left: - return SDL_HAT_LEFT; - case GameControllerSwitchPosition_UpLeft: - return SDL_HAT_LEFTUP; - default: - return SDL_HAT_CENTERED; - } -} - -static void WGI_JoystickUpdate(SDL_Joystick *joystick) -{ - struct joystick_hwdata *hwdata = joystick->hwdata; - HRESULT hr; - UINT32 nbuttons = SDL_min(joystick->nbuttons, SDL_MAX_UINT8); - boolean *buttons = NULL; - UINT32 nhats = SDL_min(joystick->nhats, SDL_MAX_UINT8); - __x_ABI_CWindows_CGaming_CInput_CGameControllerSwitchPosition *hats = NULL; - UINT32 naxes = SDL_min(joystick->naxes, SDL_MAX_UINT8); - DOUBLE *axes = NULL; - UINT64 timestamp; - - if (nbuttons > 0) { - buttons = SDL_stack_alloc(boolean, nbuttons); - } - if (nhats > 0) { - hats = SDL_stack_alloc(__x_ABI_CWindows_CGaming_CInput_CGameControllerSwitchPosition, nhats); - } - if (naxes > 0) { - axes = SDL_stack_alloc(DOUBLE, naxes); - } - - hr = __x_ABI_CWindows_CGaming_CInput_CIRawGameController_GetCurrentReading(hwdata->controller, nbuttons, buttons, nhats, hats, naxes, axes, ×tamp); - if (SUCCEEDED(hr) && (!timestamp || timestamp != hwdata->timestamp)) { - UINT32 i; - bool all_zero = false; - - hwdata->timestamp = timestamp; - - // The axes are all zero when the application loses focus - if (naxes > 0) { - all_zero = true; - for (i = 0; i < naxes; ++i) { - if (axes[i] != 0.0f) { - all_zero = false; - break; - } - } - } - if (all_zero) { - SDL_PrivateJoystickForceRecentering(joystick); - } else { - // FIXME: What units are the timestamp we get from GetCurrentReading()? - timestamp = SDL_GetTicksNS(); - for (i = 0; i < nbuttons; ++i) { - SDL_SendJoystickButton(timestamp, joystick, (Uint8)i, buttons[i]); - } - for (i = 0; i < nhats; ++i) { - SDL_SendJoystickHat(timestamp, joystick, (Uint8)i, ConvertHatValue(hats[i])); - } - for (i = 0; i < naxes; ++i) { - SDL_SendJoystickAxis(timestamp, joystick, (Uint8)i, (Sint16)((int)(axes[i] * 65535) - 32768)); - } - } - } - - SDL_stack_free(buttons); - SDL_stack_free(hats); - SDL_stack_free(axes); - - if (hwdata->battery) { - __x_ABI_CWindows_CDevices_CPower_CIBatteryReport *report = NULL; - - hr = __x_ABI_CWindows_CGaming_CInput_CIGameControllerBatteryInfo_TryGetBatteryReport(hwdata->battery, &report); - if (SUCCEEDED(hr) && report) { - SDL_PowerState state = SDL_POWERSTATE_UNKNOWN; - int percent = 0; - __x_ABI_CWindows_CSystem_CPower_CBatteryStatus status; - int full_capacity = 0, curr_capacity = 0; - __FIReference_1_int *full_capacityP, *curr_capacityP; - - hr = __x_ABI_CWindows_CDevices_CPower_CIBatteryReport_get_Status(report, &status); - if (SUCCEEDED(hr)) { - switch (status) { - case BatteryStatus_NotPresent: - state = SDL_POWERSTATE_NO_BATTERY; - break; - case BatteryStatus_Discharging: - state = SDL_POWERSTATE_ON_BATTERY; - break; - case BatteryStatus_Idle: - state = SDL_POWERSTATE_CHARGED; - break; - case BatteryStatus_Charging: - state = SDL_POWERSTATE_CHARGING; - break; - default: - state = SDL_POWERSTATE_UNKNOWN; - break; - } - } - - hr = __x_ABI_CWindows_CDevices_CPower_CIBatteryReport_get_FullChargeCapacityInMilliwattHours(report, &full_capacityP); - if (SUCCEEDED(hr)) { - __FIReference_1_int_get_Value(full_capacityP, &full_capacity); - __FIReference_1_int_Release(full_capacityP); - } - - hr = __x_ABI_CWindows_CDevices_CPower_CIBatteryReport_get_RemainingCapacityInMilliwattHours(report, &curr_capacityP); - if (SUCCEEDED(hr)) { - __FIReference_1_int_get_Value(curr_capacityP, &curr_capacity); - __FIReference_1_int_Release(curr_capacityP); - } - - if (full_capacity > 0) { - percent = (int)SDL_roundf(((float)curr_capacity / full_capacity) * 100.0f); - } - - SDL_SendJoystickPowerInfo(joystick, state, percent); - - __x_ABI_CWindows_CDevices_CPower_CIBatteryReport_Release(report); - } - } -} - -static void WGI_JoystickClose(SDL_Joystick *joystick) -{ - struct joystick_hwdata *hwdata = joystick->hwdata; - - if (hwdata) { - if (hwdata->controller) { - __x_ABI_CWindows_CGaming_CInput_CIRawGameController_Release(hwdata->controller); - } - if (hwdata->game_controller) { - __x_ABI_CWindows_CGaming_CInput_CIGameController_Release(hwdata->game_controller); - } - if (hwdata->battery) { - __x_ABI_CWindows_CGaming_CInput_CIGameControllerBatteryInfo_Release(hwdata->battery); - } - if (hwdata->gamepad) { - __x_ABI_CWindows_CGaming_CInput_CIGamepad_Release(hwdata->gamepad); - } - SDL_free(hwdata); - } - joystick->hwdata = NULL; -} - -static void WGI_JoystickQuit(void) -{ - if (wgi.controller_statics) { - while (wgi.controller_count > 0) { - IEventHandler_CRawGameControllerVtbl_InvokeRemoved(&controller_removed.iface, NULL, wgi.controllers[wgi.controller_count - 1].controller); - } - if (wgi.controllers) { - SDL_free(wgi.controllers); - } - - if (wgi.arcade_stick_statics) { - __x_ABI_CWindows_CGaming_CInput_CIArcadeStickStatics_Release(wgi.arcade_stick_statics); - } - if (wgi.arcade_stick_statics2) { - __x_ABI_CWindows_CGaming_CInput_CIArcadeStickStatics2_Release(wgi.arcade_stick_statics2); - } - if (wgi.flight_stick_statics) { - __x_ABI_CWindows_CGaming_CInput_CIFlightStickStatics_Release(wgi.flight_stick_statics); - } - if (wgi.gamepad_statics) { - __x_ABI_CWindows_CGaming_CInput_CIGamepadStatics_Release(wgi.gamepad_statics); - } - if (wgi.gamepad_statics2) { - __x_ABI_CWindows_CGaming_CInput_CIGamepadStatics2_Release(wgi.gamepad_statics2); - } - if (wgi.racing_wheel_statics) { - __x_ABI_CWindows_CGaming_CInput_CIRacingWheelStatics_Release(wgi.racing_wheel_statics); - } - if (wgi.racing_wheel_statics2) { - __x_ABI_CWindows_CGaming_CInput_CIRacingWheelStatics2_Release(wgi.racing_wheel_statics2); - } - - __x_ABI_CWindows_CGaming_CInput_CIRawGameControllerStatics_remove_RawGameControllerAdded(wgi.controller_statics, wgi.controller_added_token); - __x_ABI_CWindows_CGaming_CInput_CIRawGameControllerStatics_remove_RawGameControllerRemoved(wgi.controller_statics, wgi.controller_removed_token); - __x_ABI_CWindows_CGaming_CInput_CIRawGameControllerStatics_Release(wgi.controller_statics); - } - - WIN_RoUninitialize(); - - SDL_zero(wgi); -} - -static bool WGI_JoystickGetGamepadMapping(int device_index, SDL_GamepadMapping *out) -{ - return false; -} - -SDL_JoystickDriver SDL_WGI_JoystickDriver = { - WGI_JoystickInit, - WGI_JoystickGetCount, - WGI_JoystickDetect, - WGI_JoystickIsDevicePresent, - WGI_JoystickGetDeviceName, - WGI_JoystickGetDevicePath, - WGI_JoystickGetDeviceSteamVirtualGamepadSlot, - WGI_JoystickGetDevicePlayerIndex, - WGI_JoystickSetDevicePlayerIndex, - WGI_JoystickGetDeviceGUID, - WGI_JoystickGetDeviceInstanceID, - WGI_JoystickOpen, - WGI_JoystickRumble, - WGI_JoystickRumbleTriggers, - WGI_JoystickSetLED, - WGI_JoystickSendEffect, - WGI_JoystickSetSensorsEnabled, - WGI_JoystickUpdate, - WGI_JoystickClose, - WGI_JoystickQuit, - WGI_JoystickGetGamepadMapping -}; - -#endif // SDL_JOYSTICK_WGI diff --git a/contrib/SDL-3.2.8/src/joystick/windows/SDL_windowsjoystick.c b/contrib/SDL-3.2.8/src/joystick/windows/SDL_windowsjoystick.c deleted file mode 100644 index e7fbfcb..0000000 --- a/contrib/SDL-3.2.8/src/joystick/windows/SDL_windowsjoystick.c +++ /dev/null @@ -1,693 +0,0 @@ -/* - Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. -*/ -#include "SDL_internal.h" - -#if defined(SDL_JOYSTICK_DINPUT) || defined(SDL_JOYSTICK_XINPUT) - -/* DirectInput joystick driver; written by Glenn Maynard, based on Andrei de - * A. Formiga's WINMM driver. - * - * Hats and sliders are completely untested; the app I'm writing this for mostly - * doesn't use them and I don't own any joysticks with them. - * - * We don't bother to use event notification here. It doesn't seem to work - * with polled devices, and it's fine to call IDirectInputDevice8_GetDeviceData and - * let it return 0 events. */ - -#include "../SDL_sysjoystick.h" -#include "../../thread/SDL_systhread.h" -#include "../../core/windows/SDL_windows.h" -#include "../../core/windows/SDL_hid.h" -#if !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES) -#include -#endif - -#define INITGUID // Only set here, if set twice will cause mingw32 to break. -#include "SDL_windowsjoystick_c.h" -#include "SDL_dinputjoystick_c.h" -#include "SDL_xinputjoystick_c.h" -#include "SDL_rawinputjoystick_c.h" - -#include "../../haptic/windows/SDL_dinputhaptic_c.h" // For haptic hot plugging - -#ifndef DEVICE_NOTIFY_WINDOW_HANDLE -#define DEVICE_NOTIFY_WINDOW_HANDLE 0x00000000 -#endif - -// local variables -static bool s_bJoystickThread = false; -static SDL_Condition *s_condJoystickThread = NULL; -static SDL_Mutex *s_mutexJoyStickEnum = NULL; -static SDL_Thread *s_joystickThread = NULL; -static bool s_bJoystickThreadQuit = false; -static Uint64 s_lastDeviceChange = 0; -static GUID GUID_DEVINTERFACE_HID = { 0x4D1E55B2L, 0xF16F, 0x11CF, { 0x88, 0xCB, 0x00, 0x11, 0x11, 0x00, 0x00, 0x30 } }; - -JoyStick_DeviceData *SYS_Joystick; // array to hold joystick ID values - - -static bool WindowsDeviceChanged(void) -{ - return (s_lastDeviceChange != WIN_GetLastDeviceNotification()); -} - -static void SetWindowsDeviceChanged(void) -{ - s_lastDeviceChange = 0; -} - -void WINDOWS_RAWINPUTEnabledChanged(void) -{ - SetWindowsDeviceChanged(); -} - -#if !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES) - -typedef struct -{ - HRESULT coinitialized; - WNDCLASSEX wincl; - HWND messageWindow; - HDEVNOTIFY hNotify; -} SDL_DeviceNotificationData; - -#define IDT_SDL_DEVICE_CHANGE_TIMER_1 1200 -#define IDT_SDL_DEVICE_CHANGE_TIMER_2 1201 - -// windowproc for our joystick detect thread message only window, to detect any USB device addition/removal -static LRESULT CALLBACK SDL_PrivateJoystickDetectProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) -{ - switch (msg) { - case WM_DEVICECHANGE: - switch (wParam) { - case DBT_DEVICEARRIVAL: - case DBT_DEVICEREMOVECOMPLETE: - if (((DEV_BROADCAST_HDR *)lParam)->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE) { - // notify 300ms and 2 seconds later to ensure all APIs have updated status - SetTimer(hwnd, IDT_SDL_DEVICE_CHANGE_TIMER_1, 300, NULL); - SetTimer(hwnd, IDT_SDL_DEVICE_CHANGE_TIMER_2, 2000, NULL); - } - break; - } - return true; - case WM_TIMER: - if (wParam == IDT_SDL_DEVICE_CHANGE_TIMER_1 || - wParam == IDT_SDL_DEVICE_CHANGE_TIMER_2) { - KillTimer(hwnd, wParam); - SetWindowsDeviceChanged(); - return true; - } - break; - } - -#ifdef SDL_JOYSTICK_RAWINPUT - return CallWindowProc(RAWINPUT_WindowProc, hwnd, msg, wParam, lParam); -#else - return CallWindowProc(DefWindowProc, hwnd, msg, wParam, lParam); -#endif -} - -static void SDL_CleanupDeviceNotification(SDL_DeviceNotificationData *data) -{ -#ifdef SDL_JOYSTICK_RAWINPUT - RAWINPUT_UnregisterNotifications(); -#endif - - if (data->hNotify) { - UnregisterDeviceNotification(data->hNotify); - } - - if (data->messageWindow) { - DestroyWindow(data->messageWindow); - } - - UnregisterClass(data->wincl.lpszClassName, data->wincl.hInstance); - - if (data->coinitialized == S_OK) { - WIN_CoUninitialize(); - } -} - -static bool SDL_CreateDeviceNotification(SDL_DeviceNotificationData *data) -{ - DEV_BROADCAST_DEVICEINTERFACE dbh; - - SDL_zerop(data); - - data->coinitialized = WIN_CoInitialize(); - - data->wincl.hInstance = GetModuleHandle(NULL); - data->wincl.lpszClassName = TEXT("Message"); - data->wincl.lpfnWndProc = SDL_PrivateJoystickDetectProc; // This function is called by windows - data->wincl.cbSize = sizeof(WNDCLASSEX); - - if (!RegisterClassEx(&data->wincl)) { - WIN_SetError("Failed to create register class for joystick autodetect"); - SDL_CleanupDeviceNotification(data); - return false; - } - - data->messageWindow = CreateWindowEx(0, TEXT("Message"), NULL, 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, NULL, NULL); - if (!data->messageWindow) { - WIN_SetError("Failed to create message window for joystick autodetect"); - SDL_CleanupDeviceNotification(data); - return false; - } - - SDL_zero(dbh); - dbh.dbcc_size = sizeof(dbh); - dbh.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE; - dbh.dbcc_classguid = GUID_DEVINTERFACE_HID; - - data->hNotify = RegisterDeviceNotification(data->messageWindow, &dbh, DEVICE_NOTIFY_WINDOW_HANDLE); - if (!data->hNotify) { - WIN_SetError("Failed to create notify device for joystick autodetect"); - SDL_CleanupDeviceNotification(data); - return false; - } - -#ifdef SDL_JOYSTICK_RAWINPUT - RAWINPUT_RegisterNotifications(data->messageWindow); -#endif - return true; -} - -static bool SDL_WaitForDeviceNotification(SDL_DeviceNotificationData *data, SDL_Mutex *mutex) -{ - MSG msg; - int lastret = 1; - - if (!data->messageWindow) { - return false; // device notifications require a window - } - - SDL_UnlockMutex(mutex); - while (lastret > 0 && !WindowsDeviceChanged()) { - lastret = GetMessage(&msg, NULL, 0, 0); // WM_QUIT causes return value of 0 - if (lastret > 0) { - TranslateMessage(&msg); - DispatchMessage(&msg); - } - } - SDL_LockMutex(mutex); - return (lastret != -1); -} - -#endif // !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES) - -#if !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES) -static SDL_DeviceNotificationData s_notification_data; -#endif - -// Function/thread to scan the system for joysticks. -static int SDLCALL SDL_JoystickThread(void *_data) -{ -#ifdef SDL_JOYSTICK_XINPUT - bool bOpenedXInputDevices[XUSER_MAX_COUNT]; - SDL_zeroa(bOpenedXInputDevices); -#endif - -#if !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES) - if (!SDL_CreateDeviceNotification(&s_notification_data)) { - return 0; - } -#endif - - SDL_LockMutex(s_mutexJoyStickEnum); - while (s_bJoystickThreadQuit == false) { -#if !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES) - if (SDL_WaitForDeviceNotification(&s_notification_data, s_mutexJoyStickEnum) == false) { -#else - { -#endif -#ifdef SDL_JOYSTICK_XINPUT - // WM_DEVICECHANGE not working, poll for new XINPUT controllers - SDL_WaitConditionTimeout(s_condJoystickThread, s_mutexJoyStickEnum, 1000); - if (SDL_XINPUT_Enabled()) { - // scan for any change in XInput devices - Uint8 userId; - for (userId = 0; userId < XUSER_MAX_COUNT; userId++) { - XINPUT_CAPABILITIES capabilities; - const DWORD result = XINPUTGETCAPABILITIES(userId, XINPUT_FLAG_GAMEPAD, &capabilities); - const bool available = (result == ERROR_SUCCESS); - if (bOpenedXInputDevices[userId] != available) { - SetWindowsDeviceChanged(); - bOpenedXInputDevices[userId] = available; - } - } - } -#else - // WM_DEVICECHANGE not working, no XINPUT, no point in keeping thread alive - break; -#endif // SDL_JOYSTICK_XINPUT - } - } - - SDL_UnlockMutex(s_mutexJoyStickEnum); - -#if !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES) - SDL_CleanupDeviceNotification(&s_notification_data); -#endif - - return 1; -} - -// spin up the thread to detect hotplug of devices -static bool SDL_StartJoystickThread(void) -{ - s_mutexJoyStickEnum = SDL_CreateMutex(); - if (!s_mutexJoyStickEnum) { - return false; - } - - s_condJoystickThread = SDL_CreateCondition(); - if (!s_condJoystickThread) { - return false; - } - - s_bJoystickThreadQuit = false; - s_joystickThread = SDL_CreateThread(SDL_JoystickThread, "SDL_joystick", NULL); - if (!s_joystickThread) { - return false; - } - return true; -} - -static void SDL_StopJoystickThread(void) -{ - if (!s_joystickThread) { - return; - } - - SDL_LockMutex(s_mutexJoyStickEnum); - s_bJoystickThreadQuit = true; - SDL_BroadcastCondition(s_condJoystickThread); // signal the joystick thread to quit - SDL_UnlockMutex(s_mutexJoyStickEnum); - PostThreadMessage((DWORD)SDL_GetThreadID(s_joystickThread), WM_QUIT, 0, 0); - - // Unlock joysticks while the joystick thread finishes processing messages - SDL_AssertJoysticksLocked(); - SDL_UnlockJoysticks(); - SDL_WaitThread(s_joystickThread, NULL); // wait for it to bugger off - SDL_LockJoysticks(); - - SDL_DestroyCondition(s_condJoystickThread); - s_condJoystickThread = NULL; - - SDL_DestroyMutex(s_mutexJoyStickEnum); - s_mutexJoyStickEnum = NULL; - - s_joystickThread = NULL; -} - -void WINDOWS_AddJoystickDevice(JoyStick_DeviceData *device) -{ - device->send_add_event = true; - device->nInstanceID = SDL_GetNextObjectID(); - device->pNext = SYS_Joystick; - SYS_Joystick = device; -} - -void WINDOWS_JoystickDetect(void); -void WINDOWS_JoystickQuit(void); - -static bool WINDOWS_JoystickInit(void) -{ - if (!SDL_XINPUT_JoystickInit()) { - WINDOWS_JoystickQuit(); - return false; - } - - if (!SDL_DINPUT_JoystickInit()) { - WINDOWS_JoystickQuit(); - return false; - } - - WIN_InitDeviceNotification(); - -#if !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES) - s_bJoystickThread = SDL_GetHintBoolean(SDL_HINT_JOYSTICK_THREAD, true); - if (s_bJoystickThread) { - if (!SDL_StartJoystickThread()) { - return false; - } - } else { - if (!SDL_CreateDeviceNotification(&s_notification_data)) { - return false; - } - } -#endif - -#if defined(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_XBOXSERIES) - // On Xbox, force create the joystick thread for device detection (since other methods don't work - s_bJoystickThread = true; - if (!SDL_StartJoystickThread()) { - return false; - } -#endif - - SetWindowsDeviceChanged(); // force a scan of the system for joysticks this first time - - WINDOWS_JoystickDetect(); - - return true; -} - -// return the number of joysticks that are connected right now -static int WINDOWS_JoystickGetCount(void) -{ - int nJoysticks = 0; - JoyStick_DeviceData *device = SYS_Joystick; - while (device) { - nJoysticks++; - device = device->pNext; - } - - return nJoysticks; -} - -// detect any new joysticks being inserted into the system -void WINDOWS_JoystickDetect(void) -{ - JoyStick_DeviceData *pCurList = NULL; - - // only enum the devices if the joystick thread told us something changed - if (!WindowsDeviceChanged()) { - return; // thread hasn't signaled, nothing to do right now. - } - - if (s_mutexJoyStickEnum) { - SDL_LockMutex(s_mutexJoyStickEnum); - } - - s_lastDeviceChange = WIN_GetLastDeviceNotification(); - - pCurList = SYS_Joystick; - SYS_Joystick = NULL; - - // Look for DirectInput joysticks, wheels, head trackers, gamepads, etc.. - SDL_DINPUT_JoystickDetect(&pCurList); - - // Look for XInput devices. Do this last, so they're first in the final list. - SDL_XINPUT_JoystickDetect(&pCurList); - - if (s_mutexJoyStickEnum) { - SDL_UnlockMutex(s_mutexJoyStickEnum); - } - - while (pCurList) { - JoyStick_DeviceData *pListNext = NULL; - - if (!pCurList->bXInputDevice) { -#ifdef SDL_HAPTIC_DINPUT - SDL_DINPUT_HapticMaybeRemoveDevice(&pCurList->dxdevice); -#endif - } - - SDL_PrivateJoystickRemoved(pCurList->nInstanceID); - - pListNext = pCurList->pNext; - SDL_free(pCurList->joystickname); - SDL_free(pCurList); - pCurList = pListNext; - } - - for (pCurList = SYS_Joystick; pCurList; pCurList = pCurList->pNext) { - if (pCurList->send_add_event) { - if (!pCurList->bXInputDevice) { -#ifdef SDL_HAPTIC_DINPUT - SDL_DINPUT_HapticMaybeAddDevice(&pCurList->dxdevice); -#endif - } - - SDL_PrivateJoystickAdded(pCurList->nInstanceID); - - pCurList->send_add_event = false; - } - } -} - -static bool WINDOWS_JoystickIsDevicePresent(Uint16 vendor_id, Uint16 product_id, Uint16 version, const char *name) -{ - if (SDL_DINPUT_JoystickPresent(vendor_id, product_id, version)) { - return true; - } - if (SDL_XINPUT_JoystickPresent(vendor_id, product_id, version)) { - return true; - } - return false; -} - -static const char *WINDOWS_JoystickGetDeviceName(int device_index) -{ - JoyStick_DeviceData *device = SYS_Joystick; - int index; - - for (index = device_index; index > 0; index--) { - device = device->pNext; - } - - return device->joystickname; -} - -static const char *WINDOWS_JoystickGetDevicePath(int device_index) -{ - JoyStick_DeviceData *device = SYS_Joystick; - int index; - - for (index = device_index; index > 0; index--) { - device = device->pNext; - } - - return device->path; -} - -static int WINDOWS_JoystickGetDeviceSteamVirtualGamepadSlot(int device_index) -{ - JoyStick_DeviceData *device = SYS_Joystick; - int index; - - for (index = device_index; index > 0; index--) { - device = device->pNext; - } - - if (device->bXInputDevice) { - // The slot for XInput devices can change as controllers are seated - return SDL_XINPUT_GetSteamVirtualGamepadSlot(device->XInputUserId); - } else { - return device->steam_virtual_gamepad_slot; - } -} - -static int WINDOWS_JoystickGetDevicePlayerIndex(int device_index) -{ - JoyStick_DeviceData *device = SYS_Joystick; - int index; - - for (index = device_index; index > 0; index--) { - device = device->pNext; - } - - return device->bXInputDevice ? (int)device->XInputUserId : -1; -} - -static void WINDOWS_JoystickSetDevicePlayerIndex(int device_index, int player_index) -{ -} - -// return the stable device guid for this device index -static SDL_GUID WINDOWS_JoystickGetDeviceGUID(int device_index) -{ - JoyStick_DeviceData *device = SYS_Joystick; - int index; - - for (index = device_index; index > 0; index--) { - device = device->pNext; - } - - return device->guid; -} - -// Function to perform the mapping between current device instance and this joysticks instance id -static SDL_JoystickID WINDOWS_JoystickGetDeviceInstanceID(int device_index) -{ - JoyStick_DeviceData *device = SYS_Joystick; - int index; - - for (index = device_index; index > 0; index--) { - device = device->pNext; - } - - return device->nInstanceID; -} - -/* Function to open a joystick for use. - The joystick to open is specified by the device index. - This should fill the nbuttons and naxes fields of the joystick structure. - It returns 0, or -1 if there is an error. - */ -static bool WINDOWS_JoystickOpen(SDL_Joystick *joystick, int device_index) -{ - JoyStick_DeviceData *device = SYS_Joystick; - int index; - - for (index = device_index; index > 0; index--) { - device = device->pNext; - } - - // allocate memory for system specific hardware data - joystick->hwdata = (struct joystick_hwdata *)SDL_calloc(1, sizeof(struct joystick_hwdata)); - if (!joystick->hwdata) { - return false; - } - joystick->hwdata->guid = device->guid; - - if (device->bXInputDevice) { - return SDL_XINPUT_JoystickOpen(joystick, device); - } else { - return SDL_DINPUT_JoystickOpen(joystick, device); - } -} - -static bool WINDOWS_JoystickRumble(SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble) -{ - if (joystick->hwdata->bXInputDevice) { - return SDL_XINPUT_JoystickRumble(joystick, low_frequency_rumble, high_frequency_rumble); - } else { - return SDL_DINPUT_JoystickRumble(joystick, low_frequency_rumble, high_frequency_rumble); - } -} - -static bool WINDOWS_JoystickRumbleTriggers(SDL_Joystick *joystick, Uint16 left_rumble, Uint16 right_rumble) -{ - return SDL_Unsupported(); -} - -static bool WINDOWS_JoystickSetLED(SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue) -{ - return SDL_Unsupported(); -} - -static bool WINDOWS_JoystickSendEffect(SDL_Joystick *joystick, const void *data, int size) -{ - return SDL_Unsupported(); -} - -static bool WINDOWS_JoystickSetSensorsEnabled(SDL_Joystick *joystick, bool enabled) -{ - return SDL_Unsupported(); -} - -static void WINDOWS_JoystickUpdate(SDL_Joystick *joystick) -{ - if (!joystick->hwdata) { - return; - } - - if (joystick->hwdata->bXInputDevice) { - SDL_XINPUT_JoystickUpdate(joystick); - } else { - SDL_DINPUT_JoystickUpdate(joystick); - } -} - -// Function to close a joystick after use -static void WINDOWS_JoystickClose(SDL_Joystick *joystick) -{ - if (joystick->hwdata->bXInputDevice) { - SDL_XINPUT_JoystickClose(joystick); - } else { - SDL_DINPUT_JoystickClose(joystick); - } - - SDL_free(joystick->hwdata); -} - -// Function to perform any system-specific joystick related cleanup -void WINDOWS_JoystickQuit(void) -{ - JoyStick_DeviceData *device = SYS_Joystick; - - while (device) { - JoyStick_DeviceData *device_next = device->pNext; - SDL_free(device->joystickname); - SDL_free(device); - device = device_next; - } - SYS_Joystick = NULL; - -#if !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES) - if (s_bJoystickThread) { - SDL_StopJoystickThread(); - } else { - SDL_CleanupDeviceNotification(&s_notification_data); - } -#endif - -#if defined(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_XBOXSERIES) - if (s_bJoystickThread) { - SDL_StopJoystickThread(); - } -#endif - - SDL_DINPUT_JoystickQuit(); - SDL_XINPUT_JoystickQuit(); - - WIN_QuitDeviceNotification(); -} - -static bool WINDOWS_JoystickGetGamepadMapping(int device_index, SDL_GamepadMapping *out) -{ - return false; -} - -SDL_JoystickDriver SDL_WINDOWS_JoystickDriver = { - WINDOWS_JoystickInit, - WINDOWS_JoystickGetCount, - WINDOWS_JoystickDetect, - WINDOWS_JoystickIsDevicePresent, - WINDOWS_JoystickGetDeviceName, - WINDOWS_JoystickGetDevicePath, - WINDOWS_JoystickGetDeviceSteamVirtualGamepadSlot, - WINDOWS_JoystickGetDevicePlayerIndex, - WINDOWS_JoystickSetDevicePlayerIndex, - WINDOWS_JoystickGetDeviceGUID, - WINDOWS_JoystickGetDeviceInstanceID, - WINDOWS_JoystickOpen, - WINDOWS_JoystickRumble, - WINDOWS_JoystickRumbleTriggers, - WINDOWS_JoystickSetLED, - WINDOWS_JoystickSendEffect, - WINDOWS_JoystickSetSensorsEnabled, - WINDOWS_JoystickUpdate, - WINDOWS_JoystickClose, - WINDOWS_JoystickQuit, - WINDOWS_JoystickGetGamepadMapping -}; - -#else - -#ifdef SDL_JOYSTICK_RAWINPUT -// The RAWINPUT driver needs the device notification setup above -#error SDL_JOYSTICK_RAWINPUT requires SDL_JOYSTICK_DINPUT || SDL_JOYSTICK_XINPUT -#endif - -#endif // SDL_JOYSTICK_DINPUT || SDL_JOYSTICK_XINPUT diff --git a/contrib/SDL-3.2.8/src/joystick/windows/SDL_windowsjoystick_c.h b/contrib/SDL-3.2.8/src/joystick/windows/SDL_windowsjoystick_c.h deleted file mode 100644 index 16b9184..0000000 --- a/contrib/SDL-3.2.8/src/joystick/windows/SDL_windowsjoystick_c.h +++ /dev/null @@ -1,103 +0,0 @@ -/* - Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. -*/ -#include "SDL_internal.h" - -#include "../SDL_sysjoystick.h" -#include "../../core/windows/SDL_windows.h" -#include "../../core/windows/SDL_directx.h" - -#define MAX_INPUTS 256 // each joystick can have up to 256 inputs - -// Set up for C function definitions, even when using C++ -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct JoyStick_DeviceData -{ - SDL_GUID guid; - char *joystickname; - Uint8 send_add_event; - SDL_JoystickID nInstanceID; - bool bXInputDevice; - BYTE SubType; - Uint8 XInputUserId; - DIDEVICEINSTANCE dxdevice; - char path[MAX_PATH]; - int steam_virtual_gamepad_slot; - struct JoyStick_DeviceData *pNext; -} JoyStick_DeviceData; - -extern JoyStick_DeviceData *SYS_Joystick; // array to hold joystick ID values - -typedef enum Type -{ - BUTTON, - AXIS, - HAT -} Type; - -typedef struct input_t -{ - // DirectInput offset for this input type: - DWORD ofs; - - // Button, axis or hat: - Type type; - - // SDL input offset: - Uint8 num; -} input_t; - -// The private structure used to keep track of a joystick -struct joystick_hwdata -{ - SDL_GUID guid; - -#ifdef SDL_JOYSTICK_DINPUT - LPDIRECTINPUTDEVICE8 InputDevice; - DIDEVCAPS Capabilities; - bool buffered; - bool first_update; - input_t Inputs[MAX_INPUTS]; - int NumInputs; - int NumSliders; - bool ff_initialized; - DIEFFECT *ffeffect; - LPDIRECTINPUTEFFECT ffeffect_ref; -#endif - - bool bXInputDevice; // true if this device supports using the xinput API rather than DirectInput - bool bXInputHaptic; // Supports force feedback via XInput. - Uint8 userid; // XInput userid index for this joystick - DWORD dwPacketNumber; -}; - -#ifdef SDL_JOYSTICK_DINPUT -extern const DIDATAFORMAT SDL_c_dfDIJoystick2; -#endif - -extern void WINDOWS_AddJoystickDevice(JoyStick_DeviceData *device); - -// Ends C function definitions when using C++ -#ifdef __cplusplus -} -#endif diff --git a/contrib/SDL-3.2.8/src/joystick/windows/SDL_xinputjoystick.c b/contrib/SDL-3.2.8/src/joystick/windows/SDL_xinputjoystick.c deleted file mode 100644 index 9f6ce10..0000000 --- a/contrib/SDL-3.2.8/src/joystick/windows/SDL_xinputjoystick.c +++ /dev/null @@ -1,473 +0,0 @@ -/* - Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. -*/ -#include "SDL_internal.h" - -#include "../SDL_sysjoystick.h" - -#ifdef SDL_JOYSTICK_XINPUT - -#include "SDL_windowsjoystick_c.h" -#include "SDL_xinputjoystick_c.h" -#include "SDL_rawinputjoystick_c.h" -#include "../hidapi/SDL_hidapijoystick_c.h" - -// Set up for C function definitions, even when using C++ -#ifdef __cplusplus -extern "C" { -#endif - -/* - * Internal stuff. - */ -static bool s_bXInputEnabled = false; - -bool SDL_XINPUT_Enabled(void) -{ - return s_bXInputEnabled; -} - -bool SDL_XINPUT_JoystickInit(void) -{ - bool enabled = SDL_GetHintBoolean(SDL_HINT_XINPUT_ENABLED, true); - - if (enabled && !WIN_LoadXInputDLL()) { - enabled = false; // oh well. - } - s_bXInputEnabled = enabled; - - return true; -} - -static const char *GetXInputName(const Uint8 userid, BYTE SubType) -{ - static char name[32]; - - switch (SubType) { - case XINPUT_DEVSUBTYPE_GAMEPAD: - (void)SDL_snprintf(name, sizeof(name), "XInput Controller #%d", 1 + userid); - break; - case XINPUT_DEVSUBTYPE_WHEEL: - (void)SDL_snprintf(name, sizeof(name), "XInput Wheel #%d", 1 + userid); - break; - case XINPUT_DEVSUBTYPE_ARCADE_STICK: - (void)SDL_snprintf(name, sizeof(name), "XInput ArcadeStick #%d", 1 + userid); - break; - case XINPUT_DEVSUBTYPE_FLIGHT_STICK: - (void)SDL_snprintf(name, sizeof(name), "XInput FlightStick #%d", 1 + userid); - break; - case XINPUT_DEVSUBTYPE_DANCE_PAD: - (void)SDL_snprintf(name, sizeof(name), "XInput DancePad #%d", 1 + userid); - break; - case XINPUT_DEVSUBTYPE_GUITAR: - case XINPUT_DEVSUBTYPE_GUITAR_ALTERNATE: - case XINPUT_DEVSUBTYPE_GUITAR_BASS: - (void)SDL_snprintf(name, sizeof(name), "XInput Guitar #%d", 1 + userid); - break; - case XINPUT_DEVSUBTYPE_DRUM_KIT: - (void)SDL_snprintf(name, sizeof(name), "XInput DrumKit #%d", 1 + userid); - break; - case XINPUT_DEVSUBTYPE_ARCADE_PAD: - (void)SDL_snprintf(name, sizeof(name), "XInput ArcadePad #%d", 1 + userid); - break; - default: - (void)SDL_snprintf(name, sizeof(name), "XInput Device #%d", 1 + userid); - break; - } - return name; -} - -static bool GetXInputDeviceInfo(Uint8 userid, Uint16 *pVID, Uint16 *pPID, Uint16 *pVersion) -{ - SDL_XINPUT_CAPABILITIES_EX capabilities; - - if (!XINPUTGETCAPABILITIESEX || XINPUTGETCAPABILITIESEX(1, userid, 0, &capabilities) != ERROR_SUCCESS) { - // Use a generic VID/PID representing an XInput controller - if (pVID) { - *pVID = USB_VENDOR_MICROSOFT; - } - if (pPID) { - *pPID = USB_PRODUCT_XBOX360_XUSB_CONTROLLER; - } - return false; - } - - // Fixup for Wireless Xbox 360 Controller - if (capabilities.ProductId == 0 && capabilities.Capabilities.Flags & XINPUT_CAPS_WIRELESS) { - capabilities.VendorId = USB_VENDOR_MICROSOFT; - capabilities.ProductId = USB_PRODUCT_XBOX360_XUSB_CONTROLLER; - } - - if (pVID) { - *pVID = capabilities.VendorId; - } - if (pPID) { - *pPID = capabilities.ProductId; - } - if (pVersion) { - *pVersion = capabilities.ProductVersion; - } - return true; -} - -int SDL_XINPUT_GetSteamVirtualGamepadSlot(Uint8 userid) -{ - SDL_XINPUT_CAPABILITIES_EX capabilities; - - if (XINPUTGETCAPABILITIESEX && - XINPUTGETCAPABILITIESEX(1, userid, 0, &capabilities) == ERROR_SUCCESS && - capabilities.VendorId == USB_VENDOR_VALVE && - capabilities.ProductId == USB_PRODUCT_STEAM_VIRTUAL_GAMEPAD) { - return (int)capabilities.unk2; - } - return -1; -} - -static void AddXInputDevice(Uint8 userid, BYTE SubType, JoyStick_DeviceData **pContext) -{ - const char *name = NULL; - Uint16 vendor = 0; - Uint16 product = 0; - Uint16 version = 0; - JoyStick_DeviceData *pPrevJoystick = NULL; - JoyStick_DeviceData *pNewJoystick = *pContext; - -#ifdef SDL_JOYSTICK_RAWINPUT - if (RAWINPUT_IsEnabled()) { - // The raw input driver handles more than 4 controllers, so prefer that when available - /* We do this check here rather than at the top of SDL_XINPUT_JoystickDetect() because - we need to check XInput state before RAWINPUT gets a hold of the device, otherwise - when a controller is connected via the wireless adapter, it will shut down at the - first subsequent XInput call. This seems like a driver stack bug? - - Reference: https://github.com/libsdl-org/SDL/issues/3468 - */ - return; - } -#endif - - if (SubType == XINPUT_DEVSUBTYPE_UNKNOWN) { - return; - } - - while (pNewJoystick) { - if (pNewJoystick->bXInputDevice && (pNewJoystick->XInputUserId == userid) && (pNewJoystick->SubType == SubType)) { - // if we are replacing the front of the list then update it - if (pNewJoystick == *pContext) { - *pContext = pNewJoystick->pNext; - } else if (pPrevJoystick) { - pPrevJoystick->pNext = pNewJoystick->pNext; - } - - pNewJoystick->pNext = SYS_Joystick; - SYS_Joystick = pNewJoystick; - return; // already in the list. - } - - pPrevJoystick = pNewJoystick; - pNewJoystick = pNewJoystick->pNext; - } - - name = GetXInputName(userid, SubType); - GetXInputDeviceInfo(userid, &vendor, &product, &version); - if (SDL_ShouldIgnoreJoystick(vendor, product, version, name) || - SDL_JoystickHandledByAnotherDriver(&SDL_WINDOWS_JoystickDriver, vendor, product, version, name)) { - return; - } - - pNewJoystick = (JoyStick_DeviceData *)SDL_calloc(1, sizeof(JoyStick_DeviceData)); - if (!pNewJoystick) { - return; // better luck next time? - } - - pNewJoystick->bXInputDevice = true; - pNewJoystick->joystickname = SDL_CreateJoystickName(vendor, product, NULL, name); - if (!pNewJoystick->joystickname) { - SDL_free(pNewJoystick); - return; // better luck next time? - } - (void)SDL_snprintf(pNewJoystick->path, sizeof(pNewJoystick->path), "XInput#%u", userid); - pNewJoystick->guid = SDL_CreateJoystickGUID(SDL_HARDWARE_BUS_USB, vendor, product, version, NULL, name, 'x', SubType); - pNewJoystick->SubType = SubType; - pNewJoystick->XInputUserId = userid; - - WINDOWS_AddJoystickDevice(pNewJoystick); -} - -void SDL_XINPUT_JoystickDetect(JoyStick_DeviceData **pContext) -{ - int iuserid; - - if (!s_bXInputEnabled) { - return; - } - - // iterate in reverse, so these are in the final list in ascending numeric order. - for (iuserid = XUSER_MAX_COUNT - 1; iuserid >= 0; iuserid--) { - const Uint8 userid = (Uint8)iuserid; - XINPUT_CAPABILITIES capabilities; - if (XINPUTGETCAPABILITIES(userid, XINPUT_FLAG_GAMEPAD, &capabilities) == ERROR_SUCCESS) { - AddXInputDevice(userid, capabilities.SubType, pContext); - } - } -} - -bool SDL_XINPUT_JoystickPresent(Uint16 vendor, Uint16 product, Uint16 version) -{ - int iuserid; - - if (!s_bXInputEnabled) { - return false; - } - - // iterate in reverse, so these are in the final list in ascending numeric order. - for (iuserid = 0; iuserid < XUSER_MAX_COUNT; ++iuserid) { - const Uint8 userid = (Uint8)iuserid; - Uint16 slot_vendor; - Uint16 slot_product; - Uint16 slot_version; - if (GetXInputDeviceInfo(userid, &slot_vendor, &slot_product, &slot_version)) { - if (vendor == slot_vendor && product == slot_product && version == slot_version) { - return true; - } - } - } - return false; -} - -bool SDL_XINPUT_JoystickOpen(SDL_Joystick *joystick, JoyStick_DeviceData *joystickdevice) -{ - const Uint8 userId = joystickdevice->XInputUserId; - XINPUT_CAPABILITIES capabilities; - XINPUT_VIBRATION state; - - SDL_assert(s_bXInputEnabled); - SDL_assert(XINPUTGETCAPABILITIES); - SDL_assert(XINPUTSETSTATE); - SDL_assert(userId < XUSER_MAX_COUNT); - - joystick->hwdata->bXInputDevice = true; - - if (XINPUTGETCAPABILITIES(userId, XINPUT_FLAG_GAMEPAD, &capabilities) != ERROR_SUCCESS) { - SDL_free(joystick->hwdata); - joystick->hwdata = NULL; - return SDL_SetError("Failed to obtain XInput device capabilities. Device disconnected?"); - } - SDL_zero(state); - joystick->hwdata->bXInputHaptic = (XINPUTSETSTATE(userId, &state) == ERROR_SUCCESS); - joystick->hwdata->userid = userId; - - // The XInput API has a hard coded button/axis mapping, so we just match it - joystick->naxes = 6; - joystick->nbuttons = 11; - joystick->nhats = 1; - - SDL_SetBooleanProperty(SDL_GetJoystickProperties(joystick), SDL_PROP_JOYSTICK_CAP_RUMBLE_BOOLEAN, true); - - return true; -} - -static void UpdateXInputJoystickBatteryInformation(SDL_Joystick *joystick, XINPUT_BATTERY_INFORMATION_EX *pBatteryInformation) -{ - SDL_PowerState state; - int percent; - switch (pBatteryInformation->BatteryType) { - case BATTERY_TYPE_WIRED: - state = SDL_POWERSTATE_CHARGING; - break; - case BATTERY_TYPE_UNKNOWN: - case BATTERY_TYPE_DISCONNECTED: - state = SDL_POWERSTATE_UNKNOWN; - break; - default: - state = SDL_POWERSTATE_ON_BATTERY; - break; - } - switch (pBatteryInformation->BatteryLevel) { - case BATTERY_LEVEL_EMPTY: - percent = 10; - break; - case BATTERY_LEVEL_LOW: - percent = 40; - break; - case BATTERY_LEVEL_MEDIUM: - percent = 70; - break; - default: - case BATTERY_LEVEL_FULL: - percent = 100; - break; - } - SDL_SendJoystickPowerInfo(joystick, state, percent); -} - -static void UpdateXInputJoystickState(SDL_Joystick *joystick, XINPUT_STATE *pXInputState, XINPUT_BATTERY_INFORMATION_EX *pBatteryInformation) -{ - static WORD s_XInputButtons[] = { - XINPUT_GAMEPAD_A, XINPUT_GAMEPAD_B, XINPUT_GAMEPAD_X, XINPUT_GAMEPAD_Y, - XINPUT_GAMEPAD_LEFT_SHOULDER, XINPUT_GAMEPAD_RIGHT_SHOULDER, XINPUT_GAMEPAD_BACK, XINPUT_GAMEPAD_START, - XINPUT_GAMEPAD_LEFT_THUMB, XINPUT_GAMEPAD_RIGHT_THUMB, - XINPUT_GAMEPAD_GUIDE - }; - WORD wButtons = pXInputState->Gamepad.wButtons; - Uint8 button; - Uint8 hat = SDL_HAT_CENTERED; - Uint64 timestamp = SDL_GetTicksNS(); - - SDL_SendJoystickAxis(timestamp, joystick, 0, pXInputState->Gamepad.sThumbLX); - SDL_SendJoystickAxis(timestamp, joystick, 1, ~pXInputState->Gamepad.sThumbLY); - SDL_SendJoystickAxis(timestamp, joystick, 2, ((int)pXInputState->Gamepad.bLeftTrigger * 257) - 32768); - SDL_SendJoystickAxis(timestamp, joystick, 3, pXInputState->Gamepad.sThumbRX); - SDL_SendJoystickAxis(timestamp, joystick, 4, ~pXInputState->Gamepad.sThumbRY); - SDL_SendJoystickAxis(timestamp, joystick, 5, ((int)pXInputState->Gamepad.bRightTrigger * 257) - 32768); - - for (button = 0; button < (Uint8)SDL_arraysize(s_XInputButtons); ++button) { - bool down = ((wButtons & s_XInputButtons[button]) != 0); - SDL_SendJoystickButton(timestamp, joystick, button, down); - } - - if (wButtons & XINPUT_GAMEPAD_DPAD_UP) { - hat |= SDL_HAT_UP; - } - if (wButtons & XINPUT_GAMEPAD_DPAD_DOWN) { - hat |= SDL_HAT_DOWN; - } - if (wButtons & XINPUT_GAMEPAD_DPAD_LEFT) { - hat |= SDL_HAT_LEFT; - } - if (wButtons & XINPUT_GAMEPAD_DPAD_RIGHT) { - hat |= SDL_HAT_RIGHT; - } - SDL_SendJoystickHat(timestamp, joystick, 0, hat); - - UpdateXInputJoystickBatteryInformation(joystick, pBatteryInformation); -} - -bool SDL_XINPUT_JoystickRumble(SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble) -{ - XINPUT_VIBRATION XVibration; - - if (!XINPUTSETSTATE) { - return SDL_Unsupported(); - } - - XVibration.wLeftMotorSpeed = low_frequency_rumble; - XVibration.wRightMotorSpeed = high_frequency_rumble; - if (XINPUTSETSTATE(joystick->hwdata->userid, &XVibration) != ERROR_SUCCESS) { - return SDL_SetError("XInputSetState() failed"); - } - return true; -} - -void SDL_XINPUT_JoystickUpdate(SDL_Joystick *joystick) -{ - DWORD result; - XINPUT_STATE XInputState; - XINPUT_BATTERY_INFORMATION_EX XBatteryInformation; - - if (!XINPUTGETSTATE) { - return; - } - - result = XINPUTGETSTATE(joystick->hwdata->userid, &XInputState); - if (result == ERROR_DEVICE_NOT_CONNECTED) { - return; - } - - SDL_zero(XBatteryInformation); - if (XINPUTGETBATTERYINFORMATION) { - result = XINPUTGETBATTERYINFORMATION(joystick->hwdata->userid, BATTERY_DEVTYPE_GAMEPAD, &XBatteryInformation); - } - -#if defined(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_XBOXSERIES) - // XInputOnGameInput doesn't ever change dwPacketNumber, so have to just update every frame - UpdateXInputJoystickState(joystick, &XInputState, &XBatteryInformation); -#else - // only fire events if the data changed from last time - if (XInputState.dwPacketNumber && XInputState.dwPacketNumber != joystick->hwdata->dwPacketNumber) { - UpdateXInputJoystickState(joystick, &XInputState, &XBatteryInformation); - joystick->hwdata->dwPacketNumber = XInputState.dwPacketNumber; - } -#endif -} - -void SDL_XINPUT_JoystickClose(SDL_Joystick *joystick) -{ -} - -void SDL_XINPUT_JoystickQuit(void) -{ - if (s_bXInputEnabled) { - s_bXInputEnabled = false; - WIN_UnloadXInputDLL(); - } -} - -// Ends C function definitions when using C++ -#ifdef __cplusplus -} -#endif - -#else // !SDL_JOYSTICK_XINPUT - -typedef struct JoyStick_DeviceData JoyStick_DeviceData; - -bool SDL_XINPUT_Enabled(void) -{ - return false; -} - -bool SDL_XINPUT_JoystickInit(void) -{ - return true; -} - -void SDL_XINPUT_JoystickDetect(JoyStick_DeviceData **pContext) -{ -} - -bool SDL_XINPUT_JoystickPresent(Uint16 vendor, Uint16 product, Uint16 version) -{ - return false; -} - -bool SDL_XINPUT_JoystickOpen(SDL_Joystick *joystick, JoyStick_DeviceData *joystickdevice) -{ - return SDL_Unsupported(); -} - -bool SDL_XINPUT_JoystickRumble(SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble) -{ - return SDL_Unsupported(); -} - -void SDL_XINPUT_JoystickUpdate(SDL_Joystick *joystick) -{ -} - -void SDL_XINPUT_JoystickClose(SDL_Joystick *joystick) -{ -} - -void SDL_XINPUT_JoystickQuit(void) -{ -} - -#endif // SDL_JOYSTICK_XINPUT diff --git a/contrib/SDL-3.2.8/src/joystick/windows/SDL_xinputjoystick_c.h b/contrib/SDL-3.2.8/src/joystick/windows/SDL_xinputjoystick_c.h deleted file mode 100644 index 305b090..0000000 --- a/contrib/SDL-3.2.8/src/joystick/windows/SDL_xinputjoystick_c.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. -*/ -#include "SDL_internal.h" - -#include "../../core/windows/SDL_xinput.h" - -// Set up for C function definitions, even when using C++ -#ifdef __cplusplus -extern "C" { -#endif - -extern bool SDL_XINPUT_Enabled(void); -extern bool SDL_XINPUT_JoystickInit(void); -extern void SDL_XINPUT_JoystickDetect(JoyStick_DeviceData **pContext); -extern bool SDL_XINPUT_JoystickPresent(Uint16 vendor, Uint16 product, Uint16 version); -extern bool SDL_XINPUT_JoystickOpen(SDL_Joystick *joystick, JoyStick_DeviceData *joystickdevice); -extern bool SDL_XINPUT_JoystickRumble(SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble); -extern void SDL_XINPUT_JoystickUpdate(SDL_Joystick *joystick); -extern void SDL_XINPUT_JoystickClose(SDL_Joystick *joystick); -extern void SDL_XINPUT_JoystickQuit(void); -extern int SDL_XINPUT_GetSteamVirtualGamepadSlot(Uint8 userid); - -// Ends C function definitions when using C++ -#ifdef __cplusplus -} -#endif -- cgit v1.2.3