diff options
Diffstat (limited to 'source/3rd-party/SDL2/src/joystick/windows')
7 files changed, 2898 insertions, 0 deletions
diff --git a/source/3rd-party/SDL2/src/joystick/windows/SDL_dinputjoystick.c b/source/3rd-party/SDL2/src/joystick/windows/SDL_dinputjoystick.c new file mode 100644 index 0000000..67d7d25 --- /dev/null +++ b/source/3rd-party/SDL2/src/joystick/windows/SDL_dinputjoystick.c @@ -0,0 +1,1155 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org> + + 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" + +#if SDL_JOYSTICK_DINPUT + +#include "SDL_windowsjoystick_c.h" +#include "SDL_dinputjoystick_c.h" +#include "SDL_xinputjoystick_c.h" +#include "../hidapi/SDL_hidapijoystick_c.h" + +#ifndef DIDFT_OPTIONAL +#define DIDFT_OPTIONAL 0x80000000 +#endif + +#define INPUT_QSIZE 32 /* Buffer up to 32 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. */ +extern HWND SDL_HelperWindow; + +/* local variables */ +static SDL_bool coinitialized = SDL_FALSE; +static LPDIRECTINPUT8 dinput = NULL; +static PRAWINPUTDEVICELIST SDL_RawDevList = NULL; +static UINT SDL_RawDevListCount = 0; + +/* Taken from Wine - Thanks! */ +static DIOBJECTDATAFORMAT dfDIJoystick2[] = { + { &GUID_XAxis, DIJOFS_X, DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 }, + { &GUID_YAxis, DIJOFS_Y, DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 }, + { &GUID_ZAxis, DIJOFS_Z, DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 }, + { &GUID_RxAxis, DIJOFS_RX, DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 }, + { &GUID_RyAxis, DIJOFS_RY, DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 }, + { &GUID_RzAxis, DIJOFS_RZ, DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 }, + { &GUID_Slider, DIJOFS_SLIDER(0), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 }, + { &GUID_Slider, DIJOFS_SLIDER(1), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 }, + { &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, 0 }, + { &GUID_YAxis, FIELD_OFFSET(DIJOYSTATE2, lVY), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 }, + { &GUID_ZAxis, FIELD_OFFSET(DIJOYSTATE2, lVZ), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 }, + { &GUID_RxAxis, FIELD_OFFSET(DIJOYSTATE2, lVRx), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 }, + { &GUID_RyAxis, FIELD_OFFSET(DIJOYSTATE2, lVRy), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 }, + { &GUID_RzAxis, FIELD_OFFSET(DIJOYSTATE2, lVRz), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 }, + { &GUID_Slider, FIELD_OFFSET(DIJOYSTATE2, rglVSlider[0]), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 }, + { &GUID_Slider, FIELD_OFFSET(DIJOYSTATE2, rglVSlider[1]), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 }, + { &GUID_XAxis, FIELD_OFFSET(DIJOYSTATE2, lAX), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 }, + { &GUID_YAxis, FIELD_OFFSET(DIJOYSTATE2, lAY), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 }, + { &GUID_ZAxis, FIELD_OFFSET(DIJOYSTATE2, lAZ), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 }, + { &GUID_RxAxis, FIELD_OFFSET(DIJOYSTATE2, lARx), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 }, + { &GUID_RyAxis, FIELD_OFFSET(DIJOYSTATE2, lARy), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 }, + { &GUID_RzAxis, FIELD_OFFSET(DIJOYSTATE2, lARz), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 }, + { &GUID_Slider, FIELD_OFFSET(DIJOYSTATE2, rglASlider[0]), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 }, + { &GUID_Slider, FIELD_OFFSET(DIJOYSTATE2, rglASlider[1]), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 }, + { &GUID_XAxis, FIELD_OFFSET(DIJOYSTATE2, lFX), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 }, + { &GUID_YAxis, FIELD_OFFSET(DIJOYSTATE2, lFY), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 }, + { &GUID_ZAxis, FIELD_OFFSET(DIJOYSTATE2, lFZ), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 }, + { &GUID_RxAxis, FIELD_OFFSET(DIJOYSTATE2, lFRx), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 }, + { &GUID_RyAxis, FIELD_OFFSET(DIJOYSTATE2, lFRy), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 }, + { &GUID_RzAxis, FIELD_OFFSET(DIJOYSTATE2, lFRz), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 }, + { &GUID_Slider, FIELD_OFFSET(DIJOYSTATE2, rglFSlider[0]), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 }, + { &GUID_Slider, FIELD_OFFSET(DIJOYSTATE2, rglFSlider[1]), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 }, +}; + +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 int +SetDIerror(const char *function, HRESULT code) +{ + /* + return SDL_SetError("%s() [%s]: %s", function, + DXGetErrorString9A(code), DXGetErrorDescription9A(code)); + */ + return SDL_SetError("%s() DirectX error 0x%8.8lx", function, code); +} + +static SDL_bool +SDL_IsXInputDevice(const GUID* pGuidProductFromDirectInput) +{ + static GUID IID_ValveStreamingGamepad = { MAKELONG(0x28DE, 0x11FF), 0x0000, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } }; + static GUID IID_X360WiredGamepad = { MAKELONG(0x045E, 0x02A1), 0x0000, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } }; + static GUID IID_X360WirelessGamepad = { MAKELONG(0x045E, 0x028E), 0x0000, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } }; + static GUID IID_XOneWiredGamepad = { MAKELONG(0x045E, 0x02FF), 0x0000, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } }; + static GUID IID_XOneWirelessGamepad = { MAKELONG(0x045E, 0x02DD), 0x0000, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } }; + static GUID IID_XOneNewWirelessGamepad = { MAKELONG(0x045E, 0x02D1), 0x0000, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } }; + static GUID IID_XOneSWirelessGamepad = { MAKELONG(0x045E, 0x02EA), 0x0000, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } }; + static GUID IID_XOneSBluetoothGamepad = { MAKELONG(0x045E, 0x02E0), 0x0000, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } }; + static GUID IID_XOneEliteWirelessGamepad = { MAKELONG(0x045E, 0x02E3), 0x0000, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } }; + + static const GUID *s_XInputProductGUID[] = { + &IID_ValveStreamingGamepad, + &IID_X360WiredGamepad, /* Microsoft's wired X360 controller for Windows. */ + &IID_X360WirelessGamepad, /* Microsoft's wireless X360 controller for Windows. */ + &IID_XOneWiredGamepad, /* Microsoft's wired Xbox One controller for Windows. */ + &IID_XOneWirelessGamepad, /* Microsoft's wireless Xbox One controller for Windows. */ + &IID_XOneNewWirelessGamepad, /* Microsoft's updated wireless Xbox One controller (w/ 3.5 mm jack) for Windows. */ + &IID_XOneSWirelessGamepad, /* Microsoft's wireless Xbox One S controller for Windows. */ + &IID_XOneSBluetoothGamepad, /* Microsoft's Bluetooth Xbox One S controller for Windows. */ + &IID_XOneEliteWirelessGamepad /* Microsoft's wireless Xbox One Elite controller for Windows. */ + }; + + size_t iDevice; + UINT i; + + if (!SDL_XINPUT_Enabled()) { + return SDL_FALSE; + } + + /* Check for well known XInput device GUIDs */ + /* This lets us skip RAWINPUT for popular devices. Also, we need to do this for the Valve Streaming Gamepad because it's virtualized and doesn't show up in the device list. */ + for (iDevice = 0; iDevice < SDL_arraysize(s_XInputProductGUID); ++iDevice) { + if (SDL_memcmp(pGuidProductFromDirectInput, s_XInputProductGUID[iDevice], sizeof(GUID)) == 0) { + return SDL_TRUE; + } + } + + /* Go through RAWINPUT (WinXP and later) to find HID devices. */ + /* Cache this if we end up using it. */ + if (SDL_RawDevList == NULL) { + if ((GetRawInputDeviceList(NULL, &SDL_RawDevListCount, sizeof(RAWINPUTDEVICELIST)) == -1) || (!SDL_RawDevListCount)) { + return SDL_FALSE; /* oh well. */ + } + + SDL_RawDevList = (PRAWINPUTDEVICELIST)SDL_malloc(sizeof(RAWINPUTDEVICELIST) * SDL_RawDevListCount); + if (SDL_RawDevList == NULL) { + SDL_OutOfMemory(); + return SDL_FALSE; + } + + if (GetRawInputDeviceList(SDL_RawDevList, &SDL_RawDevListCount, sizeof(RAWINPUTDEVICELIST)) == -1) { + SDL_free(SDL_RawDevList); + SDL_RawDevList = NULL; + return SDL_FALSE; /* oh well. */ + } + } + + for (i = 0; i < SDL_RawDevListCount; i++) { + RID_DEVICE_INFO rdi; + char devName[128]; + UINT rdiSize = sizeof(rdi); + UINT nameSize = SDL_arraysize(devName); + + rdi.cbSize = sizeof(rdi); + if ((SDL_RawDevList[i].dwType == RIM_TYPEHID) && + (GetRawInputDeviceInfoA(SDL_RawDevList[i].hDevice, RIDI_DEVICEINFO, &rdi, &rdiSize) != ((UINT)-1)) && + (MAKELONG(rdi.hid.dwVendorId, rdi.hid.dwProductId) == ((LONG)pGuidProductFromDirectInput->Data1)) && + (GetRawInputDeviceInfoA(SDL_RawDevList[i].hDevice, RIDI_DEVICENAME, devName, &nameSize) != ((UINT)-1)) && + (SDL_strstr(devName, "IG_") != NULL)) { + return SDL_TRUE; + } + } + + return SDL_FALSE; +} + +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, Uint32 duration_ms) +{ + 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 = 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; +} + +int +SDL_DINPUT_JoystickInit(void) +{ + HRESULT result; + HINSTANCE instance; + + result = WIN_CoInitialize(); + if (FAILED(result)) { + return SetDIerror("CoInitialize", result); + } + + coinitialized = SDL_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 == NULL) { + return SDL_SetError("GetModuleHandle() failed with error code %lu.", GetLastError()); + } + result = IDirectInput8_Initialize(dinput, instance, DIRECTINPUT_VERSION); + + if (FAILED(result)) { + return SetDIerror("IDirectInput::Initialize", result); + } + return 0; +} + +/* helper function for direct input, gets called for each connected joystick */ +static BOOL CALLBACK +EnumJoysticksCallback(const DIDEVICEINSTANCE * pdidInstance, VOID * pContext) +{ + JoyStick_DeviceData *pNewJoystick; + JoyStick_DeviceData *pPrevJoystick = NULL; + const DWORD devtype = (pdidInstance->dwDevType & 0xFF); + Uint16 *guid16; + Uint16 vendor = 0; + Uint16 product = 0; + Uint16 version = 0; + WCHAR hidPath[MAX_PATH]; + + if (devtype == DI8DEVTYPE_SUPPLEMENTAL) { + /* Add any supplemental devices that should be ignored here */ +#define MAKE_TABLE_ENTRY(VID, PID) ((((DWORD)PID)<<16)|VID) + static DWORD ignored_devices[] = { + MAKE_TABLE_ENTRY(0, 0) + }; +#undef MAKE_TABLE_ENTRY + unsigned int i; + + for (i = 0; i < SDL_arraysize(ignored_devices); ++i) { + if (pdidInstance->guidProduct.Data1 == ignored_devices[i]) { + return DIENUM_CONTINUE; + } + } + } + + if (SDL_IsXInputDevice(&pdidInstance->guidProduct)) { + return DIENUM_CONTINUE; /* ignore XInput devices here, keep going. */ + } + + { + HRESULT result; + LPDIRECTINPUTDEVICE8 device; + LPDIRECTINPUTDEVICE8 InputDevice; + DIPROPGUIDANDPATH dipdw2; + + result = IDirectInput8_CreateDevice(dinput, &(pdidInstance->guidInstance), &device, NULL); + if (FAILED(result)) { + return DIENUM_CONTINUE; /* better luck next time? */ + } + + /* Now get the IDirectInputDevice8 interface, instead. */ + result = IDirectInputDevice8_QueryInterface(device, &IID_IDirectInputDevice8, (LPVOID *)&InputDevice); + /* We are done with this object. Use the stored one from now on. */ + IDirectInputDevice8_Release(device); + if (FAILED(result)) { + return DIENUM_CONTINUE; /* better luck next time? */ + } + dipdw2.diph.dwSize = sizeof(dipdw2); + dipdw2.diph.dwHeaderSize = sizeof(dipdw2.diph); + dipdw2.diph.dwObj = 0; // device property + dipdw2.diph.dwHow = DIPH_DEVICE; + + result = IDirectInputDevice8_GetProperty(InputDevice, DIPROP_GUIDANDPATH, &dipdw2.diph); + IDirectInputDevice8_Release(InputDevice); + if (FAILED(result)) { + return DIENUM_CONTINUE; /* better luck next time? */ + } + + /* Get device path, compare that instead of GUID, additionally update GUIDs of joysticks with matching paths, in case they're not open yet. */ + SDL_wcslcpy(hidPath, dipdw2.wszPath, SDL_arraysize(hidPath)); + } + + pNewJoystick = *(JoyStick_DeviceData **)pContext; + while (pNewJoystick) { + if (SDL_wcscmp(pNewJoystick->hidPath, 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 + pNewJoystick->dxdevice = *pdidInstance; + + pNewJoystick->pNext = SYS_Joystick; + SYS_Joystick = pNewJoystick; + + return DIENUM_CONTINUE; /* already have this joystick loaded, just keep going */ + } + + pPrevJoystick = pNewJoystick; + pNewJoystick = pNewJoystick->pNext; + } + + pNewJoystick = (JoyStick_DeviceData *)SDL_malloc(sizeof(JoyStick_DeviceData)); + if (!pNewJoystick) { + return DIENUM_CONTINUE; /* better luck next time? */ + } + + SDL_zerop(pNewJoystick); + SDL_wcslcpy(pNewJoystick->hidPath, hidPath, SDL_arraysize(pNewJoystick->hidPath)); + pNewJoystick->joystickname = WIN_StringToUTF8(pdidInstance->tszProductName); + if (!pNewJoystick->joystickname) { + SDL_free(pNewJoystick); + return DIENUM_CONTINUE; /* better luck next time? */ + } + + SDL_memcpy(&(pNewJoystick->dxdevice), pdidInstance, + sizeof(DIDEVICEINSTANCE)); + + SDL_memset(pNewJoystick->guid.data, 0, sizeof(pNewJoystick->guid.data)); + + guid16 = (Uint16 *)pNewJoystick->guid.data; + if (SDL_memcmp(&pdidInstance->guidProduct.Data4[2], "PIDVID", 6) == 0) { + vendor = (Uint16)LOWORD(pdidInstance->guidProduct.Data1); + product = (Uint16)HIWORD(pdidInstance->guidProduct.Data1); + version = 0; + + *guid16++ = SDL_SwapLE16(SDL_HARDWARE_BUS_USB); + *guid16++ = 0; + *guid16++ = SDL_SwapLE16(vendor); + *guid16++ = 0; + *guid16++ = SDL_SwapLE16(product); + *guid16++ = 0; + *guid16++ = SDL_SwapLE16(version); + *guid16++ = 0; + } else { + *guid16++ = SDL_SwapLE16(SDL_HARDWARE_BUS_BLUETOOTH); + *guid16++ = 0; + SDL_strlcpy((char*)guid16, pNewJoystick->joystickname, sizeof(pNewJoystick->guid.data) - 4); + } + + if (SDL_ShouldIgnoreJoystick(pNewJoystick->joystickname, pNewJoystick->guid)) { + SDL_free(pNewJoystick); + return DIENUM_CONTINUE; + } + +#ifdef SDL_JOYSTICK_HIDAPI + if (HIDAPI_IsDevicePresent(vendor, product, 0)) { + /* The HIDAPI driver is taking care of this device */ + SDL_free(pNewJoystick); + return DIENUM_CONTINUE; + } +#endif + + WINDOWS_AddJoystickDevice(pNewJoystick); + + return DIENUM_CONTINUE; /* get next device, please */ +} + +void +SDL_DINPUT_JoystickDetect(JoyStick_DeviceData **pContext) +{ + IDirectInput8_EnumDevices(dinput, DI8DEVCLASS_GAMECTRL, EnumJoysticksCallback, pContext, DIEDFL_ATTACHEDONLY); + + if (SDL_RawDevList) { + SDL_free(SDL_RawDevList); /* in case we used this in DirectInput detection */ + SDL_RawDevList = NULL; + } + SDL_RawDevListCount = 0; +} + +static BOOL CALLBACK +EnumDevObjectsCallback(LPCDIDEVICEOBJECTINSTANCE dev, LPVOID pvRef) +{ + SDL_Joystick *joystick = (SDL_Joystick *)pvRef; + HRESULT result; + input_t *in = &joystick->hwdata->Inputs[joystick->hwdata->NumInputs]; + + if (dev->dwType & DIDFT_BUTTON) { + in->type = BUTTON; + in->num = joystick->nbuttons; + in->ofs = DIJOFS_BUTTON(in->num); + joystick->nbuttons++; + } else if (dev->dwType & DIDFT_POV) { + in->type = HAT; + in->num = joystick->nhats; + in->ofs = DIJOFS_POV(in->num); + joystick->nhats++; + } else if (dev->dwType & DIDFT_AXIS) { + DIPROPRANGE diprg; + DIPROPDWORD dilong; + + in->type = AXIS; + in->num = joystick->naxes; + if (!SDL_memcmp(&dev->guidType, &GUID_XAxis, sizeof(dev->guidType))) + in->ofs = DIJOFS_X; + else if (!SDL_memcmp(&dev->guidType, &GUID_YAxis, sizeof(dev->guidType))) + in->ofs = DIJOFS_Y; + else if (!SDL_memcmp(&dev->guidType, &GUID_ZAxis, sizeof(dev->guidType))) + in->ofs = DIJOFS_Z; + else if (!SDL_memcmp(&dev->guidType, &GUID_RxAxis, sizeof(dev->guidType))) + in->ofs = DIJOFS_RX; + else if (!SDL_memcmp(&dev->guidType, &GUID_RyAxis, sizeof(dev->guidType))) + in->ofs = DIJOFS_RY; + else if (!SDL_memcmp(&dev->guidType, &GUID_RzAxis, sizeof(dev->guidType))) + in->ofs = DIJOFS_RZ; + else if (!SDL_memcmp(&dev->guidType, &GUID_Slider, sizeof(dev->guidType))) { + 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 = dev->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 = dev->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 +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; + int nButtons = 0; + int nHats = 0; + int 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; + } + } +} + +int +SDL_DINPUT_JoystickOpen(SDL_Joystick * joystick, JoyStick_DeviceData *joystickdevice) +{ + HRESULT result; + LPDIRECTINPUTDEVICE8 device; + DIPROPDWORD dipdw; + + joystick->hwdata->buffered = SDL_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), &device, NULL); + if (FAILED(result)) { + return SetDIerror("IDirectInput::CreateDevice", result); + } + + /* Now get the IDirectInputDevice8 interface, instead. */ + result = IDirectInputDevice8_QueryInterface(device, + &IID_IDirectInputDevice8, + (LPVOID *)& joystick-> + hwdata->InputDevice); + /* We are done with this object. Use the stored one from now on. */ + IDirectInputDevice8_Release(device); + + if (FAILED(result)) { + return SetDIerror("IDirectInputDevice8::QueryInterface", 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); + } + */ + } + + /* 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 = SDL_FALSE; + } else if (FAILED(result)) { + return SetDIerror("IDirectInputDevice8::SetProperty", result); + } + return 0; +} + +static int +SDL_DINPUT_JoystickInitRumble(SDL_Joystick * joystick, Sint16 magnitude, Uint32 duration_ms) +{ + 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, duration_ms); + if (!joystick->hwdata->ffeffect) { + return SDL_OutOfMemory(); + } + + 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 0; +} + +int +SDL_DINPUT_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms) +{ + 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); + joystick->hwdata->ffeffect->dwDuration = duration_ms * 1000; /* In microseconds. */ + 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, duration_ms) < 0) { + return -1; + } + joystick->hwdata->ff_initialized = SDL_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 0; +} + +static Uint8 +TranslatePOV(DWORD value) +{ + const int 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]; +} + +static void +UpdateDINPUTJoystickState_Buffered(SDL_Joystick * joystick) +{ + int i; + HRESULT result; + DWORD numevents; + DIDEVICEOBJECTDATA evtbuf[INPUT_QSIZE]; + + 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_PrivateJoystickAxis(joystick, in->num, (Sint16)evtbuf[i].dwData); + break; + case BUTTON: + SDL_PrivateJoystickButton(joystick, in->num, + (Uint8)(evtbuf[i].dwData ? SDL_PRESSED : SDL_RELEASED)); + break; + case HAT: + { + Uint8 pos = TranslatePOV(evtbuf[i].dwData); + SDL_PrivateJoystickHat(joystick, in->num, pos); + } + break; + } + } + } +} + +/* 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; + + 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_PrivateJoystickAxis(joystick, in->num, (Sint16)state.lX); + break; + case DIJOFS_Y: + SDL_PrivateJoystickAxis(joystick, in->num, (Sint16)state.lY); + break; + case DIJOFS_Z: + SDL_PrivateJoystickAxis(joystick, in->num, (Sint16)state.lZ); + break; + case DIJOFS_RX: + SDL_PrivateJoystickAxis(joystick, in->num, (Sint16)state.lRx); + break; + case DIJOFS_RY: + SDL_PrivateJoystickAxis(joystick, in->num, (Sint16)state.lRy); + break; + case DIJOFS_RZ: + SDL_PrivateJoystickAxis(joystick, in->num, (Sint16)state.lRz); + break; + case DIJOFS_SLIDER(0): + SDL_PrivateJoystickAxis(joystick, in->num, (Sint16)state.rglSlider[0]); + break; + case DIJOFS_SLIDER(1): + SDL_PrivateJoystickAxis(joystick, in->num, (Sint16)state.rglSlider[1]); + break; + } + break; + + case BUTTON: + SDL_PrivateJoystickButton(joystick, in->num, + (Uint8)(state.rgbButtons[in->ofs - DIJOFS_BUTTON0] ? SDL_PRESSED : SDL_RELEASED)); + break; + case HAT: + { + Uint8 pos = TranslatePOV(state.rgdwPOV[in->ofs - DIJOFS_POV(0)]); + SDL_PrivateJoystickHat(joystick, in->num, pos); + break; + } + } + } +} + +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->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 = SDL_FALSE; +} + +void +SDL_DINPUT_JoystickQuit(void) +{ + if (dinput != NULL) { + IDirectInput8_Release(dinput); + dinput = NULL; + } + + if (coinitialized) { + WIN_CoUninitialize(); + coinitialized = SDL_FALSE; + } +} + +#else /* !SDL_JOYSTICK_DINPUT */ + +typedef struct JoyStick_DeviceData JoyStick_DeviceData; + +int +SDL_DINPUT_JoystickInit(void) +{ + return 0; +} + +void +SDL_DINPUT_JoystickDetect(JoyStick_DeviceData **pContext) +{ +} + +int +SDL_DINPUT_JoystickOpen(SDL_Joystick * joystick, JoyStick_DeviceData *joystickdevice) +{ + return SDL_Unsupported(); +} + +int +SDL_DINPUT_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms) +{ + 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 */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/source/3rd-party/SDL2/src/joystick/windows/SDL_dinputjoystick_c.h b/source/3rd-party/SDL2/src/joystick/windows/SDL_dinputjoystick_c.h new file mode 100644 index 0000000..9f29fc7 --- /dev/null +++ b/source/3rd-party/SDL2/src/joystick/windows/SDL_dinputjoystick_c.h @@ -0,0 +1,31 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org> + + 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" + +extern int SDL_DINPUT_JoystickInit(void); +extern void SDL_DINPUT_JoystickDetect(JoyStick_DeviceData **pContext); +extern int SDL_DINPUT_JoystickOpen(SDL_Joystick * joystick, JoyStick_DeviceData *joystickdevice); +extern int SDL_DINPUT_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms); +extern void SDL_DINPUT_JoystickUpdate(SDL_Joystick * joystick); +extern void SDL_DINPUT_JoystickClose(SDL_Joystick * joystick); +extern void SDL_DINPUT_JoystickQuit(void); + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/source/3rd-party/SDL2/src/joystick/windows/SDL_mmjoystick.c b/source/3rd-party/SDL2/src/joystick/windows/SDL_mmjoystick.c new file mode 100644 index 0000000..60e3fcb --- /dev/null +++ b/source/3rd-party/SDL2/src/joystick/windows/SDL_mmjoystick.c @@ -0,0 +1,452 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org> + + 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_WINMM + +/* Win32 MultiMedia Joystick driver, contributed by Andrei de A. Formiga */ + +#include "../../core/windows/SDL_windows.h" +#include <mmsystem.h> +#include <regstr.h> + +#include "SDL_events.h" +#include "SDL_joystick.h" +#include "../SDL_sysjoystick.h" +#include "../SDL_joystick_c.h" + +#ifdef REGSTR_VAL_JOYOEMNAME +#undef REGSTR_VAL_JOYOEMNAME +#endif +#define REGSTR_VAL_JOYOEMNAME "OEMName" + +#define MAX_JOYSTICKS 16 +#define MAX_AXES 6 /* each joystick can have up to 6 axes */ +#define MAX_BUTTONS 32 /* and 32 buttons */ +#define JOY_BUTTON_FLAG(n) (1<<n) + + +/* array to hold joystick ID values */ +static UINT SYS_JoystickID[MAX_JOYSTICKS]; +static JOYCAPSA SYS_Joystick[MAX_JOYSTICKS]; +static char *SYS_JoystickName[MAX_JOYSTICKS]; + +/* The private structure used to keep track of a joystick */ +struct joystick_hwdata +{ + /* joystick ID */ + UINT id; + + /* values used to translate device-specific coordinates into + SDL-standard ranges */ + struct _transaxis + { + int offset; + float scale; + } transaxis[6]; +}; + +/* Convert a Windows Multimedia API return code to a text message */ +static void SetMMerror(char *function, int code); + + +static char * +GetJoystickName(int index, const char *szRegKey) +{ + /* added 7/24/2004 by Eckhard Stolberg */ + /* + see if there is a joystick for the current + index (1-16) listed in the registry + */ + char *name = NULL; + HKEY hTopKey; + HKEY hKey; + DWORD regsize; + LONG regresult; + char regkey[256]; + char regvalue[256]; + char regname[256]; + + SDL_snprintf(regkey, SDL_arraysize(regkey), +#ifdef UNICODE + "%S\\%s\\%S", +#else + "%s\\%s\\%s", +#endif + REGSTR_PATH_JOYCONFIG, szRegKey, REGSTR_KEY_JOYCURR); + hTopKey = HKEY_LOCAL_MACHINE; + regresult = RegOpenKeyExA(hTopKey, regkey, 0, KEY_READ, &hKey); + if (regresult != ERROR_SUCCESS) { + hTopKey = HKEY_CURRENT_USER; + regresult = RegOpenKeyExA(hTopKey, regkey, 0, KEY_READ, &hKey); + } + if (regresult != ERROR_SUCCESS) { + return NULL; + } + + /* find the registry key name for the joystick's properties */ + regsize = sizeof(regname); + SDL_snprintf(regvalue, SDL_arraysize(regvalue), "Joystick%d%s", index + 1, + REGSTR_VAL_JOYOEMNAME); + regresult = + RegQueryValueExA(hKey, regvalue, 0, 0, (LPBYTE) regname, ®size); + RegCloseKey(hKey); + + if (regresult != ERROR_SUCCESS) { + return NULL; + } + + /* open that registry key */ + SDL_snprintf(regkey, SDL_arraysize(regkey), +#ifdef UNICODE + "%S\\%s", +#else + "%s\\%s", +#endif + REGSTR_PATH_JOYOEM, regname); + regresult = RegOpenKeyExA(hTopKey, regkey, 0, KEY_READ, &hKey); + if (regresult != ERROR_SUCCESS) { + return NULL; + } + + /* find the size for the OEM name text */ + regsize = sizeof(regvalue); + regresult = + RegQueryValueExA(hKey, REGSTR_VAL_JOYOEMNAME, 0, 0, NULL, ®size); + if (regresult == ERROR_SUCCESS) { + /* allocate enough memory for the OEM name text ... */ + name = (char *) SDL_malloc(regsize); + if (name) { + /* ... and read it from the registry */ + regresult = RegQueryValueExA(hKey, + REGSTR_VAL_JOYOEMNAME, 0, 0, + (LPBYTE) name, ®size); + } + } + RegCloseKey(hKey); + + return (name); +} + +static int SDL_SYS_numjoysticks = 0; + +/* Function to scan the system for joysticks. + * Joystick 0 should be the system default joystick. + * It should return 0, or -1 on an unrecoverable fatal error. + */ +int +SDL_SYS_JoystickInit(void) +{ + int i; + int maxdevs; + JOYINFOEX joyinfo; + JOYCAPSA joycaps; + MMRESULT result; + + /* Reset the joystick ID & name mapping tables */ + for (i = 0; i < MAX_JOYSTICKS; ++i) { + SYS_JoystickID[i] = 0; + SYS_JoystickName[i] = NULL; + } + + /* Loop over all potential joystick devices */ + SDL_SYS_numjoysticks = 0; + maxdevs = joyGetNumDevs(); + for (i = JOYSTICKID1; i < maxdevs && SDL_SYS_numjoysticks < MAX_JOYSTICKS; ++i) { + + joyinfo.dwSize = sizeof(joyinfo); + joyinfo.dwFlags = JOY_RETURNALL; + result = joyGetPosEx(i, &joyinfo); + if (result == JOYERR_NOERROR) { + result = joyGetDevCapsA(i, &joycaps, sizeof(joycaps)); + if (result == JOYERR_NOERROR) { + SYS_JoystickID[SDL_SYS_numjoysticks] = i; + SYS_Joystick[SDL_SYS_numjoysticks] = joycaps; + SYS_JoystickName[SDL_SYS_numjoysticks] = + GetJoystickName(i, joycaps.szRegKey); + SDL_SYS_numjoysticks++; + } + } + } + return (SDL_SYS_numjoysticks); +} + +int +SDL_SYS_NumJoysticks(void) +{ + return SDL_SYS_numjoysticks; +} + +void +SDL_SYS_JoystickDetect(void) +{ +} + +/* Function to get the device-dependent name of a joystick */ +const char * +SDL_SYS_JoystickNameForDeviceIndex(int device_index) +{ + if (SYS_JoystickName[device_index] != NULL) { + return (SYS_JoystickName[device_index]); + } else { + return (SYS_Joystick[device_index].szPname); + } +} + +/* Function to perform the mapping from device index to the instance id for this index */ +SDL_JoystickID SDL_SYS_GetInstanceIdOfDeviceIndex(int device_index) +{ + return device_index; +} + +/* 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. + */ +int +SDL_SYS_JoystickOpen(SDL_Joystick * joystick, int device_index) +{ + int index, i; + int caps_flags[MAX_AXES - 2] = + { JOYCAPS_HASZ, JOYCAPS_HASR, JOYCAPS_HASU, JOYCAPS_HASV }; + int axis_min[MAX_AXES], axis_max[MAX_AXES]; + + + /* shortcut */ + index = device_index; + axis_min[0] = SYS_Joystick[index].wXmin; + axis_max[0] = SYS_Joystick[index].wXmax; + axis_min[1] = SYS_Joystick[index].wYmin; + axis_max[1] = SYS_Joystick[index].wYmax; + axis_min[2] = SYS_Joystick[index].wZmin; + axis_max[2] = SYS_Joystick[index].wZmax; + axis_min[3] = SYS_Joystick[index].wRmin; + axis_max[3] = SYS_Joystick[index].wRmax; + axis_min[4] = SYS_Joystick[index].wUmin; + axis_max[4] = SYS_Joystick[index].wUmax; + axis_min[5] = SYS_Joystick[index].wVmin; + axis_max[5] = SYS_Joystick[index].wVmax; + + /* allocate memory for system specific hardware data */ + joystick->instance_id = device_index; + joystick->hwdata = + (struct joystick_hwdata *) SDL_malloc(sizeof(*joystick->hwdata)); + if (joystick->hwdata == NULL) { + return SDL_OutOfMemory(); + } + SDL_memset(joystick->hwdata, 0, sizeof(*joystick->hwdata)); + + /* set hardware data */ + joystick->hwdata->id = SYS_JoystickID[index]; + for (i = 0; i < MAX_AXES; ++i) { + if ((i < 2) || (SYS_Joystick[index].wCaps & caps_flags[i - 2])) { + joystick->hwdata->transaxis[i].offset = SDL_JOYSTICK_AXIS_MIN - axis_min[i]; + joystick->hwdata->transaxis[i].scale = + (float) (SDL_JOYSTICK_AXIS_MAX - SDL_JOYSTICK_AXIS_MIN) / (axis_max[i] - axis_min[i]); + } else { + joystick->hwdata->transaxis[i].offset = 0; + joystick->hwdata->transaxis[i].scale = 1.0; /* Just in case */ + } + } + + /* fill nbuttons, naxes, and nhats fields */ + joystick->nbuttons = SYS_Joystick[index].wNumButtons; + joystick->naxes = SYS_Joystick[index].wNumAxes; + if (SYS_Joystick[index].wCaps & JOYCAPS_HASPOV) { + joystick->nhats = 1; + } else { + joystick->nhats = 0; + } + return (0); +} + +static Uint8 +TranslatePOV(DWORD value) +{ + Uint8 pos; + + pos = SDL_HAT_CENTERED; + if (value != JOY_POVCENTERED) { + if ((value > JOY_POVLEFT) || (value < JOY_POVRIGHT)) { + pos |= SDL_HAT_UP; + } + if ((value > JOY_POVFORWARD) && (value < JOY_POVBACKWARD)) { + pos |= SDL_HAT_RIGHT; + } + if ((value > JOY_POVRIGHT) && (value < JOY_POVLEFT)) { + pos |= SDL_HAT_DOWN; + } + if (value > JOY_POVBACKWARD) { + pos |= SDL_HAT_LEFT; + } + } + return (pos); +} + +/* 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. + */ +void +SDL_SYS_JoystickUpdate(SDL_Joystick * joystick) +{ + MMRESULT result; + int i; + DWORD flags[MAX_AXES] = { JOY_RETURNX, JOY_RETURNY, JOY_RETURNZ, + JOY_RETURNR, JOY_RETURNU, JOY_RETURNV + }; + DWORD pos[MAX_AXES]; + struct _transaxis *transaxis; + int value; + JOYINFOEX joyinfo; + + joyinfo.dwSize = sizeof(joyinfo); + joyinfo.dwFlags = JOY_RETURNALL | JOY_RETURNPOVCTS; + if (!joystick->hats) { + joyinfo.dwFlags &= ~(JOY_RETURNPOV | JOY_RETURNPOVCTS); + } + result = joyGetPosEx(joystick->hwdata->id, &joyinfo); + if (result != JOYERR_NOERROR) { + SetMMerror("joyGetPosEx", result); + return; + } + + /* joystick motion events */ + pos[0] = joyinfo.dwXpos; + pos[1] = joyinfo.dwYpos; + pos[2] = joyinfo.dwZpos; + pos[3] = joyinfo.dwRpos; + pos[4] = joyinfo.dwUpos; + pos[5] = joyinfo.dwVpos; + + transaxis = joystick->hwdata->transaxis; + for (i = 0; i < joystick->naxes; i++) { + if (joyinfo.dwFlags & flags[i]) { + value = (int) (((float) pos[i] + transaxis[i].offset) * transaxis[i].scale); + SDL_PrivateJoystickAxis(joystick, (Uint8) i, (Sint16) value); + } + } + + /* joystick button events */ + if (joyinfo.dwFlags & JOY_RETURNBUTTONS) { + for (i = 0; i < joystick->nbuttons; ++i) { + if (joyinfo.dwButtons & JOY_BUTTON_FLAG(i)) { + SDL_PrivateJoystickButton(joystick, (Uint8) i, SDL_PRESSED); + } else { + SDL_PrivateJoystickButton(joystick, (Uint8) i, SDL_RELEASED); + } + } + } + + /* joystick hat events */ + if (joyinfo.dwFlags & JOY_RETURNPOV) { + SDL_PrivateJoystickHat(joystick, 0, TranslatePOV(joyinfo.dwPOV)); + } +} + +/* Function to close a joystick after use */ +void +SDL_SYS_JoystickClose(SDL_Joystick * joystick) +{ + SDL_free(joystick->hwdata); +} + +/* Function to perform any system-specific joystick related cleanup */ +void +SDL_SYS_JoystickQuit(void) +{ + int i; + for (i = 0; i < MAX_JOYSTICKS; i++) { + SDL_free(SYS_JoystickName[i]); + SYS_JoystickName[i] = NULL; + } +} + +SDL_JoystickGUID SDL_SYS_JoystickGetDeviceGUID( int device_index ) +{ + SDL_JoystickGUID guid; + /* the GUID is just the first 16 chars of the name for now */ + const char *name = SDL_SYS_JoystickNameForDeviceIndex( device_index ); + SDL_zero( guid ); + SDL_memcpy( &guid, name, SDL_min( sizeof(guid), SDL_strlen( name ) ) ); + return guid; +} + +SDL_JoystickGUID SDL_SYS_JoystickGetGUID(SDL_Joystick * joystick) +{ + SDL_JoystickGUID guid; + /* the GUID is just the first 16 chars of the name for now */ + const char *name = joystick->name; + SDL_zero( guid ); + SDL_memcpy( &guid, name, SDL_min( sizeof(guid), SDL_strlen( name ) ) ); + return guid; +} + + +/* implementation functions */ +void +SetMMerror(char *function, int code) +{ + static char *error; + static char errbuf[1024]; + + errbuf[0] = 0; + switch (code) { + case MMSYSERR_NODRIVER: + error = "Joystick driver not present"; + break; + + case MMSYSERR_INVALPARAM: + case JOYERR_PARMS: + error = "Invalid parameter(s)"; + break; + + case MMSYSERR_BADDEVICEID: + error = "Bad device ID"; + break; + + case JOYERR_UNPLUGGED: + error = "Joystick not attached"; + break; + + case JOYERR_NOCANDO: + error = "Can't capture joystick input"; + break; + + default: + SDL_snprintf(errbuf, SDL_arraysize(errbuf), + "%s: Unknown Multimedia system error: 0x%x", + function, code); + break; + } + + if (!errbuf[0]) { + SDL_snprintf(errbuf, SDL_arraysize(errbuf), "%s: %s", function, + error); + } + SDL_SetError("%s", errbuf); +} + +#endif /* SDL_JOYSTICK_WINMM */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/source/3rd-party/SDL2/src/joystick/windows/SDL_windowsjoystick.c b/source/3rd-party/SDL2/src/joystick/windows/SDL_windowsjoystick.c new file mode 100644 index 0000000..71b72e6 --- /dev/null +++ b/source/3rd-party/SDL2/src/joystick/windows/SDL_windowsjoystick.c @@ -0,0 +1,571 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org> + + 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 SDL_JOYSTICK_DINPUT || 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_error.h" +#include "SDL_assert.h" +#include "SDL_events.h" +#include "SDL_timer.h" +#include "SDL_mutex.h" +#include "SDL_joystick.h" +#include "../SDL_sysjoystick.h" +#include "../../thread/SDL_systhread.h" +#include "../../core/windows/SDL_windows.h" +#if !defined(__WINRT__) +#include <dbt.h> +#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 "../../haptic/windows/SDL_dinputhaptic_c.h" /* For haptic hot plugging */ +#include "../../haptic/windows/SDL_xinputhaptic_c.h" /* For haptic hot plugging */ + + +#ifndef DEVICE_NOTIFY_WINDOW_HANDLE +#define DEVICE_NOTIFY_WINDOW_HANDLE 0x00000000 +#endif + +/* local variables */ +static SDL_bool s_bDeviceAdded = SDL_FALSE; +static SDL_bool s_bDeviceRemoved = SDL_FALSE; +static SDL_cond *s_condJoystickThread = NULL; +static SDL_mutex *s_mutexJoyStickEnum = NULL; +static SDL_Thread *s_threadJoystick = NULL; +static SDL_bool s_bJoystickThreadQuit = SDL_FALSE; + +JoyStick_DeviceData *SYS_Joystick; /* array to hold joystick ID values */ + +static SDL_bool s_bWindowsDeviceChanged = SDL_FALSE; + +#ifdef __WINRT__ + +typedef struct +{ + int unused; +} SDL_DeviceNotificationData; + +static void +SDL_CleanupDeviceNotification(SDL_DeviceNotificationData *data) +{ +} + +static int +SDL_CreateDeviceNotification(SDL_DeviceNotificationData *data) +{ + return 0; +} + +static SDL_bool +SDL_WaitForDeviceNotification(SDL_DeviceNotificationData *data, SDL_mutex *mutex) +{ + return SDL_FALSE; +} + +#else /* !__WINRT__ */ + +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 message, WPARAM wParam, LPARAM lParam) +{ + switch (message) { + 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 0; + case WM_TIMER: + KillTimer(hwnd, wParam); + s_bWindowsDeviceChanged = SDL_TRUE; + return 0; + } + + return DefWindowProc (hwnd, message, wParam, lParam); +} + +static void +SDL_CleanupDeviceNotification(SDL_DeviceNotificationData *data) +{ + 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 int +SDL_CreateDeviceNotification(SDL_DeviceNotificationData *data) +{ + DEV_BROADCAST_DEVICEINTERFACE dbh; + GUID GUID_DEVINTERFACE_HID = { 0x4D1E55B2L, 0xF16F, 0x11CF, { 0x88, 0xCB, 0x00, 0x11, 0x11, 0x00, 0x00, 0x30 } }; + + SDL_zerop(data); + + data->coinitialized = WIN_CoInitialize(); + + data->wincl.hInstance = GetModuleHandle(NULL); + data->wincl.lpszClassName = L"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 -1; + } + + data->messageWindow = (HWND)CreateWindowEx(0, L"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 -1; + } + + 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 -1; + } + return 0; +} + +static SDL_bool +SDL_WaitForDeviceNotification(SDL_DeviceNotificationData *data, SDL_mutex *mutex) +{ + MSG msg; + int lastret = 1; + + if (!data->messageWindow) { + return SDL_FALSE; /* device notifications require a window */ + } + + SDL_UnlockMutex(mutex); + while (lastret > 0 && s_bWindowsDeviceChanged == SDL_FALSE) { + 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) ? SDL_TRUE : SDL_FALSE; +} + +#endif /* __WINRT__ */ + +/* Function/thread to scan the system for joysticks. */ +static int +SDL_JoystickThread(void *_data) +{ + SDL_DeviceNotificationData notification_data; + +#if SDL_JOYSTICK_XINPUT + SDL_bool bOpenedXInputDevices[XUSER_MAX_COUNT]; + SDL_zero(bOpenedXInputDevices); +#endif + + if (SDL_CreateDeviceNotification(¬ification_data) < 0) { + return -1; + } + + SDL_LockMutex(s_mutexJoyStickEnum); + while (s_bJoystickThreadQuit == SDL_FALSE) { + SDL_bool bXInputChanged = SDL_FALSE; + + if (SDL_WaitForDeviceNotification(¬ification_data, s_mutexJoyStickEnum) == SDL_FALSE) { +#if SDL_JOYSTICK_XINPUT + /* WM_DEVICECHANGE not working, poll for new XINPUT controllers */ + SDL_CondWaitTimeout(s_condJoystickThread, s_mutexJoyStickEnum, 1000); + if (SDL_XINPUT_Enabled() && XINPUTGETCAPABILITIES) { + /* 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 SDL_bool available = (result == ERROR_SUCCESS); + if (bOpenedXInputDevices[userId] != available) { + bXInputChanged = SDL_TRUE; + bOpenedXInputDevices[userId] = available; + } + } + } +#else + /* WM_DEVICECHANGE not working, no XINPUT, no point in keeping thread alive */ + break; +#endif /* SDL_JOYSTICK_XINPUT */ + } + + if (s_bWindowsDeviceChanged || bXInputChanged) { + s_bDeviceRemoved = SDL_TRUE; + s_bDeviceAdded = SDL_TRUE; + s_bWindowsDeviceChanged = SDL_FALSE; + } + } + SDL_UnlockMutex(s_mutexJoyStickEnum); + + SDL_CleanupDeviceNotification(¬ification_data); + + return 1; +} + +void WINDOWS_AddJoystickDevice(JoyStick_DeviceData *device) +{ + device->send_add_event = SDL_TRUE; + device->nInstanceID = SDL_GetNextJoystickInstanceID(); + device->pNext = SYS_Joystick; + SYS_Joystick = device; + + s_bDeviceAdded = SDL_TRUE; +} + +static void WINDOWS_JoystickDetect(void); +static void WINDOWS_JoystickQuit(void); + +/* Function to scan the system for joysticks. + * Joystick 0 should be the system default joystick. + * It should return 0, or -1 on an unrecoverable fatal error. + */ +static int +WINDOWS_JoystickInit(void) +{ + if (SDL_DINPUT_JoystickInit() < 0) { + WINDOWS_JoystickQuit(); + return -1; + } + + if (SDL_XINPUT_JoystickInit() < 0) { + WINDOWS_JoystickQuit(); + return -1; + } + + s_mutexJoyStickEnum = SDL_CreateMutex(); + s_condJoystickThread = SDL_CreateCond(); + s_bDeviceAdded = SDL_TRUE; /* force a scan of the system for joysticks this first time */ + + WINDOWS_JoystickDetect(); + + if (!s_threadJoystick) { + /* spin up the thread to detect hotplug of devices */ + s_bJoystickThreadQuit = SDL_FALSE; + s_threadJoystick = SDL_CreateThreadInternal(SDL_JoystickThread, "SDL_joystick", 64 * 1024, NULL); + } + return 0; +} + +/* 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 */ +static void +WINDOWS_JoystickDetect(void) +{ + JoyStick_DeviceData *pCurList = NULL; + + /* only enum the devices if the joystick thread told us something changed */ + if (!s_bDeviceAdded && !s_bDeviceRemoved) { + return; /* thread hasn't signaled, nothing to do right now. */ + } + + SDL_LockMutex(s_mutexJoyStickEnum); + + s_bDeviceAdded = SDL_FALSE; + s_bDeviceRemoved = SDL_FALSE; + + 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); + + SDL_UnlockMutex(s_mutexJoyStickEnum); + + while (pCurList) { + JoyStick_DeviceData *pListNext = NULL; + + if (pCurList->bXInputDevice) { + SDL_XINPUT_MaybeRemoveDevice(pCurList->XInputUserId); + } else { + SDL_DINPUT_MaybeRemoveDevice(&pCurList->dxdevice); + } + + SDL_PrivateJoystickRemoved(pCurList->nInstanceID); + + pListNext = pCurList->pNext; + SDL_free(pCurList->joystickname); + SDL_free(pCurList); + pCurList = pListNext; + } + + if (s_bDeviceAdded) { + JoyStick_DeviceData *pNewJoystick; + int device_index = 0; + s_bDeviceAdded = SDL_FALSE; + pNewJoystick = SYS_Joystick; + while (pNewJoystick) { + if (pNewJoystick->send_add_event) { + if (pNewJoystick->bXInputDevice) { + SDL_XINPUT_MaybeAddDevice(pNewJoystick->XInputUserId); + } else { + SDL_DINPUT_MaybeAddDevice(&pNewJoystick->dxdevice); + } + + SDL_PrivateJoystickAdded(pNewJoystick->nInstanceID); + + pNewJoystick->send_add_event = SDL_FALSE; + } + device_index++; + pNewJoystick = pNewJoystick->pNext; + } + } +} + +/* Function to get the device-dependent name of a joystick */ +static const char * +WINDOWS_JoystickGetDeviceName(int device_index) +{ + JoyStick_DeviceData *device = SYS_Joystick; + + for (; device_index > 0; device_index--) + device = device->pNext; + + return device->joystickname; +} + +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; +} + +/* return the stable device guid for this device index */ +static SDL_JoystickGUID +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 int +WINDOWS_JoystickOpen(SDL_Joystick * joystick, int device_index) +{ + JoyStick_DeviceData *joystickdevice = SYS_Joystick; + + for (; device_index > 0; device_index--) + joystickdevice = joystickdevice->pNext; + + /* allocate memory for system specific hardware data */ + joystick->instance_id = joystickdevice->nInstanceID; + joystick->hwdata = + (struct joystick_hwdata *) SDL_malloc(sizeof(struct joystick_hwdata)); + if (joystick->hwdata == NULL) { + return SDL_OutOfMemory(); + } + SDL_zerop(joystick->hwdata); + joystick->hwdata->guid = joystickdevice->guid; + + if (joystickdevice->bXInputDevice) { + return SDL_XINPUT_JoystickOpen(joystick, joystickdevice); + } else { + return SDL_DINPUT_JoystickOpen(joystick, joystickdevice); + } +} + +static int +WINDOWS_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms) +{ + if (joystick->hwdata->bXInputDevice) { + return SDL_XINPUT_JoystickRumble(joystick, low_frequency_rumble, high_frequency_rumble, duration_ms); + } else { + return SDL_DINPUT_JoystickRumble(joystick, low_frequency_rumble, high_frequency_rumble, duration_ms); + } +} + +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 */ +static 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 (s_threadJoystick) { + SDL_LockMutex(s_mutexJoyStickEnum); + s_bJoystickThreadQuit = SDL_TRUE; + SDL_CondBroadcast(s_condJoystickThread); /* signal the joystick thread to quit */ + SDL_UnlockMutex(s_mutexJoyStickEnum); +#ifndef __WINRT__ + PostThreadMessage(SDL_GetThreadID(s_threadJoystick), WM_QUIT, 0, 0); +#endif + SDL_WaitThread(s_threadJoystick, NULL); /* wait for it to bugger off */ + + SDL_DestroyMutex(s_mutexJoyStickEnum); + SDL_DestroyCond(s_condJoystickThread); + s_condJoystickThread= NULL; + s_mutexJoyStickEnum = NULL; + s_threadJoystick = NULL; + } + + SDL_DINPUT_JoystickQuit(); + SDL_XINPUT_JoystickQuit(); + + s_bDeviceAdded = SDL_FALSE; + s_bDeviceRemoved = SDL_FALSE; +} + +SDL_JoystickDriver SDL_WINDOWS_JoystickDriver = +{ + WINDOWS_JoystickInit, + WINDOWS_JoystickGetCount, + WINDOWS_JoystickDetect, + WINDOWS_JoystickGetDeviceName, + WINDOWS_JoystickGetDevicePlayerIndex, + WINDOWS_JoystickGetDeviceGUID, + WINDOWS_JoystickGetDeviceInstanceID, + WINDOWS_JoystickOpen, + WINDOWS_JoystickRumble, + WINDOWS_JoystickUpdate, + WINDOWS_JoystickClose, + WINDOWS_JoystickQuit, +}; + +#endif /* SDL_JOYSTICK_DINPUT || SDL_JOYSTICK_XINPUT */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/source/3rd-party/SDL2/src/joystick/windows/SDL_windowsjoystick_c.h b/source/3rd-party/SDL2/src/joystick/windows/SDL_windowsjoystick_c.h new file mode 100644 index 0000000..611f7e6 --- /dev/null +++ b/source/3rd-party/SDL2/src/joystick/windows/SDL_windowsjoystick_c.h @@ -0,0 +1,95 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org> + + 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_events.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 */ + +typedef struct JoyStick_DeviceData +{ + SDL_JoystickGUID guid; + char *joystickname; + Uint8 send_add_event; + SDL_JoystickID nInstanceID; + SDL_bool bXInputDevice; + BYTE SubType; + Uint8 XInputUserId; + DIDEVICEINSTANCE dxdevice; + WCHAR hidPath[MAX_PATH]; + 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_JoystickGUID guid; + Uint32 rumble_expiration; + +#if SDL_JOYSTICK_DINPUT + LPDIRECTINPUTDEVICE8 InputDevice; + DIDEVCAPS Capabilities; + SDL_bool buffered; + input_t Inputs[MAX_INPUTS]; + int NumInputs; + int NumSliders; + SDL_bool ff_initialized; + DIEFFECT *ffeffect; + LPDIRECTINPUTEFFECT ffeffect_ref; +#endif + + SDL_bool bXInputDevice; /* SDL_TRUE if this device supports using the xinput API rather than DirectInput */ + SDL_bool bXInputHaptic; /* Supports force feedback via XInput. */ + Uint8 userid; /* XInput userid index for this joystick */ + DWORD dwPacketNumber; +}; + +#if SDL_JOYSTICK_DINPUT +extern const DIDATAFORMAT SDL_c_dfDIJoystick2; +#endif + +extern void WINDOWS_AddJoystickDevice(JoyStick_DeviceData *device); + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/source/3rd-party/SDL2/src/joystick/windows/SDL_xinputjoystick.c b/source/3rd-party/SDL2/src/joystick/windows/SDL_xinputjoystick.c new file mode 100644 index 0000000..6bbe475 --- /dev/null +++ b/source/3rd-party/SDL2/src/joystick/windows/SDL_xinputjoystick.c @@ -0,0 +1,560 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org> + + 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" + +#if SDL_JOYSTICK_XINPUT + +#include "SDL_assert.h" +#include "SDL_hints.h" +#include "SDL_timer.h" +#include "SDL_windowsjoystick_c.h" +#include "SDL_xinputjoystick_c.h" +#include "../hidapi/SDL_hidapijoystick_c.h" + +/* + * Internal stuff. + */ +static SDL_bool s_bXInputEnabled = SDL_TRUE; +static char *s_arrXInputDevicePath[XUSER_MAX_COUNT]; + + +static SDL_bool +SDL_XInputUseOldJoystickMapping() +{ +#ifdef __WINRT__ + /* TODO: remove this __WINRT__ block, but only after integrating with UWP/WinRT's HID API */ + /* FIXME: Why are Win8/10 different here? -flibit */ + return (NTDDI_VERSION < NTDDI_WIN10); +#else + static int s_XInputUseOldJoystickMapping = -1; + if (s_XInputUseOldJoystickMapping < 0) { + s_XInputUseOldJoystickMapping = SDL_GetHintBoolean(SDL_HINT_XINPUT_USE_OLD_JOYSTICK_MAPPING, SDL_FALSE); + } + return (s_XInputUseOldJoystickMapping > 0); +#endif +} + +SDL_bool SDL_XINPUT_Enabled(void) +{ + return s_bXInputEnabled; +} + +int +SDL_XINPUT_JoystickInit(void) +{ + s_bXInputEnabled = SDL_GetHintBoolean(SDL_HINT_XINPUT_ENABLED, SDL_TRUE); + + if (s_bXInputEnabled && WIN_LoadXInputDLL() < 0) { + s_bXInputEnabled = SDL_FALSE; /* oh well. */ + } + return 0; +} + +static char * +GetXInputName(const Uint8 userid, BYTE SubType) +{ + char name[32]; + + if (SDL_XInputUseOldJoystickMapping()) { + SDL_snprintf(name, sizeof(name), "X360 Controller #%u", 1 + userid); + } else { + switch (SubType) { + case XINPUT_DEVSUBTYPE_GAMEPAD: + SDL_snprintf(name, sizeof(name), "XInput Controller #%u", 1 + userid); + break; + case XINPUT_DEVSUBTYPE_WHEEL: + SDL_snprintf(name, sizeof(name), "XInput Wheel #%u", 1 + userid); + break; + case XINPUT_DEVSUBTYPE_ARCADE_STICK: + SDL_snprintf(name, sizeof(name), "XInput ArcadeStick #%u", 1 + userid); + break; + case XINPUT_DEVSUBTYPE_FLIGHT_STICK: + SDL_snprintf(name, sizeof(name), "XInput FlightStick #%u", 1 + userid); + break; + case XINPUT_DEVSUBTYPE_DANCE_PAD: + SDL_snprintf(name, sizeof(name), "XInput DancePad #%u", 1 + userid); + break; + case XINPUT_DEVSUBTYPE_GUITAR: + case XINPUT_DEVSUBTYPE_GUITAR_ALTERNATE: + case XINPUT_DEVSUBTYPE_GUITAR_BASS: + SDL_snprintf(name, sizeof(name), "XInput Guitar #%u", 1 + userid); + break; + case XINPUT_DEVSUBTYPE_DRUM_KIT: + SDL_snprintf(name, sizeof(name), "XInput DrumKit #%u", 1 + userid); + break; + case XINPUT_DEVSUBTYPE_ARCADE_PAD: + SDL_snprintf(name, sizeof(name), "XInput ArcadePad #%u", 1 + userid); + break; + default: + SDL_snprintf(name, sizeof(name), "XInput Device #%u", 1 + userid); + break; + } + } + return SDL_strdup(name); +} + +/* We can't really tell what device is being used for XInput, but we can guess + and we'll be correct for the case where only one device is connected. + */ +static void +GuessXInputDevice(Uint8 userid, Uint16 *pVID, Uint16 *pPID, Uint16 *pVersion) +{ +#ifndef __WINRT__ /* TODO: remove this ifndef __WINRT__ block, but only after integrating with UWP/WinRT's HID API */ + + PRAWINPUTDEVICELIST devices = NULL; + UINT i, j, device_count = 0; + + if ((GetRawInputDeviceList(NULL, &device_count, sizeof(RAWINPUTDEVICELIST)) == -1) || (!device_count)) { + return; /* oh well. */ + } + + devices = (PRAWINPUTDEVICELIST)SDL_malloc(sizeof(RAWINPUTDEVICELIST) * device_count); + if (devices == NULL) { + return; + } + + if (GetRawInputDeviceList(devices, &device_count, sizeof(RAWINPUTDEVICELIST)) == -1) { + SDL_free(devices); + return; /* oh well. */ + } + + for (i = 0; i < device_count; i++) { + RID_DEVICE_INFO rdi; + char devName[128]; + UINT rdiSize = sizeof(rdi); + UINT nameSize = SDL_arraysize(devName); + + rdi.cbSize = sizeof(rdi); + if ((devices[i].dwType == RIM_TYPEHID) && + (GetRawInputDeviceInfoA(devices[i].hDevice, RIDI_DEVICEINFO, &rdi, &rdiSize) != ((UINT)-1)) && + (GetRawInputDeviceInfoA(devices[i].hDevice, RIDI_DEVICENAME, devName, &nameSize) != ((UINT)-1)) && + (SDL_strstr(devName, "IG_") != NULL)) { + SDL_bool found = SDL_FALSE; + for (j = 0; j < SDL_arraysize(s_arrXInputDevicePath); ++j) { + if (j == userid) { + continue; + } + if (!s_arrXInputDevicePath[j]) { + continue; + } + if (SDL_strcmp(devName, s_arrXInputDevicePath[j]) == 0) { + found = SDL_TRUE; + break; + } + } + if (found) { + /* We already have this device in our XInput device list */ + continue; + } + + /* We don't actually know if this is the right device for this + * userid, but we'll record it so we'll at least be consistent + * when the raw device list changes. + */ + *pVID = (Uint16)rdi.hid.dwVendorId; + *pPID = (Uint16)rdi.hid.dwProductId; + *pVersion = (Uint16)rdi.hid.dwVersionNumber; + if (s_arrXInputDevicePath[userid]) { + SDL_free(s_arrXInputDevicePath[userid]); + } + s_arrXInputDevicePath[userid] = SDL_strdup(devName); + break; + } + } + SDL_free(devices); +#endif /* ifndef __WINRT__ */ +} + +static void +AddXInputDevice(Uint8 userid, BYTE SubType, JoyStick_DeviceData **pContext) +{ + Uint16 vendor = 0; + Uint16 product = 0; + Uint16 version = 0; + JoyStick_DeviceData *pPrevJoystick = NULL; + JoyStick_DeviceData *pNewJoystick = *pContext; + + if (SDL_XInputUseOldJoystickMapping() && SubType != XINPUT_DEVSUBTYPE_GAMEPAD) + return; + + 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; + } + + pNewJoystick = (JoyStick_DeviceData *)SDL_malloc(sizeof(JoyStick_DeviceData)); + if (!pNewJoystick) { + return; /* better luck next time? */ + } + SDL_zerop(pNewJoystick); + + pNewJoystick->joystickname = GetXInputName(userid, SubType); + if (!pNewJoystick->joystickname) { + SDL_free(pNewJoystick); + return; /* better luck next time? */ + } + + pNewJoystick->bXInputDevice = SDL_TRUE; + if (SDL_XInputUseOldJoystickMapping()) { + SDL_zero(pNewJoystick->guid); + } else { + Uint16 *guid16 = (Uint16 *)pNewJoystick->guid.data; + + GuessXInputDevice(userid, &vendor, &product, &version); + + *guid16++ = SDL_SwapLE16(SDL_HARDWARE_BUS_USB); + *guid16++ = 0; + *guid16++ = SDL_SwapLE16(vendor); + *guid16++ = 0; + *guid16++ = SDL_SwapLE16(product); + *guid16++ = 0; + *guid16++ = SDL_SwapLE16(version); + *guid16++ = 0; + + /* Note that this is an XInput device and what subtype it is */ + pNewJoystick->guid.data[14] = 'x'; + pNewJoystick->guid.data[15] = SubType; + } + pNewJoystick->SubType = SubType; + pNewJoystick->XInputUserId = userid; + + if (SDL_ShouldIgnoreJoystick(pNewJoystick->joystickname, pNewJoystick->guid)) { + SDL_free(pNewJoystick); + return; + } + +#ifdef SDL_JOYSTICK_HIDAPI + if (HIDAPI_IsDevicePresent(vendor, product, version)) { + /* The HIDAPI driver is taking care of this device */ + SDL_free(pNewJoystick); + return; + } +#endif + + WINDOWS_AddJoystickDevice(pNewJoystick); +} + +static void +DelXInputDevice(Uint8 userid) +{ + if (s_arrXInputDevicePath[userid]) { + SDL_free(s_arrXInputDevicePath[userid]); + s_arrXInputDevicePath[userid] = NULL; + } +} + +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); + } else { + DelXInputDevice(userid); + } + } +} + +int +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->player_index = userId; + + joystick->hwdata->bXInputDevice = SDL_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 */ + if (SDL_XInputUseOldJoystickMapping()) { + joystick->naxes = 6; + joystick->nbuttons = 15; + } else { + joystick->naxes = 6; + joystick->nbuttons = 11; + joystick->nhats = 1; + } + return 0; +} + +static void +UpdateXInputJoystickBatteryInformation(SDL_Joystick * joystick, XINPUT_BATTERY_INFORMATION_EX *pBatteryInformation) +{ + if (pBatteryInformation->BatteryType != BATTERY_TYPE_UNKNOWN) { + SDL_JoystickPowerLevel ePowerLevel = SDL_JOYSTICK_POWER_UNKNOWN; + if (pBatteryInformation->BatteryType == BATTERY_TYPE_WIRED) { + ePowerLevel = SDL_JOYSTICK_POWER_WIRED; + } else { + switch (pBatteryInformation->BatteryLevel) { + case BATTERY_LEVEL_EMPTY: + ePowerLevel = SDL_JOYSTICK_POWER_EMPTY; + break; + case BATTERY_LEVEL_LOW: + ePowerLevel = SDL_JOYSTICK_POWER_LOW; + break; + case BATTERY_LEVEL_MEDIUM: + ePowerLevel = SDL_JOYSTICK_POWER_MEDIUM; + break; + default: + case BATTERY_LEVEL_FULL: + ePowerLevel = SDL_JOYSTICK_POWER_FULL; + break; + } + } + + SDL_PrivateJoystickBatteryLevel(joystick, ePowerLevel); + } +} + +static void +UpdateXInputJoystickState_OLD(SDL_Joystick * joystick, XINPUT_STATE_EX *pXInputState, XINPUT_BATTERY_INFORMATION_EX *pBatteryInformation) +{ + static WORD s_XInputButtons[] = { + XINPUT_GAMEPAD_DPAD_UP, XINPUT_GAMEPAD_DPAD_DOWN, XINPUT_GAMEPAD_DPAD_LEFT, XINPUT_GAMEPAD_DPAD_RIGHT, + XINPUT_GAMEPAD_START, XINPUT_GAMEPAD_BACK, XINPUT_GAMEPAD_LEFT_THUMB, XINPUT_GAMEPAD_RIGHT_THUMB, + XINPUT_GAMEPAD_LEFT_SHOULDER, XINPUT_GAMEPAD_RIGHT_SHOULDER, + XINPUT_GAMEPAD_A, XINPUT_GAMEPAD_B, XINPUT_GAMEPAD_X, XINPUT_GAMEPAD_Y, + XINPUT_GAMEPAD_GUIDE + }; + WORD wButtons = pXInputState->Gamepad.wButtons; + Uint8 button; + + SDL_PrivateJoystickAxis(joystick, 0, (Sint16)pXInputState->Gamepad.sThumbLX); + SDL_PrivateJoystickAxis(joystick, 1, (Sint16)(-SDL_max(-32767, pXInputState->Gamepad.sThumbLY))); + SDL_PrivateJoystickAxis(joystick, 2, (Sint16)pXInputState->Gamepad.sThumbRX); + SDL_PrivateJoystickAxis(joystick, 3, (Sint16)(-SDL_max(-32767, pXInputState->Gamepad.sThumbRY))); + SDL_PrivateJoystickAxis(joystick, 4, (Sint16)(((int)pXInputState->Gamepad.bLeftTrigger * 65535 / 255) - 32768)); + SDL_PrivateJoystickAxis(joystick, 5, (Sint16)(((int)pXInputState->Gamepad.bRightTrigger * 65535 / 255) - 32768)); + + for (button = 0; button < SDL_arraysize(s_XInputButtons); ++button) { + SDL_PrivateJoystickButton(joystick, button, (wButtons & s_XInputButtons[button]) ? SDL_PRESSED : SDL_RELEASED); + } + + UpdateXInputJoystickBatteryInformation(joystick, pBatteryInformation); +} + +static void +UpdateXInputJoystickState(SDL_Joystick * joystick, XINPUT_STATE_EX *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; + + SDL_PrivateJoystickAxis(joystick, 0, pXInputState->Gamepad.sThumbLX); + SDL_PrivateJoystickAxis(joystick, 1, ~pXInputState->Gamepad.sThumbLY); + SDL_PrivateJoystickAxis(joystick, 2, ((int)pXInputState->Gamepad.bLeftTrigger * 257) - 32768); + SDL_PrivateJoystickAxis(joystick, 3, pXInputState->Gamepad.sThumbRX); + SDL_PrivateJoystickAxis(joystick, 4, ~pXInputState->Gamepad.sThumbRY); + SDL_PrivateJoystickAxis(joystick, 5, ((int)pXInputState->Gamepad.bRightTrigger * 257) - 32768); + + for (button = 0; button < SDL_arraysize(s_XInputButtons); ++button) { + SDL_PrivateJoystickButton(joystick, button, (wButtons & s_XInputButtons[button]) ? SDL_PRESSED : SDL_RELEASED); + } + + 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_PrivateJoystickHat(joystick, 0, hat); + + UpdateXInputJoystickBatteryInformation(joystick, pBatteryInformation); +} + +int +SDL_XINPUT_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms) +{ + 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"); + } + + if ((low_frequency_rumble || high_frequency_rumble) && duration_ms) { + joystick->hwdata->rumble_expiration = SDL_GetTicks() + duration_ms; + } else { + joystick->hwdata->rumble_expiration = 0; + } + return 0; +} + +void +SDL_XINPUT_JoystickUpdate(SDL_Joystick * joystick) +{ + HRESULT result; + XINPUT_STATE_EX 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); + } + + /* only fire events if the data changed from last time */ + if (XInputState.dwPacketNumber && XInputState.dwPacketNumber != joystick->hwdata->dwPacketNumber) { + if (SDL_XInputUseOldJoystickMapping()) { + UpdateXInputJoystickState_OLD(joystick, &XInputState, &XBatteryInformation); + } else { + UpdateXInputJoystickState(joystick, &XInputState, &XBatteryInformation); + } + joystick->hwdata->dwPacketNumber = XInputState.dwPacketNumber; + } + + if (joystick->hwdata->rumble_expiration) { + Uint32 now = SDL_GetTicks(); + if (SDL_TICKS_PASSED(now, joystick->hwdata->rumble_expiration)) { + SDL_XINPUT_JoystickRumble(joystick, 0, 0, 0); + } + } +} + +void +SDL_XINPUT_JoystickClose(SDL_Joystick * joystick) +{ +} + +void +SDL_XINPUT_JoystickQuit(void) +{ + if (s_bXInputEnabled) { + WIN_UnloadXInputDLL(); + } +} + +#else /* !SDL_JOYSTICK_XINPUT */ + +typedef struct JoyStick_DeviceData JoyStick_DeviceData; + +SDL_bool SDL_XINPUT_Enabled(void) +{ + return SDL_FALSE; +} + +int +SDL_XINPUT_JoystickInit(void) +{ + return 0; +} + +void +SDL_XINPUT_JoystickDetect(JoyStick_DeviceData **pContext) +{ +} + +int +SDL_XINPUT_JoystickOpen(SDL_Joystick * joystick, JoyStick_DeviceData *joystickdevice) +{ + return SDL_Unsupported(); +} + +int +SDL_XINPUT_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms) +{ + 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 */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/source/3rd-party/SDL2/src/joystick/windows/SDL_xinputjoystick_c.h b/source/3rd-party/SDL2/src/joystick/windows/SDL_xinputjoystick_c.h new file mode 100644 index 0000000..8d57b62 --- /dev/null +++ b/source/3rd-party/SDL2/src/joystick/windows/SDL_xinputjoystick_c.h @@ -0,0 +1,34 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org> + + 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" + +extern SDL_bool SDL_XINPUT_Enabled(void); +extern int SDL_XINPUT_JoystickInit(void); +extern void SDL_XINPUT_JoystickDetect(JoyStick_DeviceData **pContext); +extern int SDL_XINPUT_JoystickOpen(SDL_Joystick * joystick, JoyStick_DeviceData *joystickdevice); +extern int SDL_XINPUT_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms); +extern void SDL_XINPUT_JoystickUpdate(SDL_Joystick * joystick); +extern void SDL_XINPUT_JoystickClose(SDL_Joystick * joystick); +extern void SDL_XINPUT_JoystickQuit(void); + +/* vi: set ts=4 sw=4 expandtab: */ |