Merge commit 'dec0d4ec4153bf9fc2b78ae6c2df45b6ea8dde7a' as 'external/sdl/SDL'

This commit is contained in:
2023-07-25 22:27:55 +02:00
1663 changed files with 627495 additions and 0 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,50 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 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.
*/
#ifndef SDL_gamepad_c_h_
#define SDL_gamepad_c_h_
#include "SDL_internal.h"
/* Useful functions and variables from SDL_gamepad.c */
/* Initialization and shutdown functions */
extern int SDL_InitGamepadMappings(void);
extern void SDL_QuitGamepadMappings(void);
extern int SDL_InitGamepads(void);
extern void SDL_QuitGamepads(void);
extern void SDL_PrivateGamepadAdded(SDL_JoystickID instance_id);
extern void SDL_PrivateGamepadRemoved(SDL_JoystickID instance_id);
/* Function to return whether a joystick name and GUID is a gamepad */
extern SDL_bool SDL_IsGamepadNameAndGUID(const char *name, SDL_JoystickGUID guid);
/* Function to return whether a gamepad should be ignored */
extern SDL_bool SDL_ShouldIgnoreGamepad(const char *name, SDL_JoystickGUID guid);
/* Handle delayed guide button on a gamepad */
extern void SDL_GamepadHandleDelayedGuideButton(SDL_Joystick *joystick);
/* Handle system sensor data */
extern void SDL_GamepadSensorWatcher(Uint64 timestamp, SDL_SensorID sensor, Uint64 sensor_timestamp, float *data, int num_values);
#endif /* SDL_gamepad_c_h_ */

View File

@@ -0,0 +1,995 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 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"
/* Default mappings we support
The easiest way to generate a new mapping is to start Steam in Big Picture
mode, configure your joystick and then look in config/config.vdf in your
Steam installation directory for the "SDL_GamepadBind" entry.
Alternatively, you can use the app located in test/controllermap
*/
static const char *s_GamepadMappings[] = {
#ifdef SDL_JOYSTICK_XINPUT
"xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
#endif
#ifdef SDL_JOYSTICK_WGI
"03000000491900001904000000007700,Amazon Luna Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b9,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b7,x:b2,y:b3,",
"03000000d11800000094000000007700,Google Stadia Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b12,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,",
"030000007e0500000920000000007701,Nintendo Switch Pro Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"030000007e0500000920000000007701,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"030000004c050000c405000000007701,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
"030000004c050000e60c000000007700,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b14,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
"0300000032150000000a000000007703,Razer Atrox Arcade Stick,a:b0,b:b1,dpdown:b12,dpleft:b13,dpright:b11,dpup:b10,leftshoulder:b4,lefttrigger:b8,rightshoulder:b5,righttrigger:b9,x:b2,y:b3,",
"03000000de280000ff11000000007701,Steam Virtual Gamepad,a:b0,b:b1,back:b6,dpdown:b12,dpleft:b13,dpright:b11,dpup:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a4,leftx:a1,lefty:a0~,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a2~,start:b7,x:b2,y:b3,",
#endif
#ifdef SDL_JOYSTICK_DINPUT
"03000000fa2d00000100000000000000,3DRUDDER,leftx:a0,lefty:a1,rightx:a5,righty:a2,",
"03000000c82d00000090000000000000,8BitDo FC30 Pro,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"03000000c82d00000090000000000000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"03000000c82d00001038000000000000,8BitDo FC30 Pro,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"03000000c82d00001038000000000000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"03000000c82d00000650000000000000,8BitDo M30 Gamepad,a:b0,b:b1,back:b10,guide:b2,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,start:b11,x:b3,y:b4,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"03000000c82d00000650000000000000,8BitDo M30 Gamepad,a:b1,b:b0,back:b10,guide:b2,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"03000000c82d00005106000000000000,8BitDo M30 Gamepad,a:b0,b:b1,back:b10,guide:b2,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,start:b11,x:b3,y:b4,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"03000000c82d00005106000000000000,8BitDo M30 Gamepad,a:b1,b:b0,back:b10,guide:b2,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"03000000c82d00001590000000000000,8BitDo N30 Pro 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"03000000c82d00001590000000000000,8BitDo N30 Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"03000000c82d00006528000000000000,8BitDo N30 Pro 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"03000000c82d00006528000000000000,8BitDo N30 Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"030000003512000012ab000000000000,8BitDo NES30 Gamepad,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"030000003512000012ab000000000000,8BitDo NES30 Gamepad,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"03000000022000000090000000000000,8BitDo NES30 Pro,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"03000000022000000090000000000000,8BitDo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"03000000203800000900000000000000,8BitDo NES30 Pro,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"03000000203800000900000000000000,8BitDo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"03000000c82d00002038000000000000,8BitDo NES30 Pro,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"03000000c82d00002038000000000000,8BitDo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"03000000c82d00000660000000000000,8BitDo Pro 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"03000000c82d00000660000000000000,8BitDo Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"03000000c82d00000060000000000000,8BitDo SF30 Pro,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"03000000c82d00000060000000000000,8BitDo SF30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"03000000c82d00000061000000000000,8BitDo SF30 Pro,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"03000000c82d00000061000000000000,8BitDo SF30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"03000000102800000900000000000000,8BitDo SFC30 Gamepad,a:b0,b:b1,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b3,y:b4,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"03000000102800000900000000000000,8BitDo SFC30 Gamepad,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"03000000c82d00001290000000000000,8BitDo SN30 Gamepad,a:b0,b:b1,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b3,y:b4,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"03000000c82d00001290000000000000,8BitDo SN30 Gamepad,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"03000000c82d00006228000000000000,8BitDo SN30 Gamepad,a:b0,b:b1,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b3,y:b4,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"03000000c82d00006228000000000000,8BitDo SN30 Gamepad,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"03000000c82d00000260000000000000,8BitDo SN30 Pro+,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"03000000c82d00000260000000000000,8BitDo SN30 Pro+,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"03000000c82d00000261000000000000,8BitDo SN30 Pro+,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"03000000c82d00000261000000000000,8BitDo SN30 Pro+,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"03000000c82d00000160000000000000,8BitDo SN30 Pro,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"03000000c82d00000160000000000000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"030000003512000020ab000000000000,8BitDo SNES30 Gamepad,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"030000003512000020ab000000000000,8BitDo SNES30 Gamepad,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"03000000c82d00001130000000000000,8BitDo Ultimate Wired Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,misc1:b26,paddle1:b24,paddle2:b25,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,",
"03000000c82d00001330000000000000,8BitDo Ultimate Wireless Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,misc1:b26,paddle1:b23,paddle2:b19,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,",
"03000000c82d00001890000000000000,8BitDo Zero 2,a:b0,b:b1,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b3,y:b4,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"03000000c82d00001890000000000000,8BitDo Zero 2,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"03000000c82d00003032000000000000,8BitDo Zero 2,a:b0,b:b1,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b3,y:b4,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"03000000c82d00003032000000000000,8BitDo Zero 2,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"03000000a00500003232000000000000,8BitDo Zero Gamepad,a:b0,b:b1,back:b10,dpdown:+a2,dpleft:-a0,dpright:+a0,dpup:-a2,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"03000000a00500003232000000000000,8BitDo Zero Gamepad,a:b1,b:b0,back:b10,dpdown:+a2,dpleft:-a0,dpright:+a0,dpup:-a2,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"03000000050b00000579000000000000,ASUS ROG Kunai 3 Gamepad,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,",
"03000000050b00000679000000000000,ASUS ROG Kunai 3 Gamepad,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,",
"030000008f0e00001200000000000000,Acme GA-02,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b2,y:b3,",
"03000000fa190000f0ff000000000000,Acteck AGJ-3200,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,",
"03000000341a00003608000000000000,Afterglow PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
"030000006f0e00000263000000000000,Afterglow PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
"030000006f0e00001101000000000000,Afterglow PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
"030000006f0e00001401000000000000,Afterglow PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
"030000006f0e00001402000000000000,Afterglow PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
"030000006f0e00001901000000000000,Afterglow PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
"030000006f0e00001a01000000000000,Afterglow PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
"03000000d62000001d57000000000000,Airflo PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
"03000000491900001904000000000000,Amazon Luna Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b9,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b7,x:b2,y:b3,",
"03000000d62000002a79000000000000,BDA PS4 Fightpad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
"03000000d81d00000b00000000000000,BUFFALO BSGP1601 Series ,a:b5,b:b3,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b9,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b13,x:b4,y:b2,",
"03000000d6200000e557000000000000,Batarang,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
"03000000c01100001352000000000000,Battalife Joystick,a:b6,b:b7,back:b2,leftshoulder:b0,leftx:a0,lefty:a1,rightshoulder:b1,start:b3,x:b4,y:b5,",
"030000006f0e00003201000000000000,Battlefield 4 PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
"03000000bc2000006012000000000000,Betop 2126F,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,",
"03000000bc2000000055000000000000,Betop BFM Gamepad,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,",
"03000000bc2000006312000000000000,Betop Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,",
"03000000bc2000006412000000000000,Betop Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,",
"03000000c01100000555000000000000,Betop Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,",
"03000000c01100000655000000000000,Betop Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,",
"03000000790000000700000000000000,Betop Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b3,y:b0,",
"03000000808300000300000000000000,Betop Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b3,y:b0,",
"030000006b1400000055000000000000,Bigben PS3 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,",
"030000006b1400000103000000000000,Bigben PS3 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,",
"0300000066f700000500000000000000,BrutalLegendTest,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b3,",
"03000000e82000006058000000000000,Cideko AK08b,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,",
"03000000260900008888000000000000,Cyber Gadget GameCube Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:a4,rightx:a2,righty:a3~,start:b7,x:b2,y:b3,",
"03000000a306000022f6000000000000,Cyborg V.3 Rumble Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:+a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:-a3,rightx:a2,righty:a4,start:b9,x:b0,y:b3,",
"03000000451300000830000000000000,Defender Game Racer X7,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,",
"03000000791d00000103000000000000,Dual Box WII,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,rightx:a2,righty:a3,start:b9,x:b3,y:b0,",
"03000000bd12000002e0000000000000,Dual USB Vibration Joystick,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a3,righty:a2,start:b11,x:b3,y:b0,",
"030000006f0e00003001000000000000,EA SPORTS PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
"03000000341a00000108000000000000,EXEQ RF USB Gamepad 8206,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,",
"030000008f0e00000f31000000000000,EXEQ,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,",
"03000000b80500000410000000000000,Elecom Gamepad,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b1,",
"03000000b80500000610000000000000,Elecom Gamepad,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b1,",
"03000000852100000201000000000000,FF-GP1,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
"030000000d0f00002700000000000000,FIGHTING STICK V3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,",
"030000008f0e00000d31000000000000,GAMEPAD 3 TURBO,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
"03000000300f00000b01000000000000,GGE909 Recoil Pad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b3,y:b0,",
"03000000790000002201000000000000,Game Controller for PC,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,",
"0300000066f700000100000000000000,Game VIB Joystick,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,start:b11,x:b0,y:b1,",
"03000000491900000204000000000000,GameSir T4 Pro,crc:1aa4,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,",
"03000000ac0500003d03000000000000,GameSir,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,",
"03000000ac0500004d04000000000000,GameSir,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,",
"03000000ac0500001a06000000000000,GameSir-T3 2.02,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,",
"03000000ffff00000000000000000000,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,",
"03000000c01100000140000000000000,GameStop PS4 Fun Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
"03000000260900002625000000000000,Gamecube Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,lefttrigger:a4,leftx:a0,lefty:a1,righttrigger:a5,rightx:a2,righty:a3,start:b7,x:b2,y:b3,",
"03000000280400000140000000000000,Gamepad Pro USB,a:b1,b:b2,back:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,",
"030000005c1a00003330000000000000,Genius MaxFire Grandias 12V,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b2,y:b3,",
"030000008305000031b0000000000000,Genius Maxfire Blaze 3,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,",
"03000000451300000010000000000000,Genius Maxfire Grandias 12,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,",
"030000008305000009a0000000000000,Genius,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,",
"03000000f025000021c1000000000000,Gioteck PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,",
"03000000f0250000c383000000000000,Gioteck VX2 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,",
"03000000f0250000c483000000000000,Gioteck VX2 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,",
"03000000f0250000c283000000000000,Gioteck,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,",
"03000000d11800000094000000000000,Google Stadia Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:b12,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:b11,rightx:a3,righty:a4,start:b9,x:b2,y:b3,",
"03000000632500002605000000000000,HJD-X,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,",
"030000000d0f00008400000000000000,HORI Fighting Commander,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
"030000000d0f00008500000000000000,HORI Fighting Commander,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
"030000000d0f00008800000000000000,HORI Fighting Stick mini 4 (PS3),a:b1,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b8,x:b0,y:b3,",
"030000000d0f00008700000000000000,HORI Fighting Stick mini 4 (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,",
"030000000d0f00006e00000000000000,HORIPAD 4 (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
"030000000d0f00006600000000000000,HORIPAD 4 (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
"030000000d0f0000ee00000000000000,HORIPAD mini4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
"03000000250900000017000000000000,HRAP2 on PS/SS/N64 Joypad to USB BOX,a:b2,b:b1,back:b9,leftshoulder:b5,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b6,start:b8,x:b3,y:b0,",
"03000000341a00000302000000000000,Hama Scorpad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
"030000000d0f00004900000000000000,Hatsune Miku Sho Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
"03000000d81400000862000000000000,HitBox Edition Cthulhu+,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b5,lefttrigger:b4,rightshoulder:b7,righttrigger:b6,start:b9,x:b0,y:b3,",
"030000000d0f00005f00000000000000,Hori Fighting Commander 4 (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
"030000000d0f00005e00000000000000,Hori Fighting Commander 4 (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
"030000000d0f00004000000000000000,Hori Fighting Stick Mini 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b5,lefttrigger:b4,rightshoulder:b7,righttrigger:b6,start:b9,x:b0,y:b3,",
"030000000d0f00000900000000000000,Hori Pad 3 Turbo,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
"030000000d0f00005400000000000000,Hori Pad 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
"030000000d0f00004d00000000000000,Hori Pad A,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
"030000000d0f00009200000000000000,Hori Pokken Tournament DX Pro Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,",
"030000000d0f0000c100000000000000,Horipad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
"030000008f0e00001330000000000000,HuiJia SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b9,x:b3,y:b0,",
"030000006f0e00002401000000000000,INJUSTICE FightStick PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,",
"03000000ac0500002c02000000000000,IPEGA,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,leftstick:b13,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b9,rightstick:b14,righttrigger:b7,rightx:a3,righty:a4,start:b11,x:b3,y:b4,",
"03000000b50700001403000000000000,Impact Black,a:b2,b:b3,back:b8,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,",
"03000000491900000204000000000000,Ipega PG-9023,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,",
"030000006e0500000520000000000000,JC-P301U,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b0,y:b1,",
"030000006e0500000320000000000000,JC-U3613M (DInput),a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b0,y:b1,",
"030000006e0500000720000000000000,JC-W01U,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b1,",
"03000000790000000200000000000000,King PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b3,y:b0,",
"030000006d040000d1ca000000000000,Logitech ChillStream,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
"030000006d040000d2ca000000000000,Logitech Cordless Precision,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
"030000006d04000011c2000000000000,Logitech Cordless Wingman,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b5,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b2,righttrigger:b7,rightx:a3,righty:a4,x:b4,",
"030000006d04000016c2000000000000,Logitech Dual Action,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
"030000006d04000018c2000000000000,Logitech F510 Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
"030000006d04000019c2000000000000,Logitech F710 Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,", /* Guide button doesn't seem to be sent in DInput mode. */
"030000006d0400001ac2000000000000,Logitech Precision Gamepad,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,",
"03000000380700008081000000000000,MADCATZ SFV Arcade FightStick Alpha PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
"03000000380700006382000000000000,MLG Gamepad PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
"03000000c62400002a89000000000000,MOGA XP5-A Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,",
"03000000c62400002b89000000000000,MOGA XP5-A Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,",
"03000000c62400001a89000000000000,MOGA XP5-X Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,",
"03000000c62400001b89000000000000,MOGA XP5-X Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,",
"03000000250900006688000000000000,MP-8866 Super Dual Box,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,",
"03000000380700006652000000000000,Mad Catz C.T.R.L.R,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b0,y:b3,",
"03000000380700005032000000000000,Mad Catz FightPad PRO (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
"03000000380700005082000000000000,Mad Catz FightPad PRO (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
"03000000380700008433000000000000,Mad Catz FightStick TE S+ (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
"03000000380700008483000000000000,Mad Catz FightStick TE S+ (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
"03000000380700008134000000000000,Mad Catz FightStick TE2+ PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b7,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b4,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
"03000000380700008184000000000000,Mad Catz FightStick TE2+ PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b5,leftstick:b10,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
"03000000380700006252000000000000,Mad Catz Micro C.T.R.L.R,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b0,y:b3,",
"03000000380700008034000000000000,Mad Catz TE2 PS3 Fightstick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
"03000000380700008084000000000000,Mad Catz TE2 PS4 Fightstick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
"03000000380700001888000000000000,MadCatz SFIV FightStick PS3,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b5,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b4,righttrigger:b6,rightx:a2,righty:a3,start:b9,x:b2,y:b3,",
"03000000380700008532000000000000,Madcatz Arcade Fightstick TE S PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
"03000000380700003888000000000000,Madcatz Arcade Fightstick TE S+ PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
"030000002a0600001024000000000000,Matricom,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b2,y:b3,",
"03000000250900000128000000000000,Mayflash Arcade Stick,a:b1,b:b2,back:b8,leftshoulder:b0,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b3,righttrigger:b7,start:b9,x:b5,y:b6,",
"03000000790000004418000000000000,Mayflash GameCube Controller,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b0,y:b3,",
"030000008f0e00001030000000000000,Mayflash USB Adapter for original Sega Saturn controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b5,rightshoulder:b2,righttrigger:b7,start:b9,x:b3,y:b4,",
"0300000025090000e803000000000000,Mayflash Wii Classic Controller,a:b1,b:b0,back:b8,dpdown:b13,dpleft:b12,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,",
"03000000790000000018000000000000,Mayflash WiiU Pro Game Controller Adapter (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
"03000000efbe0000edfe000000000000,Monect Virtual Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b0,",
"030000006b140000010c000000000000,NACON GC-400ES,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,",
"030000001008000001e5000000000000,NEXT SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b6,start:b9,x:b3,y:b0,",
"03000000152000000182000000000000,NGDS,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b3,y:b0,",
"030000005509000000b4000000000000,NVIDIA Virtual Gamepad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:+a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:-a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
"030000004b120000014d000000000000,NYKO AIRFLO EX,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b2,y:b3,",
"03000000790000004318000000000000,Nintendo GameCube Controller,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b0,y:b3,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"03000000790000004318000000000000,Nintendo GameCube Controller,a:b1,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b2,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"03000000bd12000015d0000000000000,Nintendo Retrolink USB Super SNES Classic Controller,a:b2,b:b1,back:b8,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b9,x:b3,y:b0,",
"030000007e0500000920000000000000,Nintendo Switch Pro Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"030000007e0500000920000000000000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"030000000d0500000308000000000000,Nostromo N45,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b12,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b10,x:b2,y:b3,",
"03000000d62000006d57000000000000,OPP PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
"03000000362800000100000000000000,OUYA Game Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:b13,rightx:a3,righty:a4,x:b1,y:b2,",
"03000000782300000a10000000000000,Onlive Wireless Controller,a:b15,b:b14,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b11,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b13,y:b12,",
"030000006b14000001a1000000000000,Orange Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b2,y:b3,",
"03000000120c0000f60e000000000000,P4 Wired Gamepad,a:b1,b:b2,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b5,lefttrigger:b7,rightshoulder:b4,righttrigger:b6,start:b9,x:b0,y:b3,",
"030000006f0e00000901000000000000,PDP Versus Fighting Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,",
"03000000632500002306000000000000,PS Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
"03000000e30500009605000000000000,PS to USB convert cable,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,",
"03000000100800000100000000000000,PS1 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,",
"030000008f0e00007530000000000000,PS1 Controller,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b1,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
"03000000100800000300000000000000,PS2 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a4,righty:a2,start:b9,x:b3,y:b0,",
"03000000250900008888000000000000,PS2 Controller,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,",
"03000000666600006706000000000000,PS2 Controller,a:b2,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a2,righty:a3,start:b11,x:b3,y:b0,",
"030000006b1400000303000000000000,PS2 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,",
"030000009d0d00001330000000000000,PS2 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,",
"03000000250900000500000000000000,PS3 Controller,a:b2,b:b1,back:b9,dpdown:h0.8,dpleft:h0.4,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b0,y:b3,",
"030000004c0500006802000000000000,PS3 Controller,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b10,lefttrigger:a3~,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:a4~,rightx:a2,righty:a5,start:b8,x:b3,y:b0,",
"03000000632500007505000000000000,PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,",
"03000000888800000803000000000000,PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.8,dpleft:h0.4,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b9,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:b7,rightx:a3,righty:a4,start:b11,x:b0,y:b3,",
"030000008f0e00001431000000000000,PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
"030000003807000056a8000000000000,PS3 RF pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
"03000000100000008200000000000000,PS360+ v1.66,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:h0.4,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,",
"030000004c050000a00b000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
"030000004c050000c405000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,",
"030000004c050000cc09000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
"030000004c050000e60c000000000000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
"030000008f0e00000300000000000000,Piranha xtreme,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,",
"03000000d62000006dca000000000000,PowerA Pro Ex,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
"03000000d62000009557000000000000,Pro Elite PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
"03000000d62000009f31000000000000,Pro Ex mini PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
"03000000d6200000c757000000000000,Pro Ex mini PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
"03000000222c00000020000000000000,QANBA DRONE ARCADE JOYSTICK,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:a3,rightshoulder:b5,righttrigger:a4,start:b9,x:b0,y:b3,",
"03000000300f00000011000000000000,QanBa Arcade JoyStick 1008,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b10,x:b0,y:b3,",
"03000000300f00001611000000000000,QanBa Arcade JoyStick 4018,a:b1,b:b2,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b8,x:b0,y:b3,",
"03000000300f00001210000000000000,QanBa Joystick Plus,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b2,y:b3,",
"03000000341a00000104000000000000,QanBa Joystick Q4RAF,a:b5,b:b6,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b0,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b3,righttrigger:b7,start:b9,x:b1,y:b2,",
"03000000222c00000025000000000000,Qanba Dragon Arcade Joystick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
"03000000222c00000223000000000000,Qanba Obsidian Arcade Joystick (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
"03000000222c00000023000000000000,Qanba Obsidian Arcade Joystick (PS4),a:b1,b:b2,back:b13,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
"030000000d0f00001100000000000000,REAL ARCADE PRO.3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,rightstick:b11,righttrigger:b7,start:b9,x:b0,y:b3,",
"030000000d0f00007000000000000000,REAL ARCADE PRO.4 VLX,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,rightstick:b11,righttrigger:b7,start:b9,x:b0,y:b3,",
"030000000d0f00002200000000000000,REAL ARCADE Pro.V3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
"03000000050b00005819000000000000,ROG Chakram Core,a:b1,b:b0,leftx:a0,lefty:a1,x:b2,y:b3,",
"03000000050b0000181a000000000000,ROG Chakram X,a:b1,b:b0,leftx:a0,lefty:a1,x:b2,y:b3,",
"03000000050b00001a1a000000000000,ROG Chakram X,a:b1,b:b0,leftx:a0,lefty:a1,x:b2,y:b3,",
"03000000050b00001c1a000000000000,ROG Chakram X,a:b1,b:b0,leftx:a0,lefty:a1,x:b2,y:b3,",
"03000000050b0000e318000000000000,ROG Chakram,a:b1,b:b0,leftx:a0,lefty:a1,x:b2,y:b3,",
"03000000050b0000e518000000000000,ROG Chakram,a:b1,b:b0,leftx:a0,lefty:a1,x:b2,y:b3,",
"03000000321500000003000000000000,Razer Hydra,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
"03000000321500000204000000000000,Razer Panthera (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
"03000000321500000104000000000000,Razer Panthera (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
"03000000321500000507000000000000,Razer Raiju Mobile,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,",
"03000000321500000707000000000000,Razer Raiju Mobile,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,",
"03000000321500000011000000000000,Razer Raion Fightpad for PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
"03000000321500000009000000000000,Razer Serval,+lefty:+a2,-lefty:-a1,a:b0,b:b1,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,leftx:a0,rightshoulder:b5,rightstick:b9,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
"030000000d0f00006a00000000000000,Real Arcade Pro.4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
"030000000d0f00006b00000000000000,Real Arcade Pro.4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
"030000000d0f00008a00000000000000,Real Arcade Pro.4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
"030000000d0f00008b00000000000000,Real Arcade Pro.4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
"030000000d0f00005b00000000000000,Real Arcade Pro.V4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
"030000000d0f00005c00000000000000,Real Arcade Pro.V4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
"0300000000f000000300000000000000,RetroUSB.com RetroPad,a:b1,b:b5,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b0,y:b4,",
"0300000000f00000f100000000000000,RetroUSB.com Super RetroPort,a:b1,b:b5,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b0,y:b4,",
"03000000790000001100000000000000,Retrolink SNES Controller,a:b1,b:b2,back:b8,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,leftshoulder:b4,rightshoulder:b5,start:b9,x:b0,y:b3,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"03000000790000001100000000000000,Retrolink SNES Controller,a:b2,b:b1,back:b8,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"030000006b140000130d000000000000,Revolution Pro Controller 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
"030000006b140000010d000000000000,Revolution Pro Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
"030000006f0e00001e01000000000000,Rock Candy PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
"030000006f0e00002801000000000000,Rock Candy PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
"030000006f0e00002f01000000000000,Rock Candy PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
"03000000341a00000208000000000000,SL-6555-SBK,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:-a4,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a4,rightx:a3,righty:a2,start:b7,x:b2,y:b3,",
"03000000341a00000908000000000000,SL-6566,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,",
"03000000790000001c18000000000000,STK-7024X,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,",
"03000000ff1100003133000000000000,SVEN X-PAD,a:b2,b:b3,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a4,start:b5,x:b0,y:b1,",
"03000000457500002211000000000000,SZMY-POWER PC Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
"03000000a306000023f6000000000000,Saitek Cyborg V.1 Game pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b0,y:b3,",
"03000000a30600001af5000000000000,Saitek Cyborg,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b0,y:b3,",
"03000000300f00001201000000000000,Saitek Dual Analog Pad,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,",
"03000000a30600000cff000000000000,Saitek P2500 Force Rumble Pad,a:b2,b:b3,back:b11,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,x:b0,y:b1,",
"03000000a30600000c04000000000000,Saitek P2900,a:b1,b:b2,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b3,",
"03000000300f00001001000000000000,Saitek P480 Rumble Pad,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,",
"03000000a30600000b04000000010000,Saitek P990 Dual Analog Pad,a:b1,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b8,x:b0,y:b3,",
"03000000a30600000b04000000000000,Saitek P990,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b3,",
"03000000a30600002106000000000000,Saitek PS1000,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b0,y:b3,",
"03000000a306000020f6000000000000,Saitek PS2700,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b0,y:b3,",
"03000000300f00001101000000000000,Saitek Rumble Pad,a:b2,b:b3,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,",
"0300000000050000289b000000000000,Saturn_Adapter_2.0,a:b1,b:b2,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b0,y:b3,",
"030000009b2800000500000000000000,Saturn_Adapter_2.0,a:b1,b:b2,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b0,y:b3,",
"030000008f0e00000800000000000000,SpeedLink Strike FX,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,",
"03000000c01100000591000000000000,Speedlink Torid,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,",
"03000000de280000ff11000000000000,Steam Virtual Gamepad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:+a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:-a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
"03000000110100003114000000000000,SteelSeries Stratus Duo,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,",
"03000000381000001814000000000000,SteelSeries Stratus XL,a:b0,b:b1,back:b18,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,guide:b19,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b2,y:b3,",
"03000000110100001914000000000000,SteelSeries,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:,leftstick:b13,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:,rightstick:b14,righttrigger:b7,rightx:a3,righty:a4,start:b11,x:b3,y:b4,",
"03000000d620000011a7000000000000,Switch,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
"030000004f04000007d0000000000000,T Mini Wireless,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
"03000000fa1900000706000000000000,Team 5,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,",
"03000000b50700001203000000000000,Techmobility X6-38V,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,",
"030000004f0400000ed0000000000000,ThrustMaster eSwap PRO Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
"030000004f04000015b3000000000000,Thrustmaster Dual Analog 4,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,",
"030000004f04000023b3000000000000,Thrustmaster Dual Trigger 3-in-1,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
"030000004f04000004b3000000000000,Thrustmaster Firestorm Dual Power 3,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,",
"030000004f04000000b3000000000000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b11,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b10,x:b1,y:b3,",
"03000000666600000488000000000000,TigerGame PS/PS2 Game Controller Adapter,a:b2,b:b1,back:b9,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,",
"03000000d62000006000000000000000,Tournament PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
"030000005f140000c501000000000000,Trust Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,",
"03000000b80500000210000000000000,Trust Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,",
"03000000d90400000200000000000000,TwinShock PS2,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,",
"03000000300f00000701000000000000,USB 4-Axis 12-Button Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b3,y:b0,",
"03000000341a00002308000000000000,USB Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,",
"030000006b1400000203000000000000,USB Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,",
"03000000790000000a00000000000000,USB Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b3,y:b0,",
"03000000f0250000c183000000000000,USB Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
"03000000ff1100004133000000000000,USB Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a4,righty:a2,start:b9,x:b3,y:b0,",
"03000000632500002305000000000000,USB Vibration Joystick (BM),a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,",
"03000000790000001b18000000000000,Venom Arcade Joystick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,",
"030000006f0e00000302000000000000,Victrix Pro Fight Stick for PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,",
"030000006f0e00000702000000000000,Victrix Pro Fight Stick for PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,",
"03000000450c00002043000000000000,XEOX Gamepad SL-6556-BK,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,",
"03000000341a00000608000000000000,Xeox,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,",
"03000000172700004431000000000000,XiaoMi Game Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b20,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a7,rightx:a2,righty:a5,start:b11,x:b3,y:b4,",
"03000000c0160000e105000000000000,Xin-Mo Dual Arcade,crc:2246,a:b1,b:b2,back:b9,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,rightshoulder:b4,righttrigger:b5,start:b8,x:b0,y:b3,", /* Ultimate Atari Fight Stick */
"03000000790000004f18000000000000,ZD-T Android,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,",
"03000000120c0000101e000000000000,ZEROPLUS P4 Wired Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
"03000000d81d00000f00000000000000,iBUFFALO BSGP1204 Series,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b9,x:b3,y:b0,",
"03000000d81d00001000000000000000,iBUFFALO BSGP1204P Series,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b9,x:b3,y:b0,",
"03000000830500006020000000000000,iBuffalo SNES Controller,a:b0,b:b1,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b2,y:b3,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"03000000830500006020000000000000,iBuffalo SNES Controller,a:b1,b:b0,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b3,y:b2,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"030000004f04000003d0000000000000,run'n'drive,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b7,leftshoulder:a3,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:a4,rightstick:b11,righttrigger:b5,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
"03000000101c0000171c000000000000,uRage Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,",
#endif
#ifdef __MACOS__
"03000000c82d00000090000001000000,8BitDo FC30 Pro,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b3,y:b4,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"03000000c82d00000090000001000000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"03000000c82d00001038000000010000,8BitDo FC30 Pro,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"03000000c82d00001038000000010000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"03000000c82d00000650000001000000,8BitDo M30 Gamepad,a:b0,b:b1,back:b10,guide:b2,leftshoulder:b6,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a5,start:b11,x:b3,y:b4,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"03000000c82d00000650000001000000,8BitDo M30 Gamepad,a:b1,b:b0,back:b10,guide:b2,leftshoulder:b6,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a5,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"03000000c82d00005106000000010000,8BitDo M30 Gamepad,a:b0,b:b1,back:b10,guide:b2,leftshoulder:b6,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,start:b11,x:b3,y:b4,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"03000000c82d00005106000000010000,8BitDo M30 Gamepad,a:b1,b:b0,back:b10,guide:b2,leftshoulder:b6,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"03000000c82d00001590000001000000,8BitDo N30 Pro 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b3,y:b4,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"03000000c82d00001590000001000000,8BitDo N30 Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"03000000c82d00006528000000010000,8BitDo N30 Pro 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"03000000c82d00006528000000010000,8BitDo N30 Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"030000003512000012ab000001000000,8BitDo NES30 Gamepad,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"030000003512000012ab000001000000,8BitDo NES30 Gamepad,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"03000000022000000090000001000000,8BitDo NES30 Pro,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"03000000022000000090000001000000,8BitDo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"03000000203800000900000000010000,8BitDo NES30 Pro,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"03000000203800000900000000010000,8BitDo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"03000000c82d00000660000000020000,8BitDo Pro 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"03000000c82d00000660000000020000,8BitDo Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"03000000102800000900000000000000,8BitDo SFC30 Gamepad,a:b0,b:b1,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b3,y:b4,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"03000000102800000900000000000000,8BitDo SFC30 Gamepad,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"03000000c82d00001290000001000000,8BitDo SN30 Gamepad,a:b0,b:b1,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b3,y:b4,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"03000000c82d00001290000001000000,8BitDo SN30 Gamepad,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"03000000c82d00000260000001000000,8BitDo SN30 Pro+,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"03000000c82d00000260000001000000,8BitDo SN30 Pro+,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"03000000c82d00000261000000010000,8BitDo SN30 Pro+,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"03000000c82d00000261000000010000,8BitDo SN30 Pro+,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"03000000c82d00000160000001000000,8BitDo SN30 Pro,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b3,y:b4,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"03000000c82d00000160000001000000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"03000000c82d00001130000000020000,8BitDo Ultimate Wired Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b26,paddle1:b24,paddle2:b25,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
"03000000c82d00001330000000020000,8BitDo Ultimate Wireless Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b26,paddle1:b23,paddle2:b19,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
"03000000c82d00001890000001000000,8BitDo Zero 2,a:b0,b:b1,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b3,y:b4,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"03000000c82d00001890000001000000,8BitDo Zero 2,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"03000000c82d00003032000000010000,8BitDo Zero 2,a:b0,b:b1,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b3,y:b4,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"03000000c82d00003032000000010000,8BitDo Zero 2,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"03000000a00500003232000008010000,8BitDo Zero Gamepad,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"03000000a00500003232000008010000,8BitDo Zero Gamepad,a:b1,b:b2,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"03000000a00500003232000009010000,8BitDo Zero Gamepad,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"03000000a00500003232000009010000,8BitDo Zero Gamepad,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"03000000050b00000579000000010000,ASUS ROG Kunai 3 Gamepad,a:b0,b:b1,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b14,leftshoulder:b6,leftstick:b15,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b42,paddle1:b9,paddle2:b11,rightshoulder:b7,rightstick:b16,righttrigger:a4,rightx:a2,righty:a3,start:b13,x:b3,y:b4,",
"03000000050b00000679000000010000,ASUS ROG Kunai 3 Gamepad,a:b0,b:b1,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b14,leftshoulder:b6,leftstick:b15,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b23,rightshoulder:b7,rightstick:b16,righttrigger:a4,rightx:a2,righty:a3,start:b13,x:b3,y:b4,",
"03000000491900001904000001010000,Amazon Luna Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b9,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b7,x:b2,y:b3,",
"03000000710100001904000000010000,Amazon Luna Controller,a:b0,b:b1,back:b11,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b9,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
"03000000c62400001a89000000010000,BDA MOGA XP5-X Plus,a:b0,b:b1,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b14,leftshoulder:b6,leftstick:b15,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b16,righttrigger:a4,rightx:a2,righty:a3,start:b13,x:b3,y:b4,",
"03000000c62400001b89000000010000,BDA MOGA XP5-X Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
"03000000d62000002a79000000010000,BDA PS4 Fightpad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
"030000008305000031b0000000000000,Cideko AK08b,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
"03000000260900008888000088020000,Cyber Gadget GameCube Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:a5,rightx:a2,righty:a3~,start:b7,x:b2,y:b3,",
"03000000a306000022f6000001030000,Cyborg V.3 Rumble Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:+a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:-a3,rightx:a2,righty:a4,start:b9,x:b0,y:b3,",
"030000000d0f00008400000000010000,Fighting Commander,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
"030000000d0f00008500000000010000,Fighting Commander,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
"03000000ac0500001a06000002020000,GameSir-T3 2.02,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
"0500000047532047616d657061640000,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,",
"03000000c01100000140000000010000,GameStop PS4 Fun Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
"03000000ad1b000001f9000000000000,Gamestop BB-070 X360 Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,",
"03000000d11800000094000000010000,Google Stadia Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,",
"030000000d0f00005f00000000000000,HORI Fighting Commander 4 PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
"030000000d0f00005e00000000000000,HORI Fighting Commander 4 PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
"030000000d0f00008800000000010000,HORI Fighting Stick mini 4 (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,rightstick:b11,righttrigger:b7,start:b9,x:b0,y:b3,",
"030000000d0f00008700000000010000,HORI Fighting Stick mini 4 (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,rightstick:b11,righttrigger:b7,start:b9,x:b0,y:b3,",
"030000000d0f00004d00000000000000,HORI Gem Pad 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
"030000000d0f0000aa00000072050000,HORI Real Arcade Pro,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,",
"030000000d0f00006e00000000010000,HORIPAD 4 (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
"030000000d0f00006600000000010000,HORIPAD 4 (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
"030000000d0f00006600000000000000,HORIPAD FPS PLUS 4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
"030000000d0f00005f00000000010000,Hori Fighting Commander 4 (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
"030000000d0f00005e00000000010000,Hori Fighting Commander 4 (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
"030000008f0e00001330000011010000,HuiJia SNES Controller,a:b4,b:b2,back:b16,dpdown:+a2,dpleft:-a0,dpright:+a0,dpup:-a2,leftshoulder:b12,rightshoulder:b14,start:b18,x:b6,y:b0,",
"030000006d04000016c2000000020000,Logitech Dual Action,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
"030000006d04000016c2000000030000,Logitech Dual Action,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
"030000006d04000016c2000014040000,Logitech Dual Action,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
"030000006d04000016c2000000000000,Logitech F310 Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,", /* Guide button doesn't seem to be sent in DInput mode. */
"030000006d04000018c2000000000000,Logitech F510 Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
"030000006d0400001fc2000000000000,Logitech F710 Gamepad (XInput),a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,",
"030000006d04000019c2000000000000,Logitech Wireless Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,", /* This includes F710 in DInput mode and the "Logitech Cordless RumblePad 2", at the very least. */
"03000000d8140000cecf000000000000,MC Cthulhu,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,",
"03000000c62400002a89000000010000,MOGA XP5-A Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b21,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
"03000000c62400002b89000000010000,MOGA XP5-A Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
"03000000380700005032000000010000,Mad Catz FightPad PRO (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
"03000000380700005082000000010000,Mad Catz FightPad PRO (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
"03000000380700008433000000010000,Mad Catz FightStick TE S+ (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
"03000000380700008483000000010000,Mad Catz FightStick TE S+ (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
"03000000790000004418000000010000,Mayflash GameCube Controller,a:b1,b:b2,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b0,y:b3,",
"0300000025090000e803000000000000,Mayflash Wii Classic Controller,a:b1,b:b0,back:b8,dpdown:b13,dpleft:b12,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,",
"03000000790000000018000000000000,Mayflash WiiU Pro Game Controller Adapter (DInput),a:b4,b:b8,back:b32,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b16,leftstick:b40,lefttrigger:b24,leftx:a0,lefty:a4,rightshoulder:b20,rightstick:b44,righttrigger:b28,rightx:a8,righty:a12,start:b36,x:b0,y:b12,",
"030000001008000001e5000006010000,NEXT SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b6,start:b9,x:b3,y:b0,",
"03000000550900001472000025050000,NVIDIA Controller v01.04,a:b0,b:b1,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b4,leftstick:b7,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a5,start:b6,x:b2,y:b3,",
"030000004b120000014d000000010000,NYKO AIRFLO EX,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b2,y:b3,",
"030000007e0500000920000000000000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,",
"050000007e05000009200000ff070000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"050000007e05000009200000ff070000,Nintendo Switch Pro Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b3,y:b2,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"030000006f0e00000901000002010000,PDP Versus Fighting Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,",
"030000004c0500006802000000000000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,",
"030000004c0500006802000000010000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,",
"030000004c050000a00b000000010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
"030000004c050000c405000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
"030000004c050000c405000000010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
"030000004c050000cc09000000010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
"050000004c050000e60c000000010000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
"030000008f0e00000300000000000000,Piranha xtreme,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,",
"03000000222c00000225000000010000,Qanba Dragon Arcade Joystick (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
"030000008916000000fd000000000000,Razer Onza TE,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,",
"03000000321500000204000000010000,Razer Panthera (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
"03000000321500000104000000010000,Razer Panthera (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
"03000000321500000010000000010000,Razer RAIJU,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
"03000000321500000507000001010000,Razer Raiju Mobile,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b21,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
"03000000321500000011000000010000,Razer Raion Fightpad for PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
"03000000321500000009000000020000,Razer Serval,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,",
"0300000032150000030a000000000000,Razer Wildcat,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,",
"03000000790000001100000000000000,Retrolink Classic Controller,a:b2,b:b1,back:b8,leftshoulder:b4,leftx:a3,lefty:a4,rightshoulder:b5,start:b9,x:b3,y:b0,",
"03000000790000001100000006010000,Retrolink SNES Controller,a:b1,b:b2,back:b8,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,leftshoulder:b4,rightshoulder:b5,start:b9,x:b0,y:b3,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"03000000790000001100000006010000,Retrolink SNES Controller,a:b2,b:b1,back:b8,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"030000006b140000130d000000010000,Revolution Pro Controller 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
"030000006b140000010d000000010000,Revolution Pro Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
"030000003512000021ab000000000000,SFC30 Joystick,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,",
"03000000457500002211000000010000,SZMY-POWER PC Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
"03000000b40400000a01000000000000,Sega Saturn USB Gamepad,a:b0,b:b1,back:b5,guide:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b8,x:b3,y:b4,",
"03000000811700007e05000000000000,Sega Saturn,a:b2,b:b4,dpdown:b16,dpleft:b15,dpright:b14,dpup:b17,leftshoulder:b8,lefttrigger:a5,leftx:a0,lefty:a2,rightshoulder:b9,righttrigger:a4,start:b13,x:b0,y:b6,",
"030000004c050000cc09000000000000,Sony DualShock 4 V2,a:b1,b:b2,back:b13,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
"030000004c050000a00b000000000000,Sony DualShock 4 Wireless Adaptor,a:b1,b:b2,back:b13,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
"030000005e0400008e02000001000000,Steam Virtual Gamepad,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,",
"050000004e696d6275732b0000000000,SteelSeries Nimbus+,a:b0,b:b1,back:b15,dpdown:b11,dpleft:b13,dpright:b12,dpup:b10,guide:b16,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3~,start:b14,x:b2,y:b3,",
"03000000110100002014000000000000,SteelSeries Nimbus,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b12,x:b2,y:b3,",
"03000000110100002014000001000000,SteelSeries Nimbus,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3~,x:b2,y:b3,",
"03000000381000002014000001000000,SteelSeries Nimbus,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3~,x:b2,y:b3,",
"03000000110100001714000000000000,SteelSeries Stratus XL,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3~,start:b12,x:b2,y:b3,",
"03000000110100001714000020010000,SteelSeries Stratus XL,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3~,start:b12,x:b2,y:b3,",
"030000004f0400000ed0000000020000,ThrustMaster eSwap PRO Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
"030000004f04000015b3000000000000,Thrustmaster Dual Analog 3.2,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,",
"030000004f04000000b3000000000000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b11,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,rightx:a2,righty:a3,start:b10,x:b1,y:b3,",
"03000000bd12000015d0000000000000,Tomee SNES USB Controller,a:b2,b:b1,back:b8,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b9,x:b3,y:b0,",
"03000000bd12000015d0000000010000,Tomee SNES USB Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,",
"03000000100800000100000000000000,Twin USB Joystick,a:b4,b:b2,back:b16,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b12,leftstick:b20,lefttrigger:b8,leftx:a0,lefty:a2,rightshoulder:b14,rightstick:b22,righttrigger:b10,rightx:a6,righty:a4,start:b18,x:b6,y:b0,",
"030000006f0e00000302000025040000,Victrix Pro Fight Stick for PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,",
"030000006f0e00000702000003060000,Victrix Pro Fight Stick for PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,",
"050000005769696d6f74652028303000,Wii Remote,a:b4,b:b5,back:b7,dpdown:b3,dpleft:b0,dpright:b1,dpup:b2,guide:b8,leftshoulder:b11,lefttrigger:b12,leftx:a0,lefty:a1,start:b6,x:b10,y:b9,",
"050000005769696d6f74652028313800,Wii U Pro Controller,a:b16,b:b15,back:b7,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b8,leftshoulder:b19,leftstick:b23,lefttrigger:b21,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b24,righttrigger:b22,rightx:a2,righty:a3,start:b6,x:b18,y:b17,",
"030000005e0400008e02000000000000,X360 Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,",
"03000000c6240000045d000000000000,Xbox 360 Wired Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,",
"030000005e040000050b000003090000,Xbox Elite Wireless Controller,a:b0,b:b1,back:b38,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
"030000005e040000d102000000000000,Xbox One Wired Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,",
"030000005e040000dd02000000000000,Xbox One Wired Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,",
"030000005e040000e302000000000000,Xbox One Wired Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,",
"030000005e040000200b000011050000,Xbox Wireless Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
"030000005e040000e002000000000000,Xbox Wireless Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
"030000005e040000e002000003090000,Xbox Wireless Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
"030000005e040000ea02000000000000,Xbox Wireless Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,",
"030000005e040000fd02000003090000,Xbox Wireless Controller,a:b0,b:b1,back:b16,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
"03000000172700004431000029010000,XiaoMi Game Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a6,rightx:a2,righty:a5,start:b11,x:b3,y:b4,",
"03000000c0160000e105000000040000,Xin-Mo Dual Arcade,crc:82d5,a:b2,b:b4,back:b18,dpdown:+a2,dpleft:-a0,dpright:+a0,dpup:-a2,rightshoulder:b8,righttrigger:b10,start:b16,x:b0,y:b6,", /* Ultimate Atari Fight Stick */
"03000000120c0000100e000000010000,ZEROPLUS P4 Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
"03000000120c0000101e000000010000,ZEROPLUS P4 Wired Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
"03000000830500006020000000010000,iBuffalo SNES Controller,a:b0,b:b1,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b2,y:b3,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"03000000830500006020000000010000,iBuffalo SNES Controller,a:b1,b:b0,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b3,y:b2,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"03000000830500006020000000000000,iBuffalo USB 2-axis 8-button Gamepad,a:b1,b:b0,back:b6,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b3,y:b2,",
#endif
#if defined(SDL_JOYSTICK_LINUX) || defined(__OpenBSD__)
"03000000c82d00000090000011010000,8BitDo FC30 Pro,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b3,y:b4,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"03000000c82d00000090000011010000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"05000000c82d00001038000000010000,8BitDo FC30 Pro,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"05000000c82d00001038000000010000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"03000000c82d00000650000011010000,8BitDo M30 Gamepad,a:b0,b:b1,back:b10,guide:b2,leftshoulder:b6,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a5,start:b11,x:b3,y:b4,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"05000000c82d00005106000000010000,8BitDo M30 Gamepad,a:b1,b:b0,back:b10,guide:b2,leftshoulder:b6,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"03000000c82d00001590000011010000,8BitDo N30 Pro 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b3,y:b4,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"03000000c82d00001590000011010000,8BitDo N30 Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"05000000c82d00006528000000010000,8BitDo N30 Pro 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"05000000c82d00006528000000010000,8BitDo N30 Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"030000003512000012ab000010010000,8BitDo NES30 Gamepad,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"030000003512000012ab000010010000,8BitDo NES30 Gamepad,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"03000000022000000090000011010000,8BitDo NES30 Pro,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"03000000022000000090000011010000,8BitDo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"03000000c82d00000190000011010000,8BitDo NES30 Pro,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b3,y:b4,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"03000000c82d00000190000011010000,8BitDo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"05000000203800000900000000010000,8BitDo NES30 Pro,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"05000000203800000900000000010000,8BitDo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"05000000c82d00002038000000010000,8BitDo NES30 Pro,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"05000000c82d00002038000000010000,8BitDo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"03000000c82d00000020000000000000,8BitDo Pro 2 Wired Controller for Xbox,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
"06000000c82d00000020000006010000,8BitDo Pro 2 Wired Controller for Xbox,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
"03000000c82d00000660000011010000,8BitDo Pro 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"03000000c82d00000660000011010000,8BitDo Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"05000000c82d00000660000000010000,8BitDo Pro 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"05000000c82d00000660000000010000,8BitDo Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"05000000c82d00000061000000010000,8BitDo SF30 Pro,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"05000000c82d00000061000000010000,8BitDo SF30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"05000000102800000900000000010000,8BitDo SFC30 Gamepad,a:b0,b:b1,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b3,y:b4,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"05000000102800000900000000010000,8BitDo SFC30 Gamepad,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"05000000c82d00003028000000010000,8BitDo SFC30 Gamepad,a:b0,b:b1,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b3,y:b4,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"05000000c82d00003028000000010000,8BitDo SFC30 Gamepad,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"03000000c82d00000260000011010000,8BitDo SN30 Pro+,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"03000000c82d00000260000011010000,8BitDo SN30 Pro+,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"05000000c82d00000261000000010000,8BitDo SN30 Pro+,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"05000000c82d00000261000000010000,8BitDo SN30 Pro+,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"03000000c82d00000160000011010000,8BitDo SN30 Pro,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b3,y:b4,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"03000000c82d00000160000011010000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"030000003512000020ab000010010000,8BitDo SNES30 Gamepad,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"030000003512000020ab000010010000,8BitDo SNES30 Gamepad,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"05000000202800000900000000010000,8BitDo SNES30 Gamepad,a:b0,b:b1,back:b10,dpdown:b122,dpleft:b119,dpright:b120,dpup:b117,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"05000000202800000900000000010000,8BitDo SNES30 Gamepad,a:b1,b:b0,back:b10,dpdown:b122,dpleft:b119,dpright:b120,dpup:b117,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"03000000c82d00001130000011010000,8BitDo Ultimate Wired Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b26,paddle1:b24,paddle2:b25,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
"03000000c82d00001330000011010000,8BitDo Ultimate Wireless Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b26,paddle1:b23,paddle2:b19,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
"03000000c82d00001890000011010000,8BitDo Zero 2,a:b0,b:b1,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b3,y:b4,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"03000000c82d00001890000011010000,8BitDo Zero 2,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"05000000c82d00003032000000010000,8BitDo Zero 2,a:b0,b:b1,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b3,y:b4,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"05000000c82d00003032000000010000,8BitDo Zero 2,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"05000000a00500003232000001000000,8BitDo Zero Gamepad,a:b0,b:b1,back:b10,dpdown:b122,dpleft:b119,dpright:b120,dpup:b117,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"05000000a00500003232000001000000,8BitDo Zero Gamepad,a:b1,b:b0,back:b10,dpdown:b122,dpleft:b119,dpright:b120,dpup:b117,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"05000000a00500003232000008010000,8BitDo Zero Gamepad,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"05000000a00500003232000008010000,8BitDo Zero Gamepad,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"03000000c82d00000031000011010000,8Bitdo Receiver,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,",
"03000000c82d00001290000011010000,8Bitdo SN30 Gamepad,a:b0,b:b1,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b3,y:b4,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"03000000c82d00001290000011010000,8Bitdo SN30 Gamepad,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"05000000c82d00006228000000010000,8Bitdo SN30 Gamepad,a:b0,b:b1,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b3,y:b4,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"05000000c82d00006228000000010000,8Bitdo SN30 Gamepad,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"05000000050b00000045000031000000,ASUS Gamepad,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b10,x:b2,y:b3,",
"05000000050b00000045000040000000,ASUS Gamepad,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b10,x:b2,y:b3,",
"03000000050b00000579000011010000,ASUS ROG Kunai 3 Gamepad,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b36,paddle1:b52,paddle2:b53,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
"05000000050b00000679000000010000,ASUS ROG Kunai 3 Gamepad,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b21,paddle1:b22,paddle2:b23,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
"030000006f0e00003901000020060000,Afterglow Controller for Xbox One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
"030000006f0e00003901000000430000,Afterglow Prismatic Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
"030000006f0e00001302000000010000,Afterglow,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
"03000000100000008200000011010000,Akishop Customs PS360+ v1.66,a:b1,b:b2,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,",
"05000000491900000204000021000000,Amazon Fire Game Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b17,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b12,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
"03000000491900001904000011010000,Amazon Luna Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b9,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b7,x:b2,y:b3,",
"05000000710100001904000000010000,Amazon Luna Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
"03000000790000003018000011010000,Arcade Fightstick F300,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,",
"03000000503200000110000000000000,Atari Classic Controller,a:b0,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b4,start:b3,x:b1,",
"05000000503200000110000000000000,Atari Classic Controller,a:b0,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b4,start:b3,x:b1,",
"03000000503200000210000000000000,Atari Game Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a4,rightx:a2,righty:a3,start:b8,x:b2,y:b3,",
"05000000503200000210000000000000,Atari Game Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b2,",
"030000005e0400008e02000047010000,Atari Xbox 360 Game Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
"03000000c62400001b89000011010000,BDA MOGA XP5-X Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
"03000000d62000002a79000011010000,BDA PS4 Fightpad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
"03000000120c0000f70e000011010000,Brook Universal Fighting Board,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:,lefty:,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:,righty:,start:b9,x:b0,y:b3,",
"03000000b40400000a01000000010000,CYPRESS USB Gamepad,a:b0,b:b1,back:b5,guide:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b8,x:b3,y:b4,",
"03000000ffff0000ffff000000010000,Chinese-made Xbox Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b4,",
"03000000e82000006058000001010000,Cideko AK08b,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,",
"03000000260900008888000000010000,Cyber Gadget GameCube Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:a5,rightx:a2,righty:a3~,start:b7,x:b2,y:b3,",
"03000000a306000022f6000011010000,Cyborg V.3 Rumble Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:+a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:-a3,rightx:a2,righty:a4,start:b9,x:b0,y:b3,",
"050000004c050000f20d000000010000,DualSense Edge Wireless Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
"030000006f0e00003001000001010000,EA Sports PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
"03000000790000001100000010010000,Elecom Gamepad,crc:e86c,a:b2,b:b3,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b0,y:b1,",
"0300000079000000d418000000010000,GPD Win 2 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
"0500000047532067616d657061640000,GS Gamepad,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,",
"03000000341a000005f7000010010000,GameCube {HuiJia USB box},a:b1,b:b2,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b0,y:b3,",
"03000000bc2000000055000011010000,GameSir G3w,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
"0500000049190000020400001b010000,GameSir T4 Pro,crc:8283,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b23,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
"03000000ac0500001a06000011010000,GameSir-T3 2.02,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
"0500000047532047616d657061640000,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,",
"03000000c01100000140000011010000,GameStop PS4 Fun Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
"030000006f0e00000104000000010000,Gamestop Logic3 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
"030000008f0e00000800000010010000,Gasia Co. Ltd PS(R) Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,",
"030000006f0e00001304000000010000,Generic X-Box pad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
"03000000f0250000c183000010010000,Goodbetterbest Ltd USB Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
"03000000d11800000094000011010000,Google Stadia Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,",
"05000000d11800000094000000010000,Google Stadia Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,",
"03000000280400000140000000010000,Gravis Gamepad Pro USB ,a:b1,b:b2,back:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,",
"030000008f0e00000610000000010000,GreenAsia Electronics 4Axes 12Keys Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a3,righty:a2,start:b11,x:b3,y:b0,",
"030000008f0e00001200000010010000,GreenAsia Inc. USB Joystick,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b2,y:b3,",
"03000000c9110000f055000011010000,HJC Game GAMEPAD,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,",
"030000000d0f00001000000011010000,HORI CO. LTD. FIGHTING STICK 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,",
"030000000d0f00002200000011010000,HORI CO. LTD. REAL ARCADE Pro.V3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,",
"030000000d0f00006a00000011010000,HORI CO. LTD. Real Arcade Pro.4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
"030000000d0f00006b00000011010000,HORI CO. LTD. Real Arcade Pro.4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
"030000000d0f00005001000009040000,HORI Fighting Commander OCTA,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
"030000000d0f00008400000011010000,HORI Fighting Commander,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
"030000000d0f00008500000010010000,HORI Fighting Commander,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
"030000000d0f00008800000011010000,HORI Fighting Stick mini 4 (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,rightstick:b11,righttrigger:b7,start:b9,x:b0,y:b3,",
"030000000d0f00008700000011010000,HORI Fighting Stick mini 4 (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,rightshoulder:b5,rightstick:b11,righttrigger:a4,start:b9,x:b0,y:b3,",
"030000000d0f0000d800000072056800,HORI Real Arcade Pro S,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
"030000000d0f0000aa00000011010000,HORI Real Arcade Pro,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,",
"030000000d0f00006e00000011010000,HORIPAD 4 (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
"030000000d0f00006600000011010000,HORIPAD 4 (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
"030000000d0f00006700000001010000,HORIPAD ONE,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
"06000000adde0000efbe000002010000,Hidromancer Game Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
"03000000d81400000862000011010000,HitBox (PS3/PC) Analog Mode,a:b1,b:b2,back:b8,guide:b9,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b12,x:b0,y:b3,",
"030000000d0f00005f00000011010000,Hori Fighting Commander 4 (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
"030000000d0f00005e00000011010000,Hori Fighting Commander 4 (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
"030000000d0f00008600000002010000,Hori Fighting Commander,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,",
"03000000ad1b000001f5000033050000,Hori Pad EX Turbo 2,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
"030000008f0e00001330000010010000,HuiJia SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b9,x:b3,y:b0,",
"03000000242e00008816000001010000,Hyperkin X91,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
"03000000d80400008200000003000000,IMS PCU#0 Gamepad Interface,a:b1,b:b0,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,start:b5,x:b3,y:b2,",
"03000000fd0500000030000000010000,InterAct GoPad I-73000 (Fighting Game Layout),a:b3,b:b4,back:b6,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,start:b7,x:b0,y:b1,",
"05000000491900000204000000000000,Ipega PG-9087S,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
"030000006e0500000320000010010000,JC-U3613M - DirectInput Mode,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b0,y:b1,",
"03000000300f00001001000010010000,Jess Tech Dual Analog Rumble Pad,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,",
"03000000ba2200002010000001010000,Jess Technology USB Game Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b3,y:b0,",
"030000006f0e00000103000000020000,Logic3 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
"030000006d040000d1ca000011010000,Logitech Chillstream,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
"030000006d04000019c2000010010000,Logitech Cordless RumblePad 2,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
"030000006d04000016c2000010010000,Logitech Dual Action,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
"030000006d04000016c2000011010000,Logitech Dual Action,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
"030000006d0400001dc2000014400000,Logitech F310 Gamepad (XInput),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
"030000006d0400001ec2000020200000,Logitech F510 Gamepad (XInput),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
"030000006d04000019c2000011010000,Logitech F710 Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,", /* Guide button doesn't seem to be sent in DInput mode. */
"030000006d0400001fc2000005030000,Logitech F710 Gamepad (XInput),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
"030000006d04000018c2000010010000,Logitech RumblePad 2,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
"030000006d04000011c2000010010000,Logitech WingMan Cordless RumblePad,a:b0,b:b1,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b6,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b10,rightx:a3,righty:a4,start:b8,x:b3,y:b4,",
"03000000c62400002b89000011010000,MOGA XP5-A Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
"05000000c62400002a89000000010000,MOGA XP5-A Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b22,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
"05000000c62400001a89000000010000,MOGA XP5-X Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
"03000000250900006688000000010000,MP-8866 Super Dual Box,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,",
"05000000380700006652000025010000,Mad Catz C.T.R.L.R ,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
"03000000380700005032000011010000,Mad Catz FightPad PRO (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
"03000000380700005082000011010000,Mad Catz FightPad PRO (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
"03000000380700008433000011010000,Mad Catz FightStick TE S+ (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
"03000000380700008483000011010000,Mad Catz FightStick TE S+ (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
"03000000ad1b00002ef0000090040000,Mad Catz Fightpad SFxT,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,start:b7,x:b2,y:b3,",
"03000000380700003847000090040000,Mad Catz Wired Xbox 360 Controller (SFIV),a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,",
"03000000380700001647000010040000,Mad Catz Wired Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
"03000000ad1b000016f0000090040000,Mad Catz Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
"03000000380700008034000011010000,Mad Catz fightstick (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
"03000000380700008084000011010000,Mad Catz fightstick (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
"03000000380700001888000010010000,MadCatz PC USB Wired Stick 8818,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
"03000000380700003888000010010000,MadCatz PC USB Wired Stick 8838,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:a0,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
"03000000790000004418000010010000,Mayflash GameCube Controller,a:b1,b:b2,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b0,y:b3,",
"03000000780000000600000010010000,Microntek USB Joystick,a:b2,b:b1,back:b8,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,",
"030000005e0400000e00000000010000,Microsoft SideWinder,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,rightshoulder:b7,start:b8,x:b3,y:b4,",
"030000005e0400008e02000004010000,Microsoft X-Box 360 pad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
"030000005e0400008e02000062230000,Microsoft X-Box 360 pad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
"030000005e040000d102000003020000,Microsoft X-Box One pad v2,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
"030000005e040000d102000001010000,Microsoft X-Box One pad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
"030000005e0400008502000000010000,Microsoft X-Box pad (Japan),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b4,",
"030000005e0400008902000021010000,Microsoft X-Box pad v2 (US),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b4,",
"030000005e0400008902000020010000,Microsoft Xbox Controller S,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b4,",
"05000000d6200000ad0d000001000000,Moga Pro,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
"030000006b140000010c000010010000,NACON GC-400ES,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,",
"030000001008000001e5000010010000,NEXT SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b6,start:b9,x:b3,y:b0,",
"03000000550900001472000011010000,NVIDIA Controller v01.04,a:b0,b:b1,back:b14,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b17,leftshoulder:b4,leftstick:b7,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a5,start:b6,x:b2,y:b3,",
"03000000550900001072000011010000,NVIDIA Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b13,leftshoulder:b4,leftstick:b8,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,",
"030000004b120000014d000000010000,NYKO AIRFLO EX,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b2,y:b3,",
"03000000451300000830000010010000,NYKO CORE,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
"03000000790000004318000010010000,Nintendo GameCube Controller,a:b1,b:b2,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b0,y:b3,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"03000000790000004318000010010000,Nintendo GameCube Controller,a:b1,b:b0,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b2,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"030000007e0500003703000000016800,Nintendo GameCube Controller,a:b0,b:b2,dpdown:b6,dpleft:b4,dpright:b5,dpup:b7,lefttrigger:a4,leftx:a0,lefty:a1~,rightshoulder:b9,righttrigger:a5,rightx:a2,righty:a3~,start:b8,x:b1,y:b3,",
"050000007e0500000620000001800000,Nintendo Switch Joy-Con (L),a:b15,b:b16,guide:b4,leftshoulder:b6,leftstick:b12,leftx:a1,lefty:a0~,rightshoulder:b8,start:b9,x:b17,y:b14,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"050000007e0500000620000001800000,Nintendo Switch Joy-Con (L),a:b16,b:b15,guide:b4,leftshoulder:b6,leftstick:b12,leftx:a1,lefty:a0~,rightshoulder:b8,start:b9,x:b14,y:b17,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"060000007e0500000620000000000000,Nintendo Switch Joy-Con (L/R),a:b1,b:b0,back:b9,dpdown:b15,dpleft:b16,dpright:b17,dpup:b14,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b2,y:b3,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"060000007e0500000620000000000000,Nintendo Switch Joy-Con (L/R),a:b0,b:b1,back:b9,dpdown:b15,dpleft:b16,dpright:b17,dpup:b14,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b3,y:b2,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"060000007e0500000820000000000000,Nintendo Switch Joy-Con (L/R),a:b1,b:b0,back:b9,dpdown:b15,dpleft:b16,dpright:b17,dpup:b14,guide:b11,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b2,y:b3,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"060000007e0500000820000000000000,Nintendo Switch Joy-Con (L/R),a:b0,b:b1,back:b9,dpdown:b15,dpleft:b16,dpright:b17,dpup:b14,guide:b11,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b3,y:b2,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"050000007e0500000720000001800000,Nintendo Switch Joy-Con (R),a:b2,b:b1,guide:b9,leftshoulder:b4,leftstick:b10,leftx:a1~,lefty:a0,rightshoulder:b6,start:b8,x:b3,y:b0,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"050000007e0500000720000001800000,Nintendo Switch Joy-Con (R),a:b1,b:b2,guide:b9,leftshoulder:b4,leftstick:b10,leftx:a1~,lefty:a0,rightshoulder:b6,start:b8,x:b0,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"03000000d620000013a7000011010000,Nintendo Switch PowerA Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"03000000d620000013a7000011010000,Nintendo Switch PowerA Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"03000000d620000011a7000011010000,Nintendo Switch PowerA Core Plus Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"03000000d620000011a7000011010000,Nintendo Switch PowerA Core Plus Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"030000007e0500000920000011810000,Nintendo Switch Pro Controller,a:b1,b:b0,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,misc1:b4,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b2,y:b3,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"030000007e0500000920000011810000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,misc1:b4,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b3,y:b2,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"050000004c69632050726f20436f6e00,Nintendo Switch Pro Controller,crc:15b7,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"050000004c69632050726f20436f6e00,Nintendo Switch Pro Controller,crc:15b7,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"050000007e0500000920000001000000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"050000007e0500000920000001000000,Nintendo Switch Pro Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"050000007e0500000920000001800000,Nintendo Switch Pro Controller,a:b1,b:b0,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b2,y:b3,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"050000007e0500000920000001800000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b3,y:b2,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"050000007e0500000603000000060000,Nintendo Wii Remote Classic Controller,crc:0d8a,a:b0,b:b1,back:b10,dpdown:b14,dpleft:b12,dpright:b13,dpup:b11,guide:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3~,start:b9,x:b2,y:b3,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"050000007e0500000603000000060000,Nintendo Wii Remote Classic Controller,crc:0d8a,a:b1,b:b0,back:b10,dpdown:b14,dpleft:b12,dpright:b13,dpup:b11,guide:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3~,start:b9,x:b3,y:b2,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"050000007e0500003003000001000000,Nintendo Wii Remote Pro Controller,a:b1,b:b0,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"050000007e0500003003000001000000,Nintendo Wii Remote Pro Controller,a:b0,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"050000007e0500000603000000060000,Nintendo Wii Remote,crc:60be,a:b1,b:b0,back:b4,dpdown:b8,dpleft:b6,dpright:b7,dpup:b5,guide:b2,start:b3,x:b9,y:b10,",
"05000000010000000100000003000000,Nintendo Wiimote,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,",
"030000000d0500000308000010010000,Nostromo n45 Dual Analog Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b12,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b10,x:b2,y:b3,",
"05000000362800000100000002010000,OUYA Game Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,x:b1,y:b2,",
"05000000362800000100000003010000,OUYA Game Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,x:b1,y:b2,",
"030000005e0400000202000000010000,Old Xbox pad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b4,",
"03000000ff1100003133000010010000,PC Game Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,",
"030000006f0e00006401000001010000,PDP Battlefield One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
"030000006f0e00000901000011010000,PDP Versus Fighting Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,",
"03000000ff1100004133000010010000,PS2 Controller,a:b2,b:b1,back:b8,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,",
"03000000341a00003608000011010000,PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
"030000004c0500006802000010010000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,",
"030000004c0500006802000010810000,PS3 Controller,a:b0,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,",
"030000004c0500006802000011010000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:a12,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:a13,rightx:a2,righty:a3,start:b3,x:b15,y:b12,",
"030000004c0500006802000011810000,PS3 Controller,a:b0,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,",
"030000006f0e00001402000011010000,PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
"030000008f0e00000300000010010000,PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,",
"050000004c0500006802000000010000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:a12,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:a13,rightx:a2,righty:a3,start:b3,x:b15,y:b12,",
"050000004c0500006802000000800000,PS3 Controller,a:b0,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,",
"050000004c0500006802000000810000,PS3 Controller,a:b0,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,",
"05000000504c415953544154494f4e00,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,",
"060000004c0500006802000000010000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,",
"030000004c050000a00b000011010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
"030000004c050000a00b000011810000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,",
"030000004c050000c405000011010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
"030000004c050000c405000011810000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,",
"030000004c050000cc09000000010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
"030000004c050000cc09000011010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
"030000004c050000cc09000011810000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,",
"050000004c050000c405000000010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
"050000004c050000c405000000810000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,",
"050000004c050000cc09000000010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
"050000004c050000cc09000000810000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,",
"050000004c050000cc09000001800000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,",
"030000004c050000e60c000000010000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
"030000004c050000e60c000011010000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
"030000004c050000e60c000011810000,PS5 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,",
"050000004c050000e60c000000010000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
"050000004c050000e60c000000810000,PS5 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,",
"030000004c050000da0c000011010000,Playstation Controller,a:b2,b:b1,back:b8,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,",
"03000000c62400003a54000001010000,PowerA XBox One Controller,a:b0,b:b1,back:b6,dpdown:h0.7,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
"03000000c62400000053000000010000,PowerA,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
"03000000300f00001211000011010000,QanBa Arcade JoyStick,a:b2,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b5,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b6,start:b9,x:b1,y:b3,",
"03000000222c00000225000011010000,Qanba Dragon Arcade Joystick (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
"03000000222c00000025000011010000,Qanba Dragon Arcade Joystick (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
"03000000222c00000020000011010000,Qanba Drone Arcade Joystick (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,rightshoulder:b5,righttrigger:a4,start:b9,x:b0,y:b3,",
"03000000222c00000223000011010000,Qanba Obsidian Arcade Joystick (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
"03000000222c00000023000011010000,Qanba Obsidian Arcade Joystick (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
"030000008916000001fd000024010000,Razer Onza Classic Edition,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
"03000000321500000204000011010000,Razer Panthera (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
"03000000321500000104000011010000,Razer Panthera (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
"03000000321500000010000011010000,Razer RAIJU,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
"03000000321500000507000000010000,Razer Raiju Mobile,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b21,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
"03000000321500000011000011010000,Razer Raion Fightpad for PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
"030000008916000000fe000024010000,Razer Sabertooth,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
"03000000c6240000045d000024010000,Razer Sabertooth,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
"03000000c6240000045d000025010000,Razer Sabertooth,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
"03000000321500000009000011010000,Razer Serval,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,",
"050000003215000000090000163a0000,Razer Serval,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,",
"0300000032150000030a000001010000,Razer Wildcat,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
"0300000000f000000300000000010000,RetroPad,a:b1,b:b5,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b0,y:b4,",
"03000000790000001100000010010000,Retrolink SNES Controller,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b0,y:b3,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"03000000790000001100000010010000,Retrolink SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"030000006b140000130d000011010000,Revolution Pro Controller 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
"030000006b140000010d000011010000,Revolution Pro Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
"030000006f0e00001e01000011010000,Rock Candy PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
"030000006f0e00004601000001010000,Rock Candy Xbox One Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
"030000006f0e00001f01000000010000,Rock Candy,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
"03000000632500007505000010010000,SHANWAN PS3/PC Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,",
"03000000341a00000908000010010000,SL-6566,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,",
"03000000457500002211000010010000,SZMY-POWER PC Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
"03000000a306000023f6000011010000,Saitek Cyborg V.1 Game Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b0,y:b3,",
"03000000a30600000cff000010010000,Saitek P2500 Force Rumble Pad,a:b2,b:b3,back:b11,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,x:b0,y:b1,",
"03000000a30600000c04000011010000,Saitek P2900 Wireless Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b12,x:b0,y:b3,",
"03000000a30600000901000000010000,Saitek P880,a:b2,b:b3,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,x:b0,y:b1,",
"03000000a30600000b04000000010000,Saitek P990 Dual Analog Pad,a:b1,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b8,x:b0,y:b3,",
"03000000a306000018f5000010010000,Saitek PLC Saitek P3200 Rumble Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b0,y:b3,",
"03000000c01600008704000011010000,Serial/Keyboard/Mouse/Joystick,a:b12,b:b10,back:b4,dpdown:b2,dpleft:b3,dpright:b1,dpup:b0,leftshoulder:b9,leftstick:b14,lefttrigger:b6,leftx:a1,lefty:a0,rightshoulder:b8,rightstick:b15,righttrigger:b7,rightx:a2,righty:a3,start:b5,x:b13,y:b11,",
"03000000f025000021c1000010010000,ShanWan Gioteck PS3 Wired Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,",
"03000000632500002305000010010000,ShanWan USB Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,",
"03000000250900000500000000010000,Sony PS2 pad with SmartJoy adapter,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,",
"030000005e0400008e02000020200000,SpeedLink XEOX Pro Analog Gamepad pad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
"030000005e0400008e02000073050000,Speedlink TORID Wireless Gamepad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
"03000000de2800000112000001000000,Steam Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b10,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,",
"03000000de2800000112000011010000,Steam Controller,a:b2,b:b3,back:b10,dpdown:+a5,dpleft:-a4,dpright:+a4,dpup:-a5,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a7,leftx:a0,lefty:a1,paddle1:b15,paddle2:b16,rightshoulder:b7,rightstick:b14,righttrigger:a6,rightx:a2,righty:a3,start:b11,x:b4,y:b5,",
"03000000de2800000211000001000000,Steam Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b10,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,",
"03000000de2800000211000011010000,Steam Controller,a:b2,b:b3,back:b10,dpdown:+a5,dpleft:-a4,dpright:+a4,dpup:-a5,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a7,leftx:a0,lefty:a1,paddle1:b15,paddle2:b16,rightshoulder:b7,rightstick:b14,righttrigger:a6,rightx:a2,righty:a3,start:b11,x:b4,y:b5,",
"03000000de2800004211000001000000,Steam Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b10,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,",
"03000000de2800004211000011010000,Steam Controller,a:b2,b:b3,back:b10,dpdown:+a5,dpleft:-a4,dpright:+a4,dpup:-a5,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a7,leftx:a0,lefty:a1,paddle1:b15,paddle2:b16,rightshoulder:b7,rightstick:b14,righttrigger:a6,rightx:a2,righty:a3,start:b11,x:b4,y:b5,",
"03000000de280000fc11000001000000,Steam Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
"05000000de2800000212000001000000,Steam Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b10,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,",
"05000000de2800000511000001000000,Steam Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b10,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,",
"05000000de2800000611000001000000,Steam Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b10,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,",
"03000000de280000ff11000001000000,Steam Virtual Gamepad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
"0500000011010000311400001b010000,SteelSeries Stratus Duo,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b32,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
"05000000110100001914000009010000,SteelSeries Stratus XL,a:b0,b:b1,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b18,leftshoulder:b6,leftstick:b13,lefttrigger:+a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:+a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
"03000000ad1b000038f0000090040000,Street Fighter IV FightStick TE,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
"03000000666600000488000000010000,Super Joy Box 5 Pro,a:b2,b:b1,back:b9,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,",
"0300000000f00000f100000000010000,Super RetroPort,a:b1,b:b5,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b0,y:b4,",
"030000004f0400000ed0000011010000,ThrustMaster eSwap PRO Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
"030000004f04000020b3000010010000,Thrustmaster 2 in 1 DT,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,",
"030000004f04000015b3000001010000,Thrustmaster Dual Analog 3.2,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,",
"030000004f04000015b3000010010000,Thrustmaster Dual Analog 4,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,",
"030000004f04000023b3000000010000,Thrustmaster Dual Trigger 3-in-1,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
"030000004f04000000b3000010010000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b11,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b10,x:b1,y:b3,",
"030000004f04000009d0000000010000,Thrustmaster Run N Drive Wireless PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
"030000004f04000008d0000000010000,Thrustmaster Run N Drive Wireless,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
"03000000bd12000015d0000010010000,Tomee SNES USB Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,",
"03000000d814000007cd000011010000,Toodles 2008 Chimp PC/PS3,a:b0,b:b1,back:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b3,y:b2,",
"03000000100800000100000010010000,Twin USB PS2 Adapter,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,",
"03000000100800000300000010010000,USB Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,",
"03000000790000001100000000010000,USB Gamepad1,a:b2,b:b1,back:b8,dpdown:a0,dpleft:a1,dpright:a2,dpup:a4,start:b9,",
"05000000ac0500003232000001000000,VR-BOX,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b2,y:b3,",
"030000006f0e00000302000011010000,Victrix Pro Fight Stick for PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,",
"030000006f0e00000702000011010000,Victrix Pro Fight Stick for PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,",
"030000005e0400008e02000010010000,X360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
"030000005e0400008e02000014010000,X360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
"030000005e0400001907000000010000,X360 Wireless Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
"030000005e0400009102000007010000,X360 Wireless Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
"030000005e040000a102000000010000,X360 Wireless Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
"030000005e040000a102000007010000,X360 Wireless Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
"03000000450c00002043000010010000,XEOX Gamepad SL-6556-BK,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,",
"0000000058626f782033363020576900,Xbox 360 Wireless Controller,a:b0,b:b1,back:b14,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,guide:b7,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b2,y:b3,",
"030000005e040000a102000014010000,Xbox 360 Wireless Receiver (XBOX),a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
"0000000058626f782047616d65706100,Xbox Gamepad (userspace driver),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,",
"050000005e040000e002000003090000,Xbox One Wireless Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
"050000005e040000fd02000003090000,Xbox One Wireless Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,guide:b16,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
"05000000172700004431000029010000,XiaoMi Game Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b20,leftshoulder:b6,leftstick:b13,lefttrigger:a7,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a6,rightx:a2,righty:a5,start:b11,x:b3,y:b4,",
"03000000c0160000e105000010010000,Xin-Mo Dual Arcade,crc:82d5,a:b1,b:b2,back:b9,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,rightshoulder:b4,righttrigger:b5,start:b8,x:b0,y:b3,", /* Ultimate Atari Fight Stick */
"03000000120c0000100e000011010000,ZEROPLUS P4 Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
"03000000120c0000101e000011010000,ZEROPLUS P4 Wired Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
"03000000666600006706000000010000,boom PSX to PC Converter,a:b2,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a2,righty:a3,start:b11,x:b3,y:b0,",
"030000000d0f00000d00000000010000,hori,a:b0,b:b6,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b3,leftx:b4,lefty:b5,rightshoulder:b7,start:b9,x:b1,y:b2,",
"03000000830500006020000010010000,iBuffalo SNES Controller,a:b0,b:b1,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b2,y:b3,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"03000000830500006020000010010000,iBuffalo SNES Controller,a:b1,b:b0,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b3,y:b2,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"050000006964726f69643a636f6e0000,idroid:con,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
"03000000b50700001503000010010000,impact,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,",
"030000009b2800008000000020020000,raphnet technologies 1-player WUSBMote v2.2,a:b1,b:b4,back:b2,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,leftshoulder:b6,rightshoulder:b7,start:b3,x:b0,y:b5,",
"030000009b2800000300000001010000,raphnet.net 4nes4snes v1.5,a:b0,b:b4,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b1,y:b5,",
#endif
#ifdef __OpenBSD__
"030000004c050000c405000000010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
"030000004c050000e60c000000010000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
"030000005e0400008e02000010010000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1~,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4~,start:b7,x:b2,y:b3,",
#endif
#ifdef __ANDROID__
"05000000c82d000006500000ffff3f00,8BitDo M30 Gamepad,a:b0,b:b1,back:b4,guide:b17,leftshoulder:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:a4,start:b6,x:b2,y:b3,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"05000000c82d000006500000ffff3f00,8BitDo M30 Gamepad,a:b1,b:b0,back:b4,guide:b17,leftshoulder:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:a4,start:b6,x:b3,y:b2,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"05000000c82d000051060000ffff3f00,8BitDo M30 Gamepad,a:b0,b:b1,back:b4,guide:b17,leftshoulder:b9,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:a5,start:b6,x:b2,y:b3,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"05000000c82d000051060000ffff3f00,8BitDo M30 Gamepad,a:b1,b:b0,back:b4,guide:b17,leftshoulder:b9,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:a5,start:b6,x:b3,y:b2,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"05000000c82d000015900000ffff3f00,8BitDo N30 Pro 2,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"05000000c82d000015900000ffff3f00,8BitDo N30 Pro 2,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b3,y:b2,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"05000000c82d000065280000ffff3f00,8BitDo N30 Pro 2,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b17,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"05000000c82d000065280000ffff3f00,8BitDo N30 Pro 2,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b17,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b3,y:b2,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"050000000220000000900000ffff3f00,8BitDo NES30 Pro,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"050000000220000000900000ffff3f00,8BitDo NES30 Pro,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b3,y:b2,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"050000002038000009000000ffff3f00,8BitDo NES30 Pro,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"050000002038000009000000ffff3f00,8BitDo NES30 Pro,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b3,y:b2,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"05000000c82d000000600000ffff3f00,8BitDo SF30 Pro,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:b15,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b16,rightx:a2,righty:a3,start:b6,x:b2,y:b3,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"05000000c82d000000600000ffff3f00,8BitDo SF30 Pro,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:b15,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b16,rightx:a2,righty:a3,start:b6,x:b3,y:b2,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"05000000c82d000000610000ffff3f00,8BitDo SF30 Pro,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"05000000c82d000000610000ffff3f00,8BitDo SF30 Pro,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b3,y:b2,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"05000000c82d000012900000ffff3f00,8BitDo SN30 Gamepad,a:b0,b:b1,back:b4,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,start:b6,x:b2,y:b3,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"05000000c82d000012900000ffff3f00,8BitDo SN30 Gamepad,a:b1,b:b0,back:b4,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,start:b6,x:b3,y:b2,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"05000000c82d000062280000ffff3f00,8BitDo SN30 Gamepad,a:b0,b:b1,back:b4,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,start:b6,x:b2,y:b3,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"05000000c82d000062280000ffff3f00,8BitDo SN30 Gamepad,a:b1,b:b0,back:b4,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,start:b6,x:b3,y:b2,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"05000000c82d000002600000ffff0f00,8BitDo SN30 Pro+,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b17,leftshoulder:b9,leftstick:b7,lefttrigger:b15,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b16,rightx:a2,righty:a3,start:b6,x:b2,y:b3,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"05000000c82d000002600000ffff0f00,8BitDo SN30 Pro+,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b17,leftshoulder:b9,leftstick:b7,lefttrigger:b15,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b16,rightx:a2,righty:a3,start:b6,x:b3,y:b2,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"05000000c82d000001600000ffff3f00,8BitDo SN30 Pro,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"05000000c82d000001600000ffff3f00,8BitDo SN30 Pro,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b3,y:b2,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"050000002028000009000000ffff3f00,8BitDo SNES30 Gamepad,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"050000002028000009000000ffff3f00,8BitDo SNES30 Gamepad,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b3,y:b2,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"050000003512000020ab000000780f00,8BitDo SNES30 Gamepad,a:b20,b:b21,back:b30,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b26,rightshoulder:b27,start:b31,x:b23,y:b24,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"050000003512000020ab000000780f00,8BitDo SNES30 Gamepad,a:b21,b:b20,back:b30,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b26,rightshoulder:b27,start:b31,x:b24,y:b23,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"05000000c82d000018900000ffff0f00,8BitDo Zero 2,a:b0,b:b1,back:b4,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,start:b6,x:b2,y:b3,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"05000000c82d000018900000ffff0f00,8BitDo Zero 2,a:b1,b:b0,back:b4,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,start:b6,x:b3,y:b2,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"05000000c82d000030320000ffff0f00,8BitDo Zero 2,a:b0,b:b1,back:b4,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,start:b6,x:b2,y:b3,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"05000000c82d000030320000ffff0f00,8BitDo Zero 2,a:b1,b:b0,back:b4,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,start:b6,x:b3,y:b2,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"05000000d6020000e5890000dfff3f80,GPD XD Plus,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a3,rightx:a4,righty:a5,start:b6,x:b2,y:b3,",
"0500000031366332860c44aadfff0f00,GS Gamepad,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:b15,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b16,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
"05000000bc20000000550000ffff3f00,GameSir G3w,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
"050000005509000003720000cf7f3f00,NVIDIA Controller v01.01,a:b0,b:b1,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
"050000005509000010720000ffff3f00,NVIDIA Controller v01.03,a:b0,b:b1,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
"050000005509000014720000df7f3f80,NVIDIA Controller v01.04,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a3,rightx:a4,righty:a5,start:b6,x:b2,y:b3,",
"050000007e05000009200000ffff0f00,Nintendo Switch Pro Controller,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:b15,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b16,rightx:a2,righty:a3,start:b6,x:b3,y:b2,sdk>=:29,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"050000007e05000009200000ffff0f00,Nintendo Switch Pro Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:b15,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b16,rightx:a2,righty:a3,start:b6,x:b2,y:b3,sdk>=:29,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"050000007e05000009200000ffff0f00,Nintendo Switch Pro Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b3,leftstick:b4,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b16,x:b17,y:b2,sdk<=:28,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,", /* Extremely slow in Bluetooth mode on Android */
"050000007e05000009200000ffff0f00,Nintendo Switch Pro Controller,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b3,leftstick:b4,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b16,x:b2,y:b17,sdk<=:28,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,", /* Extremely slow in Bluetooth mode on Android */
"050000004c05000068020000dfff3f00,PS3 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
"030000004c050000cc09000000006800,PS4 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
"050000004c050000c405000000783f00,PS4 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
"050000004c050000c4050000fffe3f80,PS4 Controller,a:b1,b:b17,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b3,leftstick:b4,lefttrigger:+a2,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:+a3,rightx:a4,righty:a5,start:b16,x:b0,y:b2,",
"050000004c050000c4050000ffff3f00,PS4 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
"050000004c050000cc090000fffe3f80,PS4 Controller,a:b1,b:b17,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b3,leftstick:b4,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:a3,rightx:a4,righty:a5,start:b16,x:b0,y:b2,",
"050000004c050000cc090000ffff3f00,PS4 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
"050000004c050000e60c0000fffe3f80,PS5 Controller,a:b1,b:b17,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b3,leftstick:b4,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:a3,rightx:a4,righty:a5,start:b16,x:b0,y:b2,",
"050000004c050000e60c0000ffff3f00,PS5 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
"05000000f8270000bf0b0000ffff3f00,Razer Kishi,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
"050000003215000005070000ffff3f00,Razer Raiju Mobile,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
"050000003215000007070000ffff3f00,Razer Raiju Mobile,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
"050000003215000000090000bf7f3f00,Razer Serval,a:b0,b:b1,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,x:b2,y:b3,",
"050000004f0400000ed00000fffe3f00,ThrustMaster eSwap PRO Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
"050000005e0400008e02000000783f00,Xbox 360 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
"050000005e040000000b000000783f80,Xbox One Elite 2 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
"050000005e040000050b0000ffff3f00,Xbox One Elite 2 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a6,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
"050000005e040000e002000000783f00,Xbox One S Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
"050000005e040000ea02000000783f00,Xbox One S Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
"050000005e040000fd020000ff7f3f00,Xbox One S Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
"050000005e040000e00200000ffe3f80,Xbox One Wireless Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b15,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b16,righttrigger:a5,rightx:a2,righty:a3,start:b10,x:b17,y:b2,",
"050000005e040000fd020000ffff3f00,Xbox One Wireless Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
"050000005e040000120b000000783f80,Xbox Series X Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
"050000005e040000130b0000ffff3f00,Xbox Series X Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
"050000005e04000091020000ff073f80,Xbox Wireless Controller,a:b0,b:b1,back:b4,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,", /* The DPAD doesn't seem to work on this controller on Android TV? */
"050000001727000044310000ffff3f80,XiaoMi Game Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a7,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a6,rightx:a4,righty:a5,start:b6,x:b2,y:b3,",
"0500000083050000602000000ffe0000,iBuffalo SNES Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b15,rightshoulder:b16,start:b10,x:b2,y:b3,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"0500000083050000602000000ffe0000,iBuffalo SNES Controller,a:b1,b:b0,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b15,rightshoulder:b16,start:b10,x:b3,y:b2,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
#endif
#ifdef SDL_JOYSTICK_MFI
"05000000ac050000010000004f066d01,*,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,leftshoulder:b4,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a5,rightx:a3,righty:a4,x:b2,y:b3,",
"05000000ac05000001000000cf076d01,*,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,x:b2,y:b3,",
"05000000ac05000001000000df076d01,*,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b2,y:b3,",
"05000000ac05000001000000ff076d01,*,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,",
"05000000ac050000020000004f066d02,*,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,leftshoulder:b4,rightshoulder:b5,x:b2,y:b3,",
"050000008a35000003010000ff070000,Backbone One,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,",
"050000008a35000004010000ff070000,Backbone One,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,",
"050000007e050000062000000f060000,Nintendo Switch Joy-Con (L),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b2,b:b0,leftshoulder:b4,rightshoulder:b5,x:b3,y:b1,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"050000007e050000062000000f060000,Nintendo Switch Joy-Con (L),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b2,leftshoulder:b4,rightshoulder:b5,x:b1,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"050000007e050000062000004f060000,Nintendo Switch Joy-Con (L),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b2,b:b0,guide:b6,leftshoulder:b4,rightshoulder:b5,x:b3,y:b1,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"050000007e050000062000004f060000,Nintendo Switch Joy-Con (L),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b2,guide:b6,leftshoulder:b4,rightshoulder:b5,x:b1,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"050000007e05000008200000df070000,Nintendo Switch Joy-Con (L/R),a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b2,y:b3,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"050000007e05000008200000df070000,Nintendo Switch Joy-Con (L/R),a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"050000007e050000072000000f060000,Nintendo Switch Joy-Con (R),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b2,b:b0,leftshoulder:b4,rightshoulder:b5,x:b3,y:b1,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"050000007e050000072000000f060000,Nintendo Switch Joy-Con (R),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b2,leftshoulder:b4,rightshoulder:b5,x:b1,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"050000007e050000072000004f060000,Nintendo Switch Joy-Con (R),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b2,b:b0,guide:b6,leftshoulder:b4,rightshoulder:b5,x:b3,y:b1,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"050000007e050000072000004f060000,Nintendo Switch Joy-Con (R),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b2,guide:b6,leftshoulder:b4,rightshoulder:b5,x:b1,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"050000007e05000009200000df870000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b10,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b2,y:b3,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"050000007e05000009200000df870000,Nintendo Switch Pro Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b10,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"050000007e05000009200000ff870000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"050000007e05000009200000ff870000,Nintendo Switch Pro Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b3,y:b2,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"050000004c050000cc090000df070000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b2,y:b3,",
"050000004c050000cc090000df870001,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b2,y:b3,",
"050000004c050000cc090000ff070000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,",
"050000004c050000cc090000ff870001,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,touchpad:b11,x:b2,y:b3,",
"050000004c050000e60c0000df870000,PS5 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b9,touchpad:b10,x:b2,y:b3,",
"050000004c050000e60c0000ff870000,PS5 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,touchpad:b11,x:b2,y:b3,",
"05000000ac0500000300000043006d03,Remote,a:b0,b:b2,leftx:a0,lefty:a1,",
"050000005e040000050b0000df070001,Xbox Elite Wireless Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b10,paddle2:b12,paddle3:b11,paddle4:b13,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b2,y:b3,",
"050000005e040000050b0000ff070001,Xbox Elite Wireless Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b13,paddle3:b12,paddle4:b14,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,",
"050000005e040000130b0000df870001,Xbox Series X Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b10,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b2,y:b3,",
"050000005e040000130b0000ff870001,Xbox Series X Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,",
"050000005e040000e0020000df070000,Xbox Wireless Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b2,y:b3,",
"050000005e040000e0020000ff070000,Xbox Wireless Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,",
#endif
#ifdef SDL_JOYSTICK_EMSCRIPTEN
"default,Standard Gamepad,a:b0,b:b1,back:b8,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,guide:b16,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,",
#endif
#ifdef SDL_JOYSTICK_PS2
"0000000050533220436f6e74726f6c00,PS2 Controller,crc:ed87,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,",
#endif
#ifdef SDL_JOYSTICK_PSP
"00000000505350206275696c74696e00,PSP builtin joypad,crc:bb86,a:b2,b:b1,back:b10,dpdown:b6,dpleft:b7,dpright:b9,dpup:b8,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a2,righty:a3,start:b11,x:b3,y:b0,",
#endif
#ifdef SDL_JOYSTICK_VITA
"0000000050535669746120436f6e7400,PSVita Controller,crc:d598,a:b2,b:b1,back:b10,dpdown:b6,dpleft:b7,dpright:b9,dpup:b8,leftshoulder:b4,leftstick:b14,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b15,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b3,y:b0,",
#endif
#ifdef SDL_JOYSTICK_N3DS
"000000004e696e74656e646f20334400,Nintendo 3DS,crc:3210,a:b0,b:b1,back:b2,dpdown:b7,dpleft:b5,dpright:b4,dpup:b6,leftshoulder:b9,lefttrigger:b14,leftx:a0,lefty:a1,rightshoulder:b8,righttrigger:b15,rightx:a2,righty:a3,start:b3,x:b10,y:b11,",
#endif
"hidapi,*,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
NULL
};

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,232 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 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.
*/
#ifndef SDL_joystick_c_h_
#define SDL_joystick_c_h_
#include "SDL_internal.h"
/* Useful functions and variables from SDL_joystick.c */
/* Set up for C function definitions, even when using C++ */
#ifdef __cplusplus
extern "C" {
#endif
struct SDL_JoystickDriver;
extern char SDL_joystick_magic;
/* Initialization and shutdown functions */
extern int SDL_InitJoysticks(void);
extern void SDL_QuitJoysticks(void);
/* Return whether the joystick system is currently initialized */
extern SDL_bool SDL_JoysticksInitialized(void);
/* Return whether the joystick system is shutting down */
extern SDL_bool SDL_JoysticksQuitting(void);
/* Return whether the joysticks are currently locked */
extern SDL_bool SDL_JoysticksLocked(void);
/* Make sure we currently have the joysticks locked */
extern void SDL_AssertJoysticksLocked(void) SDL_ASSERT_CAPABILITY(SDL_joystick_lock);
/* Function to return whether there are any joysticks opened by the application */
extern SDL_bool SDL_JoysticksOpened(void);
/* Function to get the next available joystick instance ID */
extern SDL_JoystickID SDL_GetNextJoystickInstanceID(void);
/* Function to standardize the name for a controller
This should be freed with SDL_free() when no longer needed
*/
extern char *SDL_CreateJoystickName(Uint16 vendor, Uint16 product, const char *vendor_name, const char *product_name);
/* Function to create a GUID for a joystick based on the VID/PID and name */
extern SDL_JoystickGUID SDL_CreateJoystickGUID(Uint16 bus, Uint16 vendor, Uint16 product, Uint16 version, const char *name, Uint8 driver_signature, Uint8 driver_data);
/* Function to create a GUID for a joystick based on the name, with no VID/PID information */
extern SDL_JoystickGUID SDL_CreateJoystickGUIDForName(const char *name);
/* Function to set the vendor field of a joystick GUID */
extern void SDL_SetJoystickGUIDVendor(SDL_JoystickGUID *guid, Uint16 vendor);
/* Function to set the product field of a joystick GUID */
extern void SDL_SetJoystickGUIDProduct(SDL_JoystickGUID *guid, Uint16 product);
/* Function to set the version field of a joystick GUID */
extern void SDL_SetJoystickGUIDVersion(SDL_JoystickGUID *guid, Uint16 version);
/* Function to set the CRC field of a joystick GUID */
extern void SDL_SetJoystickGUIDCRC(SDL_JoystickGUID *guid, Uint16 crc);
/* Function to return the type of a controller */
extern SDL_GamepadType SDL_GetGamepadTypeFromVIDPID(Uint16 vendor, Uint16 product, const char *name, SDL_bool forUI);
extern SDL_GamepadType SDL_GetGamepadTypeFromGUID(SDL_JoystickGUID guid, const char *name);
/* Function to return whether a joystick is an Xbox One controller */
extern SDL_bool SDL_IsJoystickXboxOne(Uint16 vendor_id, Uint16 product_id);
/* Function to return whether a joystick is an Xbox One Elite controller */
extern SDL_bool SDL_IsJoystickXboxOneElite(Uint16 vendor_id, Uint16 product_id);
/* Function to return whether a joystick is an Xbox Series X controller */
extern SDL_bool SDL_IsJoystickXboxSeriesX(Uint16 vendor_id, Uint16 product_id);
/* Function to return whether a joystick is an Xbox One controller connected via Bluetooth */
extern SDL_bool SDL_IsJoystickBluetoothXboxOne(Uint16 vendor_id, Uint16 product_id);
/* Function to return whether a joystick is a PS4 controller */
extern SDL_bool SDL_IsJoystickPS4(Uint16 vendor_id, Uint16 product_id);
/* Function to return whether a joystick is a PS5 controller */
extern SDL_bool SDL_IsJoystickPS5(Uint16 vendor_id, Uint16 product_id);
extern SDL_bool SDL_IsJoystickDualSenseEdge(Uint16 vendor_id, Uint16 product_id);
/* Function to return whether a joystick is a Nintendo Switch Pro controller */
extern SDL_bool SDL_IsJoystickNintendoSwitchPro(Uint16 vendor_id, Uint16 product_id);
extern SDL_bool SDL_IsJoystickNintendoSwitchProInputOnly(Uint16 vendor_id, Uint16 product_id);
extern SDL_bool SDL_IsJoystickNintendoSwitchJoyCon(Uint16 vendor_id, Uint16 product_id);
extern SDL_bool SDL_IsJoystickNintendoSwitchJoyConLeft(Uint16 vendor_id, Uint16 product_id);
extern SDL_bool SDL_IsJoystickNintendoSwitchJoyConRight(Uint16 vendor_id, Uint16 product_id);
extern SDL_bool SDL_IsJoystickNintendoSwitchJoyConGrip(Uint16 vendor_id, Uint16 product_id);
extern SDL_bool SDL_IsJoystickNintendoSwitchJoyConPair(Uint16 vendor_id, Uint16 product_id);
/* Function to return whether a joystick is an Amazon Luna controller */
extern SDL_bool SDL_IsJoystickAmazonLunaController(Uint16 vendor_id, Uint16 product_id);
/* Function to return whether a joystick is a Google Stadia controller */
extern SDL_bool SDL_IsJoystickGoogleStadiaController(Uint16 vendor_id, Uint16 product_id);
/* Function to return whether a joystick is an NVIDIA SHIELD controller */
extern SDL_bool SDL_IsJoystickNVIDIASHIELDController(Uint16 vendor_id, Uint16 product_id);
/* Function to return whether a joystick is a Steam Controller */
extern SDL_bool SDL_IsJoystickSteamController(Uint16 vendor_id, Uint16 product_id);
/* Function to return whether a joystick guid comes from the XInput driver */
extern SDL_bool SDL_IsJoystickXInput(SDL_JoystickGUID guid);
/* Function to return whether a joystick guid comes from the WGI driver */
extern SDL_bool SDL_IsJoystickWGI(SDL_JoystickGUID guid);
/* Function to return whether a joystick guid comes from the HIDAPI driver */
extern SDL_bool SDL_IsJoystickHIDAPI(SDL_JoystickGUID guid);
/* Function to return whether a joystick guid comes from the RAWINPUT driver */
extern SDL_bool SDL_IsJoystickRAWINPUT(SDL_JoystickGUID guid);
/* Function to return whether a joystick guid comes from the Virtual driver */
extern SDL_bool SDL_IsJoystickVIRTUAL(SDL_JoystickGUID guid);
/* Function to return whether a joystick should be ignored */
extern SDL_bool SDL_ShouldIgnoreJoystick(const char *name, SDL_JoystickGUID guid);
/* Internal event queueing functions */
extern void SDL_PrivateJoystickAddTouchpad(SDL_Joystick *joystick, int nfingers);
extern void SDL_PrivateJoystickAddSensor(SDL_Joystick *joystick, SDL_SensorType type, float rate);
extern void SDL_PrivateJoystickAdded(SDL_JoystickID instance_id);
extern SDL_bool SDL_IsJoystickBeingAdded(void);
extern void SDL_PrivateJoystickRemoved(SDL_JoystickID instance_id);
extern void SDL_PrivateJoystickForceRecentering(SDL_Joystick *joystick);
extern int SDL_SendJoystickAxis(Uint64 timestamp, SDL_Joystick *joystick,
Uint8 axis, Sint16 value);
extern int SDL_SendJoystickHat(Uint64 timestamp, SDL_Joystick *joystick,
Uint8 hat, Uint8 value);
extern int SDL_SendJoystickButton(Uint64 timestamp, SDL_Joystick *joystick,
Uint8 button, Uint8 state);
extern int SDL_SendJoystickTouchpad(Uint64 timestamp, SDL_Joystick *joystick,
int touchpad, int finger, Uint8 state, float x, float y, float pressure);
extern int SDL_SendJoystickSensor(Uint64 timestamp, SDL_Joystick *joystick,
SDL_SensorType type, Uint64 sensor_timestamp, const float *data, int num_values);
extern void SDL_SendJoystickBatteryLevel(SDL_Joystick *joystick,
SDL_JoystickPowerLevel ePowerLevel);
/* Internal sanity checking functions */
extern SDL_bool SDL_IsJoystickValid(SDL_Joystick *joystick);
typedef enum
{
EMappingKind_None = 0,
EMappingKind_Button = 1,
EMappingKind_Axis = 2,
EMappingKind_Hat = 3
} EMappingKind;
typedef struct SDL_InputMapping
{
EMappingKind kind;
Uint8 target;
} SDL_InputMapping;
typedef struct SDL_GamepadMapping
{
SDL_InputMapping a;
SDL_InputMapping b;
SDL_InputMapping x;
SDL_InputMapping y;
SDL_InputMapping back;
SDL_InputMapping guide;
SDL_InputMapping start;
SDL_InputMapping leftstick;
SDL_InputMapping rightstick;
SDL_InputMapping leftshoulder;
SDL_InputMapping rightshoulder;
SDL_InputMapping dpup;
SDL_InputMapping dpdown;
SDL_InputMapping dpleft;
SDL_InputMapping dpright;
SDL_InputMapping misc1;
SDL_InputMapping paddle1;
SDL_InputMapping paddle2;
SDL_InputMapping paddle3;
SDL_InputMapping paddle4;
SDL_InputMapping leftx;
SDL_InputMapping lefty;
SDL_InputMapping rightx;
SDL_InputMapping righty;
SDL_InputMapping lefttrigger;
SDL_InputMapping righttrigger;
} SDL_GamepadMapping;
/* Function to get autodetected gamepad controller mapping from the driver */
extern SDL_bool SDL_PrivateJoystickGetAutoGamepadMapping(SDL_JoystickID instance_id,
SDL_GamepadMapping *out);
typedef struct
{
int num_entries;
int max_entries;
Uint32 *entries;
} SDL_vidpid_list;
extern void SDL_LoadVIDPIDListFromHint(const char *hint, SDL_vidpid_list *list);
extern SDL_bool SDL_VIDPIDInList(Uint16 vendor_id, Uint16 product_id, const SDL_vidpid_list *list);
extern void SDL_FreeVIDPIDList(SDL_vidpid_list *list);
/* Ends C function definitions when using C++ */
#ifdef __cplusplus
}
#endif
#endif /* SDL_joystick_c_h_ */

View File

@@ -0,0 +1,256 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 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"
#ifndef SDL_sysjoystick_h_
#define SDL_sysjoystick_h_
/* This is the system specific header for the SDL joystick API */
#include "SDL_joystick_c.h"
/* Set up for C function definitions, even when using C++ */
#ifdef __cplusplus
extern "C" {
#endif
/* The SDL joystick structure */
typedef struct SDL_JoystickAxisInfo
{
Sint16 initial_value; /* Initial axis state */
Sint16 value; /* Current axis state */
Sint16 zero; /* Zero point on the axis (-32768 for triggers) */
SDL_bool has_initial_value; /* Whether we've seen a value on the axis yet */
SDL_bool has_second_value; /* Whether we've seen a second value on the axis yet */
SDL_bool sent_initial_value; /* Whether we've sent the initial axis value */
SDL_bool sending_initial_value; /* Whether we are sending the initial axis value */
} SDL_JoystickAxisInfo;
typedef struct SDL_JoystickTouchpadFingerInfo
{
Uint8 state;
float x;
float y;
float pressure;
} SDL_JoystickTouchpadFingerInfo;
typedef struct SDL_JoystickTouchpadInfo
{
int nfingers;
SDL_JoystickTouchpadFingerInfo *fingers;
} SDL_JoystickTouchpadInfo;
typedef struct SDL_JoystickSensorInfo
{
SDL_SensorType type;
SDL_bool enabled;
float rate;
float data[3]; /* If this needs to expand, update SDL_GamepadSensorEvent */
} SDL_JoystickSensorInfo;
#define _guarded SDL_GUARDED_BY(SDL_joystick_lock)
struct SDL_Joystick
{
const void *magic _guarded;
SDL_JoystickID instance_id _guarded; /* Device instance, monotonically increasing from 0 */
char *name _guarded; /* Joystick name - system dependent */
char *path _guarded; /* Joystick path - system dependent */
char *serial _guarded; /* Joystick serial */
SDL_JoystickGUID guid _guarded; /* Joystick guid */
Uint16 firmware_version _guarded; /* Firmware version, if available */
int naxes _guarded; /* Number of axis controls on the joystick */
SDL_JoystickAxisInfo *axes _guarded;
int nhats _guarded; /* Number of hats on the joystick */
Uint8 *hats _guarded; /* Current hat states */
int nbuttons _guarded; /* Number of buttons on the joystick */
Uint8 *buttons _guarded; /* Current button states */
int ntouchpads _guarded; /* Number of touchpads on the joystick */
SDL_JoystickTouchpadInfo *touchpads _guarded; /* Current touchpad states */
int nsensors _guarded; /* Number of sensors on the joystick */
int nsensors_enabled _guarded;
SDL_JoystickSensorInfo *sensors _guarded;
Uint16 low_frequency_rumble _guarded;
Uint16 high_frequency_rumble _guarded;
Uint64 rumble_expiration _guarded;
Uint64 rumble_resend _guarded;
Uint16 left_trigger_rumble _guarded;
Uint16 right_trigger_rumble _guarded;
Uint64 trigger_rumble_expiration _guarded;
Uint8 led_red _guarded;
Uint8 led_green _guarded;
Uint8 led_blue _guarded;
Uint64 led_expiration _guarded;
SDL_bool attached _guarded;
SDL_bool is_gamepad _guarded;
SDL_bool delayed_guide_button _guarded; /* SDL_TRUE if this device has the guide button event delayed */
SDL_JoystickPowerLevel epowerlevel _guarded; /* power level of this joystick, SDL_JOYSTICK_POWER_UNKNOWN if not supported */
SDL_SensorID accel_sensor _guarded;
SDL_Sensor *accel _guarded;
SDL_SensorID gyro_sensor _guarded;
SDL_Sensor *gyro _guarded;
float sensor_transform[3][3] _guarded;
Uint64 update_complete _guarded;
struct SDL_JoystickDriver *driver _guarded;
struct joystick_hwdata *hwdata _guarded; /* Driver dependent information */
int ref_count _guarded; /* Reference count for multiple opens */
struct SDL_Joystick *next _guarded; /* pointer to next joystick we have allocated */
};
#undef _guarded
/* Device bus definitions */
#define SDL_HARDWARE_BUS_UNKNOWN 0x00
#define SDL_HARDWARE_BUS_USB 0x03
#define SDL_HARDWARE_BUS_BLUETOOTH 0x05
#define SDL_HARDWARE_BUS_VIRTUAL 0xFF
/* Joystick capability flags for GetCapabilities() */
#define SDL_JOYCAP_LED 0x01
#define SDL_JOYCAP_RUMBLE 0x02
#define SDL_JOYCAP_RUMBLE_TRIGGERS 0x04
/* Macro to combine a USB vendor ID and product ID into a single Uint32 value */
#define MAKE_VIDPID(VID, PID) (((Uint32)(VID)) << 16 | (PID))
typedef struct SDL_JoystickDriver
{
/* Function to scan the system for joysticks.
* Joystick 0 should be the system default joystick.
* This function should return 0, or -1 on an unrecoverable error.
*/
int (*Init)(void);
/* Function to return the number of joystick devices plugged in right now */
int (*GetCount)(void);
/* Function to cause any queued joystick insertions to be processed */
void (*Detect)(void);
/* Function to get the device-dependent name of a joystick */
const char *(*GetDeviceName)(int device_index);
/* Function to get the device-dependent path of a joystick */
const char *(*GetDevicePath)(int device_index);
/* Function to get the player index of a joystick */
int (*GetDevicePlayerIndex)(int device_index);
/* Function to set the player index of a joystick */
void (*SetDevicePlayerIndex)(int device_index, int player_index);
/* Function to return the stable GUID for a plugged in device */
SDL_JoystickGUID (*GetDeviceGUID)(int device_index);
/* Function to get the current instance id of the joystick located at device_index */
SDL_JoystickID (*GetDeviceInstanceID)(int 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 (*Open)(SDL_Joystick *joystick, int device_index);
/* Rumble functionality */
int (*Rumble)(SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble);
int (*RumbleTriggers)(SDL_Joystick *joystick, Uint16 left_rumble, Uint16 right_rumble);
/* Capability detection */
Uint32 (*GetCapabilities)(SDL_Joystick *joystick);
/* LED functionality */
int (*SetLED)(SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue);
/* General effects */
int (*SendEffect)(SDL_Joystick *joystick, const void *data, int size);
/* Sensor functionality */
int (*SetSensorsEnabled)(SDL_Joystick *joystick, SDL_bool enabled);
/* 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 (*Update)(SDL_Joystick *joystick);
/* Function to close a joystick after use */
void (*Close)(SDL_Joystick *joystick);
/* Function to perform any system-specific joystick related cleanup */
void (*Quit)(void);
/* Function to get the autodetected controller mapping; returns false if there isn't any. */
SDL_bool (*GetGamepadMapping)(int device_index, SDL_GamepadMapping *out);
} SDL_JoystickDriver;
/* Windows and Mac OSX has a limit of MAX_DWORD / 1000, Linux kernel has a limit of 0xFFFF */
#define SDL_MAX_RUMBLE_DURATION_MS 0xFFFF
/* Dualshock4 only rumbles for about 5 seconds max, resend rumble command every 2 seconds
* to make long rumble work. */
#define SDL_RUMBLE_RESEND_MS 2000
#define SDL_LED_MIN_REPEAT_MS 5000
/* The available joystick drivers */
extern SDL_JoystickDriver SDL_ANDROID_JoystickDriver;
extern SDL_JoystickDriver SDL_BSD_JoystickDriver;
extern SDL_JoystickDriver SDL_DARWIN_JoystickDriver;
extern SDL_JoystickDriver SDL_DUMMY_JoystickDriver;
extern SDL_JoystickDriver SDL_EMSCRIPTEN_JoystickDriver;
extern SDL_JoystickDriver SDL_HAIKU_JoystickDriver;
extern SDL_JoystickDriver SDL_HIDAPI_JoystickDriver;
extern SDL_JoystickDriver SDL_RAWINPUT_JoystickDriver;
extern SDL_JoystickDriver SDL_IOS_JoystickDriver;
extern SDL_JoystickDriver SDL_LINUX_JoystickDriver;
extern SDL_JoystickDriver SDL_VIRTUAL_JoystickDriver;
extern SDL_JoystickDriver SDL_WGI_JoystickDriver;
extern SDL_JoystickDriver SDL_WINDOWS_JoystickDriver;
extern SDL_JoystickDriver SDL_WINMM_JoystickDriver;
extern SDL_JoystickDriver SDL_PS2_JoystickDriver;
extern SDL_JoystickDriver SDL_PSP_JoystickDriver;
extern SDL_JoystickDriver SDL_VITA_JoystickDriver;
extern SDL_JoystickDriver SDL_N3DS_JoystickDriver;
/* Ends C function definitions when using C++ */
#ifdef __cplusplus
}
#endif
#endif /* SDL_sysjoystick_h_ */

View File

@@ -0,0 +1,697 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 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_ANDROID
#include <stdio.h> /* For the definition of NULL */
#include "SDL_sysjoystick_c.h"
#include "../SDL_joystick_c.h"
#include "../../events/SDL_keyboard_c.h"
#include "../../core/android/SDL_android.h"
#include "../hidapi/SDL_hidapijoystick_c.h"
#include "android/keycodes.h"
/* As of platform android-14, android/keycodes.h is missing these defines */
#ifndef AKEYCODE_BUTTON_1
#define AKEYCODE_BUTTON_1 188
#define AKEYCODE_BUTTON_2 189
#define AKEYCODE_BUTTON_3 190
#define AKEYCODE_BUTTON_4 191
#define AKEYCODE_BUTTON_5 192
#define AKEYCODE_BUTTON_6 193
#define AKEYCODE_BUTTON_7 194
#define AKEYCODE_BUTTON_8 195
#define AKEYCODE_BUTTON_9 196
#define AKEYCODE_BUTTON_10 197
#define AKEYCODE_BUTTON_11 198
#define AKEYCODE_BUTTON_12 199
#define AKEYCODE_BUTTON_13 200
#define AKEYCODE_BUTTON_14 201
#define AKEYCODE_BUTTON_15 202
#define AKEYCODE_BUTTON_16 203
#endif
#define ANDROID_ACCELEROMETER_NAME "Android Accelerometer"
#define ANDROID_ACCELEROMETER_DEVICE_ID INT_MIN
#define ANDROID_MAX_NBUTTONS 36
static SDL_joylist_item *JoystickByDeviceId(int device_id);
static SDL_joylist_item *SDL_joylist = NULL;
static SDL_joylist_item *SDL_joylist_tail = NULL;
static int numjoysticks = 0;
/* Function to convert Android keyCodes into SDL ones.
* This code manipulation is done to get a sequential list of codes.
* FIXME: This is only suited for the case where we use a fixed number of buttons determined by ANDROID_MAX_NBUTTONS
*/
static int keycode_to_SDL(int keycode)
{
/* FIXME: If this function gets too unwieldy in the future, replace with a lookup table */
int button = 0;
switch (keycode) {
/* Some gamepad buttons (API 9) */
case AKEYCODE_BUTTON_A:
button = SDL_GAMEPAD_BUTTON_A;
break;
case AKEYCODE_BUTTON_B:
button = SDL_GAMEPAD_BUTTON_B;
break;
case AKEYCODE_BUTTON_X:
button = SDL_GAMEPAD_BUTTON_X;
break;
case AKEYCODE_BUTTON_Y:
button = SDL_GAMEPAD_BUTTON_Y;
break;
case AKEYCODE_BUTTON_L1:
button = SDL_GAMEPAD_BUTTON_LEFT_SHOULDER;
break;
case AKEYCODE_BUTTON_R1:
button = SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER;
break;
case AKEYCODE_BUTTON_THUMBL:
button = SDL_GAMEPAD_BUTTON_LEFT_STICK;
break;
case AKEYCODE_BUTTON_THUMBR:
button = SDL_GAMEPAD_BUTTON_RIGHT_STICK;
break;
case AKEYCODE_MENU:
case AKEYCODE_BUTTON_START:
button = SDL_GAMEPAD_BUTTON_START;
break;
case AKEYCODE_BACK:
case AKEYCODE_BUTTON_SELECT:
button = SDL_GAMEPAD_BUTTON_BACK;
break;
case AKEYCODE_BUTTON_MODE:
button = SDL_GAMEPAD_BUTTON_GUIDE;
break;
case AKEYCODE_BUTTON_L2:
button = 15;
break;
case AKEYCODE_BUTTON_R2:
button = 16;
break;
case AKEYCODE_BUTTON_C:
button = 17;
break;
case AKEYCODE_BUTTON_Z:
button = 18;
break;
/* D-Pad key codes (API 1) */
case AKEYCODE_DPAD_UP:
button = SDL_GAMEPAD_BUTTON_DPAD_UP;
break;
case AKEYCODE_DPAD_DOWN:
button = SDL_GAMEPAD_BUTTON_DPAD_DOWN;
break;
case AKEYCODE_DPAD_LEFT:
button = SDL_GAMEPAD_BUTTON_DPAD_LEFT;
break;
case AKEYCODE_DPAD_RIGHT:
button = SDL_GAMEPAD_BUTTON_DPAD_RIGHT;
break;
case AKEYCODE_DPAD_CENTER:
/* This is handled better by applications as the A button */
/*button = 19;*/
button = SDL_GAMEPAD_BUTTON_A;
break;
/* More gamepad buttons (API 12), these get mapped to 20...35*/
case AKEYCODE_BUTTON_1:
case AKEYCODE_BUTTON_2:
case AKEYCODE_BUTTON_3:
case AKEYCODE_BUTTON_4:
case AKEYCODE_BUTTON_5:
case AKEYCODE_BUTTON_6:
case AKEYCODE_BUTTON_7:
case AKEYCODE_BUTTON_8:
case AKEYCODE_BUTTON_9:
case AKEYCODE_BUTTON_10:
case AKEYCODE_BUTTON_11:
case AKEYCODE_BUTTON_12:
case AKEYCODE_BUTTON_13:
case AKEYCODE_BUTTON_14:
case AKEYCODE_BUTTON_15:
case AKEYCODE_BUTTON_16:
button = 20 + (keycode - AKEYCODE_BUTTON_1);
break;
default:
return -1;
/* break; -Wunreachable-code-break */
}
/* This is here in case future generations, probably with six fingers per hand,
* happily add new cases up above and forget to update the max number of buttons.
*/
SDL_assert(button < ANDROID_MAX_NBUTTONS);
return button;
}
static SDL_Scancode button_to_scancode(int button)
{
switch (button) {
case SDL_GAMEPAD_BUTTON_A:
return SDL_SCANCODE_RETURN;
case SDL_GAMEPAD_BUTTON_B:
return SDL_SCANCODE_ESCAPE;
case SDL_GAMEPAD_BUTTON_BACK:
return SDL_SCANCODE_ESCAPE;
case SDL_GAMEPAD_BUTTON_START:
return SDL_SCANCODE_MENU;
case SDL_GAMEPAD_BUTTON_DPAD_UP:
return SDL_SCANCODE_UP;
case SDL_GAMEPAD_BUTTON_DPAD_DOWN:
return SDL_SCANCODE_DOWN;
case SDL_GAMEPAD_BUTTON_DPAD_LEFT:
return SDL_SCANCODE_LEFT;
case SDL_GAMEPAD_BUTTON_DPAD_RIGHT:
return SDL_SCANCODE_RIGHT;
}
/* Unsupported button */
return SDL_SCANCODE_UNKNOWN;
}
int Android_OnPadDown(int device_id, int keycode)
{
SDL_joylist_item *item;
int button = keycode_to_SDL(keycode);
if (button >= 0) {
SDL_LockJoysticks();
item = JoystickByDeviceId(device_id);
if (item && item->joystick) {
SDL_SendJoystickButton(0, item->joystick, button, SDL_PRESSED);
} else {
SDL_SendKeyboardKey(0, SDL_PRESSED, button_to_scancode(button));
}
SDL_UnlockJoysticks();
return 0;
}
return -1;
}
int Android_OnPadUp(int device_id, int keycode)
{
SDL_joylist_item *item;
int button = keycode_to_SDL(keycode);
if (button >= 0) {
SDL_LockJoysticks();
item = JoystickByDeviceId(device_id);
if (item && item->joystick) {
SDL_SendJoystickButton(0, item->joystick, button, SDL_RELEASED);
} else {
SDL_SendKeyboardKey(0, SDL_RELEASED, button_to_scancode(button));
}
SDL_UnlockJoysticks();
return 0;
}
return -1;
}
int Android_OnJoy(int device_id, int axis, float value)
{
/* Android gives joy info normalized as [-1.0, 1.0] or [0.0, 1.0] */
SDL_joylist_item *item;
SDL_LockJoysticks();
item = JoystickByDeviceId(device_id);
if (item && item->joystick) {
SDL_SendJoystickAxis(0, item->joystick, axis, (Sint16)(32767. * value));
}
SDL_UnlockJoysticks();
return 0;
}
int Android_OnHat(int device_id, int hat_id, int x, int y)
{
const int DPAD_UP_MASK = (1 << SDL_GAMEPAD_BUTTON_DPAD_UP);
const int DPAD_DOWN_MASK = (1 << SDL_GAMEPAD_BUTTON_DPAD_DOWN);
const int DPAD_LEFT_MASK = (1 << SDL_GAMEPAD_BUTTON_DPAD_LEFT);
const int DPAD_RIGHT_MASK = (1 << SDL_GAMEPAD_BUTTON_DPAD_RIGHT);
if (x >= -1 && x <= 1 && y >= -1 && y <= 1) {
SDL_joylist_item *item;
SDL_LockJoysticks();
item = JoystickByDeviceId(device_id);
if (item && item->joystick) {
int dpad_state = 0;
int dpad_delta;
if (x < 0) {
dpad_state |= DPAD_LEFT_MASK;
} else if (x > 0) {
dpad_state |= DPAD_RIGHT_MASK;
}
if (y < 0) {
dpad_state |= DPAD_UP_MASK;
} else if (y > 0) {
dpad_state |= DPAD_DOWN_MASK;
}
dpad_delta = (dpad_state ^ item->dpad_state);
if (dpad_delta) {
if (dpad_delta & DPAD_UP_MASK) {
SDL_SendJoystickButton(0, item->joystick, SDL_GAMEPAD_BUTTON_DPAD_UP, (dpad_state & DPAD_UP_MASK) ? SDL_PRESSED : SDL_RELEASED);
}
if (dpad_delta & DPAD_DOWN_MASK) {
SDL_SendJoystickButton(0, item->joystick, SDL_GAMEPAD_BUTTON_DPAD_DOWN, (dpad_state & DPAD_DOWN_MASK) ? SDL_PRESSED : SDL_RELEASED);
}
if (dpad_delta & DPAD_LEFT_MASK) {
SDL_SendJoystickButton(0, item->joystick, SDL_GAMEPAD_BUTTON_DPAD_LEFT, (dpad_state & DPAD_LEFT_MASK) ? SDL_PRESSED : SDL_RELEASED);
}
if (dpad_delta & DPAD_RIGHT_MASK) {
SDL_SendJoystickButton(0, item->joystick, SDL_GAMEPAD_BUTTON_DPAD_RIGHT, (dpad_state & DPAD_RIGHT_MASK) ? SDL_PRESSED : SDL_RELEASED);
}
item->dpad_state = dpad_state;
}
}
SDL_UnlockJoysticks();
return 0;
}
return -1;
}
int Android_AddJoystick(int device_id, const char *name, const char *desc, int vendor_id, int product_id, SDL_bool is_accelerometer, int button_mask, int naxes, int axis_mask, int nhats)
{
SDL_joylist_item *item;
SDL_JoystickGUID guid;
int i;
int result = -1;
SDL_LockJoysticks();
if (!SDL_GetHintBoolean(SDL_HINT_TV_REMOTE_AS_JOYSTICK, SDL_TRUE)) {
/* Ignore devices that aren't actually controllers (e.g. remotes), they'll be handled as keyboard input */
if (naxes < 2 && nhats < 1) {
goto done;
}
}
if (JoystickByDeviceId(device_id) != NULL || name == NULL) {
goto done;
}
#ifdef SDL_JOYSTICK_HIDAPI
if (HIDAPI_IsDevicePresent(vendor_id, product_id, 0, name)) {
/* The HIDAPI driver is taking care of this device */
goto done;
}
#endif
#ifdef DEBUG_JOYSTICK
SDL_Log("Joystick: %s, descriptor %s, vendor = 0x%.4x, product = 0x%.4x, %d axes, %d hats\n", name, desc, vendor_id, product_id, naxes, nhats);
#endif
if (nhats > 0) {
/* Hat is translated into DPAD buttons */
button_mask |= ((1 << SDL_GAMEPAD_BUTTON_DPAD_UP) |
(1 << SDL_GAMEPAD_BUTTON_DPAD_DOWN) |
(1 << SDL_GAMEPAD_BUTTON_DPAD_LEFT) |
(1 << SDL_GAMEPAD_BUTTON_DPAD_RIGHT));
nhats = 0;
}
guid = SDL_CreateJoystickGUID(SDL_HARDWARE_BUS_BLUETOOTH, vendor_id, product_id, 0, desc, 0, 0);
/* Update the GUID with capability bits */
{
Uint16 *guid16 = (Uint16 *)guid.data;
guid16[6] = SDL_SwapLE16(button_mask);
guid16[7] = SDL_SwapLE16(axis_mask);
}
item = (SDL_joylist_item *)SDL_malloc(sizeof(SDL_joylist_item));
if (item == NULL) {
goto done;
}
SDL_zerop(item);
item->guid = guid;
item->device_id = device_id;
item->name = SDL_CreateJoystickName(vendor_id, product_id, NULL, name);
if (item->name == NULL) {
SDL_free(item);
goto done;
}
item->is_accelerometer = is_accelerometer;
if (button_mask == 0xFFFFFFFF) {
item->nbuttons = ANDROID_MAX_NBUTTONS;
} else {
for (i = 0; i < sizeof(button_mask) * 8; ++i) {
if (button_mask & (1 << i)) {
item->nbuttons = i + 1;
}
}
}
item->naxes = naxes;
item->nhats = nhats;
item->device_instance = SDL_GetNextJoystickInstanceID();
if (SDL_joylist_tail == NULL) {
SDL_joylist = SDL_joylist_tail = item;
} else {
SDL_joylist_tail->next = item;
SDL_joylist_tail = item;
}
/* Need to increment the joystick count before we post the event */
++numjoysticks;
SDL_PrivateJoystickAdded(item->device_instance);
result = numjoysticks;
#ifdef DEBUG_JOYSTICK
SDL_Log("Added joystick %s with device_id %d", item->name, device_id);
#endif
done:
SDL_UnlockJoysticks();
return result;
}
int Android_RemoveJoystick(int device_id)
{
SDL_joylist_item *item = SDL_joylist;
SDL_joylist_item *prev = NULL;
int result = -1;
SDL_LockJoysticks();
/* Don't call JoystickByDeviceId here or there'll be an infinite loop! */
while (item != NULL) {
if (item->device_id == device_id) {
break;
}
prev = item;
item = item->next;
}
if (item == NULL) {
goto done;
}
if (item->joystick) {
item->joystick->hwdata = NULL;
}
if (prev != NULL) {
prev->next = item->next;
} else {
SDL_assert(SDL_joylist == item);
SDL_joylist = item->next;
}
if (item == SDL_joylist_tail) {
SDL_joylist_tail = prev;
}
/* Need to decrement the joystick count before we post the event */
--numjoysticks;
SDL_PrivateJoystickRemoved(item->device_instance);
result = numjoysticks;
#ifdef DEBUG_JOYSTICK
SDL_Log("Removed joystick with device_id %d", device_id);
#endif
SDL_free(item->name);
SDL_free(item);
done:
SDL_UnlockJoysticks();
return result;
}
static void ANDROID_JoystickDetect(void);
static int ANDROID_JoystickInit(void)
{
ANDROID_JoystickDetect();
if (SDL_GetHintBoolean(SDL_HINT_ACCELEROMETER_AS_JOYSTICK, SDL_TRUE)) {
/* Default behavior, accelerometer as joystick */
Android_AddJoystick(ANDROID_ACCELEROMETER_DEVICE_ID, ANDROID_ACCELEROMETER_NAME, ANDROID_ACCELEROMETER_NAME, 0, 0, SDL_TRUE, 0, 3, 0x0003, 0);
}
return 0;
}
static int ANDROID_JoystickGetCount(void)
{
return numjoysticks;
}
static void ANDROID_JoystickDetect(void)
{
/* Support for device connect/disconnect is API >= 16 only,
* so we poll every three seconds
* Ref: http://developer.android.com/reference/android/hardware/input/InputManager.InputDeviceListener.html
*/
static Uint64 timeout = 0;
Uint64 now = SDL_GetTicks();
if (!timeout || now >= timeout) {
timeout = now + 3000;
Android_JNI_PollInputDevices();
}
}
static SDL_joylist_item *GetJoystickByDevIndex(int device_index)
{
SDL_joylist_item *item = SDL_joylist;
if ((device_index < 0) || (device_index >= numjoysticks)) {
return NULL;
}
while (device_index > 0) {
SDL_assert(item != NULL);
device_index--;
item = item->next;
}
return item;
}
static SDL_joylist_item *JoystickByDeviceId(int device_id)
{
SDL_joylist_item *item = SDL_joylist;
while (item != NULL) {
if (item->device_id == device_id) {
return item;
}
item = item->next;
}
/* Joystick not found, try adding it */
ANDROID_JoystickDetect();
while (item != NULL) {
if (item->device_id == device_id) {
return item;
}
item = item->next;
}
return NULL;
}
static const char *ANDROID_JoystickGetDeviceName(int device_index)
{
return GetJoystickByDevIndex(device_index)->name;
}
static const char *ANDROID_JoystickGetDevicePath(int device_index)
{
return NULL;
}
static int ANDROID_JoystickGetDevicePlayerIndex(int device_index)
{
return -1;
}
static void ANDROID_JoystickSetDevicePlayerIndex(int device_index, int player_index)
{
}
static SDL_JoystickGUID ANDROID_JoystickGetDeviceGUID(int device_index)
{
return GetJoystickByDevIndex(device_index)->guid;
}
static SDL_JoystickID ANDROID_JoystickGetDeviceInstanceID(int device_index)
{
return GetJoystickByDevIndex(device_index)->device_instance;
}
static int ANDROID_JoystickOpen(SDL_Joystick *joystick, int device_index)
{
SDL_joylist_item *item = GetJoystickByDevIndex(device_index);
if (item == NULL) {
return SDL_SetError("No such device");
}
if (item->joystick != NULL) {
return SDL_SetError("Joystick already opened");
}
joystick->instance_id = item->device_instance;
joystick->hwdata = (struct joystick_hwdata *)item;
item->joystick = joystick;
joystick->nhats = item->nhats;
joystick->nbuttons = item->nbuttons;
joystick->naxes = item->naxes;
return 0;
}
static int ANDROID_JoystickRumble(SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble)
{
return SDL_Unsupported();
}
static int ANDROID_JoystickRumbleTriggers(SDL_Joystick *joystick, Uint16 left_rumble, Uint16 right_rumble)
{
return SDL_Unsupported();
}
static Uint32 ANDROID_JoystickGetCapabilities(SDL_Joystick *joystick)
{
return 0;
}
static int ANDROID_JoystickSetLED(SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue)
{
return SDL_Unsupported();
}
static int ANDROID_JoystickSendEffect(SDL_Joystick *joystick, const void *data, int size)
{
return SDL_Unsupported();
}
static int ANDROID_JoystickSetSensorsEnabled(SDL_Joystick *joystick, SDL_bool enabled)
{
return SDL_Unsupported();
}
static void ANDROID_JoystickUpdate(SDL_Joystick *joystick)
{
SDL_joylist_item *item = (SDL_joylist_item *)joystick->hwdata;
if (item == NULL) {
return;
}
if (item->is_accelerometer) {
int i;
Sint16 value;
float values[3];
Uint64 timestamp = SDL_GetTicksNS();
if (Android_JNI_GetAccelerometerValues(values)) {
for (i = 0; i < 3; i++) {
if (values[i] > 1.0f) {
values[i] = 1.0f;
} else if (values[i] < -1.0f) {
values[i] = -1.0f;
}
value = (Sint16)(values[i] * 32767.0f);
SDL_SendJoystickAxis(timestamp, item->joystick, i, value);
}
}
}
}
static void ANDROID_JoystickClose(SDL_Joystick *joystick)
{
SDL_joylist_item *item = (SDL_joylist_item *)joystick->hwdata;
if (item) {
item->joystick = NULL;
}
}
static void ANDROID_JoystickQuit(void)
{
/* We don't have any way to scan for joysticks at init, so don't wipe the list
* of joysticks here in case this is a reinit.
*/
#if 0
SDL_joylist_item *item = NULL;
SDL_joylist_item *next = NULL;
for (item = SDL_joylist; item; item = next) {
next = item->next;
SDL_free(item->name);
SDL_free(item);
}
SDL_joylist = SDL_joylist_tail = NULL;
numjoysticks = 0;
#endif /* 0 */
}
static SDL_bool ANDROID_JoystickGetGamepadMapping(int device_index, SDL_GamepadMapping *out)
{
return SDL_FALSE;
}
SDL_JoystickDriver SDL_ANDROID_JoystickDriver = {
ANDROID_JoystickInit,
ANDROID_JoystickGetCount,
ANDROID_JoystickDetect,
ANDROID_JoystickGetDeviceName,
ANDROID_JoystickGetDevicePath,
ANDROID_JoystickGetDevicePlayerIndex,
ANDROID_JoystickSetDevicePlayerIndex,
ANDROID_JoystickGetDeviceGUID,
ANDROID_JoystickGetDeviceInstanceID,
ANDROID_JoystickOpen,
ANDROID_JoystickRumble,
ANDROID_JoystickRumbleTriggers,
ANDROID_JoystickGetCapabilities,
ANDROID_JoystickSetLED,
ANDROID_JoystickSendEffect,
ANDROID_JoystickSetSensorsEnabled,
ANDROID_JoystickUpdate,
ANDROID_JoystickClose,
ANDROID_JoystickQuit,
ANDROID_JoystickGetGamepadMapping
};
#endif /* SDL_JOYSTICK_ANDROID */

View File

@@ -0,0 +1,57 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 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_ANDROID
#ifndef SDL_sysjoystick_c_h_
#define SDL_sysjoystick_c_h_
#include "../SDL_sysjoystick.h"
extern int Android_OnPadDown(int device_id, int keycode);
extern int Android_OnPadUp(int device_id, int keycode);
extern int Android_OnJoy(int device_id, int axisnum, float value);
extern int Android_OnHat(int device_id, int hat_id, int x, int y);
extern int Android_AddJoystick(int device_id, const char *name, const char *desc, int vendor_id, int product_id, SDL_bool is_accelerometer, int button_mask, int naxes, int axis_mask, int nhats);
extern int Android_RemoveJoystick(int device_id);
/* A linked list of available joysticks */
typedef struct SDL_joylist_item
{
int device_instance;
int device_id; /* Android's device id */
char *name; /* "SideWinder 3D Pro" or whatever */
SDL_JoystickGUID guid;
SDL_bool is_accelerometer;
SDL_Joystick *joystick;
int nbuttons, naxes, nhats;
int dpad_state;
struct SDL_joylist_item *next;
} SDL_joylist_item;
typedef SDL_joylist_item joystick_hwdata;
#endif /* SDL_sysjoystick_c_h_ */
#endif /* SDL_JOYSTICK_ANDROID */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,59 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 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"
#ifndef SDL_JOYSTICK_IOS_H
#define SDL_JOYSTICK_IOS_H
#include "../SDL_sysjoystick.h"
@class GCController;
typedef struct joystick_hwdata
{
SDL_bool accelerometer;
SDL_bool remote;
GCController __unsafe_unretained *controller;
void *rumble;
SDL_bool uses_pause_handler;
int num_pause_presses;
Uint32 pause_button_down_time;
char *name;
SDL_Joystick *joystick;
SDL_JoystickID instance_id;
SDL_JoystickGUID guid;
int naxes;
int nbuttons;
int nhats;
Uint32 button_mask;
SDL_bool has_dualshock_touchpad;
SDL_bool has_xbox_paddles;
SDL_bool has_xbox_share_button;
struct joystick_hwdata *next;
} joystick_hwdata;
typedef joystick_hwdata SDL_JoystickDeviceItem;
#endif /* SDL_JOYSTICK_IOS_H */

View File

@@ -0,0 +1,871 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 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_USBHID
/*
* Joystick driver for the uhid(4) / ujoy(4) interface found in OpenBSD,
* NetBSD and FreeBSD.
*
* Maintainer: <vedge at csoft.org>
*/
#include <sys/param.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#ifndef __FreeBSD_kernel_version
#define __FreeBSD_kernel_version __FreeBSD_version
#endif
#ifdef HAVE_USB_H
#include <usb.h>
#endif
#ifdef __DragonFly__
#include <bus/u4b/usb.h>
#include <bus/u4b/usbhid.h>
#else
#include <dev/usb/usb.h>
#include <dev/usb/usbhid.h>
#endif
#ifdef HAVE_USBHID_H
#include <usbhid.h>
#elif defined(HAVE_LIBUSB_H)
#include <libusb.h>
#elif defined(HAVE_LIBUSBHID_H)
#include <libusbhid.h>
#endif
#if defined(__FREEBSD__) || defined(__FreeBSD_kernel__)
#include <osreldate.h>
#if __FreeBSD_kernel_version > 800063
#include <dev/usb/usb_ioctl.h>
#elif defined(__DragonFly__)
#include <bus/u4b/usb_ioctl.h>
#endif
#include <sys/joystick.h>
#endif
#if SDL_HAVE_MACHINE_JOYSTICK_H
#include <machine/joystick.h>
#endif
#include "../SDL_sysjoystick.h"
#include "../SDL_joystick_c.h"
#include "../hidapi/SDL_hidapijoystick_c.h"
#if defined(__FREEBSD__) || SDL_HAVE_MACHINE_JOYSTICK_H || defined(__FreeBSD_kernel__) || defined(__DragonFly_)
#define SUPPORT_JOY_GAMEPORT
#endif
#define MAX_UHID_JOYS 64
#define MAX_JOY_JOYS 2
#define MAX_JOYS (MAX_UHID_JOYS + MAX_JOY_JOYS)
#ifdef __OpenBSD__
#define HUG_DPAD_UP 0x90
#define HUG_DPAD_DOWN 0x91
#define HUG_DPAD_RIGHT 0x92
#define HUG_DPAD_LEFT 0x93
#define HAT_UP 0x01
#define HAT_RIGHT 0x02
#define HAT_DOWN 0x04
#define HAT_LEFT 0x08
#endif
struct report
{
#if defined(__FREEBSD__) && (__FreeBSD_kernel_version > 900000) || \
defined(__DragonFly__)
void *buf; /* Buffer */
#elif defined(__FREEBSD__) && (__FreeBSD_kernel_version > 800063)
struct usb_gen_descriptor *buf; /* Buffer */
#else
struct usb_ctl_report *buf; /* Buffer */
#endif
size_t size; /* Buffer size */
int rid; /* Report ID */
enum
{
SREPORT_UNINIT,
SREPORT_CLEAN,
SREPORT_DIRTY
} status;
};
static struct
{
int uhid_report;
hid_kind_t kind;
const char *name;
} const repinfo[] = {
{ UHID_INPUT_REPORT, hid_input, "input" },
{ UHID_OUTPUT_REPORT, hid_output, "output" },
{ UHID_FEATURE_REPORT, hid_feature, "feature" }
};
enum
{
REPORT_INPUT = 0,
REPORT_OUTPUT = 1,
REPORT_FEATURE = 2
};
enum
{
JOYAXE_X,
JOYAXE_Y,
JOYAXE_Z,
JOYAXE_SLIDER,
JOYAXE_WHEEL,
JOYAXE_RX,
JOYAXE_RY,
JOYAXE_RZ,
JOYAXE_count
};
struct joystick_hwdata
{
int fd;
enum
{
BSDJOY_UHID, /* uhid(4) */
BSDJOY_JOY /* joy(4) */
} type;
int naxes;
int nbuttons;
int nhats;
struct report_desc *repdesc;
struct report inreport;
int axis_map[JOYAXE_count]; /* map present JOYAXE_* to 0,1,.. */
};
/* A linked list of available joysticks */
typedef struct SDL_joylist_item
{
SDL_JoystickID device_instance;
char *path; /* "/dev/uhid0" or whatever */
char *name; /* "SideWinder 3D Pro" or whatever */
SDL_JoystickGUID guid;
dev_t devnum;
struct SDL_joylist_item *next;
} SDL_joylist_item;
static SDL_joylist_item *SDL_joylist = NULL;
static SDL_joylist_item *SDL_joylist_tail = NULL;
static int numjoysticks = 0;
static int report_alloc(struct report *, struct report_desc *, int);
static void report_free(struct report *);
#if defined(USBHID_UCR_DATA) || (defined(__FreeBSD_kernel__) && __FreeBSD_kernel_version <= 800063)
#define REP_BUF_DATA(rep) ((rep)->buf->ucr_data)
#elif (defined(__FREEBSD__) && (__FreeBSD_kernel_version > 900000)) || \
defined(__DragonFly__)
#define REP_BUF_DATA(rep) ((rep)->buf)
#elif (defined(__FREEBSD__) && (__FreeBSD_kernel_version > 800063))
#define REP_BUF_DATA(rep) ((rep)->buf->ugd_data)
#else
#define REP_BUF_DATA(rep) ((rep)->buf->data)
#endif
static int usage_to_joyaxe(int usage)
{
int joyaxe;
switch (usage) {
case HUG_X:
joyaxe = JOYAXE_X;
break;
case HUG_Y:
joyaxe = JOYAXE_Y;
break;
case HUG_Z:
joyaxe = JOYAXE_Z;
break;
case HUG_SLIDER:
joyaxe = JOYAXE_SLIDER;
break;
case HUG_WHEEL:
joyaxe = JOYAXE_WHEEL;
break;
case HUG_RX:
joyaxe = JOYAXE_RX;
break;
case HUG_RY:
joyaxe = JOYAXE_RY;
break;
case HUG_RZ:
joyaxe = JOYAXE_RZ;
break;
default:
joyaxe = -1;
}
return joyaxe;
}
static void FreeJoylistItem(SDL_joylist_item *item)
{
SDL_free(item->path);
SDL_free(item->name);
SDL_free(item);
}
static void FreeHwData(struct joystick_hwdata *hw)
{
if (hw->type == BSDJOY_UHID) {
report_free(&hw->inreport);
if (hw->repdesc) {
hid_dispose_report_desc(hw->repdesc);
}
}
close(hw->fd);
SDL_free(hw);
}
static struct joystick_hwdata *
CreateHwData(const char *path)
{
struct joystick_hwdata *hw;
struct hid_item hitem;
struct hid_data *hdata;
struct report *rep = NULL;
int fd;
int i;
fd = open(path, O_RDONLY | O_CLOEXEC);
if (fd == -1) {
SDL_SetError("%s: %s", path, strerror(errno));
return NULL;
}
hw = (struct joystick_hwdata *)
SDL_calloc(1, sizeof(struct joystick_hwdata));
if (hw == NULL) {
close(fd);
SDL_OutOfMemory();
return NULL;
}
hw->fd = fd;
#ifdef SUPPORT_JOY_GAMEPORT
if (SDL_strncmp(path, "/dev/joy", 8) == 0) {
hw->type = BSDJOY_JOY;
hw->naxes = 2;
hw->nbuttons = 2;
} else
#endif
{
hw->type = BSDJOY_UHID;
{
int ax;
for (ax = 0; ax < JOYAXE_count; ax++) {
hw->axis_map[ax] = -1;
}
}
hw->repdesc = hid_get_report_desc(fd);
if (hw->repdesc == NULL) {
SDL_SetError("%s: USB_GET_REPORT_DESC: %s", path,
strerror(errno));
goto usberr;
}
rep = &hw->inreport;
#if defined(__FREEBSD__) && (__FreeBSD_kernel_version > 800063) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
rep->rid = hid_get_report_id(fd);
if (rep->rid < 0) {
#else
if (ioctl(fd, USB_GET_REPORT_ID, &rep->rid) < 0) {
#endif
rep->rid = -1; /* XXX */
}
if (report_alloc(rep, hw->repdesc, REPORT_INPUT) < 0) {
goto usberr;
}
if (rep->size <= 0) {
SDL_SetError("%s: Input report descriptor has invalid length",
path);
goto usberr;
}
#if defined(USBHID_NEW) || (defined(__FREEBSD__) && __FreeBSD_kernel_version >= 500111) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
hdata = hid_start_parse(hw->repdesc, 1 << hid_input, rep->rid);
#else
hdata = hid_start_parse(hw->repdesc, 1 << hid_input);
#endif
if (hdata == NULL) {
SDL_SetError("%s: Cannot start HID parser", path);
goto usberr;
}
for (i = 0; i < JOYAXE_count; i++) {
hw->axis_map[i] = -1;
}
while (hid_get_item(hdata, &hitem) > 0) {
switch (hitem.kind) {
case hid_input:
switch (HID_PAGE(hitem.usage)) {
case HUP_GENERIC_DESKTOP:
{
int usage = HID_USAGE(hitem.usage);
int joyaxe = usage_to_joyaxe(usage);
if (joyaxe >= 0) {
hw->axis_map[joyaxe] = 1;
} else if (usage == HUG_HAT_SWITCH
#ifdef __OpenBSD__
|| usage == HUG_DPAD_UP
#endif
) {
hw->nhats++;
}
break;
}
case HUP_BUTTON:
{
int usage = HID_USAGE(hitem.usage);
if (usage > hw->nbuttons) {
hw->nbuttons = usage;
}
} break;
default:
break;
}
break;
default:
break;
}
}
hid_end_parse(hdata);
for (i = 0; i < JOYAXE_count; i++) {
if (hw->axis_map[i] > 0) {
hw->axis_map[i] = hw->naxes++;
}
}
if (hw->naxes == 0 && hw->nbuttons == 0 && hw->nhats == 0) {
SDL_SetError("%s: Not a joystick, ignoring", path);
goto usberr;
}
}
/* The poll blocks the event thread. */
fcntl(fd, F_SETFL, O_NONBLOCK);
#ifdef __NetBSD__
/* Flush pending events */
if (rep) {
while (read(fd, REP_BUF_DATA(rep), rep->size) == rep->size)
;
}
#endif
return hw;
usberr:
FreeHwData(hw);
return NULL;
}
static int MaybeAddDevice(const char *path)
{
struct stat sb;
char *name = NULL;
SDL_JoystickGUID guid;
SDL_joylist_item *item;
struct joystick_hwdata *hw;
if (path == NULL) {
return -1;
}
if (stat(path, &sb) == -1) {
return -1;
}
/* Check to make sure it's not already in list. */
for (item = SDL_joylist; item != NULL; item = item->next) {
if (sb.st_rdev == item->devnum) {
return -1; /* already have this one */
}
}
hw = CreateHwData(path);
if (hw == NULL) {
return -1;
}
if (hw->type == BSDJOY_JOY) {
name = SDL_strdup("Gameport joystick");
guid = SDL_CreateJoystickGUIDForName(name);
} else {
#ifdef USB_GET_DEVICEINFO
struct usb_device_info di;
if (ioctl(hw->fd, USB_GET_DEVICEINFO, &di) != -1) {
name = SDL_CreateJoystickName(di.udi_vendorNo, di.udi_productNo, di.udi_vendor, di.udi_product);
guid = SDL_CreateJoystickGUID(SDL_HARDWARE_BUS_USB, di.udi_vendorNo, di.udi_productNo, di.udi_releaseNo, name, 0, 0);
#ifdef SDL_JOYSTICK_HIDAPI
if (HIDAPI_IsDevicePresent(di.udi_vendorNo, di.udi_productNo, di.udi_releaseNo, name)) {
/* The HIDAPI driver is taking care of this device */
SDL_free(name);
FreeHwData(hw);
return -1;
}
#endif
if (SDL_ShouldIgnoreJoystick(name, guid)) {
SDL_free(name);
FreeHwData(hw);
return -1;
}
}
#endif /* USB_GET_DEVICEINFO */
}
if (name == NULL) {
name = SDL_strdup(path);
guid = SDL_CreateJoystickGUIDForName(name);
}
FreeHwData(hw);
item = (SDL_joylist_item *)SDL_calloc(1, sizeof(SDL_joylist_item));
if (item == NULL) {
SDL_free(name);
return -1;
}
item->devnum = sb.st_rdev;
item->path = SDL_strdup(path);
item->name = name;
item->guid = guid;
if ((item->path == NULL) || (item->name == NULL)) {
FreeJoylistItem(item);
return -1;
}
item->device_instance = SDL_GetNextJoystickInstanceID();
if (SDL_joylist_tail == NULL) {
SDL_joylist = SDL_joylist_tail = item;
} else {
SDL_joylist_tail->next = item;
SDL_joylist_tail = item;
}
/* Need to increment the joystick count before we post the event */
++numjoysticks;
SDL_PrivateJoystickAdded(item->device_instance);
return numjoysticks;
}
static int BSD_JoystickInit(void)
{
char s[16];
int i;
for (i = 0; i < MAX_UHID_JOYS; i++) {
#if defined(__OpenBSD__) && (OpenBSD >= 202105)
SDL_snprintf(s, SDL_arraysize(s), "/dev/ujoy/%d", i);
#else
SDL_snprintf(s, SDL_arraysize(s), "/dev/uhid%d", i);
#endif
MaybeAddDevice(s);
}
#ifdef SUPPORT_JOY_GAMEPORT
for (i = 0; i < MAX_JOY_JOYS; i++) {
SDL_snprintf(s, SDL_arraysize(s), "/dev/joy%d", i);
MaybeAddDevice(s);
}
#endif /* SUPPORT_JOY_GAMEPORT */
/* Read the default USB HID usage table. */
hid_init(NULL);
return numjoysticks;
}
static int BSD_JoystickGetCount(void)
{
return numjoysticks;
}
static void BSD_JoystickDetect(void)
{
}
static SDL_joylist_item *GetJoystickByDevIndex(int device_index)
{
SDL_joylist_item *item = SDL_joylist;
if ((device_index < 0) || (device_index >= numjoysticks)) {
return NULL;
}
while (device_index > 0) {
SDL_assert(item != NULL);
device_index--;
item = item->next;
}
return item;
}
static const char *BSD_JoystickGetDeviceName(int device_index)
{
return GetJoystickByDevIndex(device_index)->name;
}
static const char *BSD_JoystickGetDevicePath(int device_index)
{
return GetJoystickByDevIndex(device_index)->path;
}
static int BSD_JoystickGetDevicePlayerIndex(int device_index)
{
return -1;
}
static void BSD_JoystickSetDevicePlayerIndex(int device_index, int player_index)
{
}
static SDL_JoystickGUID BSD_JoystickGetDeviceGUID(int device_index)
{
return GetJoystickByDevIndex(device_index)->guid;
}
/* Function to perform the mapping from device index to the instance id for this index */
static SDL_JoystickID BSD_JoystickGetDeviceInstanceID(int device_index)
{
return GetJoystickByDevIndex(device_index)->device_instance;
}
static unsigned hatval_to_sdl(Sint32 hatval)
{
static const unsigned hat_dir_map[8] = {
SDL_HAT_UP, SDL_HAT_RIGHTUP, SDL_HAT_RIGHT, SDL_HAT_RIGHTDOWN,
SDL_HAT_DOWN, SDL_HAT_LEFTDOWN, SDL_HAT_LEFT, SDL_HAT_LEFTUP
};
unsigned result;
if ((hatval & 7) == hatval)
result = hat_dir_map[hatval];
else
result = SDL_HAT_CENTERED;
return result;
}
static int BSD_JoystickOpen(SDL_Joystick *joy, int device_index)
{
SDL_joylist_item *item = GetJoystickByDevIndex(device_index);
struct joystick_hwdata *hw;
if (item == NULL) {
return SDL_SetError("No such device");
}
hw = CreateHwData(item->path);
if (hw == NULL) {
return -1;
}
joy->instance_id = item->device_instance;
joy->hwdata = hw;
joy->naxes = hw->naxes;
joy->nbuttons = hw->nbuttons;
joy->nhats = hw->nhats;
return 0;
}
static void BSD_JoystickUpdate(SDL_Joystick *joy)
{
struct hid_item hitem;
struct hid_data *hdata;
struct report *rep;
int nbutton, naxe = -1;
Sint32 v;
#ifdef __OpenBSD__
Sint32 dpad[4] = { 0, 0, 0, 0 };
#endif
Uint64 timestamp = SDL_GetTicksNS();
#ifdef SUPPORT_JOY_GAMEPORT
struct joystick gameport;
static int x, y, xmin = 0xffff, ymin = 0xffff, xmax = 0, ymax = 0;
if (joy->hwdata->type == BSDJOY_JOY) {
while (read(joy->hwdata->fd, &gameport, sizeof(gameport)) == sizeof(gameport)) {
if (SDL_abs(x - gameport.x) > 8) {
x = gameport.x;
if (x < xmin) {
xmin = x;
}
if (x > xmax) {
xmax = x;
}
if (xmin == xmax) {
xmin--;
xmax++;
}
v = (((SDL_JOYSTICK_AXIS_MAX - SDL_JOYSTICK_AXIS_MIN) * ((Sint32)x - xmin)) / (xmax - xmin)) + SDL_JOYSTICK_AXIS_MIN;
SDL_SendJoystickAxis(timestamp, joy, 0, v);
}
if (SDL_abs(y - gameport.y) > 8) {
y = gameport.y;
if (y < ymin) {
ymin = y;
}
if (y > ymax) {
ymax = y;
}
if (ymin == ymax) {
ymin--;
ymax++;
}
v = (((SDL_JOYSTICK_AXIS_MAX - SDL_JOYSTICK_AXIS_MIN) * ((Sint32)y - ymin)) / (ymax - ymin)) + SDL_JOYSTICK_AXIS_MIN;
SDL_SendJoystickAxis(timestamp, joy, 1, v);
}
SDL_SendJoystickButton(timestamp, joy, 0, gameport.b1);
SDL_SendJoystickButton(timestamp, joy, 1, gameport.b2);
}
return;
}
#endif /* SUPPORT_JOY_GAMEPORT */
rep = &joy->hwdata->inreport;
while (read(joy->hwdata->fd, REP_BUF_DATA(rep), rep->size) == rep->size) {
#if defined(USBHID_NEW) || (defined(__FREEBSD__) && __FreeBSD_kernel_version >= 500111) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
hdata = hid_start_parse(joy->hwdata->repdesc, 1 << hid_input, rep->rid);
#else
hdata = hid_start_parse(joy->hwdata->repdesc, 1 << hid_input);
#endif
if (hdata == NULL) {
/*fprintf(stderr, "%s: Cannot start HID parser\n", joy->hwdata->path);*/
continue;
}
while (hid_get_item(hdata, &hitem) > 0) {
switch (hitem.kind) {
case hid_input:
switch (HID_PAGE(hitem.usage)) {
case HUP_GENERIC_DESKTOP:
{
int usage = HID_USAGE(hitem.usage);
int joyaxe = usage_to_joyaxe(usage);
if (joyaxe >= 0) {
naxe = joy->hwdata->axis_map[joyaxe];
/* scaleaxe */
v = (Sint32)hid_get_data(REP_BUF_DATA(rep), &hitem);
v = (((SDL_JOYSTICK_AXIS_MAX - SDL_JOYSTICK_AXIS_MIN) * (v - hitem.logical_minimum)) / (hitem.logical_maximum - hitem.logical_minimum)) + SDL_JOYSTICK_AXIS_MIN;
SDL_SendJoystickAxis(timestamp, joy, naxe, v);
} else if (usage == HUG_HAT_SWITCH) {
v = (Sint32)hid_get_data(REP_BUF_DATA(rep), &hitem);
SDL_SendJoystickHat(timestamp, joy, 0,
hatval_to_sdl(v) -
hitem.logical_minimum);
}
#ifdef __OpenBSD__
/* here D-pad directions are reported like separate buttons.
* calculate the SDL hat value from the 4 separate values.
*/
switch (usage) {
case HUG_DPAD_UP:
dpad[0] = (Sint32)hid_get_data(REP_BUF_DATA(rep), &hitem);
break;
case HUG_DPAD_DOWN:
dpad[1] = (Sint32)hid_get_data(REP_BUF_DATA(rep), &hitem);
break;
case HUG_DPAD_RIGHT:
dpad[2] = (Sint32)hid_get_data(REP_BUF_DATA(rep), &hitem);
break;
case HUG_DPAD_LEFT:
dpad[3] = (Sint32)hid_get_data(REP_BUF_DATA(rep), &hitem);
break;
//default:
// no-op
}
SDL_PrivateJoystickHat(joy, 0, (dpad[0] * HAT_UP) |
(dpad[1] * HAT_DOWN) |
(dpad[2] * HAT_RIGHT) |
(dpad[3] * HAT_LEFT) );
#endif
break;
}
case HUP_BUTTON:
v = (Sint32)hid_get_data(REP_BUF_DATA(rep), &hitem);
nbutton = HID_USAGE(hitem.usage) - 1; /* SDL buttons are zero-based */
SDL_SendJoystickButton(timestamp, joy, nbutton, v);
break;
default:
continue;
}
break;
default:
break;
}
}
hid_end_parse(hdata);
}
}
/* Function to close a joystick after use */
static void BSD_JoystickClose(SDL_Joystick *joy)
{
if (joy->hwdata) {
FreeHwData(joy->hwdata);
joy->hwdata = NULL;
}
}
static void BSD_JoystickQuit(void)
{
SDL_joylist_item *item = NULL;
SDL_joylist_item *next = NULL;
for (item = SDL_joylist; item; item = next) {
next = item->next;
FreeJoylistItem(item);
}
SDL_joylist = SDL_joylist_tail = NULL;
numjoysticks = 0;
}
static int report_alloc(struct report *r, struct report_desc *rd, int repind)
{
int len;
#ifdef __DragonFly__
len = hid_report_size(rd, repinfo[repind].kind, r->rid);
#elif __FREEBSD__
#if (__FreeBSD_kernel_version >= 460000) || defined(__FreeBSD_kernel__)
#if (__FreeBSD_kernel_version <= 500111)
len = hid_report_size(rd, r->rid, repinfo[repind].kind);
#else
len = hid_report_size(rd, repinfo[repind].kind, r->rid);
#endif
#else
len = hid_report_size(rd, repinfo[repind].kind, &r->rid);
#endif
#else
#ifdef USBHID_NEW
len = hid_report_size(rd, repinfo[repind].kind, r->rid);
#else
len = hid_report_size(rd, repinfo[repind].kind, &r->rid);
#endif
#endif
if (len < 0) {
return SDL_SetError("Negative HID report size");
}
r->size = len;
if (r->size > 0) {
#if defined(__FREEBSD__) && (__FreeBSD_kernel_version > 900000) || defined(__DragonFly__)
r->buf = SDL_malloc(r->size);
#else
r->buf = SDL_malloc(sizeof(*r->buf) - sizeof(REP_BUF_DATA(r)) +
r->size);
#endif
if (r->buf == NULL) {
return SDL_OutOfMemory();
}
} else {
r->buf = NULL;
}
r->status = SREPORT_CLEAN;
return 0;
}
static void report_free(struct report *r)
{
SDL_free(r->buf);
r->status = SREPORT_UNINIT;
}
static int BSD_JoystickRumble(SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble)
{
return SDL_Unsupported();
}
static int BSD_JoystickRumbleTriggers(SDL_Joystick *joystick, Uint16 left_rumble, Uint16 right_rumble)
{
return SDL_Unsupported();
}
static SDL_bool BSD_JoystickGetGamepadMapping(int device_index, SDL_GamepadMapping *out)
{
return SDL_FALSE;
}
static Uint32 BSD_JoystickGetCapabilities(SDL_Joystick *joystick)
{
return 0;
}
static int BSD_JoystickSetLED(SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue)
{
return SDL_Unsupported();
}
static int BSD_JoystickSendEffect(SDL_Joystick *joystick, const void *data, int size)
{
return SDL_Unsupported();
}
static int BSD_JoystickSetSensorsEnabled(SDL_Joystick *joystick, SDL_bool enabled)
{
return SDL_Unsupported();
}
SDL_JoystickDriver SDL_BSD_JoystickDriver = {
BSD_JoystickInit,
BSD_JoystickGetCount,
BSD_JoystickDetect,
BSD_JoystickGetDeviceName,
BSD_JoystickGetDevicePath,
BSD_JoystickGetDevicePlayerIndex,
BSD_JoystickSetDevicePlayerIndex,
BSD_JoystickGetDeviceGUID,
BSD_JoystickGetDeviceInstanceID,
BSD_JoystickOpen,
BSD_JoystickRumble,
BSD_JoystickRumbleTriggers,
BSD_JoystickGetCapabilities,
BSD_JoystickSetLED,
BSD_JoystickSendEffect,
BSD_JoystickSetSensorsEnabled,
BSD_JoystickUpdate,
BSD_JoystickClose,
BSD_JoystickQuit,
BSD_JoystickGetGamepadMapping
};
#endif /* SDL_JOYSTICK_USBHID */

15
external/sdl/SDL/src/joystick/check_8bitdo.sh vendored Executable file
View File

@@ -0,0 +1,15 @@
#!/bin/sh
#
# Check to make sure 8BitDo controller configurations are correct
echo "Expected output:"
cat <<__EOF__
"050000003512000020ab000000780f00,8BitDo SNES30 Gamepad,a:b20,b:b21,back:b30,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b26,rightshoulder:b27,start:b31,x:b23,y:b24,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"050000003512000020ab000000780f00,8BitDo SNES30 Gamepad,a:b21,b:b20,back:b30,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b26,rightshoulder:b27,start:b31,x:b24,y:b23,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
__EOF__
echo "Actual output:"
${FGREP:-grep -F} 8BitDo SDL_gamepad_db.h | ${FGREP:-grep -F} -v hint
${EGREP:-grep -E} "hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1" SDL_gamepad_db.h | ${FGREP:-grep -F} -i 8bit | ${FGREP:-grep -F} -v x:b2,y:b3 | ${FGREP:-grep -F} -v x:b3,y:b4
${EGREP:-grep -E} "hint:.SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1" SDL_gamepad_db.h | ${FGREP:-grep -F} -i 8bit | ${FGREP:-grep -F} -v x:b3,y:b2 | ${FGREP:-grep -F} -v x:b4,y:b3

View File

@@ -0,0 +1,592 @@
/*
Copyright (C) Valve Corporation
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.
*/
#define MAKE_CONTROLLER_ID( nVID, nPID ) (unsigned int)( (unsigned int)nVID << 16 | (unsigned int)nPID )
static const ControllerDescription_t arrControllers[] = {
{ MAKE_CONTROLLER_ID( 0x0079, 0x181a ), k_eControllerType_PS3Controller, NULL }, // Venom Arcade Stick
{ MAKE_CONTROLLER_ID( 0x0079, 0x1844 ), k_eControllerType_PS3Controller, NULL }, // From SDL
{ MAKE_CONTROLLER_ID( 0x044f, 0xb315 ), k_eControllerType_PS3Controller, NULL }, // Firestorm Dual Analog 3
{ MAKE_CONTROLLER_ID( 0x044f, 0xd007 ), k_eControllerType_PS3Controller, NULL }, // Thrustmaster wireless 3-1
//{ MAKE_CONTROLLER_ID( 0x046d, 0xc24f ), k_eControllerType_PS3Controller, NULL }, // Logitech G29 (PS3)
{ MAKE_CONTROLLER_ID( 0x054c, 0x0268 ), k_eControllerType_PS3Controller, NULL }, // Sony PS3 Controller
{ MAKE_CONTROLLER_ID( 0x056e, 0x200f ), k_eControllerType_PS3Controller, NULL }, // From SDL
{ MAKE_CONTROLLER_ID( 0x056e, 0x2013 ), k_eControllerType_PS3Controller, NULL }, // JC-U4113SBK
{ MAKE_CONTROLLER_ID( 0x05b8, 0x1004 ), k_eControllerType_PS3Controller, NULL }, // From SDL
{ MAKE_CONTROLLER_ID( 0x05b8, 0x1006 ), k_eControllerType_PS3Controller, NULL }, // JC-U3412SBK
{ MAKE_CONTROLLER_ID( 0x06a3, 0xf622 ), k_eControllerType_PS3Controller, NULL }, // Cyborg V3
{ MAKE_CONTROLLER_ID( 0x0738, 0x3180 ), k_eControllerType_PS3Controller, NULL }, // Mad Catz Alpha PS3 mode
{ MAKE_CONTROLLER_ID( 0x0738, 0x3250 ), k_eControllerType_PS3Controller, NULL }, // madcats fightpad pro ps3
{ MAKE_CONTROLLER_ID( 0x0738, 0x3481 ), k_eControllerType_PS3Controller, NULL }, // Mad Catz FightStick TE 2+ PS3
{ MAKE_CONTROLLER_ID( 0x0738, 0x8180 ), k_eControllerType_PS3Controller, NULL }, // Mad Catz Alpha PS4 mode (no touchpad on device)
{ MAKE_CONTROLLER_ID( 0x0738, 0x8838 ), k_eControllerType_PS3Controller, NULL }, // Madcatz Fightstick Pro
{ MAKE_CONTROLLER_ID( 0x0810, 0x0001 ), k_eControllerType_PS3Controller, NULL }, // actually ps2 - maybe break out later
{ MAKE_CONTROLLER_ID( 0x0810, 0x0003 ), k_eControllerType_PS3Controller, NULL }, // actually ps2 - maybe break out later
{ MAKE_CONTROLLER_ID( 0x0925, 0x0005 ), k_eControllerType_PS3Controller, NULL }, // Sony PS3 Controller
{ MAKE_CONTROLLER_ID( 0x0925, 0x8866 ), k_eControllerType_PS3Controller, NULL }, // PS2 maybe break out later
{ MAKE_CONTROLLER_ID( 0x0925, 0x8888 ), k_eControllerType_PS3Controller, NULL }, // Actually ps2 -maybe break out later Lakeview Research WiseGroup Ltd, MP-8866 Dual Joypad
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0109 ), k_eControllerType_PS3Controller, NULL }, // PDP Versus Fighting Pad
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x011e ), k_eControllerType_PS3Controller, NULL }, // Rock Candy PS4
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0128 ), k_eControllerType_PS3Controller, NULL }, // Rock Candy PS3
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0214 ), k_eControllerType_PS3Controller, NULL }, // afterglow ps3
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x1314 ), k_eControllerType_PS3Controller, NULL }, // PDP Afterglow Wireless PS3 controller
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x6302 ), k_eControllerType_PS3Controller, NULL }, // From SDL
{ MAKE_CONTROLLER_ID( 0x0e8f, 0x0008 ), k_eControllerType_PS3Controller, NULL }, // Green Asia
{ MAKE_CONTROLLER_ID( 0x0e8f, 0x3075 ), k_eControllerType_PS3Controller, NULL }, // SpeedLink Strike FX
{ MAKE_CONTROLLER_ID( 0x0e8f, 0x310d ), k_eControllerType_PS3Controller, NULL }, // From SDL
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x0009 ), k_eControllerType_PS3Controller, NULL }, // HORI BDA GP1
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x004d ), k_eControllerType_PS3Controller, NULL }, // Horipad 3
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x005f ), k_eControllerType_PS3Controller, NULL }, // HORI Fighting Commander 4 PS3
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x006a ), k_eControllerType_PS3Controller, NULL }, // Real Arcade Pro 4
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x006e ), k_eControllerType_PS3Controller, NULL }, // HORI horipad4 ps3
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x0085 ), k_eControllerType_PS3Controller, NULL }, // HORI Fighting Commander PS3
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x0086 ), k_eControllerType_PS3Controller, NULL }, // HORI Fighting Commander PC (Uses the Xbox 360 protocol, but has PS3 buttons)
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x0088 ), k_eControllerType_PS3Controller, NULL }, // HORI Fighting Stick mini 4
{ MAKE_CONTROLLER_ID( 0x0f30, 0x1100 ), k_eControllerType_PS3Controller, NULL }, // Qanba Q1 fight stick
{ MAKE_CONTROLLER_ID( 0x11ff, 0x3331 ), k_eControllerType_PS3Controller, NULL }, // SRXJ-PH2400
{ MAKE_CONTROLLER_ID( 0x1345, 0x1000 ), k_eControllerType_PS3Controller, NULL }, // PS2 ACME GA-D5
{ MAKE_CONTROLLER_ID( 0x1345, 0x6005 ), k_eControllerType_PS3Controller, NULL }, // ps2 maybe break out later
{ MAKE_CONTROLLER_ID( 0x146b, 0x5500 ), k_eControllerType_PS3Controller, NULL }, // From SDL
{ MAKE_CONTROLLER_ID( 0x1a34, 0x0836 ), k_eControllerType_PS3Controller, NULL }, // Afterglow PS3
{ MAKE_CONTROLLER_ID( 0x20bc, 0x5500 ), k_eControllerType_PS3Controller, NULL }, // ShanWan PS3
{ MAKE_CONTROLLER_ID( 0x20d6, 0x576d ), k_eControllerType_PS3Controller, NULL }, // Power A PS3
{ MAKE_CONTROLLER_ID( 0x20d6, 0xca6d ), k_eControllerType_PS3Controller, NULL }, // From SDL
{ MAKE_CONTROLLER_ID( 0x2563, 0x0523 ), k_eControllerType_PS3Controller, NULL }, // Digiflip GP006
{ MAKE_CONTROLLER_ID( 0x2563, 0x0575 ), k_eControllerType_PS3Controller, NULL }, // From SDL
{ MAKE_CONTROLLER_ID( 0x25f0, 0x83c3 ), k_eControllerType_PS3Controller, NULL }, // gioteck vx2
{ MAKE_CONTROLLER_ID( 0x25f0, 0xc121 ), k_eControllerType_PS3Controller, NULL }, //
{ MAKE_CONTROLLER_ID( 0x2c22, 0x2003 ), k_eControllerType_PS3Controller, NULL }, // Qanba Drone
{ MAKE_CONTROLLER_ID( 0x2c22, 0x2302 ), k_eControllerType_PS3Controller, NULL }, // Qanba Obsidian
{ MAKE_CONTROLLER_ID( 0x2c22, 0x2502 ), k_eControllerType_PS3Controller, NULL }, // Qanba Dragon
{ MAKE_CONTROLLER_ID( 0x8380, 0x0003 ), k_eControllerType_PS3Controller, NULL }, // BTP 2163
{ MAKE_CONTROLLER_ID( 0x8888, 0x0308 ), k_eControllerType_PS3Controller, NULL }, // Sony PS3 Controller
{ MAKE_CONTROLLER_ID( 0x0079, 0x181b ), k_eControllerType_PS4Controller, NULL }, // Venom Arcade Stick - XXX:this may not work and may need to be called a ps3 controller
//{ MAKE_CONTROLLER_ID( 0x046d, 0xc260 ), k_eControllerType_PS4Controller, NULL }, // Logitech G29 (PS4)
{ MAKE_CONTROLLER_ID( 0x044f, 0xd00e ), k_eControllerType_PS4Controller, NULL }, // Thrustmaster Eswap Pro - No gyro and lightbar doesn't change color. Works otherwise
{ MAKE_CONTROLLER_ID( 0x054c, 0x05c4 ), k_eControllerType_PS4Controller, NULL }, // Sony PS4 Controller
{ MAKE_CONTROLLER_ID( 0x054c, 0x05c5 ), k_eControllerType_PS4Controller, NULL }, // STRIKEPAD PS4 Grip Add-on
{ MAKE_CONTROLLER_ID( 0x054c, 0x09cc ), k_eControllerType_PS4Controller, NULL }, // Sony PS4 Slim Controller
{ MAKE_CONTROLLER_ID( 0x054c, 0x0ba0 ), k_eControllerType_PS4Controller, NULL }, // Sony PS4 Controller (Wireless dongle)
{ MAKE_CONTROLLER_ID( 0x0738, 0x8250 ), k_eControllerType_PS4Controller, NULL }, // Mad Catz FightPad Pro PS4
{ MAKE_CONTROLLER_ID( 0x0738, 0x8384 ), k_eControllerType_PS4Controller, NULL }, // Mad Catz FightStick TE S+ PS4
{ MAKE_CONTROLLER_ID( 0x0738, 0x8480 ), k_eControllerType_PS4Controller, NULL }, // Mad Catz FightStick TE 2 PS4
{ MAKE_CONTROLLER_ID( 0x0738, 0x8481 ), k_eControllerType_PS4Controller, NULL }, // Mad Catz FightStick TE 2+ PS4
{ MAKE_CONTROLLER_ID( 0x0c12, 0x0e10 ), k_eControllerType_PS4Controller, NULL }, // Armor Armor 3 Pad PS4
{ MAKE_CONTROLLER_ID( 0x0c12, 0x0e13 ), k_eControllerType_PS4Controller, NULL }, // ZEROPLUS P4 Wired Gamepad
{ MAKE_CONTROLLER_ID( 0x0c12, 0x0e15 ), k_eControllerType_PS4Controller, NULL }, // Game:Pad 4
{ MAKE_CONTROLLER_ID( 0x0c12, 0x0e20 ), k_eControllerType_PS4Controller, NULL }, // Brook Mars Controller - needs FW update to show up as Ps4 controller on PC. Has Gyro but touchpad is a single button.
{ MAKE_CONTROLLER_ID( 0x0c12, 0x0ef6 ), k_eControllerType_PS4Controller, NULL }, // Hitbox Arcade Stick
{ MAKE_CONTROLLER_ID( 0x0c12, 0x1cf6 ), k_eControllerType_PS4Controller, NULL }, // EMIO PS4 Elite Controller
{ MAKE_CONTROLLER_ID( 0x0c12, 0x1e10 ), k_eControllerType_PS4Controller, NULL }, // P4 Wired Gamepad generic knock off - lightbar but not trackpad or gyro
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0203 ), k_eControllerType_PS4Controller, NULL }, // Victrix Pro FS (PS4 peripheral but no trackpad/lightbar)
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0207 ), k_eControllerType_PS4Controller, NULL }, // Victrix Pro FS V2 w/ Touchpad for PS4
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x0055 ), k_eControllerType_PS4Controller, NULL }, // HORIPAD 4 FPS
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x005e ), k_eControllerType_PS4Controller, NULL }, // HORI Fighting Commander 4 PS4
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x0066 ), k_eControllerType_PS4Controller, NULL }, // HORIPAD 4 FPS Plus
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x0084 ), k_eControllerType_PS4Controller, NULL }, // HORI Fighting Commander PS4
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x0087 ), k_eControllerType_PS4Controller, NULL }, // HORI Fighting Stick mini 4
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x008a ), k_eControllerType_PS4Controller, NULL }, // HORI Real Arcade Pro 4
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x009c ), k_eControllerType_PS4Controller, NULL }, // HORI TAC PRO mousething
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x00a0 ), k_eControllerType_PS4Controller, NULL }, // HORI TAC4 mousething
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x00ed ), k_eControllerType_XInputPS4Controller, NULL }, // Hori Fighting Stick mini 4 kai - becomes an Xbox 360 controller on PC
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x00ee ), k_eControllerType_PS4Controller, NULL }, // Hori mini wired https://www.playstation.com/en-us/explore/accessories/gaming-controllers/mini-wired-gamepad/
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x011c ), k_eControllerType_PS4Controller, NULL }, // Hori Fighting Stick α
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x0123 ), k_eControllerType_PS4Controller, NULL }, // HORI Wireless Controller Light (Japan only) - only over bt- over usb is xbox and pid 0x0124
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x0162 ), k_eControllerType_PS4Controller, NULL }, // HORI Fighting Commander OCTA
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x0164 ), k_eControllerType_XInputPS4Controller, NULL }, // HORI Fighting Commander OCTA
{ MAKE_CONTROLLER_ID( 0x11c0, 0x4001 ), k_eControllerType_PS4Controller, NULL }, // "PS4 Fun Controller" added from user log
{ MAKE_CONTROLLER_ID( 0x146b, 0x0603 ), k_eControllerType_XInputPS4Controller, NULL }, // Nacon PS4 Compact Controller
{ MAKE_CONTROLLER_ID( 0x146b, 0x0604 ), k_eControllerType_XInputPS4Controller, NULL }, // NACON Daija Arcade Stick
{ MAKE_CONTROLLER_ID( 0x146b, 0x0605 ), k_eControllerType_XInputPS4Controller, NULL }, // NACON PS4 controller in Xbox mode - might also be other bigben brand xbox controllers
{ MAKE_CONTROLLER_ID( 0x146b, 0x0606 ), k_eControllerType_XInputPS4Controller, NULL }, // NACON Unknown Controller
{ MAKE_CONTROLLER_ID( 0x146b, 0x0609 ), k_eControllerType_XInputPS4Controller, NULL }, // NACON Wireless Controller for PS4
{ MAKE_CONTROLLER_ID( 0x146b, 0x0d01 ), k_eControllerType_PS4Controller, NULL }, // Nacon Revolution Pro Controller - has gyro
{ MAKE_CONTROLLER_ID( 0x146b, 0x0d02 ), k_eControllerType_PS4Controller, NULL }, // Nacon Revolution Pro Controller v2 - has gyro
{ MAKE_CONTROLLER_ID( 0x146b, 0x0d06 ), k_eControllerType_PS4Controller, NULL }, // NACON Asymmetric Controller Wireless Dongle -- show up as ps4 until you connect controller to it then it reboots into Xbox controller with different vvid/pid
{ MAKE_CONTROLLER_ID( 0x146b, 0x0d08 ), k_eControllerType_PS4Controller, NULL }, // NACON Revolution Unlimited Wireless Dongle
{ MAKE_CONTROLLER_ID( 0x146b, 0x0d09 ), k_eControllerType_PS4Controller, NULL }, // NACON Daija Fight Stick - touchpad but no gyro/rumble
{ MAKE_CONTROLLER_ID( 0x146b, 0x0d10 ), k_eControllerType_PS4Controller, NULL }, // NACON Revolution Infinite - has gyro
{ MAKE_CONTROLLER_ID( 0x146b, 0x0d10 ), k_eControllerType_PS4Controller, NULL }, // NACON Revolution Unlimited
{ MAKE_CONTROLLER_ID( 0x146b, 0x0d13 ), k_eControllerType_PS4Controller, NULL }, // NACON Revolution Pro Controller 3
{ MAKE_CONTROLLER_ID( 0x146b, 0x1103 ), k_eControllerType_PS4Controller, NULL }, // NACON Asymmetric Controller -- on windows this doesn't enumerate
{ MAKE_CONTROLLER_ID( 0x1532, 0X0401 ), k_eControllerType_PS4Controller, NULL }, // Razer Panthera PS4 Controller
{ MAKE_CONTROLLER_ID( 0x1532, 0x1000 ), k_eControllerType_PS4Controller, NULL }, // Razer Raiju PS4 Controller
{ MAKE_CONTROLLER_ID( 0x1532, 0x1004 ), k_eControllerType_PS4Controller, NULL }, // Razer Raiju 2 Ultimate USB
{ MAKE_CONTROLLER_ID( 0x1532, 0x1007 ), k_eControllerType_PS4Controller, NULL }, // Razer Raiju 2 Tournament edition USB
{ MAKE_CONTROLLER_ID( 0x1532, 0x1008 ), k_eControllerType_PS4Controller, NULL }, // Razer Panthera Evo Fightstick
{ MAKE_CONTROLLER_ID( 0x1532, 0x1009 ), k_eControllerType_PS4Controller, NULL }, // Razer Raiju 2 Ultimate BT
{ MAKE_CONTROLLER_ID( 0x1532, 0x100A ), k_eControllerType_PS4Controller, NULL }, // Razer Raiju 2 Tournament edition BT
{ MAKE_CONTROLLER_ID( 0x1532, 0x1100 ), k_eControllerType_PS4Controller, NULL }, // Razer RAION Fightpad - Trackpad, no gyro, lightbar hardcoded to green
{ MAKE_CONTROLLER_ID( 0x20d6, 0x792a ), k_eControllerType_PS4Controller, NULL }, // PowerA Fusion Fight Pad
{ MAKE_CONTROLLER_ID( 0x2c22, 0x2000 ), k_eControllerType_PS4Controller, NULL }, // Qanba Drone
{ MAKE_CONTROLLER_ID( 0x2c22, 0x2300 ), k_eControllerType_PS4Controller, NULL }, // Qanba Obsidian
{ MAKE_CONTROLLER_ID( 0x2c22, 0x2303 ), k_eControllerType_XInputPS4Controller, NULL }, // Qanba Obsidian Arcade Joystick
{ MAKE_CONTROLLER_ID( 0x2c22, 0x2500 ), k_eControllerType_PS4Controller, NULL }, // Qanba Dragon
{ MAKE_CONTROLLER_ID( 0x2c22, 0x2503 ), k_eControllerType_XInputPS4Controller, NULL }, // Qanba Dragon Arcade Joystick
{ MAKE_CONTROLLER_ID( 0x7545, 0x0104 ), k_eControllerType_PS4Controller, NULL }, // Armor 3 or Level Up Cobra - At least one variant has gyro
{ MAKE_CONTROLLER_ID (0x9886, 0x0024 ), k_eControllerType_XInputPS4Controller, NULL }, // Astro C40 in Xbox 360 mode
{ MAKE_CONTROLLER_ID( 0x9886, 0x0025 ), k_eControllerType_PS4Controller, NULL }, // Astro C40
// Removing the Giotek because there were a bunch of help tickets from users w/ issues including from non-PS4 controller users. This VID/PID is probably used in different FW's
// { MAKE_CONTROLLER_ID( 0x7545, 0x1122 ), k_eControllerType_PS4Controller, NULL }, // Giotek VX4 - trackpad/gyro don't work. Had to not filter on interface info. Light bar is flaky, but works.
{ MAKE_CONTROLLER_ID( 0x054c, 0x0ce6 ), k_eControllerType_PS5Controller, NULL }, // Sony DualSense Controller
{ MAKE_CONTROLLER_ID( 0x054c, 0x0df2 ), k_eControllerType_PS5Controller, NULL }, // Sony DualSense Edge Controller
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x0163 ), k_eControllerType_PS5Controller, NULL }, // HORI Fighting Commander OCTA
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x0184 ), k_eControllerType_PS5Controller, NULL }, // Hori Fighting Stick α
{ MAKE_CONTROLLER_ID( 0x1532, 0x100b ), k_eControllerType_PS5Controller, NULL }, // Razer Wolverine V2 Pro (Wired)
{ MAKE_CONTROLLER_ID( 0x1532, 0x100c ), k_eControllerType_PS5Controller, NULL }, // Razer Wolverine V2 Pro (Wireless)
{ MAKE_CONTROLLER_ID( 0x358a, 0x0104 ), k_eControllerType_PS5Controller, NULL }, // Backbone One PlayStation Edition for iOS
{ MAKE_CONTROLLER_ID( 0x0079, 0x0006 ), k_eControllerType_UnknownNonSteamController, NULL }, // DragonRise Generic USB PCB, sometimes configured as a PC Twin Shock Controller - looks like a DS3 but the face buttons are 1-4 instead of symbols
{ MAKE_CONTROLLER_ID( 0x0079, 0x18d4 ), k_eControllerType_XBox360Controller, NULL }, // GPD Win 2 X-Box Controller
{ MAKE_CONTROLLER_ID( 0x03eb, 0xff02 ), k_eControllerType_XBox360Controller, NULL }, // Wooting Two
{ MAKE_CONTROLLER_ID( 0x044f, 0xb326 ), k_eControllerType_XBox360Controller, NULL }, // Thrustmaster Gamepad GP XID
{ MAKE_CONTROLLER_ID( 0x045e, 0x028e ), k_eControllerType_XBox360Controller, "Xbox 360 Controller" }, // Microsoft X-Box 360 pad
{ MAKE_CONTROLLER_ID( 0x045e, 0x028f ), k_eControllerType_XBox360Controller, "Xbox 360 Controller" }, // Microsoft X-Box 360 pad v2
{ MAKE_CONTROLLER_ID( 0x045e, 0x0291 ), k_eControllerType_XBox360Controller, "Xbox 360 Wireless Controller" }, // Xbox 360 Wireless Receiver (XBOX)
{ MAKE_CONTROLLER_ID( 0x045e, 0x02a0 ), k_eControllerType_XBox360Controller, NULL }, // Microsoft X-Box 360 Big Button IR
{ MAKE_CONTROLLER_ID( 0x045e, 0x02a1 ), k_eControllerType_XBox360Controller, NULL }, // Microsoft X-Box 360 Wireless Controller with XUSB driver on Windows
{ MAKE_CONTROLLER_ID( 0x045e, 0x02a9 ), k_eControllerType_XBox360Controller, "Xbox 360 Wireless Controller" }, // Xbox 360 Wireless Receiver (third party knockoff)
{ MAKE_CONTROLLER_ID( 0x045e, 0x0719 ), k_eControllerType_XBox360Controller, "Xbox 360 Wireless Controller" }, // Xbox 360 Wireless Receiver
{ MAKE_CONTROLLER_ID( 0x046d, 0xc21d ), k_eControllerType_XBox360Controller, NULL }, // Logitech Gamepad F310
{ MAKE_CONTROLLER_ID( 0x046d, 0xc21e ), k_eControllerType_XBox360Controller, NULL }, // Logitech Gamepad F510
{ MAKE_CONTROLLER_ID( 0x046d, 0xc21f ), k_eControllerType_XBox360Controller, NULL }, // Logitech Gamepad F710
{ MAKE_CONTROLLER_ID( 0x046d, 0xc242 ), k_eControllerType_XBox360Controller, NULL }, // Logitech Chillstream Controller
{ MAKE_CONTROLLER_ID( 0x056e, 0x2004 ), k_eControllerType_XBox360Controller, NULL }, // Elecom JC-U3613M
// This isn't actually an Xbox 360 controller, it just looks like one
// { MAKE_CONTROLLER_ID( 0x06a3, 0xf51a ), k_eControllerType_XBox360Controller, NULL }, // Saitek P3600
{ MAKE_CONTROLLER_ID( 0x0738, 0x4716 ), k_eControllerType_XBox360Controller, NULL }, // Mad Catz Wired Xbox 360 Controller
{ MAKE_CONTROLLER_ID( 0x0738, 0x4718 ), k_eControllerType_XBox360Controller, NULL }, // Mad Catz Street Fighter IV FightStick SE
{ MAKE_CONTROLLER_ID( 0x0738, 0x4726 ), k_eControllerType_XBox360Controller, NULL }, // Mad Catz Xbox 360 Controller
{ MAKE_CONTROLLER_ID( 0x0738, 0x4728 ), k_eControllerType_XBox360Controller, NULL }, // Mad Catz Street Fighter IV FightPad
{ MAKE_CONTROLLER_ID( 0x0738, 0x4736 ), k_eControllerType_XBox360Controller, NULL }, // Mad Catz MicroCon Gamepad
{ MAKE_CONTROLLER_ID( 0x0738, 0x4738 ), k_eControllerType_XBox360Controller, NULL }, // Mad Catz Wired Xbox 360 Controller (SFIV)
{ MAKE_CONTROLLER_ID( 0x0738, 0x4740 ), k_eControllerType_XBox360Controller, NULL }, // Mad Catz Beat Pad
{ MAKE_CONTROLLER_ID( 0x0738, 0xb726 ), k_eControllerType_XBox360Controller, NULL }, // Mad Catz Xbox controller - MW2
{ MAKE_CONTROLLER_ID( 0x0738, 0xbeef ), k_eControllerType_XBox360Controller, NULL }, // Mad Catz JOYTECH NEO SE Advanced GamePad
{ MAKE_CONTROLLER_ID( 0x0738, 0xcb02 ), k_eControllerType_XBox360Controller, NULL }, // Saitek Cyborg Rumble Pad - PC/Xbox 360
{ MAKE_CONTROLLER_ID( 0x0738, 0xcb03 ), k_eControllerType_XBox360Controller, NULL }, // Saitek P3200 Rumble Pad - PC/Xbox 360
{ MAKE_CONTROLLER_ID( 0x0738, 0xf738 ), k_eControllerType_XBox360Controller, NULL }, // Super SFIV FightStick TE S
{ MAKE_CONTROLLER_ID( 0x0955, 0x7210 ), k_eControllerType_XBox360Controller, NULL }, // Nvidia Shield local controller
{ MAKE_CONTROLLER_ID( 0x0955, 0xb400 ), k_eControllerType_XBox360Controller, NULL }, // NVIDIA Shield streaming controller
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0105 ), k_eControllerType_XBox360Controller, NULL }, // HSM3 Xbox360 dancepad
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0113 ), k_eControllerType_XBox360Controller, "PDP Xbox 360 Afterglow" }, // PDP Afterglow Gamepad for Xbox 360
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x011f ), k_eControllerType_XBox360Controller, "PDP Xbox 360 Rock Candy" }, // PDP Rock Candy Gamepad for Xbox 360
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0125 ), k_eControllerType_XBox360Controller, "PDP INJUSTICE FightStick" }, // PDP INJUSTICE FightStick for Xbox 360
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0127 ), k_eControllerType_XBox360Controller, "PDP INJUSTICE FightPad" }, // PDP INJUSTICE FightPad for Xbox 360
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0131 ), k_eControllerType_XBox360Controller, "PDP EA Soccer Controller" }, // PDP EA Soccer Gamepad
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0133 ), k_eControllerType_XBox360Controller, "PDP Battlefield 4 Controller" }, // PDP Battlefield 4 Gamepad
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0143 ), k_eControllerType_XBox360Controller, "PDP MK X Fight Stick" }, // PDP MK X Fight Stick for Xbox 360
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0147 ), k_eControllerType_XBox360Controller, "PDP Xbox 360 Marvel Controller" }, // PDP Marvel Controller for Xbox 360
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0201 ), k_eControllerType_XBox360Controller, "PDP Xbox 360 Controller" }, // PDP Gamepad for Xbox 360
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0213 ), k_eControllerType_XBox360Controller, "PDP Xbox 360 Afterglow" }, // PDP Afterglow Gamepad for Xbox 360
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x021f ), k_eControllerType_XBox360Controller, "PDP Xbox 360 Rock Candy" }, // PDP Rock Candy Gamepad for Xbox 360
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0301 ), k_eControllerType_XBox360Controller, "PDP Xbox 360 Controller" }, // PDP Gamepad for Xbox 360
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0313 ), k_eControllerType_XBox360Controller, "PDP Xbox 360 Afterglow" }, // PDP Afterglow Gamepad for Xbox 360
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0314 ), k_eControllerType_XBox360Controller, "PDP Xbox 360 Afterglow" }, // PDP Afterglow Gamepad for Xbox 360
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0401 ), k_eControllerType_XBox360Controller, "PDP Xbox 360 Controller" }, // PDP Gamepad for Xbox 360
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0413 ), k_eControllerType_XBox360Controller, NULL }, // PDP Afterglow AX.1 (unlisted)
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0501 ), k_eControllerType_XBox360Controller, NULL }, // PDP Xbox 360 Controller (unlisted)
{ MAKE_CONTROLLER_ID( 0x0e6f, 0xf900 ), k_eControllerType_XBox360Controller, NULL }, // PDP Afterglow AX.1 (unlisted)
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x000a ), k_eControllerType_XBox360Controller, NULL }, // Hori Co. DOA4 FightStick
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x000c ), k_eControllerType_XBox360Controller, NULL }, // Hori PadEX Turbo
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x000d ), k_eControllerType_XBox360Controller, NULL }, // Hori Fighting Stick EX2
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x0016 ), k_eControllerType_XBox360Controller, NULL }, // Hori Real Arcade Pro.EX
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x001b ), k_eControllerType_XBox360Controller, NULL }, // Hori Real Arcade Pro VX
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x008c ), k_eControllerType_XBox360Controller, NULL }, // Hori Real Arcade Pro 4
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x00db ), k_eControllerType_XBox360Controller, "HORI Slime Controller" }, // Hori Dragon Quest Slime Controller
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x011e ), k_eControllerType_XBox360Controller, NULL }, // Hori Fighting Stick α
{ MAKE_CONTROLLER_ID( 0x1038, 0x1430 ), k_eControllerType_XBox360Controller, "SteelSeries Stratus Duo" }, // SteelSeries Stratus Duo
{ MAKE_CONTROLLER_ID( 0x1038, 0x1431 ), k_eControllerType_XBox360Controller, "SteelSeries Stratus Duo" }, // SteelSeries Stratus Duo
{ MAKE_CONTROLLER_ID( 0x1038, 0xb360 ), k_eControllerType_XBox360Controller, NULL }, // SteelSeries Nimbus/Stratus XL
{ MAKE_CONTROLLER_ID( 0x11c9, 0x55f0 ), k_eControllerType_XBox360Controller, NULL }, // Nacon GC-100XF
{ MAKE_CONTROLLER_ID( 0x12ab, 0x0004 ), k_eControllerType_XBox360Controller, NULL }, // Honey Bee Xbox360 dancepad
{ MAKE_CONTROLLER_ID( 0x12ab, 0x0301 ), k_eControllerType_XBox360Controller, NULL }, // PDP AFTERGLOW AX.1
{ MAKE_CONTROLLER_ID( 0x12ab, 0x0303 ), k_eControllerType_XBox360Controller, NULL }, // Mortal Kombat Klassic FightStick
{ MAKE_CONTROLLER_ID( 0x1430, 0x02a0 ), k_eControllerType_XBox360Controller, NULL }, // RedOctane Controller Adapter
{ MAKE_CONTROLLER_ID( 0x1430, 0x4748 ), k_eControllerType_XBox360Controller, NULL }, // RedOctane Guitar Hero X-plorer
{ MAKE_CONTROLLER_ID( 0x1430, 0xf801 ), k_eControllerType_XBox360Controller, NULL }, // RedOctane Controller
{ MAKE_CONTROLLER_ID( 0x146b, 0x0601 ), k_eControllerType_XBox360Controller, NULL }, // BigBen Interactive XBOX 360 Controller
// { MAKE_CONTROLLER_ID( 0x1532, 0x0037 ), k_eControllerType_XBox360Controller, NULL }, // Razer Sabertooth
{ MAKE_CONTROLLER_ID( 0x15e4, 0x3f00 ), k_eControllerType_XBox360Controller, NULL }, // Power A Mini Pro Elite
{ MAKE_CONTROLLER_ID( 0x15e4, 0x3f0a ), k_eControllerType_XBox360Controller, NULL }, // Xbox Airflo wired controller
{ MAKE_CONTROLLER_ID( 0x15e4, 0x3f10 ), k_eControllerType_XBox360Controller, NULL }, // Batarang Xbox 360 controller
{ MAKE_CONTROLLER_ID( 0x162e, 0xbeef ), k_eControllerType_XBox360Controller, NULL }, // Joytech Neo-Se Take2
{ MAKE_CONTROLLER_ID( 0x1689, 0xfd00 ), k_eControllerType_XBox360Controller, NULL }, // Razer Onza Tournament Edition
{ MAKE_CONTROLLER_ID( 0x1689, 0xfd01 ), k_eControllerType_XBox360Controller, NULL }, // Razer Onza Classic Edition
{ MAKE_CONTROLLER_ID( 0x1689, 0xfe00 ), k_eControllerType_XBox360Controller, NULL }, // Razer Sabertooth
{ MAKE_CONTROLLER_ID( 0x1949, 0x041a ), k_eControllerType_XBox360Controller, "Amazon Luna Controller" }, // Amazon Luna Controller
{ MAKE_CONTROLLER_ID( 0x1bad, 0x0002 ), k_eControllerType_XBox360Controller, NULL }, // Harmonix Rock Band Guitar
{ MAKE_CONTROLLER_ID( 0x1bad, 0x0003 ), k_eControllerType_XBox360Controller, NULL }, // Harmonix Rock Band Drumkit
{ MAKE_CONTROLLER_ID( 0x1bad, 0xf016 ), k_eControllerType_XBox360Controller, NULL }, // Mad Catz Xbox 360 Controller
{ MAKE_CONTROLLER_ID( 0x1bad, 0xf018 ), k_eControllerType_XBox360Controller, NULL }, // Mad Catz Street Fighter IV SE Fighting Stick
{ MAKE_CONTROLLER_ID( 0x1bad, 0xf019 ), k_eControllerType_XBox360Controller, NULL }, // Mad Catz Brawlstick for Xbox 360
{ MAKE_CONTROLLER_ID( 0x1bad, 0xf021 ), k_eControllerType_XBox360Controller, NULL }, // Mad Cats Ghost Recon FS GamePad
{ MAKE_CONTROLLER_ID( 0x1bad, 0xf023 ), k_eControllerType_XBox360Controller, NULL }, // MLG Pro Circuit Controller (Xbox)
{ MAKE_CONTROLLER_ID( 0x1bad, 0xf025 ), k_eControllerType_XBox360Controller, NULL }, // Mad Catz Call Of Duty
{ MAKE_CONTROLLER_ID( 0x1bad, 0xf027 ), k_eControllerType_XBox360Controller, NULL }, // Mad Catz FPS Pro
{ MAKE_CONTROLLER_ID( 0x1bad, 0xf028 ), k_eControllerType_XBox360Controller, NULL }, // Street Fighter IV FightPad
{ MAKE_CONTROLLER_ID( 0x1bad, 0xf02e ), k_eControllerType_XBox360Controller, NULL }, // Mad Catz Fightpad
{ MAKE_CONTROLLER_ID( 0x1bad, 0xf036 ), k_eControllerType_XBox360Controller, NULL }, // Mad Catz MicroCon GamePad Pro
{ MAKE_CONTROLLER_ID( 0x1bad, 0xf038 ), k_eControllerType_XBox360Controller, NULL }, // Street Fighter IV FightStick TE
{ MAKE_CONTROLLER_ID( 0x1bad, 0xf039 ), k_eControllerType_XBox360Controller, NULL }, // Mad Catz MvC2 TE
{ MAKE_CONTROLLER_ID( 0x1bad, 0xf03a ), k_eControllerType_XBox360Controller, NULL }, // Mad Catz SFxT Fightstick Pro
{ MAKE_CONTROLLER_ID( 0x1bad, 0xf03d ), k_eControllerType_XBox360Controller, NULL }, // Street Fighter IV Arcade Stick TE - Chun Li
{ MAKE_CONTROLLER_ID( 0x1bad, 0xf03e ), k_eControllerType_XBox360Controller, NULL }, // Mad Catz MLG FightStick TE
{ MAKE_CONTROLLER_ID( 0x1bad, 0xf03f ), k_eControllerType_XBox360Controller, NULL }, // Mad Catz FightStick SoulCaliber
{ MAKE_CONTROLLER_ID( 0x1bad, 0xf042 ), k_eControllerType_XBox360Controller, NULL }, // Mad Catz FightStick TES+
{ MAKE_CONTROLLER_ID( 0x1bad, 0xf080 ), k_eControllerType_XBox360Controller, NULL }, // Mad Catz FightStick TE2
{ MAKE_CONTROLLER_ID( 0x1bad, 0xf501 ), k_eControllerType_XBox360Controller, NULL }, // HoriPad EX2 Turbo
{ MAKE_CONTROLLER_ID( 0x1bad, 0xf502 ), k_eControllerType_XBox360Controller, NULL }, // Hori Real Arcade Pro.VX SA
{ MAKE_CONTROLLER_ID( 0x1bad, 0xf503 ), k_eControllerType_XBox360Controller, NULL }, // Hori Fighting Stick VX
{ MAKE_CONTROLLER_ID( 0x1bad, 0xf504 ), k_eControllerType_XBox360Controller, NULL }, // Hori Real Arcade Pro. EX
{ MAKE_CONTROLLER_ID( 0x1bad, 0xf505 ), k_eControllerType_XBox360Controller, NULL }, // Hori Fighting Stick EX2B
{ MAKE_CONTROLLER_ID( 0x1bad, 0xf506 ), k_eControllerType_XBox360Controller, NULL }, // Hori Real Arcade Pro.EX Premium VLX
{ MAKE_CONTROLLER_ID( 0x1bad, 0xf900 ), k_eControllerType_XBox360Controller, NULL }, // Harmonix Xbox 360 Controller
{ MAKE_CONTROLLER_ID( 0x1bad, 0xf901 ), k_eControllerType_XBox360Controller, NULL }, // Gamestop Xbox 360 Controller
{ MAKE_CONTROLLER_ID( 0x1bad, 0xf902 ), k_eControllerType_XBox360Controller, NULL }, // Mad Catz Gamepad2
{ MAKE_CONTROLLER_ID( 0x1bad, 0xf903 ), k_eControllerType_XBox360Controller, NULL }, // Tron Xbox 360 controller
{ MAKE_CONTROLLER_ID( 0x1bad, 0xf904 ), k_eControllerType_XBox360Controller, NULL }, // PDP Versus Fighting Pad
{ MAKE_CONTROLLER_ID( 0x1bad, 0xf906 ), k_eControllerType_XBox360Controller, NULL }, // MortalKombat FightStick
{ MAKE_CONTROLLER_ID( 0x1bad, 0xfa01 ), k_eControllerType_XBox360Controller, NULL }, // MadCatz GamePad
{ MAKE_CONTROLLER_ID( 0x1bad, 0xfd00 ), k_eControllerType_XBox360Controller, NULL }, // Razer Onza TE
{ MAKE_CONTROLLER_ID( 0x1bad, 0xfd01 ), k_eControllerType_XBox360Controller, NULL }, // Razer Onza
{ MAKE_CONTROLLER_ID( 0x24c6, 0x5000 ), k_eControllerType_XBox360Controller, NULL }, // Razer Atrox Arcade Stick
{ MAKE_CONTROLLER_ID( 0x24c6, 0x5300 ), k_eControllerType_XBox360Controller, NULL }, // PowerA MINI PROEX Controller
{ MAKE_CONTROLLER_ID( 0x24c6, 0x5303 ), k_eControllerType_XBox360Controller, NULL }, // Xbox Airflo wired controller
{ MAKE_CONTROLLER_ID( 0x24c6, 0x530a ), k_eControllerType_XBox360Controller, NULL }, // Xbox 360 Pro EX Controller
{ MAKE_CONTROLLER_ID( 0x24c6, 0x531a ), k_eControllerType_XBox360Controller, NULL }, // PowerA Pro Ex
{ MAKE_CONTROLLER_ID( 0x24c6, 0x5397 ), k_eControllerType_XBox360Controller, NULL }, // FUS1ON Tournament Controller
{ MAKE_CONTROLLER_ID( 0x24c6, 0x5500 ), k_eControllerType_XBox360Controller, NULL }, // Hori XBOX 360 EX 2 with Turbo
{ MAKE_CONTROLLER_ID( 0x24c6, 0x5501 ), k_eControllerType_XBox360Controller, NULL }, // Hori Real Arcade Pro VX-SA
{ MAKE_CONTROLLER_ID( 0x24c6, 0x5502 ), k_eControllerType_XBox360Controller, NULL }, // Hori Fighting Stick VX Alt
{ MAKE_CONTROLLER_ID( 0x24c6, 0x5503 ), k_eControllerType_XBox360Controller, NULL }, // Hori Fighting Edge
{ MAKE_CONTROLLER_ID( 0x24c6, 0x5506 ), k_eControllerType_XBox360Controller, NULL }, // Hori SOULCALIBUR V Stick
{ MAKE_CONTROLLER_ID( 0x24c6, 0x550d ), k_eControllerType_XBox360Controller, NULL }, // Hori GEM Xbox controller
{ MAKE_CONTROLLER_ID( 0x24c6, 0x550e ), k_eControllerType_XBox360Controller, NULL }, // Hori Real Arcade Pro V Kai 360
{ MAKE_CONTROLLER_ID( 0x24c6, 0x5508 ), k_eControllerType_XBox360Controller, NULL }, // Hori PAD A
{ MAKE_CONTROLLER_ID( 0x24c6, 0x5510 ), k_eControllerType_XBox360Controller, NULL }, // Hori Fighting Commander ONE
{ MAKE_CONTROLLER_ID( 0x24c6, 0x5b00 ), k_eControllerType_XBox360Controller, NULL }, // ThrustMaster Ferrari Italia 458 Racing Wheel
{ MAKE_CONTROLLER_ID( 0x24c6, 0x5b02 ), k_eControllerType_XBox360Controller, NULL }, // Thrustmaster, Inc. GPX Controller
{ MAKE_CONTROLLER_ID( 0x24c6, 0x5b03 ), k_eControllerType_XBox360Controller, NULL }, // Thrustmaster Ferrari 458 Racing Wheel
{ MAKE_CONTROLLER_ID( 0x24c6, 0x5d04 ), k_eControllerType_XBox360Controller, NULL }, // Razer Sabertooth
{ MAKE_CONTROLLER_ID( 0x24c6, 0xfafa ), k_eControllerType_XBox360Controller, NULL }, // Aplay Controller
{ MAKE_CONTROLLER_ID( 0x24c6, 0xfafb ), k_eControllerType_XBox360Controller, NULL }, // Aplay Controller
{ MAKE_CONTROLLER_ID( 0x24c6, 0xfafc ), k_eControllerType_XBox360Controller, NULL }, // Afterglow Gamepad 1
{ MAKE_CONTROLLER_ID( 0x24c6, 0xfafd ), k_eControllerType_XBox360Controller, NULL }, // Afterglow Gamepad 3
{ MAKE_CONTROLLER_ID( 0x24c6, 0xfafe ), k_eControllerType_XBox360Controller, NULL }, // Rock Candy Gamepad for Xbox 360
{ MAKE_CONTROLLER_ID( 0x044f, 0xd012 ), k_eControllerType_XBoxOneController, NULL }, // ThrustMaster eSwap PRO Controller Xbox
{ MAKE_CONTROLLER_ID( 0x045e, 0x02d1 ), k_eControllerType_XBoxOneController, "Xbox One Controller" }, // Microsoft X-Box One pad
{ MAKE_CONTROLLER_ID( 0x045e, 0x02dd ), k_eControllerType_XBoxOneController, "Xbox One Controller" }, // Microsoft X-Box One pad (Firmware 2015)
{ MAKE_CONTROLLER_ID( 0x045e, 0x02e0 ), k_eControllerType_XBoxOneController, "Xbox One S Controller" }, // Microsoft X-Box One S pad (Bluetooth)
{ MAKE_CONTROLLER_ID( 0x045e, 0x02e3 ), k_eControllerType_XBoxOneController, "Xbox One Elite Controller" }, // Microsoft X-Box One Elite pad
{ MAKE_CONTROLLER_ID( 0x045e, 0x02ea ), k_eControllerType_XBoxOneController, "Xbox One S Controller" }, // Microsoft X-Box One S pad
{ MAKE_CONTROLLER_ID( 0x045e, 0x02fd ), k_eControllerType_XBoxOneController, "Xbox One S Controller" }, // Microsoft X-Box One S pad (Bluetooth)
{ MAKE_CONTROLLER_ID( 0x045e, 0x02ff ), k_eControllerType_XBoxOneController, NULL }, // Microsoft X-Box One controller with XBOXGIP driver on Windows
{ MAKE_CONTROLLER_ID( 0x045e, 0x0b00 ), k_eControllerType_XBoxOneController, "Xbox One Elite 2 Controller" }, // Microsoft X-Box One Elite Series 2 pad
// { MAKE_CONTROLLER_ID( 0x045e, 0x0b02 ), k_eControllerType_XBoxOneController, "Xbox One Elite 2 Controller" }, // The virtual keyboard generated by XboxGip drivers for Xbox One Controllers (see https://github.com/libsdl-org/SDL/pull/5121 for details)
{ MAKE_CONTROLLER_ID( 0x045e, 0x0b05 ), k_eControllerType_XBoxOneController, "Xbox One Elite 2 Controller" }, // Microsoft X-Box One Elite Series 2 pad (Bluetooth)
{ MAKE_CONTROLLER_ID( 0x045e, 0x0b0a ), k_eControllerType_XBoxOneController, "Xbox Adaptive Controller" }, // Microsoft X-Box Adaptive pad
{ MAKE_CONTROLLER_ID( 0x045e, 0x0b0c ), k_eControllerType_XBoxOneController, "Xbox Adaptive Controller" }, // Microsoft X-Box Adaptive pad (Bluetooth)
{ MAKE_CONTROLLER_ID( 0x045e, 0x0b12 ), k_eControllerType_XBoxOneController, "Xbox Series X Controller" }, // Microsoft X-Box Series X pad
{ MAKE_CONTROLLER_ID( 0x045e, 0x0b13 ), k_eControllerType_XBoxOneController, "Xbox Series X Controller" }, // Microsoft X-Box Series X pad (BLE)
{ MAKE_CONTROLLER_ID( 0x045e, 0x0b20 ), k_eControllerType_XBoxOneController, "Xbox One S Controller" }, // Microsoft X-Box One S pad (BLE)
{ MAKE_CONTROLLER_ID( 0x045e, 0x0b21 ), k_eControllerType_XBoxOneController, "Xbox Adaptive Controller" }, // Microsoft X-Box Adaptive pad (BLE)
{ MAKE_CONTROLLER_ID( 0x045e, 0x0b22 ), k_eControllerType_XBoxOneController, "Xbox One Elite 2 Controller" }, // Microsoft X-Box One Elite Series 2 pad (BLE)
{ MAKE_CONTROLLER_ID( 0x0738, 0x4a01 ), k_eControllerType_XBoxOneController, NULL }, // Mad Catz FightStick TE 2
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0139 ), k_eControllerType_XBoxOneController, "PDP Xbox One Afterglow" }, // PDP Afterglow Wired Controller for Xbox One
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x013B ), k_eControllerType_XBoxOneController, "PDP Xbox One Face-Off Controller" }, // PDP Face-Off Gamepad for Xbox One
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x013a ), k_eControllerType_XBoxOneController, NULL }, // PDP Xbox One Controller (unlisted)
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0145 ), k_eControllerType_XBoxOneController, "PDP MK X Fight Pad" }, // PDP MK X Fight Pad for Xbox One
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0146 ), k_eControllerType_XBoxOneController, "PDP Xbox One Rock Candy" }, // PDP Rock Candy Wired Controller for Xbox One
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x015b ), k_eControllerType_XBoxOneController, "PDP Fallout 4 Vault Boy Controller" }, // PDP Fallout 4 Vault Boy Wired Controller for Xbox One
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x015c ), k_eControllerType_XBoxOneController, "PDP Xbox One @Play Controller" }, // PDP @Play Wired Controller for Xbox One
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x015d ), k_eControllerType_XBoxOneController, "PDP Mirror's Edge Controller" }, // PDP Mirror's Edge Wired Controller for Xbox One
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x015f ), k_eControllerType_XBoxOneController, "PDP Metallic Controller" }, // PDP Metallic Wired Controller for Xbox One
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0160 ), k_eControllerType_XBoxOneController, "PDP NFL Face-Off Controller" }, // PDP NFL Official Face-Off Wired Controller for Xbox One
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0161 ), k_eControllerType_XBoxOneController, "PDP Xbox One Camo" }, // PDP Camo Wired Controller for Xbox One
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0162 ), k_eControllerType_XBoxOneController, "PDP Xbox One Controller" }, // PDP Wired Controller for Xbox One
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0163 ), k_eControllerType_XBoxOneController, "PDP Deliverer of Truth" }, // PDP Legendary Collection: Deliverer of Truth
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0164 ), k_eControllerType_XBoxOneController, "PDP Battlefield 1 Controller" }, // PDP Battlefield 1 Official Wired Controller for Xbox One
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0165 ), k_eControllerType_XBoxOneController, "PDP Titanfall 2 Controller" }, // PDP Titanfall 2 Official Wired Controller for Xbox One
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0166 ), k_eControllerType_XBoxOneController, "PDP Mass Effect: Andromeda Controller" }, // PDP Mass Effect: Andromeda Official Wired Controller for Xbox One
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0167 ), k_eControllerType_XBoxOneController, "PDP Halo Wars 2 Face-Off Controller" }, // PDP Halo Wars 2 Official Face-Off Wired Controller for Xbox One
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0205 ), k_eControllerType_XBoxOneController, "PDP Victrix Pro Fight Stick" }, // PDP Victrix Pro Fight Stick
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0206 ), k_eControllerType_XBoxOneController, "PDP Mortal Kombat Controller" }, // PDP Mortal Kombat 25 Anniversary Edition Stick (Xbox One)
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0246 ), k_eControllerType_XBoxOneController, "PDP Xbox One Rock Candy" }, // PDP Rock Candy Wired Controller for Xbox One
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0261 ), k_eControllerType_XBoxOneController, "PDP Xbox One Camo" }, // PDP Camo Wired Controller
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0262 ), k_eControllerType_XBoxOneController, "PDP Xbox One Controller" }, // PDP Wired Controller
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02a0 ), k_eControllerType_XBoxOneController, "PDP Xbox One Midnight Blue" }, // PDP Wired Controller for Xbox One - Midnight Blue
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02a1 ), k_eControllerType_XBoxOneController, "PDP Xbox One Verdant Green" }, // PDP Wired Controller for Xbox One - Verdant Green
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02a2 ), k_eControllerType_XBoxOneController, "PDP Xbox One Crimson Red" }, // PDP Wired Controller for Xbox One - Crimson Red
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02a3 ), k_eControllerType_XBoxOneController, "PDP Xbox One Arctic White" }, // PDP Wired Controller for Xbox One - Arctic White
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02a4 ), k_eControllerType_XBoxOneController, "PDP Xbox One Phantom Black" }, // PDP Wired Controller for Xbox One - Stealth Series | Phantom Black
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02a5 ), k_eControllerType_XBoxOneController, "PDP Xbox One Ghost White" }, // PDP Wired Controller for Xbox One - Stealth Series | Ghost White
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02a6 ), k_eControllerType_XBoxOneController, "PDP Xbox One Revenant Blue" }, // PDP Wired Controller for Xbox One - Stealth Series | Revenant Blue
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02a7 ), k_eControllerType_XBoxOneController, "PDP Xbox One Raven Black" }, // PDP Wired Controller for Xbox One - Raven Black
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02a8 ), k_eControllerType_XBoxOneController, "PDP Xbox One Arctic White" }, // PDP Wired Controller for Xbox One - Arctic White
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02a9 ), k_eControllerType_XBoxOneController, "PDP Xbox One Midnight Blue" }, // PDP Wired Controller for Xbox One - Midnight Blue
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02aa ), k_eControllerType_XBoxOneController, "PDP Xbox One Verdant Green" }, // PDP Wired Controller for Xbox One - Verdant Green
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02ab ), k_eControllerType_XBoxOneController, "PDP Xbox One Crimson Red" }, // PDP Wired Controller for Xbox One - Crimson Red
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02ac ), k_eControllerType_XBoxOneController, "PDP Xbox One Ember Orange" }, // PDP Wired Controller for Xbox One - Ember Orange
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02ad ), k_eControllerType_XBoxOneController, "PDP Xbox One Phantom Black" }, // PDP Wired Controller for Xbox One - Stealth Series | Phantom Black
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02ae ), k_eControllerType_XBoxOneController, "PDP Xbox One Ghost White" }, // PDP Wired Controller for Xbox One - Stealth Series | Ghost White
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02af ), k_eControllerType_XBoxOneController, "PDP Xbox One Revenant Blue" }, // PDP Wired Controller for Xbox One - Stealth Series | Revenant Blue
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02b0 ), k_eControllerType_XBoxOneController, "PDP Xbox One Raven Black" }, // PDP Wired Controller for Xbox One - Raven Black
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02b1 ), k_eControllerType_XBoxOneController, "PDP Xbox One Arctic White" }, // PDP Wired Controller for Xbox One - Arctic White
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02b3 ), k_eControllerType_XBoxOneController, "PDP Xbox One Afterglow" }, // PDP Afterglow Prismatic Wired Controller
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02b5 ), k_eControllerType_XBoxOneController, "PDP Xbox One GAMEware Controller" }, // PDP GAMEware Wired Controller Xbox One
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02b6 ), k_eControllerType_XBoxOneController, NULL }, // PDP One-Handed Joystick Adaptive Controller
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02bd ), k_eControllerType_XBoxOneController, "PDP Xbox One Royal Purple" }, // PDP Wired Controller for Xbox One - Royal Purple
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02be ), k_eControllerType_XBoxOneController, "PDP Xbox One Raven Black" }, // PDP Deluxe Wired Controller for Xbox One - Raven Black
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02bf ), k_eControllerType_XBoxOneController, "PDP Xbox One Midnight Blue" }, // PDP Deluxe Wired Controller for Xbox One - Midnight Blue
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02c0 ), k_eControllerType_XBoxOneController, "PDP Xbox One Phantom Black" }, // PDP Deluxe Wired Controller for Xbox One - Stealth Series | Phantom Black
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02c1 ), k_eControllerType_XBoxOneController, "PDP Xbox One Ghost White" }, // PDP Deluxe Wired Controller for Xbox One - Stealth Series | Ghost White
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02c2 ), k_eControllerType_XBoxOneController, "PDP Xbox One Revenant Blue" }, // PDP Deluxe Wired Controller for Xbox One - Stealth Series | Revenant Blue
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02c3 ), k_eControllerType_XBoxOneController, "PDP Xbox One Verdant Green" }, // PDP Deluxe Wired Controller for Xbox One - Verdant Green
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02c4 ), k_eControllerType_XBoxOneController, "PDP Xbox One Ember Orange" }, // PDP Deluxe Wired Controller for Xbox One - Ember Orange
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02c5 ), k_eControllerType_XBoxOneController, "PDP Xbox One Royal Purple" }, // PDP Deluxe Wired Controller for Xbox One - Royal Purple
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02c6 ), k_eControllerType_XBoxOneController, "PDP Xbox One Crimson Red" }, // PDP Deluxe Wired Controller for Xbox One - Crimson Red
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02c7 ), k_eControllerType_XBoxOneController, "PDP Xbox One Arctic White" }, // PDP Deluxe Wired Controller for Xbox One - Arctic White
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02c8 ), k_eControllerType_XBoxOneController, "PDP Kingdom Hearts Controller" }, // PDP Kingdom Hearts Wired Controller
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02c9 ), k_eControllerType_XBoxOneController, "PDP Xbox One Phantasm Red" }, // PDP Deluxe Wired Controller for Xbox One - Stealth Series | Phantasm Red
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02ca ), k_eControllerType_XBoxOneController, "PDP Xbox One Specter Violet" }, // PDP Deluxe Wired Controller for Xbox One - Stealth Series | Specter Violet
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02cb ), k_eControllerType_XBoxOneController, "PDP Xbox One Specter Violet" }, // PDP Wired Controller for Xbox One - Stealth Series | Specter Violet
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02cd ), k_eControllerType_XBoxOneController, "PDP Xbox One Blu-merang" }, // PDP Rock Candy Wired Controller for Xbox One - Blu-merang
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02ce ), k_eControllerType_XBoxOneController, "PDP Xbox One Cranblast" }, // PDP Rock Candy Wired Controller for Xbox One - Cranblast
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02cf ), k_eControllerType_XBoxOneController, "PDP Xbox One Aqualime" }, // PDP Rock Candy Wired Controller for Xbox One - Aqualime
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02d5 ), k_eControllerType_XBoxOneController, "PDP Xbox One Red Camo" }, // PDP Wired Controller for Xbox One - Red Camo
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0346 ), k_eControllerType_XBoxOneController, "PDP Xbox One RC Gamepad" }, // PDP RC Gamepad for Xbox One
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0446 ), k_eControllerType_XBoxOneController, "PDP Xbox One RC Gamepad" }, // PDP RC Gamepad for Xbox One
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02da ), k_eControllerType_XBoxOneController, "PDP Xbox Series X Afterglow" }, // PDP Xbox Series X Afterglow
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02d6 ), k_eControllerType_XBoxOneController, "Victrix Gambit Tournament Controller" }, // Victrix Gambit Tournament Controller
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02d9 ), k_eControllerType_XBoxOneController, "PDP Xbox Series X Midnight Blue" }, // PDP Xbox Series X Midnight Blue
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x0063 ), k_eControllerType_XBoxOneController, NULL }, // Hori Real Arcade Pro Hayabusa (USA) Xbox One
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x0067 ), k_eControllerType_XBoxOneController, NULL }, // HORIPAD ONE
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x0078 ), k_eControllerType_XBoxOneController, NULL }, // Hori Real Arcade Pro V Kai Xbox One
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x00c5 ), k_eControllerType_XBoxOneController, NULL }, // HORI Fighting Commander
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x0150 ), k_eControllerType_XBoxOneController, NULL }, // HORI Fighting Commander OCTA for Xbox Series X
{ MAKE_CONTROLLER_ID( 0x10f5, 0x7009 ), k_eControllerType_XBoxOneController, NULL }, // Turtle Beach Recon Controller
{ MAKE_CONTROLLER_ID( 0x10f5, 0x7013 ), k_eControllerType_XBoxOneController, NULL }, // Turtle Beach REACT-R
{ MAKE_CONTROLLER_ID( 0x1532, 0x0a00 ), k_eControllerType_XBoxOneController, NULL }, // Razer Atrox Arcade Stick
{ MAKE_CONTROLLER_ID( 0x1532, 0x0a03 ), k_eControllerType_XBoxOneController, NULL }, // Razer Wildcat
{ MAKE_CONTROLLER_ID( 0x1532, 0x0a14 ), k_eControllerType_XBoxOneController, NULL }, // Razer Wolverine Ultimate
{ MAKE_CONTROLLER_ID( 0x1532, 0x0a15 ), k_eControllerType_XBoxOneController, NULL }, // Razer Wolverine Tournament Edition
{ MAKE_CONTROLLER_ID( 0x20d6, 0x2001 ), k_eControllerType_XBoxOneController, "PowerA Xbox Series X Controller" }, // PowerA Xbox Series X EnWired Controller - Black Inline
{ MAKE_CONTROLLER_ID( 0x20d6, 0x2002 ), k_eControllerType_XBoxOneController, "PowerA Xbox Series X Controller" }, // PowerA Xbox Series X EnWired Controller Gray/White Inline
{ MAKE_CONTROLLER_ID( 0x20d6, 0x2003 ), k_eControllerType_XBoxOneController, "PowerA Xbox Series X Controller" }, // PowerA Xbox Series X EnWired Controller Green Inline
{ MAKE_CONTROLLER_ID( 0x20d6, 0x2004 ), k_eControllerType_XBoxOneController, "PowerA Xbox Series X Controller" }, // PowerA Xbox Series X EnWired Controller Pink inline
{ MAKE_CONTROLLER_ID( 0x20d6, 0x2005 ), k_eControllerType_XBoxOneController, "PowerA Xbox Series X Controller" }, // PowerA Xbox Series X Wired Controller Core - Black
{ MAKE_CONTROLLER_ID( 0x20d6, 0x2006 ), k_eControllerType_XBoxOneController, "PowerA Xbox Series X Controller" }, // PowerA Xbox Series X Wired Controller Core - White
{ MAKE_CONTROLLER_ID( 0x20d6, 0x2009 ), k_eControllerType_XBoxOneController, "PowerA Xbox Series X Controller" }, // PowerA Xbox Series X EnWired Controller Red inline
{ MAKE_CONTROLLER_ID( 0x20d6, 0x200a ), k_eControllerType_XBoxOneController, "PowerA Xbox Series X Controller" }, // PowerA Xbox Series X EnWired Controller Blue inline
{ MAKE_CONTROLLER_ID( 0x20d6, 0x200b ), k_eControllerType_XBoxOneController, "PowerA Xbox Series X Controller" }, // PowerA Xbox Series X EnWired Controller Camo Metallic Red
{ MAKE_CONTROLLER_ID( 0x20d6, 0x200c ), k_eControllerType_XBoxOneController, "PowerA Xbox Series X Controller" }, // PowerA Xbox Series X EnWired Controller Camo Metallic Blue
{ MAKE_CONTROLLER_ID( 0x20d6, 0x200d ), k_eControllerType_XBoxOneController, "PowerA Xbox Series X Controller" }, // PowerA Xbox Series X EnWired Controller Seafoam Fade
{ MAKE_CONTROLLER_ID( 0x20d6, 0x200e ), k_eControllerType_XBoxOneController, "PowerA Xbox Series X Controller" }, // PowerA Xbox Series X EnWired Controller Midnight Blue
{ MAKE_CONTROLLER_ID( 0x20d6, 0x200f ), k_eControllerType_XBoxOneController, "PowerA Xbox Series X Controller" }, // PowerA Xbox Series X EnWired Soldier Green
{ MAKE_CONTROLLER_ID( 0x20d6, 0x2011 ), k_eControllerType_XBoxOneController, "PowerA Xbox Series X Controller" }, // PowerA Xbox Series X EnWired - Metallic Ice
{ MAKE_CONTROLLER_ID( 0x20d6, 0x2012 ), k_eControllerType_XBoxOneController, "PowerA Xbox Series X Controller" }, // PowerA Xbox Series X Cuphead EnWired Controller - Mugman
{ MAKE_CONTROLLER_ID( 0x20d6, 0x2015 ), k_eControllerType_XBoxOneController, "PowerA Xbox Series X Controller" }, // PowerA Xbox Series X EnWired Controller - Blue Hint
{ MAKE_CONTROLLER_ID( 0x20d6, 0x2016 ), k_eControllerType_XBoxOneController, "PowerA Xbox Series X Controller" }, // PowerA Xbox Series X EnWired Controller - Green Hint
{ MAKE_CONTROLLER_ID( 0x20d6, 0x2017 ), k_eControllerType_XBoxOneController, "PowerA Xbox Series X Controller" }, // PowerA Xbox Series X EnWired Cntroller - Arctic Camo
{ MAKE_CONTROLLER_ID( 0x20d6, 0x2018 ), k_eControllerType_XBoxOneController, "PowerA Xbox Series X Controller" }, // PowerA Xbox Series X EnWired Controller Arc Lightning
{ MAKE_CONTROLLER_ID( 0x20d6, 0x2019 ), k_eControllerType_XBoxOneController, "PowerA Xbox Series X Controller" }, // PowerA Xbox Series X EnWired Controller Royal Purple
{ MAKE_CONTROLLER_ID( 0x20d6, 0x201a ), k_eControllerType_XBoxOneController, "PowerA Xbox Series X Controller" }, // PowerA Xbox Series X EnWired Controller Nebula
{ MAKE_CONTROLLER_ID( 0x20d6, 0x4001 ), k_eControllerType_XBoxOneController, "PowerA Fusion Pro 2 Controller" }, // PowerA Fusion Pro 2 Wired Controller (Xbox Series X style)
{ MAKE_CONTROLLER_ID( 0x20d6, 0x4002 ), k_eControllerType_XBoxOneController, "PowerA Spectra Infinity Controller" }, // PowerA Spectra Infinity Wired Controller (Xbox Series X style)
{ MAKE_CONTROLLER_ID( 0x20d6, 0x890b ), k_eControllerType_XBoxOneController, NULL }, // PowerA MOGA XP-Ultra Controller (Xbox Series X style)
{ MAKE_CONTROLLER_ID( 0x24c6, 0x541a ), k_eControllerType_XBoxOneController, NULL }, // PowerA Xbox One Mini Wired Controller
{ MAKE_CONTROLLER_ID( 0x24c6, 0x542a ), k_eControllerType_XBoxOneController, NULL }, // Xbox ONE spectra
{ MAKE_CONTROLLER_ID( 0x24c6, 0x543a ), k_eControllerType_XBoxOneController, "PowerA Xbox One Controller" }, // PowerA Xbox ONE liquid metal controller
{ MAKE_CONTROLLER_ID( 0x24c6, 0x551a ), k_eControllerType_XBoxOneController, NULL }, // PowerA FUSION Pro Controller
{ MAKE_CONTROLLER_ID( 0x24c6, 0x561a ), k_eControllerType_XBoxOneController, NULL }, // PowerA FUSION Controller
{ MAKE_CONTROLLER_ID( 0x24c6, 0x581a ), k_eControllerType_XBoxOneController, NULL }, // BDA XB1 Classic Controller
{ MAKE_CONTROLLER_ID( 0x24c6, 0x591a ), k_eControllerType_XBoxOneController, NULL }, // PowerA FUSION Pro Controller
{ MAKE_CONTROLLER_ID( 0x24c6, 0x592a ), k_eControllerType_XBoxOneController, NULL }, // BDA XB1 Spectra Pro
{ MAKE_CONTROLLER_ID( 0x24c6, 0x791a ), k_eControllerType_XBoxOneController, NULL }, // PowerA Fusion Fight Pad
{ MAKE_CONTROLLER_ID( 0x2dc8, 0x2002 ), k_eControllerType_XBoxOneController, NULL }, // 8BitDo Ultimate Wired Controller for Xbox
{ MAKE_CONTROLLER_ID( 0x2e24, 0x0652 ), k_eControllerType_XBoxOneController, NULL }, // Hyperkin Duke
{ MAKE_CONTROLLER_ID( 0x2e24, 0x1618 ), k_eControllerType_XBoxOneController, NULL }, // Hyperkin Duke
{ MAKE_CONTROLLER_ID( 0x2e24, 0x1688 ), k_eControllerType_XBoxOneController, NULL }, // Hyperkin X91
{ MAKE_CONTROLLER_ID( 0x146b, 0x0611 ), k_eControllerType_XBoxOneController, NULL }, // Xbox Controller Mode for NACON Revolution 3
// These have been added via Minidump for unrecognized Xinput controller assert
{ MAKE_CONTROLLER_ID( 0x0000, 0x0000 ), k_eControllerType_XBox360Controller, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0x045e, 0x02a2 ), k_eControllerType_XBox360Controller, NULL }, // Unknown Controller - Microsoft VID
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x1414 ), k_eControllerType_XBox360Controller, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0159 ), k_eControllerType_XBox360Controller, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0x24c6, 0xfaff ), k_eControllerType_XBox360Controller, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x006d ), k_eControllerType_XBox360Controller, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x00a4 ), k_eControllerType_XBox360Controller, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0x0079, 0x1832 ), k_eControllerType_XBox360Controller, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0x0079, 0x187f ), k_eControllerType_XBox360Controller, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0x0079, 0x1883 ), k_eControllerType_XBox360Controller, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0x03eb, 0xff01 ), k_eControllerType_XBox360Controller, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0x0c12, 0x0ef8 ), k_eControllerType_XBox360Controller, NULL }, // Homemade fightstick based on brook pcb (with XInput driver??)
{ MAKE_CONTROLLER_ID( 0x046d, 0x1000 ), k_eControllerType_XBox360Controller, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0x1345, 0x6006 ), k_eControllerType_XBox360Controller, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0x056e, 0x2012 ), k_eControllerType_XBox360Controller, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0x146b, 0x0602 ), k_eControllerType_XBox360Controller, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x00ae ), k_eControllerType_XBox360Controller, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0x046d, 0x0401 ), k_eControllerType_XBox360Controller, NULL }, // logitech xinput
{ MAKE_CONTROLLER_ID( 0x046d, 0x0301 ), k_eControllerType_XBox360Controller, NULL }, // logitech xinput
{ MAKE_CONTROLLER_ID( 0x046d, 0xcaa3 ), k_eControllerType_XBox360Controller, NULL }, // logitech xinput
{ MAKE_CONTROLLER_ID( 0x046d, 0xc261 ), k_eControllerType_XBox360Controller, NULL }, // logitech xinput
{ MAKE_CONTROLLER_ID( 0x046d, 0x0291 ), k_eControllerType_XBox360Controller, NULL }, // logitech xinput
{ MAKE_CONTROLLER_ID( 0x0079, 0x18d3 ), k_eControllerType_XBox360Controller, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x00b1 ), k_eControllerType_XBox360Controller, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0x0001, 0x0001 ), k_eControllerType_XBox360Controller, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0x0079, 0x188e ), k_eControllerType_XBox360Controller, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0x0079, 0x187c ), k_eControllerType_XBox360Controller, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0x0079, 0x189c ), k_eControllerType_XBox360Controller, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0x0079, 0x1874 ), k_eControllerType_XBox360Controller, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0x2f24, 0x0050 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0x2f24, 0x2e ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0x2f24, 0x91 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0x1430, 0x719 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0xf0d, 0xed ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0xf0d, 0xc0 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0xe6f, 0x152 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0xe6f, 0x2a7 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0x46d, 0x1007 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0xe6f, 0x2b8 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0xe6f, 0x2a8 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0x79, 0x18a1 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
/* Added from Minidumps 10-9-19 */
{ MAKE_CONTROLLER_ID( 0x0, 0x6686 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0x11ff, 0x511 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0x12ab, 0x304 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0x1430, 0x291 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0x1430, 0x2a9 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0x1430, 0x70b ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0x1bad, 0x28e ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0x1bad, 0x2a0 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0x1bad, 0x5500 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0x20ab, 0x55ef ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0x24c6, 0x5509 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0x2516, 0x69 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0x25b1, 0x360 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0x2c22, 0x2203 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0x2f24, 0x11 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0x2f24, 0x53 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0x2f24, 0xb7 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0x46d, 0x0 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0x46d, 0x1004 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0x46d, 0x1008 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0x46d, 0xf301 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0x738, 0x2a0 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0x738, 0x7263 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0x738, 0xb738 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0x738, 0xcb29 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0x738, 0xf401 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0x79, 0x18c2 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0x79, 0x18c8 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0x79, 0x18cf ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0xc12, 0xe17 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0xc12, 0xe1c ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0xc12, 0xe22 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0xc12, 0xe30 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0xd2d2, 0xd2d2 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0xd62, 0x9a1a ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0xd62, 0x9a1b ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0xe00, 0xe00 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0xe6f, 0x12a ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0xe6f, 0x2a1 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0xe6f, 0x2a2 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0xe6f, 0x2a5 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0xe6f, 0x2b2 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0xe6f, 0x2bd ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0xe6f, 0x2bf ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0xe6f, 0x2c0 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0xe6f, 0x2c6 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0xf0d, 0x97 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0xf0d, 0xba ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0xf0d, 0xd8 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0xfff, 0x2a1 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0x45e, 0x867 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
// Added 12-17-2020
{ MAKE_CONTROLLER_ID( 0x16d0, 0xf3f ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0x2f24, 0x8f ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0xe6f, 0xf501 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
//{ MAKE_CONTROLLER_ID( 0x1949, 0x0402 ), /*android*/, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0x05ac, 0x0001 ), k_eControllerType_AppleController, NULL }, // MFI Extended Gamepad (generic entry for iOS/tvOS)
{ MAKE_CONTROLLER_ID( 0x05ac, 0x0002 ), k_eControllerType_AppleController, NULL }, // MFI Standard Gamepad (generic entry for iOS/tvOS)
{ MAKE_CONTROLLER_ID( 0x057e, 0x2006 ), k_eControllerType_SwitchJoyConLeft, NULL }, // Nintendo Switch Joy-Con (Left)
{ MAKE_CONTROLLER_ID( 0x057e, 0x2007 ), k_eControllerType_SwitchJoyConRight, NULL }, // Nintendo Switch Joy-Con (Right)
{ MAKE_CONTROLLER_ID( 0x057e, 0x2008 ), k_eControllerType_SwitchJoyConPair, NULL }, // Nintendo Switch Joy-Con (Left+Right Combined)
// This same controller ID is spoofed by many 3rd-party Switch controllers.
// The ones we currently know of are:
// * Any 8bitdo controller with Switch support
// * ORTZ Gaming Wireless Pro Controller
// * ZhiXu Gamepad Wireless
// * Sunwaytek Wireless Motion Controller for Nintendo Switch
{ MAKE_CONTROLLER_ID( 0x057e, 0x2009 ), k_eControllerType_SwitchProController, NULL }, // Nintendo Switch Pro Controller
//{ MAKE_CONTROLLER_ID( 0x057e, 0x2017 ), k_eControllerType_SwitchProController, NULL }, // Nintendo Online SNES Controller
//{ MAKE_CONTROLLER_ID( 0x057e, 0x2019 ), k_eControllerType_SwitchProController, NULL }, // Nintendo Online N64 Controller
//{ MAKE_CONTROLLER_ID( 0x057e, 0x201e ), k_eControllerType_SwitchProController, NULL }, // Nintendo Online SEGA Genesis Controller
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x00c1 ), k_eControllerType_SwitchInputOnlyController, NULL }, // HORIPAD for Nintendo Switch
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x0092 ), k_eControllerType_SwitchInputOnlyController, NULL }, // HORI Pokken Tournament DX Pro Pad
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x00f6 ), k_eControllerType_SwitchProController, NULL }, // HORI Wireless Switch Pad
// The HORIPAD S, which comes in multiple styles:
// - NSW-108, classic GameCube controller
// - NSW-244, Fighting Commander arcade pad
// - NSW-278, Hori Pad Mini gamepad
// - NSW-326, HORIPAD FPS for Nintendo Switch
//
// The first two, at least, shouldn't have their buttons remapped, and since we
// can't tell which model we're actually using, we won't do any button remapping
// for any of them.
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x00dc ), k_eControllerType_XInputSwitchController, NULL }, // HORIPAD S - Looks like a Switch controller but uses the Xbox 360 controller protocol
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0180 ), k_eControllerType_SwitchInputOnlyController, NULL }, // PDP Faceoff Wired Pro Controller for Nintendo Switch
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0181 ), k_eControllerType_SwitchInputOnlyController, NULL }, // PDP Faceoff Deluxe Wired Pro Controller for Nintendo Switch
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0184 ), k_eControllerType_SwitchInputOnlyController, NULL }, // PDP Faceoff Wired Deluxe+ Audio Controller
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0185 ), k_eControllerType_SwitchInputOnlyController, NULL }, // PDP Wired Fight Pad Pro for Nintendo Switch
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0186 ), k_eControllerType_SwitchProController, NULL }, // PDP Afterglow Wireless Switch Controller - working gyro. USB is for charging only. Many later "Wireless" line devices w/ gyro also use this vid/pid
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0187 ), k_eControllerType_SwitchInputOnlyController, NULL }, // PDP Rockcandy Wired Controller
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0188 ), k_eControllerType_SwitchInputOnlyController, NULL }, // PDP Afterglow Wired Deluxe+ Audio Controller
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x00aa ), k_eControllerType_SwitchInputOnlyController, NULL }, // HORI Real Arcade Pro V Hayabusa in Switch Mode
{ MAKE_CONTROLLER_ID( 0x20d6, 0xa711 ), k_eControllerType_SwitchInputOnlyController, NULL }, // PowerA Wired Controller Plus/PowerA Wired Controller Nintendo GameCube Style
{ MAKE_CONTROLLER_ID( 0x20d6, 0xa712 ), k_eControllerType_SwitchInputOnlyController, NULL }, // PowerA Nintendo Switch Fusion Fight Pad
{ MAKE_CONTROLLER_ID( 0x20d6, 0xa713 ), k_eControllerType_SwitchInputOnlyController, NULL }, // PowerA Super Mario Controller
{ MAKE_CONTROLLER_ID( 0x20d6, 0xa714 ), k_eControllerType_SwitchInputOnlyController, NULL }, // PowerA Nintendo Switch Spectra Controller
{ MAKE_CONTROLLER_ID( 0x20d6, 0xa715 ), k_eControllerType_SwitchInputOnlyController, NULL }, // Power A Fusion Wireless Arcade Stick (USB Mode) Over BT is shows up as 057e 2009
{ MAKE_CONTROLLER_ID( 0x20d6, 0xa716 ), k_eControllerType_SwitchInputOnlyController, NULL }, // PowerA Nintendo Switch Fusion Pro Controller - USB requires toggling switch on back of device
// Valve products
{ MAKE_CONTROLLER_ID( 0x0000, 0x11fb ), k_eControllerType_MobileTouch, NULL }, // Streaming mobile touch virtual controls
{ MAKE_CONTROLLER_ID( 0x28de, 0x1101 ), k_eControllerType_SteamController, NULL }, // Valve Legacy Steam Controller (CHELL)
{ MAKE_CONTROLLER_ID( 0x28de, 0x1102 ), k_eControllerType_SteamController, NULL }, // Valve wired Steam Controller (D0G)
{ MAKE_CONTROLLER_ID( 0x28de, 0x1105 ), k_eControllerType_SteamController, NULL }, // Valve Bluetooth Steam Controller (D0G)
{ MAKE_CONTROLLER_ID( 0x28de, 0x1106 ), k_eControllerType_SteamController, NULL }, // Valve Bluetooth Steam Controller (D0G)
{ MAKE_CONTROLLER_ID( 0x28de, 0x1142 ), k_eControllerType_SteamController, NULL }, // Valve wireless Steam Controller
{ MAKE_CONTROLLER_ID( 0x28de, 0x1201 ), k_eControllerType_SteamControllerV2, NULL }, // Valve wired Steam Controller (HEADCRAB)
{ MAKE_CONTROLLER_ID( 0x28de, 0x1202 ), k_eControllerType_SteamControllerV2, NULL }, // Valve Bluetooth Steam Controller (HEADCRAB)
};

View File

@@ -0,0 +1,140 @@
/*
Copyright (C) Valve Corporation
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 "controller_type.h"
#include "controller_list.h"
static const char *GetControllerTypeOverride( int nVID, int nPID )
{
const char *hint = SDL_GetHint(SDL_HINT_GAMECONTROLLERTYPE);
if (hint) {
char key[32];
const char *spot = NULL;
SDL_snprintf(key, sizeof(key), "0x%.4x/0x%.4x=", nVID, nPID);
spot = SDL_strstr(hint, key);
if (!spot) {
SDL_snprintf(key, sizeof(key), "0x%.4X/0x%.4X=", nVID, nPID);
spot = SDL_strstr(hint, key);
}
if (spot) {
spot += SDL_strlen(key);
if (SDL_strncmp(spot, "k_eControllerType_", 18) == 0) {
spot += 18;
}
return spot;
}
}
return NULL;
}
EControllerType GuessControllerType( int nVID, int nPID )
{
#if 0//def _DEBUG
// Verify that there are no duplicates in the controller list
// If the list were sorted, we could do this much more efficiently, as well as improve lookup speed.
static bool s_bCheckedForDuplicates;
if ( !s_bCheckedForDuplicates )
{
s_bCheckedForDuplicates = true;
int i, j;
for ( i = 0; i < sizeof( arrControllers ) / sizeof( arrControllers[ 0 ] ); ++i )
{
for ( j = i + 1; j < sizeof( arrControllers ) / sizeof( arrControllers[ 0 ] ); ++j )
{
if ( arrControllers[ i ].m_unDeviceID == arrControllers[ j ].m_unDeviceID )
{
Log( "Duplicate controller entry found for VID 0x%.4x PID 0x%.4x\n", ( arrControllers[ i ].m_unDeviceID >> 16 ), arrControllers[ i ].m_unDeviceID & 0xFFFF );
}
}
}
}
#endif // _DEBUG
unsigned int unDeviceID = MAKE_CONTROLLER_ID( nVID, nPID );
int iIndex;
const char *pszOverride = GetControllerTypeOverride( nVID, nPID );
if ( pszOverride )
{
if ( SDL_strncasecmp( pszOverride, "Xbox360", 7 ) == 0 )
{
return k_eControllerType_XBox360Controller;
}
if ( SDL_strncasecmp( pszOverride, "XboxOne", 7 ) == 0 )
{
return k_eControllerType_XBoxOneController;
}
if ( SDL_strncasecmp( pszOverride, "PS3", 3 ) == 0 )
{
return k_eControllerType_PS3Controller;
}
if ( SDL_strncasecmp( pszOverride, "PS4", 3 ) == 0 )
{
return k_eControllerType_PS4Controller;
}
if ( SDL_strncasecmp( pszOverride, "PS5", 3 ) == 0 )
{
return k_eControllerType_PS5Controller;
}
if ( SDL_strncasecmp( pszOverride, "SwitchPro", 9 ) == 0 )
{
return k_eControllerType_SwitchProController;
}
if ( SDL_strncasecmp( pszOverride, "Steam", 5 ) == 0 )
{
return k_eControllerType_SteamController;
}
return k_eControllerType_UnknownNonSteamController;
}
for ( iIndex = 0; iIndex < sizeof( arrControllers ) / sizeof( arrControllers[0] ); ++iIndex )
{
if ( unDeviceID == arrControllers[ iIndex ].m_unDeviceID )
{
return arrControllers[ iIndex ].m_eControllerType;
}
}
return k_eControllerType_UnknownNonSteamController;
}
const char *GuessControllerName( int nVID, int nPID )
{
unsigned int unDeviceID = MAKE_CONTROLLER_ID( nVID, nPID );
int iIndex;
for ( iIndex = 0; iIndex < sizeof( arrControllers ) / sizeof( arrControllers[0] ); ++iIndex )
{
if ( unDeviceID == arrControllers[ iIndex ].m_unDeviceID )
{
return arrControllers[ iIndex ].m_pszName;
}
}
return NULL;
}
#undef MAKE_CONTROLLER_ID

View File

@@ -0,0 +1,77 @@
/*
Copyright (C) Valve Corporation
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.
*/
#ifndef CONTROLLER_TYPE_H
#define CONTROLLER_TYPE_H
#ifdef _WIN32
#pragma once
#endif
//-----------------------------------------------------------------------------
// Purpose: Steam Controller models
// WARNING: DO NOT RENUMBER EXISTING VALUES - STORED IN A DATABASE
//-----------------------------------------------------------------------------
typedef enum
{
k_eControllerType_None = -1,
k_eControllerType_Unknown = 0,
// Steam Controllers
k_eControllerType_UnknownSteamController = 1,
k_eControllerType_SteamController = 2,
k_eControllerType_SteamControllerV2 = 3,
// Other Controllers
k_eControllerType_UnknownNonSteamController = 30,
k_eControllerType_XBox360Controller = 31,
k_eControllerType_XBoxOneController = 32,
k_eControllerType_PS3Controller = 33,
k_eControllerType_PS4Controller = 34,
k_eControllerType_WiiController = 35,
k_eControllerType_AppleController = 36,
k_eControllerType_AndroidController = 37,
k_eControllerType_SwitchProController = 38,
k_eControllerType_SwitchJoyConLeft = 39,
k_eControllerType_SwitchJoyConRight = 40,
k_eControllerType_SwitchJoyConPair = 41,
k_eControllerType_SwitchInputOnlyController = 42,
k_eControllerType_MobileTouch = 43,
k_eControllerType_XInputSwitchController = 44, // Client-side only, used to mark Nintendo Switch style controllers as using XInput instead of the Nintendo Switch protocol
k_eControllerType_PS5Controller = 45,
k_eControllerType_XInputPS4Controller = 46, // Client-side only, used to mark DualShock 4 style controllers using XInput instead of the DualShock 4 controller protocol
k_eControllerType_LastController, // Don't add game controllers below this enumeration - this enumeration can change value
// Keyboards and Mice
k_eControllertype_GenericKeyboard = 400,
k_eControllertype_GenericMouse = 800,
} EControllerType;
typedef struct
{
unsigned int m_unDeviceID;
EControllerType m_eControllerType;
const char *m_pszName;
} ControllerDescription_t;
extern EControllerType GuessControllerType( int nVID, int nPID );
extern const char *GuessControllerName( int nVID, int nPID );
#endif // CONTROLLER_TYPE_H

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,79 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 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"
#ifndef SDL_JOYSTICK_IOKIT_H
#define SDL_JOYSTICK_IOKIT_H
#include <IOKit/hid/IOHIDLib.h>
#include <ForceFeedback/ForceFeedback.h>
#include <ForceFeedback/ForceFeedbackConstants.h>
struct recElement
{
IOHIDElementRef elementRef;
IOHIDElementCookie cookie;
uint32_t usagePage, usage; /* HID usage */
SInt32 min; /* reported min value possible */
SInt32 max; /* reported max value possible */
/* runtime variables used for auto-calibration */
SInt32 minReport; /* min returned value */
SInt32 maxReport; /* max returned value */
struct recElement *pNext; /* next element in list */
};
typedef struct recElement recElement;
struct joystick_hwdata
{
IOHIDDeviceRef deviceRef; /* HIDManager device handle */
io_service_t ffservice; /* Interface for force feedback, 0 = no ff */
FFDeviceObjectReference ffdevice;
FFEFFECT *ffeffect;
FFEffectObjectReference ffeffect_ref;
SDL_bool ff_initialized;
char product[256]; /* name of product */
uint32_t usage; /* usage page from IOUSBHID Parser.h which defines general usage */
uint32_t usagePage; /* usage within above page from IOUSBHID Parser.h which defines specific usage */
int axes; /* number of axis (calculated, not reported by device) */
int buttons; /* number of buttons (calculated, not reported by device) */
int hats; /* number of hat switches (calculated, not reported by device) */
int elements; /* number of total elements (should be total of above) (calculated, not reported by device) */
recElement *firstAxis;
recElement *firstButton;
recElement *firstHat;
SDL_bool removed;
SDL_Joystick *joystick;
SDL_bool runLoopAttached; /* is 'deviceRef' attached to a CFRunLoop? */
int instance_id;
SDL_JoystickGUID guid;
struct joystick_hwdata *pNext; /* next device */
};
typedef struct joystick_hwdata recDevice;
#endif /* SDL_JOYSTICK_IOKIT_H */

View File

@@ -0,0 +1,150 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 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 defined(SDL_JOYSTICK_DUMMY) || defined(SDL_JOYSTICK_DISABLED)
/* This is the dummy implementation of the SDL joystick API */
#include "../SDL_sysjoystick.h"
#include "../SDL_joystick_c.h"
static int DUMMY_JoystickInit(void)
{
return 0;
}
static int DUMMY_JoystickGetCount(void)
{
return 0;
}
static void DUMMY_JoystickDetect(void)
{
}
static const char *DUMMY_JoystickGetDeviceName(int device_index)
{
return NULL;
}
static const char *DUMMY_JoystickGetDevicePath(int device_index)
{
return NULL;
}
static int DUMMY_JoystickGetDevicePlayerIndex(int device_index)
{
return -1;
}
static void DUMMY_JoystickSetDevicePlayerIndex(int device_index, int player_index)
{
}
static SDL_JoystickGUID DUMMY_JoystickGetDeviceGUID(int device_index)
{
SDL_JoystickGUID guid;
SDL_zero(guid);
return guid;
}
static SDL_JoystickID DUMMY_JoystickGetDeviceInstanceID(int device_index)
{
return -1;
}
static int DUMMY_JoystickOpen(SDL_Joystick *joystick, int device_index)
{
return SDL_SetError("Logic error: No joysticks available");
}
static int DUMMY_JoystickRumble(SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble)
{
return SDL_Unsupported();
}
static int DUMMY_JoystickRumbleTriggers(SDL_Joystick *joystick, Uint16 left_rumble, Uint16 right_rumble)
{
return SDL_Unsupported();
}
static Uint32 DUMMY_JoystickGetCapabilities(SDL_Joystick *joystick)
{
return 0;
}
static int DUMMY_JoystickSetLED(SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue)
{
return SDL_Unsupported();
}
static int DUMMY_JoystickSendEffect(SDL_Joystick *joystick, const void *data, int size)
{
return SDL_Unsupported();
}
static int DUMMY_JoystickSetSensorsEnabled(SDL_Joystick *joystick, SDL_bool enabled)
{
return SDL_Unsupported();
}
static void DUMMY_JoystickUpdate(SDL_Joystick *joystick)
{
}
static void DUMMY_JoystickClose(SDL_Joystick *joystick)
{
}
static void DUMMY_JoystickQuit(void)
{
}
static SDL_bool DUMMY_JoystickGetGamepadMapping(int device_index, SDL_GamepadMapping *out)
{
return SDL_FALSE;
}
SDL_JoystickDriver SDL_DUMMY_JoystickDriver = {
DUMMY_JoystickInit,
DUMMY_JoystickGetCount,
DUMMY_JoystickDetect,
DUMMY_JoystickGetDeviceName,
DUMMY_JoystickGetDevicePath,
DUMMY_JoystickGetDevicePlayerIndex,
DUMMY_JoystickSetDevicePlayerIndex,
DUMMY_JoystickGetDeviceGUID,
DUMMY_JoystickGetDeviceInstanceID,
DUMMY_JoystickOpen,
DUMMY_JoystickRumble,
DUMMY_JoystickRumbleTriggers,
DUMMY_JoystickGetCapabilities,
DUMMY_JoystickSetLED,
DUMMY_JoystickSendEffect,
DUMMY_JoystickSetSensorsEnabled,
DUMMY_JoystickUpdate,
DUMMY_JoystickClose,
DUMMY_JoystickQuit,
DUMMY_JoystickGetGamepadMapping
};
#endif /* SDL_JOYSTICK_DUMMY || SDL_JOYSTICK_DISABLED */

View File

@@ -0,0 +1,439 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 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_EMSCRIPTEN
#include <stdio.h> /* For the definition of NULL */
#include "SDL_sysjoystick_c.h"
#include "../SDL_joystick_c.h"
static SDL_joylist_item *JoystickByIndex(int index);
static SDL_joylist_item *SDL_joylist = NULL;
static SDL_joylist_item *SDL_joylist_tail = NULL;
static int numjoysticks = 0;
static int instance_counter = 0;
static EM_BOOL Emscripten_JoyStickConnected(int eventType, const EmscriptenGamepadEvent *gamepadEvent, void *userData)
{
int i;
SDL_joylist_item *item;
if (JoystickByIndex(gamepadEvent->index) != NULL) {
return 1;
}
item = (SDL_joylist_item *)SDL_malloc(sizeof(SDL_joylist_item));
if (item == NULL) {
return 1;
}
SDL_zerop(item);
item->index = gamepadEvent->index;
item->name = SDL_CreateJoystickName(0, 0, NULL, gamepadEvent->id);
if (item->name == NULL) {
SDL_free(item);
return 1;
}
item->mapping = SDL_strdup(gamepadEvent->mapping);
if (item->mapping == NULL) {
SDL_free(item->name);
SDL_free(item);
return 1;
}
item->naxes = gamepadEvent->numAxes;
item->nbuttons = gamepadEvent->numButtons;
item->device_instance = instance_counter++;
item->timestamp = gamepadEvent->timestamp;
for (i = 0; i < item->naxes; i++) {
item->axis[i] = gamepadEvent->axis[i];
}
for (i = 0; i < item->nbuttons; i++) {
item->analogButton[i] = gamepadEvent->analogButton[i];
item->digitalButton[i] = gamepadEvent->digitalButton[i];
}
if (SDL_joylist_tail == NULL) {
SDL_joylist = SDL_joylist_tail = item;
} else {
SDL_joylist_tail->next = item;
SDL_joylist_tail = item;
}
++numjoysticks;
SDL_PrivateJoystickAdded(item->device_instance);
#ifdef DEBUG_JOYSTICK
SDL_Log("Number of joysticks is %d", numjoysticks);
#endif
#ifdef DEBUG_JOYSTICK
SDL_Log("Added joystick with index %d", item->index);
#endif
return 1;
}
static EM_BOOL Emscripten_JoyStickDisconnected(int eventType, const EmscriptenGamepadEvent *gamepadEvent, void *userData)
{
SDL_joylist_item *item = SDL_joylist;
SDL_joylist_item *prev = NULL;
while (item != NULL) {
if (item->index == gamepadEvent->index) {
break;
}
prev = item;
item = item->next;
}
if (item == NULL) {
return 1;
}
if (item->joystick) {
item->joystick->hwdata = NULL;
}
if (prev != NULL) {
prev->next = item->next;
} else {
SDL_assert(SDL_joylist == item);
SDL_joylist = item->next;
}
if (item == SDL_joylist_tail) {
SDL_joylist_tail = prev;
}
/* Need to decrement the joystick count before we post the event */
--numjoysticks;
SDL_PrivateJoystickRemoved(item->device_instance);
#ifdef DEBUG_JOYSTICK
SDL_Log("Removed joystick with id %d", item->device_instance);
#endif
SDL_free(item->name);
SDL_free(item->mapping);
SDL_free(item);
return 1;
}
/* Function to perform any system-specific joystick related cleanup */
static void EMSCRIPTEN_JoystickQuit(void)
{
SDL_joylist_item *item = NULL;
SDL_joylist_item *next = NULL;
for (item = SDL_joylist; item; item = next) {
next = item->next;
SDL_free(item->mapping);
SDL_free(item->name);
SDL_free(item);
}
SDL_joylist = SDL_joylist_tail = NULL;
numjoysticks = 0;
instance_counter = 0;
emscripten_set_gamepadconnected_callback(NULL, 0, NULL);
emscripten_set_gamepaddisconnected_callback(NULL, 0, NULL);
}
/* Function to scan the system for joysticks.
* It should return 0, or -1 on an unrecoverable fatal error.
*/
static int EMSCRIPTEN_JoystickInit(void)
{
int retval, i, numjs;
EmscriptenGamepadEvent gamepadState;
numjoysticks = 0;
retval = emscripten_sample_gamepad_data();
/* Check if gamepad is supported by browser */
if (retval == EMSCRIPTEN_RESULT_NOT_SUPPORTED) {
return SDL_SetError("Gamepads not supported");
}
numjs = emscripten_get_num_gamepads();
/* handle already connected gamepads */
if (numjs > 0) {
for (i = 0; i < numjs; i++) {
retval = emscripten_get_gamepad_status(i, &gamepadState);
if (retval == EMSCRIPTEN_RESULT_SUCCESS) {
Emscripten_JoyStickConnected(EMSCRIPTEN_EVENT_GAMEPADCONNECTED,
&gamepadState,
NULL);
}
}
}
retval = emscripten_set_gamepadconnected_callback(NULL,
0,
Emscripten_JoyStickConnected);
if (retval != EMSCRIPTEN_RESULT_SUCCESS) {
EMSCRIPTEN_JoystickQuit();
return SDL_SetError("Could not set gamepad connect callback");
}
retval = emscripten_set_gamepaddisconnected_callback(NULL,
0,
Emscripten_JoyStickDisconnected);
if (retval != EMSCRIPTEN_RESULT_SUCCESS) {
EMSCRIPTEN_JoystickQuit();
return SDL_SetError("Could not set gamepad disconnect callback");
}
return 0;
}
/* Returns item matching given SDL device index. */
static SDL_joylist_item *JoystickByDeviceIndex(int device_index)
{
SDL_joylist_item *item = SDL_joylist;
while (0 < device_index) {
--device_index;
item = item->next;
}
return item;
}
/* Returns item matching given HTML gamepad index. */
static SDL_joylist_item *JoystickByIndex(int index)
{
SDL_joylist_item *item = SDL_joylist;
if (index < 0) {
return NULL;
}
while (item != NULL) {
if (item->index == index) {
break;
}
item = item->next;
}
return item;
}
static int EMSCRIPTEN_JoystickGetCount(void)
{
return numjoysticks;
}
static void EMSCRIPTEN_JoystickDetect(void)
{
}
static const char *EMSCRIPTEN_JoystickGetDeviceName(int device_index)
{
return JoystickByDeviceIndex(device_index)->name;
}
static const char *EMSCRIPTEN_JoystickGetDevicePath(int device_index)
{
return NULL;
}
static int EMSCRIPTEN_JoystickGetDevicePlayerIndex(int device_index)
{
return -1;
}
static void EMSCRIPTEN_JoystickSetDevicePlayerIndex(int device_index, int player_index)
{
}
static SDL_JoystickID EMSCRIPTEN_JoystickGetDeviceInstanceID(int device_index)
{
return JoystickByDeviceIndex(device_index)->device_instance;
}
/* 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 EMSCRIPTEN_JoystickOpen(SDL_Joystick *joystick, int device_index)
{
SDL_joylist_item *item = JoystickByDeviceIndex(device_index);
if (item == NULL) {
return SDL_SetError("No such device");
}
if (item->joystick != NULL) {
return SDL_SetError("Joystick already opened");
}
joystick->instance_id = item->device_instance;
joystick->hwdata = (struct joystick_hwdata *)item;
item->joystick = joystick;
/* HTML5 Gamepad API doesn't say anything about these */
joystick->nhats = 0;
joystick->nbuttons = item->nbuttons;
joystick->naxes = item->naxes;
return 0;
}
/* 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 EMSCRIPTEN_JoystickUpdate(SDL_Joystick *joystick)
{
EmscriptenGamepadEvent gamepadState;
SDL_joylist_item *item = (SDL_joylist_item *)joystick->hwdata;
int i, result, buttonState;
Uint64 timestamp = SDL_GetTicksNS();
emscripten_sample_gamepad_data();
if (item) {
result = emscripten_get_gamepad_status(item->index, &gamepadState);
if (result == EMSCRIPTEN_RESULT_SUCCESS) {
if (gamepadState.timestamp == 0 || gamepadState.timestamp != item->timestamp) {
for (i = 0; i < item->nbuttons; i++) {
if (item->digitalButton[i] != gamepadState.digitalButton[i]) {
buttonState = gamepadState.digitalButton[i] ? SDL_PRESSED : SDL_RELEASED;
SDL_SendJoystickButton(timestamp, item->joystick, i, buttonState);
}
/* store values to compare them in the next update */
item->analogButton[i] = gamepadState.analogButton[i];
item->digitalButton[i] = gamepadState.digitalButton[i];
}
for (i = 0; i < item->naxes; i++) {
if (item->axis[i] != gamepadState.axis[i]) {
/* do we need to do conversion? */
SDL_SendJoystickAxis(timestamp, item->joystick, i,
(Sint16)(32767. * gamepadState.axis[i]));
}
/* store to compare in next update */
item->axis[i] = gamepadState.axis[i];
}
item->timestamp = gamepadState.timestamp;
}
}
}
}
/* Function to close a joystick after use */
static void EMSCRIPTEN_JoystickClose(SDL_Joystick *joystick)
{
SDL_joylist_item *item = (SDL_joylist_item *)joystick->hwdata;
if (item) {
item->joystick = NULL;
}
}
static SDL_JoystickGUID EMSCRIPTEN_JoystickGetDeviceGUID(int device_index)
{
/* the GUID is just the name for now */
const char *name = EMSCRIPTEN_JoystickGetDeviceName(device_index);
return SDL_CreateJoystickGUIDForName(name);
}
static int EMSCRIPTEN_JoystickRumble(SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble)
{
return SDL_Unsupported();
}
static int EMSCRIPTEN_JoystickRumbleTriggers(SDL_Joystick *joystick, Uint16 left_rumble, Uint16 right_rumble)
{
return SDL_Unsupported();
}
static SDL_bool EMSCRIPTEN_JoystickGetGamepadMapping(int device_index, SDL_GamepadMapping *out)
{
return SDL_FALSE;
}
static Uint32 EMSCRIPTEN_JoystickGetCapabilities(SDL_Joystick *joystick)
{
return 0;
}
static int EMSCRIPTEN_JoystickSetLED(SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue)
{
return SDL_Unsupported();
}
static int EMSCRIPTEN_JoystickSendEffect(SDL_Joystick *joystick, const void *data, int size)
{
return SDL_Unsupported();
}
static int EMSCRIPTEN_JoystickSetSensorsEnabled(SDL_Joystick *joystick, SDL_bool enabled)
{
return SDL_Unsupported();
}
SDL_JoystickDriver SDL_EMSCRIPTEN_JoystickDriver = {
EMSCRIPTEN_JoystickInit,
EMSCRIPTEN_JoystickGetCount,
EMSCRIPTEN_JoystickDetect,
EMSCRIPTEN_JoystickGetDeviceName,
EMSCRIPTEN_JoystickGetDevicePath,
EMSCRIPTEN_JoystickGetDevicePlayerIndex,
EMSCRIPTEN_JoystickSetDevicePlayerIndex,
EMSCRIPTEN_JoystickGetDeviceGUID,
EMSCRIPTEN_JoystickGetDeviceInstanceID,
EMSCRIPTEN_JoystickOpen,
EMSCRIPTEN_JoystickRumble,
EMSCRIPTEN_JoystickRumbleTriggers,
EMSCRIPTEN_JoystickGetCapabilities,
EMSCRIPTEN_JoystickSetLED,
EMSCRIPTEN_JoystickSendEffect,
EMSCRIPTEN_JoystickSetSensorsEnabled,
EMSCRIPTEN_JoystickUpdate,
EMSCRIPTEN_JoystickClose,
EMSCRIPTEN_JoystickQuit,
EMSCRIPTEN_JoystickGetGamepadMapping
};
#endif /* SDL_JOYSTICK_EMSCRIPTEN */

View File

@@ -0,0 +1,49 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 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_EMSCRIPTEN
#include "../SDL_sysjoystick.h"
#include <emscripten/html5.h>
/* A linked list of available joysticks */
typedef struct SDL_joylist_item
{
int index;
char *name;
char *mapping;
SDL_JoystickID device_instance;
SDL_Joystick *joystick;
int nbuttons;
int naxes;
double timestamp;
double axis[64];
double analogButton[64];
EM_BOOL digitalButton[64];
struct SDL_joylist_item *next;
} SDL_joylist_item;
typedef SDL_joylist_item joystick_hwdata;
#endif /* SDL_JOYSTICK_EMSCRIPTEN */

View File

@@ -0,0 +1,321 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 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_HAIKU
/* This is the Haiku implementation of the SDL joystick API */
#include <support/String.h>
#include <device/Joystick.h>
extern "C"
{
#include "../SDL_sysjoystick.h"
#include "../SDL_joystick_c.h"
/* The maximum number of joysticks we'll detect */
#define MAX_JOYSTICKS 16
/* A list of available joysticks */
static char *SDL_joyport[MAX_JOYSTICKS];
static char *SDL_joyname[MAX_JOYSTICKS];
/* The private structure used to keep track of a joystick */
struct joystick_hwdata
{
BJoystick *stick;
uint8 *new_hats;
int16 *new_axes;
};
static int 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.
*/
static int HAIKU_JoystickInit(void)
{
BJoystick joystick;
int i;
int32 nports;
char name[B_OS_NAME_LENGTH];
/* Search for attached joysticks */
nports = joystick.CountDevices();
numjoysticks = 0;
SDL_memset(SDL_joyport, 0, sizeof(SDL_joyport));
SDL_memset(SDL_joyname, 0, sizeof(SDL_joyname));
for (i = 0; (numjoysticks < MAX_JOYSTICKS) && (i < nports); ++i) {
if (joystick.GetDeviceName(i, name) == B_OK) {
if (joystick.Open(name) != B_ERROR) {
BString stick_name;
joystick.GetControllerName(&stick_name);
SDL_joyport[numjoysticks] = SDL_strdup(name);
SDL_joyname[numjoysticks] = SDL_CreateJoystickName(0, 0, NULL, stick_name.String());
numjoysticks++;
joystick.Close();
}
}
}
return (numjoysticks);
}
static int HAIKU_JoystickGetCount(void)
{
return numjoysticks;
}
static void HAIKU_JoystickDetect(void)
{
}
static const char *HAIKU_JoystickGetDeviceName(int device_index)
{
return SDL_joyname[device_index];
}
static const char *HAIKU_JoystickGetDevicePath(int device_index)
{
return SDL_joyport[device_index];
}
static int HAIKU_JoystickGetDevicePlayerIndex(int device_index)
{
return -1;
}
static void HAIKU_JoystickSetDevicePlayerIndex(int device_index, int player_index)
{
}
/* Function to perform the mapping from device index to the instance id for this index */
static SDL_JoystickID HAIKU_JoystickGetDeviceInstanceID(int device_index)
{
return device_index;
}
static void HAIKU_JoystickClose(SDL_Joystick *joystick);
/* 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 HAIKU_JoystickOpen(SDL_Joystick *joystick, int device_index)
{
BJoystick *stick;
/* Create the joystick data structure */
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));
stick = new BJoystick;
joystick->hwdata->stick = stick;
/* Open the requested joystick for use */
if (stick->Open(SDL_joyport[device_index]) == B_ERROR) {
HAIKU_JoystickClose(joystick);
return SDL_SetError("Unable to open joystick");
}
/* Set the joystick to calibrated mode */
stick->EnableCalibration();
/* Get the number of buttons, hats, and axes on the joystick */
joystick->nbuttons = stick->CountButtons();
joystick->naxes = stick->CountAxes();
joystick->nhats = stick->CountHats();
joystick->hwdata->new_axes = (int16 *)
SDL_malloc(joystick->naxes * sizeof(int16));
joystick->hwdata->new_hats = (uint8 *)
SDL_malloc(joystick->nhats * sizeof(uint8));
if (!joystick->hwdata->new_hats || !joystick->hwdata->new_axes) {
HAIKU_JoystickClose(joystick);
return SDL_OutOfMemory();
}
/* We're done! */
return 0;
}
/* 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 HAIKU_JoystickUpdate(SDL_Joystick *joystick)
{
static const Uint8 hat_map[9] = {
SDL_HAT_CENTERED,
SDL_HAT_UP,
SDL_HAT_RIGHTUP,
SDL_HAT_RIGHT,
SDL_HAT_RIGHTDOWN,
SDL_HAT_DOWN,
SDL_HAT_LEFTDOWN,
SDL_HAT_LEFT,
SDL_HAT_LEFTUP
};
BJoystick *stick;
int i;
int16 *axes;
uint8 *hats;
uint32 buttons;
Uint64 timestamp = SDL_GetTicksNS();
/* Set up data pointers */
stick = joystick->hwdata->stick;
axes = joystick->hwdata->new_axes;
hats = joystick->hwdata->new_hats;
/* Get the new joystick state */
stick->Update();
stick->GetAxisValues(axes);
stick->GetHatValues(hats);
buttons = stick->ButtonValues();
/* Generate axis motion events */
for (i = 0; i < joystick->naxes; ++i) {
SDL_SendJoystickAxis(timestamp, joystick, i, axes[i]);
}
/* Generate hat change events */
for (i = 0; i < joystick->nhats; ++i) {
SDL_SendJoystickHat(timestamp, joystick, i, hat_map[hats[i]]);
}
/* Generate button events */
for (i = 0; i < joystick->nbuttons; ++i) {
SDL_SendJoystickButton(timestamp, joystick, i, (buttons & 0x01));
buttons >>= 1;
}
}
/* Function to close a joystick after use */
static void HAIKU_JoystickClose(SDL_Joystick *joystick)
{
if (joystick->hwdata) {
joystick->hwdata->stick->Close();
delete joystick->hwdata->stick;
SDL_free(joystick->hwdata->new_hats);
SDL_free(joystick->hwdata->new_axes);
SDL_free(joystick->hwdata);
}
}
/* Function to perform any system-specific joystick related cleanup */
static void HAIKU_JoystickQuit(void)
{
int i;
for (i = 0; i < numjoysticks; ++i) {
SDL_free(SDL_joyport[i]);
}
SDL_joyport[0] = NULL;
for (i = 0; i < numjoysticks; ++i) {
SDL_free(SDL_joyname[i]);
}
SDL_joyname[0] = NULL;
}
static SDL_JoystickGUID HAIKU_JoystickGetDeviceGUID(int device_index)
{
/* the GUID is just the name for now */
const char *name = HAIKU_JoystickGetDeviceName(device_index);
return SDL_CreateJoystickGUIDForName(name);
}
static int HAIKU_JoystickRumble(SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble)
{
return SDL_Unsupported();
}
static int HAIKU_JoystickRumbleTriggers(SDL_Joystick *joystick, Uint16 left_rumble, Uint16 right_rumble)
{
return SDL_Unsupported();
}
static SDL_bool
HAIKU_JoystickGetGamepadMapping(int device_index, SDL_GamepadMapping *out)
{
return SDL_FALSE;
}
static Uint32 HAIKU_JoystickGetCapabilities(SDL_Joystick *joystick)
{
return 0;
}
static int HAIKU_JoystickSetLED(SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue)
{
return SDL_Unsupported();
}
static int HAIKU_JoystickSendEffect(SDL_Joystick *joystick, const void *data, int size)
{
return SDL_Unsupported();
}
static int HAIKU_JoystickSetSensorsEnabled(SDL_Joystick *joystick, SDL_bool enabled)
{
return SDL_Unsupported();
}
SDL_JoystickDriver SDL_HAIKU_JoystickDriver =
{
HAIKU_JoystickInit,
HAIKU_JoystickGetCount,
HAIKU_JoystickDetect,
HAIKU_JoystickGetDeviceName,
HAIKU_JoystickGetDevicePath,
HAIKU_JoystickGetDevicePlayerIndex,
HAIKU_JoystickSetDevicePlayerIndex,
HAIKU_JoystickGetDeviceGUID,
HAIKU_JoystickGetDeviceInstanceID,
HAIKU_JoystickOpen,
HAIKU_JoystickRumble,
HAIKU_JoystickRumbleTriggers,
HAIKU_JoystickGetCapabilities,
HAIKU_JoystickSetLED,
HAIKU_JoystickSendEffect,
HAIKU_JoystickSetSensorsEnabled,
HAIKU_JoystickUpdate,
HAIKU_JoystickClose,
HAIKU_JoystickQuit,
HAIKU_JoystickGetGamepadMapping
};
} // extern "C"
#endif /* SDL_JOYSTICK_HAIKU */

View File

@@ -0,0 +1,234 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 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.
*/
/* This driver supports the Nintendo Switch Joy-Cons pair controllers */
#include "SDL_internal.h"
#ifdef SDL_JOYSTICK_HIDAPI
#include "SDL_hidapijoystick_c.h"
#include "../SDL_sysjoystick.h"
static void HIDAPI_DriverCombined_RegisterHints(SDL_HintCallback callback, void *userdata)
{
}
static void HIDAPI_DriverCombined_UnregisterHints(SDL_HintCallback callback, void *userdata)
{
}
static SDL_bool HIDAPI_DriverCombined_IsEnabled(void)
{
return SDL_TRUE;
}
static SDL_bool HIDAPI_DriverCombined_IsSupportedDevice(SDL_HIDAPI_Device *device, const char *name, SDL_GamepadType type, Uint16 vendor_id, Uint16 product_id, Uint16 version, int interface_number, int interface_class, int interface_subclass, int interface_protocol)
{
/* This is always explicitly created for combined devices */
return SDL_FALSE;
}
static SDL_bool HIDAPI_DriverCombined_InitDevice(SDL_HIDAPI_Device *device)
{
return HIDAPI_JoystickConnected(device, NULL);
}
static int HIDAPI_DriverCombined_GetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id)
{
return -1;
}
static void HIDAPI_DriverCombined_SetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id, int player_index)
{
}
static SDL_bool HIDAPI_DriverCombined_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
{
int i;
char *serial = NULL, *new_serial;
size_t serial_length = 0, new_length;
SDL_AssertJoysticksLocked();
for (i = 0; i < device->num_children; ++i) {
SDL_HIDAPI_Device *child = device->children[i];
if (!child->driver->OpenJoystick(child, joystick)) {
while (i-- > 0) {
child = device->children[i];
child->driver->CloseJoystick(child, joystick);
}
if (serial) {
SDL_free(serial);
}
return SDL_FALSE;
}
/* Extend the serial number with the child serial number */
if (joystick->serial) {
new_length = serial_length + 1 + SDL_strlen(joystick->serial);
new_serial = (char *)SDL_realloc(serial, new_length);
if (new_serial) {
if (serial) {
SDL_strlcat(new_serial, ",", new_length);
SDL_strlcat(new_serial, joystick->serial, new_length);
} else {
SDL_strlcpy(new_serial, joystick->serial, new_length);
}
serial = new_serial;
serial_length = new_length;
}
SDL_free(joystick->serial);
joystick->serial = NULL;
}
}
/* Update the joystick with the combined serial numbers */
if (joystick->serial) {
SDL_free(joystick->serial);
}
joystick->serial = serial;
return SDL_TRUE;
}
static int HIDAPI_DriverCombined_RumbleJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble)
{
int i;
int result = -1;
for (i = 0; i < device->num_children; ++i) {
SDL_HIDAPI_Device *child = device->children[i];
if (child->driver->RumbleJoystick(child, joystick, low_frequency_rumble, high_frequency_rumble) == 0) {
result = 0;
}
}
return result;
}
static int HIDAPI_DriverCombined_RumbleJoystickTriggers(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint16 left_rumble, Uint16 right_rumble)
{
int i;
int result = -1;
for (i = 0; i < device->num_children; ++i) {
SDL_HIDAPI_Device *child = device->children[i];
if (child->driver->RumbleJoystickTriggers(child, joystick, left_rumble, right_rumble) == 0) {
result = 0;
}
}
return result;
}
static Uint32 HIDAPI_DriverCombined_GetJoystickCapabilities(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
{
int i;
Uint32 caps = 0;
for (i = 0; i < device->num_children; ++i) {
SDL_HIDAPI_Device *child = device->children[i];
caps |= child->driver->GetJoystickCapabilities(child, joystick);
}
return caps;
}
static int HIDAPI_DriverCombined_SetJoystickLED(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue)
{
int i;
int result = -1;
for (i = 0; i < device->num_children; ++i) {
SDL_HIDAPI_Device *child = device->children[i];
if (child->driver->SetJoystickLED(child, joystick, red, green, blue) == 0) {
result = 0;
}
}
return result;
}
static int HIDAPI_DriverCombined_SendJoystickEffect(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, const void *data, int size)
{
return SDL_Unsupported();
}
static int HIDAPI_DriverCombined_SetJoystickSensorsEnabled(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, SDL_bool enabled)
{
int i;
int result = -1;
for (i = 0; i < device->num_children; ++i) {
SDL_HIDAPI_Device *child = device->children[i];
if (child->driver->SetJoystickSensorsEnabled(child, joystick, enabled) == 0) {
result = 0;
}
}
return result;
}
static SDL_bool HIDAPI_DriverCombined_UpdateDevice(SDL_HIDAPI_Device *device)
{
int i;
int result = SDL_TRUE;
for (i = 0; i < device->num_children; ++i) {
SDL_HIDAPI_Device *child = device->children[i];
if (!child->driver->UpdateDevice(child)) {
result = SDL_FALSE;
}
}
return result;
}
static void HIDAPI_DriverCombined_CloseJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
{
int i;
for (i = 0; i < device->num_children; ++i) {
SDL_HIDAPI_Device *child = device->children[i];
child->driver->CloseJoystick(child, joystick);
}
}
static void HIDAPI_DriverCombined_FreeDevice(SDL_HIDAPI_Device *device)
{
}
SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverCombined = {
"SDL_JOYSTICK_HIDAPI_COMBINED",
SDL_TRUE,
HIDAPI_DriverCombined_RegisterHints,
HIDAPI_DriverCombined_UnregisterHints,
HIDAPI_DriverCombined_IsEnabled,
HIDAPI_DriverCombined_IsSupportedDevice,
HIDAPI_DriverCombined_InitDevice,
HIDAPI_DriverCombined_GetDevicePlayerIndex,
HIDAPI_DriverCombined_SetDevicePlayerIndex,
HIDAPI_DriverCombined_UpdateDevice,
HIDAPI_DriverCombined_OpenJoystick,
HIDAPI_DriverCombined_RumbleJoystick,
HIDAPI_DriverCombined_RumbleJoystickTriggers,
HIDAPI_DriverCombined_GetJoystickCapabilities,
HIDAPI_DriverCombined_SetJoystickLED,
HIDAPI_DriverCombined_SendJoystickEffect,
HIDAPI_DriverCombined_SetJoystickSensorsEnabled,
HIDAPI_DriverCombined_CloseJoystick,
HIDAPI_DriverCombined_FreeDevice,
};
#endif /* SDL_JOYSTICK_HIDAPI */

View File

@@ -0,0 +1,556 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 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_HIDAPI
#include "../../SDL_hints_c.h"
#include "../SDL_sysjoystick.h"
#include "SDL_hidapijoystick_c.h"
#include "SDL_hidapi_rumble.h"
#include "../../hidapi/SDL_hidapi_c.h"
#ifdef SDL_JOYSTICK_HIDAPI_GAMECUBE
/* Define this if you want to log all packets from the controller */
/*#define DEBUG_GAMECUBE_PROTOCOL*/
#define MAX_CONTROLLERS 4
typedef struct
{
SDL_bool pc_mode;
SDL_JoystickID joysticks[MAX_CONTROLLERS];
Uint8 wireless[MAX_CONTROLLERS];
Uint8 min_axis[MAX_CONTROLLERS * SDL_GAMEPAD_AXIS_MAX];
Uint8 max_axis[MAX_CONTROLLERS * SDL_GAMEPAD_AXIS_MAX];
Uint8 rumbleAllowed[MAX_CONTROLLERS];
Uint8 rumble[1 + MAX_CONTROLLERS];
/* Without this variable, hid_write starts to lag a TON */
SDL_bool rumbleUpdate;
SDL_bool m_bUseButtonLabels;
SDL_bool useRumbleBrake;
} SDL_DriverGameCube_Context;
static void HIDAPI_DriverGameCube_RegisterHints(SDL_HintCallback callback, void *userdata)
{
SDL_AddHintCallback(SDL_HINT_JOYSTICK_HIDAPI_GAMECUBE, callback, userdata);
}
static void HIDAPI_DriverGameCube_UnregisterHints(SDL_HintCallback callback, void *userdata)
{
SDL_DelHintCallback(SDL_HINT_JOYSTICK_HIDAPI_GAMECUBE, callback, userdata);
}
static SDL_bool HIDAPI_DriverGameCube_IsEnabled(void)
{
return SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI_GAMECUBE,
SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI,
SDL_HIDAPI_DEFAULT));
}
static SDL_bool HIDAPI_DriverGameCube_IsSupportedDevice(SDL_HIDAPI_Device *device, const char *name, SDL_GamepadType type, Uint16 vendor_id, Uint16 product_id, Uint16 version, int interface_number, int interface_class, int interface_subclass, int interface_protocol)
{
if (vendor_id == USB_VENDOR_NINTENDO && product_id == USB_PRODUCT_NINTENDO_GAMECUBE_ADAPTER) {
/* Nintendo Co., Ltd. Wii U GameCube Controller Adapter */
return SDL_TRUE;
}
if (vendor_id == USB_VENDOR_DRAGONRISE && product_id == USB_PRODUCT_EVORETRO_GAMECUBE_ADAPTER) {
/* EVORETRO GameCube Controller Adapter */
return SDL_TRUE;
}
return SDL_FALSE;
}
static void ResetAxisRange(SDL_DriverGameCube_Context *ctx, int joystick_index)
{
SDL_memset(&ctx->min_axis[joystick_index * SDL_GAMEPAD_AXIS_MAX], 128 - 88, SDL_GAMEPAD_AXIS_MAX);
SDL_memset(&ctx->max_axis[joystick_index * SDL_GAMEPAD_AXIS_MAX], 128 + 88, SDL_GAMEPAD_AXIS_MAX);
/* Trigger axes may have a higher resting value */
ctx->min_axis[joystick_index * SDL_GAMEPAD_AXIS_MAX + SDL_GAMEPAD_AXIS_LEFT_TRIGGER] = 40;
ctx->min_axis[joystick_index * SDL_GAMEPAD_AXIS_MAX + SDL_GAMEPAD_AXIS_RIGHT_TRIGGER] = 40;
}
static void SDLCALL SDL_GameControllerButtonReportingHintChanged(void *userdata, const char *name, const char *oldValue, const char *hint)
{
SDL_DriverGameCube_Context *ctx = (SDL_DriverGameCube_Context *)userdata;
ctx->m_bUseButtonLabels = SDL_GetStringBoolean(hint, SDL_TRUE);
}
static void SDLCALL SDL_JoystickGameCubeRumbleBrakeHintChanged(void *userdata, const char *name, const char *oldValue, const char *hint)
{
if (hint) {
SDL_DriverGameCube_Context *ctx = (SDL_DriverGameCube_Context *)userdata;
ctx->useRumbleBrake = SDL_GetStringBoolean(hint, SDL_FALSE);
}
}
static Uint8 RemapButton(SDL_DriverGameCube_Context *ctx, Uint8 button)
{
if (!ctx->m_bUseButtonLabels) {
/* Use button positions */
switch (button) {
case SDL_GAMEPAD_BUTTON_B:
return SDL_GAMEPAD_BUTTON_X;
case SDL_GAMEPAD_BUTTON_X:
return SDL_GAMEPAD_BUTTON_B;
default:
break;
}
}
return button;
}
static SDL_bool HIDAPI_DriverGameCube_InitDevice(SDL_HIDAPI_Device *device)
{
SDL_DriverGameCube_Context *ctx;
Uint8 packet[37];
Uint8 *curSlot;
Uint8 i;
int size;
Uint8 initMagic = 0x13;
Uint8 rumbleMagic = 0x11;
#ifdef HAVE_ENABLE_GAMECUBE_ADAPTORS
SDL_EnableGameCubeAdaptors();
#endif
ctx = (SDL_DriverGameCube_Context *)SDL_calloc(1, sizeof(*ctx));
if (ctx == NULL) {
SDL_OutOfMemory();
return SDL_FALSE;
}
device->context = ctx;
ctx->joysticks[0] = 0;
ctx->joysticks[1] = 0;
ctx->joysticks[2] = 0;
ctx->joysticks[3] = 0;
ctx->rumble[0] = rumbleMagic;
ctx->useRumbleBrake = SDL_FALSE;
if (device->vendor_id != USB_VENDOR_NINTENDO) {
ctx->pc_mode = SDL_TRUE;
}
if (ctx->pc_mode) {
for (i = 0; i < MAX_CONTROLLERS; ++i) {
ResetAxisRange(ctx, i);
HIDAPI_JoystickConnected(device, &ctx->joysticks[i]);
}
} else {
/* This is all that's needed to initialize the device. Really! */
if (SDL_hid_write(device->dev, &initMagic, sizeof(initMagic)) != sizeof(initMagic)) {
SDL_LogDebug(SDL_LOG_CATEGORY_INPUT,
"HIDAPI_DriverGameCube_InitDevice(): Couldn't initialize WUP-028");
return SDL_FALSE;
}
/* Wait for the adapter to initialize */
SDL_Delay(10);
/* Add all the applicable joysticks */
while ((size = SDL_hid_read_timeout(device->dev, packet, sizeof(packet), 0)) > 0) {
#ifdef DEBUG_GAMECUBE_PROTOCOL
HIDAPI_DumpPacket("Nintendo GameCube packet: size = %d", packet, size);
#endif
if (size < 37 || packet[0] != 0x21) {
continue; /* Nothing to do yet...? */
}
/* Go through all 4 slots */
curSlot = packet + 1;
for (i = 0; i < MAX_CONTROLLERS; i += 1, curSlot += 9) {
ctx->wireless[i] = (curSlot[0] & 0x20) != 0;
/* Only allow rumble if the adapter's second USB cable is connected */
ctx->rumbleAllowed[i] = (curSlot[0] & 0x04) && !ctx->wireless[i];
if (curSlot[0] & 0x30) { /* 0x10 - Wired, 0x20 - Wireless */
if (ctx->joysticks[i] == 0) {
ResetAxisRange(ctx, i);
HIDAPI_JoystickConnected(device, &ctx->joysticks[i]);
}
} else {
if (ctx->joysticks[i] != 0) {
HIDAPI_JoystickDisconnected(device, ctx->joysticks[i]);
ctx->joysticks[i] = 0;
}
continue;
}
}
}
}
SDL_AddHintCallback(SDL_HINT_JOYSTICK_GAMECUBE_RUMBLE_BRAKE,
SDL_JoystickGameCubeRumbleBrakeHintChanged, ctx);
SDL_AddHintCallback(SDL_HINT_GAMECONTROLLER_USE_BUTTON_LABELS,
SDL_GameControllerButtonReportingHintChanged, ctx);
HIDAPI_SetDeviceName(device, "Nintendo GameCube Controller");
return SDL_TRUE;
}
static int HIDAPI_DriverGameCube_GetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id)
{
SDL_DriverGameCube_Context *ctx = (SDL_DriverGameCube_Context *)device->context;
Uint8 i;
for (i = 0; i < 4; ++i) {
if (instance_id == ctx->joysticks[i]) {
return i;
}
}
return -1;
}
static void HIDAPI_DriverGameCube_SetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id, int player_index)
{
}
static void HIDAPI_DriverGameCube_HandleJoystickPacket(SDL_HIDAPI_Device *device, SDL_DriverGameCube_Context *ctx, const Uint8 *packet, int size)
{
SDL_Joystick *joystick;
Uint8 i, v;
Sint16 axis_value;
Uint64 timestamp = SDL_GetTicksNS();
if (size != 10) {
return; /* How do we handle this packet? */
}
i = packet[0] - 1;
if (i >= MAX_CONTROLLERS) {
return; /* How do we handle this packet? */
}
joystick = SDL_GetJoystickFromInstanceID(ctx->joysticks[i]);
if (joystick == NULL) {
/* Hasn't been opened yet, skip */
return;
}
#define READ_BUTTON(off, flag, button) \
SDL_SendJoystickButton( \
timestamp, \
joystick, \
RemapButton(ctx, button), \
(packet[off] & flag) ? SDL_PRESSED : SDL_RELEASED);
READ_BUTTON(1, 0x02, 0) /* A */
READ_BUTTON(1, 0x04, 1) /* B */
READ_BUTTON(1, 0x01, 2) /* X */
READ_BUTTON(1, 0x08, 3) /* Y */
READ_BUTTON(2, 0x80, 4) /* DPAD_LEFT */
READ_BUTTON(2, 0x20, 5) /* DPAD_RIGHT */
READ_BUTTON(2, 0x40, 6) /* DPAD_DOWN */
READ_BUTTON(2, 0x10, 7) /* DPAD_UP */
READ_BUTTON(2, 0x02, 8) /* START */
READ_BUTTON(1, 0x80, 9) /* RIGHTSHOULDER */
/* These two buttons are for the bottoms of the analog triggers.
* More than likely, you're going to want to read the axes instead!
* -flibit
*/
READ_BUTTON(1, 0x20, 10) /* TRIGGERRIGHT */
READ_BUTTON(1, 0x10, 11) /* TRIGGERLEFT */
#undef READ_BUTTON
#define READ_AXIS(off, axis, invert) \
v = invert ? (0xff - packet[off]) : packet[off]; \
if (v < ctx->min_axis[i * SDL_GAMEPAD_AXIS_MAX + axis]) \
ctx->min_axis[i * SDL_GAMEPAD_AXIS_MAX + axis] = v; \
if (v > ctx->max_axis[i * SDL_GAMEPAD_AXIS_MAX + axis]) \
ctx->max_axis[i * SDL_GAMEPAD_AXIS_MAX + axis] = v; \
axis_value = (Sint16)HIDAPI_RemapVal(v, ctx->min_axis[i * SDL_GAMEPAD_AXIS_MAX + axis], ctx->max_axis[i * SDL_GAMEPAD_AXIS_MAX + axis], SDL_MIN_SINT16, SDL_MAX_SINT16); \
SDL_SendJoystickAxis( \
timestamp, \
joystick, \
axis, axis_value);
READ_AXIS(3, SDL_GAMEPAD_AXIS_LEFTX, 0)
READ_AXIS(4, SDL_GAMEPAD_AXIS_LEFTY, 0)
READ_AXIS(6, SDL_GAMEPAD_AXIS_RIGHTX, 1)
READ_AXIS(5, SDL_GAMEPAD_AXIS_RIGHTY, 1)
READ_AXIS(7, SDL_GAMEPAD_AXIS_LEFT_TRIGGER, 0)
READ_AXIS(8, SDL_GAMEPAD_AXIS_RIGHT_TRIGGER, 0)
#undef READ_AXIS
}
static void HIDAPI_DriverGameCube_HandleNintendoPacket(SDL_HIDAPI_Device *device, SDL_DriverGameCube_Context *ctx, Uint8 *packet, int size)
{
SDL_Joystick *joystick;
Uint8 *curSlot;
Uint8 i;
Sint16 axis_value;
Uint64 timestamp = SDL_GetTicksNS();
if (size < 37 || packet[0] != 0x21) {
return; /* Nothing to do right now...? */
}
/* Go through all 4 slots */
curSlot = packet + 1;
for (i = 0; i < MAX_CONTROLLERS; i += 1, curSlot += 9) {
ctx->wireless[i] = (curSlot[0] & 0x20) != 0;
/* Only allow rumble if the adapter's second USB cable is connected */
ctx->rumbleAllowed[i] = (curSlot[0] & 0x04) && !ctx->wireless[i];
if (curSlot[0] & 0x30) { /* 0x10 - Wired, 0x20 - Wireless */
if (ctx->joysticks[i] == 0) {
ResetAxisRange(ctx, i);
HIDAPI_JoystickConnected(device, &ctx->joysticks[i]);
}
joystick = SDL_GetJoystickFromInstanceID(ctx->joysticks[i]);
/* Hasn't been opened yet, skip */
if (joystick == NULL) {
continue;
}
} else {
if (ctx->joysticks[i] != 0) {
HIDAPI_JoystickDisconnected(device, ctx->joysticks[i]);
ctx->joysticks[i] = 0;
}
continue;
}
#define READ_BUTTON(off, flag, button) \
SDL_SendJoystickButton( \
timestamp, \
joystick, \
RemapButton(ctx, button), \
(curSlot[off] & flag) ? SDL_PRESSED : SDL_RELEASED);
READ_BUTTON(1, 0x01, 0) /* A */
READ_BUTTON(1, 0x04, 1) /* B */
READ_BUTTON(1, 0x02, 2) /* X */
READ_BUTTON(1, 0x08, 3) /* Y */
READ_BUTTON(1, 0x10, 4) /* DPAD_LEFT */
READ_BUTTON(1, 0x20, 5) /* DPAD_RIGHT */
READ_BUTTON(1, 0x40, 6) /* DPAD_DOWN */
READ_BUTTON(1, 0x80, 7) /* DPAD_UP */
READ_BUTTON(2, 0x01, 8) /* START */
READ_BUTTON(2, 0x02, 9) /* RIGHTSHOULDER */
/* These two buttons are for the bottoms of the analog triggers.
* More than likely, you're going to want to read the axes instead!
* -flibit
*/
READ_BUTTON(2, 0x04, 10) /* TRIGGERRIGHT */
READ_BUTTON(2, 0x08, 11) /* TRIGGERLEFT */
#undef READ_BUTTON
#define READ_AXIS(off, axis) \
if (curSlot[off] < ctx->min_axis[i * SDL_GAMEPAD_AXIS_MAX + axis]) \
ctx->min_axis[i * SDL_GAMEPAD_AXIS_MAX + axis] = curSlot[off]; \
if (curSlot[off] > ctx->max_axis[i * SDL_GAMEPAD_AXIS_MAX + axis]) \
ctx->max_axis[i * SDL_GAMEPAD_AXIS_MAX + axis] = curSlot[off]; \
axis_value = (Sint16)HIDAPI_RemapVal(curSlot[off], ctx->min_axis[i * SDL_GAMEPAD_AXIS_MAX + axis], ctx->max_axis[i * SDL_GAMEPAD_AXIS_MAX + axis], SDL_MIN_SINT16, SDL_MAX_SINT16); \
SDL_SendJoystickAxis( \
timestamp, \
joystick, \
axis, axis_value);
READ_AXIS(3, SDL_GAMEPAD_AXIS_LEFTX)
READ_AXIS(4, SDL_GAMEPAD_AXIS_LEFTY)
READ_AXIS(5, SDL_GAMEPAD_AXIS_RIGHTX)
READ_AXIS(6, SDL_GAMEPAD_AXIS_RIGHTY)
READ_AXIS(7, SDL_GAMEPAD_AXIS_LEFT_TRIGGER)
READ_AXIS(8, SDL_GAMEPAD_AXIS_RIGHT_TRIGGER)
#undef READ_AXIS
}
}
static SDL_bool HIDAPI_DriverGameCube_UpdateDevice(SDL_HIDAPI_Device *device)
{
SDL_DriverGameCube_Context *ctx = (SDL_DriverGameCube_Context *)device->context;
Uint8 packet[USB_PACKET_LENGTH];
int size;
/* Read input packet */
while ((size = SDL_hid_read_timeout(device->dev, packet, sizeof(packet), 0)) > 0) {
#ifdef DEBUG_GAMECUBE_PROTOCOL
// HIDAPI_DumpPacket("Nintendo GameCube packet: size = %d", packet, size);
#endif
if (ctx->pc_mode) {
HIDAPI_DriverGameCube_HandleJoystickPacket(device, ctx, packet, size);
} else {
HIDAPI_DriverGameCube_HandleNintendoPacket(device, ctx, packet, size);
}
}
/* Write rumble packet */
if (ctx->rumbleUpdate) {
SDL_HIDAPI_SendRumble(device, ctx->rumble, sizeof(ctx->rumble));
ctx->rumbleUpdate = SDL_FALSE;
}
/* If we got here, nothing bad happened! */
return SDL_TRUE;
}
static SDL_bool HIDAPI_DriverGameCube_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
{
SDL_DriverGameCube_Context *ctx = (SDL_DriverGameCube_Context *)device->context;
Uint8 i;
SDL_AssertJoysticksLocked();
for (i = 0; i < MAX_CONTROLLERS; i += 1) {
if (joystick->instance_id == ctx->joysticks[i]) {
joystick->nbuttons = 12;
joystick->naxes = SDL_GAMEPAD_AXIS_MAX;
joystick->epowerlevel = ctx->wireless[i] ? SDL_JOYSTICK_POWER_UNKNOWN : SDL_JOYSTICK_POWER_WIRED;
return SDL_TRUE;
}
}
return SDL_FALSE; /* Should never get here! */
}
static int HIDAPI_DriverGameCube_RumbleJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble)
{
SDL_DriverGameCube_Context *ctx = (SDL_DriverGameCube_Context *)device->context;
Uint8 i, val;
SDL_AssertJoysticksLocked();
if (ctx->pc_mode) {
return SDL_Unsupported();
}
for (i = 0; i < MAX_CONTROLLERS; i += 1) {
if (joystick->instance_id == ctx->joysticks[i]) {
if (ctx->wireless[i]) {
return SDL_SetError("Nintendo GameCube WaveBird controllers do not support rumble");
}
if (!ctx->rumbleAllowed[i]) {
return SDL_SetError("Second USB cable for WUP-028 not connected");
}
if (ctx->useRumbleBrake) {
if (low_frequency_rumble == 0 && high_frequency_rumble > 0) {
val = 0; /* if only low is 0 we want to do a regular stop*/
} else if (low_frequency_rumble == 0 && high_frequency_rumble == 0) {
val = 2; /* if both frequencies are 0 we want to do a hard stop */
} else {
val = 1; /* normal rumble */
}
} else {
val = (low_frequency_rumble > 0 || high_frequency_rumble > 0);
}
if (val != ctx->rumble[i + 1]) {
ctx->rumble[i + 1] = val;
ctx->rumbleUpdate = SDL_TRUE;
}
return 0;
}
}
/* Should never get here! */
return SDL_SetError("Couldn't find joystick");
}
static int HIDAPI_DriverGameCube_RumbleJoystickTriggers(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint16 left_rumble, Uint16 right_rumble)
{
return SDL_Unsupported();
}
static Uint32 HIDAPI_DriverGameCube_GetJoystickCapabilities(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
{
SDL_DriverGameCube_Context *ctx = (SDL_DriverGameCube_Context *)device->context;
Uint32 result = 0;
SDL_AssertJoysticksLocked();
if (!ctx->pc_mode) {
Uint8 i;
for (i = 0; i < MAX_CONTROLLERS; i += 1) {
if (joystick->instance_id == ctx->joysticks[i]) {
if (!ctx->wireless[i] && ctx->rumbleAllowed[i]) {
result |= SDL_JOYCAP_RUMBLE;
break;
}
}
}
}
return result;
}
static int HIDAPI_DriverGameCube_SetJoystickLED(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue)
{
return SDL_Unsupported();
}
static int HIDAPI_DriverGameCube_SendJoystickEffect(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, const void *data, int size)
{
return SDL_Unsupported();
}
static int HIDAPI_DriverGameCube_SetJoystickSensorsEnabled(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, SDL_bool enabled)
{
return SDL_Unsupported();
}
static void HIDAPI_DriverGameCube_CloseJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
{
SDL_DriverGameCube_Context *ctx = (SDL_DriverGameCube_Context *)device->context;
/* Stop rumble activity */
if (ctx->rumbleUpdate) {
SDL_HIDAPI_SendRumble(device, ctx->rumble, sizeof(ctx->rumble));
ctx->rumbleUpdate = SDL_FALSE;
}
}
static void HIDAPI_DriverGameCube_FreeDevice(SDL_HIDAPI_Device *device)
{
SDL_DriverGameCube_Context *ctx = (SDL_DriverGameCube_Context *)device->context;
SDL_DelHintCallback(SDL_HINT_GAMECONTROLLER_USE_BUTTON_LABELS,
SDL_GameControllerButtonReportingHintChanged, ctx);
SDL_DelHintCallback(SDL_HINT_JOYSTICK_GAMECUBE_RUMBLE_BRAKE,
SDL_JoystickGameCubeRumbleBrakeHintChanged, ctx);
}
SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverGameCube = {
SDL_HINT_JOYSTICK_HIDAPI_GAMECUBE,
SDL_TRUE,
HIDAPI_DriverGameCube_RegisterHints,
HIDAPI_DriverGameCube_UnregisterHints,
HIDAPI_DriverGameCube_IsEnabled,
HIDAPI_DriverGameCube_IsSupportedDevice,
HIDAPI_DriverGameCube_InitDevice,
HIDAPI_DriverGameCube_GetDevicePlayerIndex,
HIDAPI_DriverGameCube_SetDevicePlayerIndex,
HIDAPI_DriverGameCube_UpdateDevice,
HIDAPI_DriverGameCube_OpenJoystick,
HIDAPI_DriverGameCube_RumbleJoystick,
HIDAPI_DriverGameCube_RumbleJoystickTriggers,
HIDAPI_DriverGameCube_GetJoystickCapabilities,
HIDAPI_DriverGameCube_SetJoystickLED,
HIDAPI_DriverGameCube_SendJoystickEffect,
HIDAPI_DriverGameCube_SetJoystickSensorsEnabled,
HIDAPI_DriverGameCube_CloseJoystick,
HIDAPI_DriverGameCube_FreeDevice,
};
#endif /* SDL_JOYSTICK_HIDAPI_GAMECUBE */
#endif /* SDL_JOYSTICK_HIDAPI */

View File

@@ -0,0 +1,449 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 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_HIDAPI
#include "../SDL_sysjoystick.h"
#include "SDL_hidapijoystick_c.h"
#include "SDL_hidapi_rumble.h"
#ifdef SDL_JOYSTICK_HIDAPI_LUNA
/* Define this if you want to log all packets from the controller */
/*#define DEBUG_LUNA_PROTOCOL*/
/* Sending rumble on macOS blocks for a long time and eventually fails */
#ifndef __MACOS__
#define ENABLE_LUNA_BLUETOOTH_RUMBLE
#endif
enum
{
SDL_CONTROLLER_BUTTON_LUNA_MIC = 15,
SDL_CONTROLLER_NUM_LUNA_BUTTONS,
};
typedef struct
{
Uint8 last_state[USB_PACKET_LENGTH];
} SDL_DriverLuna_Context;
static void HIDAPI_DriverLuna_RegisterHints(SDL_HintCallback callback, void *userdata)
{
SDL_AddHintCallback(SDL_HINT_JOYSTICK_HIDAPI_LUNA, callback, userdata);
}
static void HIDAPI_DriverLuna_UnregisterHints(SDL_HintCallback callback, void *userdata)
{
SDL_DelHintCallback(SDL_HINT_JOYSTICK_HIDAPI_LUNA, callback, userdata);
}
static SDL_bool HIDAPI_DriverLuna_IsEnabled(void)
{
return SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI_LUNA, SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI, SDL_HIDAPI_DEFAULT));
}
static SDL_bool HIDAPI_DriverLuna_IsSupportedDevice(SDL_HIDAPI_Device *device, const char *name, SDL_GamepadType type, Uint16 vendor_id, Uint16 product_id, Uint16 version, int interface_number, int interface_class, int interface_subclass, int interface_protocol)
{
return SDL_IsJoystickAmazonLunaController(vendor_id, product_id);
}
static SDL_bool HIDAPI_DriverLuna_InitDevice(SDL_HIDAPI_Device *device)
{
SDL_DriverLuna_Context *ctx;
ctx = (SDL_DriverLuna_Context *)SDL_calloc(1, sizeof(*ctx));
if (ctx == NULL) {
SDL_OutOfMemory();
return SDL_FALSE;
}
device->context = ctx;
HIDAPI_SetDeviceName(device, "Amazon Luna Controller");
return HIDAPI_JoystickConnected(device, NULL);
}
static int HIDAPI_DriverLuna_GetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id)
{
return -1;
}
static void HIDAPI_DriverLuna_SetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id, int player_index)
{
}
static SDL_bool HIDAPI_DriverLuna_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
{
SDL_DriverLuna_Context *ctx = (SDL_DriverLuna_Context *)device->context;
SDL_AssertJoysticksLocked();
SDL_zeroa(ctx->last_state);
/* Initialize the joystick capabilities */
joystick->nbuttons = SDL_CONTROLLER_NUM_LUNA_BUTTONS;
joystick->naxes = SDL_GAMEPAD_AXIS_MAX;
joystick->epowerlevel = SDL_JOYSTICK_POWER_FULL;
return SDL_TRUE;
}
static int HIDAPI_DriverLuna_RumbleJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble)
{
#ifdef ENABLE_LUNA_BLUETOOTH_RUMBLE
if (device->product_id == BLUETOOTH_PRODUCT_LUNA_CONTROLLER) {
/* Same packet as on Xbox One controllers connected via Bluetooth */
Uint8 rumble_packet[] = { 0x03, 0x0F, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xEB };
/* Magnitude is 1..100 so scale the 16-bit input here */
rumble_packet[4] = (Uint8)(low_frequency_rumble / 655);
rumble_packet[5] = (Uint8)(high_frequency_rumble / 655);
if (SDL_HIDAPI_SendRumble(device, rumble_packet, sizeof(rumble_packet)) != sizeof(rumble_packet)) {
return SDL_SetError("Couldn't send rumble packet");
}
return 0;
}
#endif /* ENABLE_LUNA_BLUETOOTH_RUMBLE */
/* There is currently no rumble packet over USB */
return SDL_Unsupported();
}
static int HIDAPI_DriverLuna_RumbleJoystickTriggers(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint16 left_rumble, Uint16 right_rumble)
{
return SDL_Unsupported();
}
static Uint32 HIDAPI_DriverLuna_GetJoystickCapabilities(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
{
Uint32 result = 0;
#ifdef ENABLE_LUNA_BLUETOOTH_RUMBLE
if (device->product_id == BLUETOOTH_PRODUCT_LUNA_CONTROLLER) {
result |= SDL_JOYCAP_RUMBLE;
}
#endif
return result;
}
static int HIDAPI_DriverLuna_SetJoystickLED(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue)
{
return SDL_Unsupported();
}
static int HIDAPI_DriverLuna_SendJoystickEffect(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, const void *data, int size)
{
return SDL_Unsupported();
}
static int HIDAPI_DriverLuna_SetJoystickSensorsEnabled(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, SDL_bool enabled)
{
return SDL_Unsupported();
}
static void HIDAPI_DriverLuna_HandleUSBStatePacket(SDL_Joystick *joystick, SDL_DriverLuna_Context *ctx, Uint8 *data, int size)
{
Uint64 timestamp = SDL_GetTicksNS();
if (ctx->last_state[1] != data[1]) {
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_A, (data[1] & 0x01) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_B, (data[1] & 0x02) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_X, (data[1] & 0x04) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_Y, (data[1] & 0x08) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_LEFT_SHOULDER, (data[1] & 0x10) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER, (data[1] & 0x20) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_BACK, (data[1] & 0x40) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_START, (data[1] & 0x80) ? SDL_PRESSED : SDL_RELEASED);
}
if (ctx->last_state[2] != data[2]) {
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_GUIDE, (data[2] & 0x01) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_CONTROLLER_BUTTON_LUNA_MIC, (data[2] & 0x02) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_LEFT_STICK, (data[2] & 0x04) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_RIGHT_STICK, (data[2] & 0x08) ? SDL_PRESSED : SDL_RELEASED);
}
if (ctx->last_state[3] != data[3]) {
SDL_bool dpad_up = SDL_FALSE;
SDL_bool dpad_down = SDL_FALSE;
SDL_bool dpad_left = SDL_FALSE;
SDL_bool dpad_right = SDL_FALSE;
switch (data[3] & 0xf) {
case 0:
dpad_up = SDL_TRUE;
break;
case 1:
dpad_up = SDL_TRUE;
dpad_right = SDL_TRUE;
break;
case 2:
dpad_right = SDL_TRUE;
break;
case 3:
dpad_right = SDL_TRUE;
dpad_down = SDL_TRUE;
break;
case 4:
dpad_down = SDL_TRUE;
break;
case 5:
dpad_left = SDL_TRUE;
dpad_down = SDL_TRUE;
break;
case 6:
dpad_left = SDL_TRUE;
break;
case 7:
dpad_up = SDL_TRUE;
dpad_left = SDL_TRUE;
break;
default:
break;
}
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_DPAD_DOWN, dpad_down);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_DPAD_UP, dpad_up);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_DPAD_RIGHT, dpad_right);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_DPAD_LEFT, dpad_left);
}
#define READ_STICK_AXIS(offset) \
(data[offset] == 0x7f ? 0 : (Sint16)HIDAPI_RemapVal((float)data[offset], 0x00, 0xff, SDL_MIN_SINT16, SDL_MAX_SINT16))
{
Sint16 axis = READ_STICK_AXIS(4);
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFTX, axis);
axis = READ_STICK_AXIS(5);
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFTY, axis);
axis = READ_STICK_AXIS(6);
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTX, axis);
axis = READ_STICK_AXIS(7);
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTY, axis);
}
#undef READ_STICK_AXIS
#define READ_TRIGGER_AXIS(offset) \
(Sint16) HIDAPI_RemapVal((float)data[offset], 0x00, 0xff, SDL_MIN_SINT16, SDL_MAX_SINT16)
{
Sint16 axis = READ_TRIGGER_AXIS(8);
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFT_TRIGGER, axis);
axis = READ_TRIGGER_AXIS(9);
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHT_TRIGGER, axis);
}
#undef READ_TRIGGER_AXIS
SDL_memcpy(ctx->last_state, data, SDL_min(size, sizeof(ctx->last_state)));
}
static void HIDAPI_DriverLuna_HandleBluetoothStatePacket(SDL_Joystick *joystick, SDL_DriverLuna_Context *ctx, Uint8 *data, int size)
{
Uint64 timestamp = SDL_GetTicksNS();
if (size >= 2 && data[0] == 0x02) {
/* Home button has dedicated report */
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_GUIDE, (data[1] & 0x1) ? SDL_PRESSED : SDL_RELEASED);
return;
}
if (size >= 2 && data[0] == 0x04) {
/* Battery level report */
int level = data[1] * 100 / 0xFF;
if (level == 0) {
SDL_SendJoystickBatteryLevel(joystick, SDL_JOYSTICK_POWER_EMPTY);
} else if (level <= 20) {
SDL_SendJoystickBatteryLevel(joystick, SDL_JOYSTICK_POWER_LOW);
} else if (level <= 70) {
SDL_SendJoystickBatteryLevel(joystick, SDL_JOYSTICK_POWER_MEDIUM);
} else {
SDL_SendJoystickBatteryLevel(joystick, SDL_JOYSTICK_POWER_FULL);
}
return;
}
if (size < 17 || data[0] != 0x01) {
/* We don't know how to handle this report */
return;
}
if (ctx->last_state[13] != data[13]) {
SDL_bool dpad_up = SDL_FALSE;
SDL_bool dpad_down = SDL_FALSE;
SDL_bool dpad_left = SDL_FALSE;
SDL_bool dpad_right = SDL_FALSE;
switch (data[13] & 0xf) {
case 1:
dpad_up = SDL_TRUE;
break;
case 2:
dpad_up = SDL_TRUE;
dpad_right = SDL_TRUE;
break;
case 3:
dpad_right = SDL_TRUE;
break;
case 4:
dpad_right = SDL_TRUE;
dpad_down = SDL_TRUE;
break;
case 5:
dpad_down = SDL_TRUE;
break;
case 6:
dpad_left = SDL_TRUE;
dpad_down = SDL_TRUE;
break;
case 7:
dpad_left = SDL_TRUE;
break;
case 8:
dpad_up = SDL_TRUE;
dpad_left = SDL_TRUE;
break;
default:
break;
}
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_DPAD_DOWN, dpad_down);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_DPAD_UP, dpad_up);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_DPAD_RIGHT, dpad_right);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_DPAD_LEFT, dpad_left);
}
if (ctx->last_state[14] != data[14]) {
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_A, (data[14] & 0x01) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_B, (data[14] & 0x02) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_X, (data[14] & 0x08) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_Y, (data[14] & 0x10) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_LEFT_SHOULDER, (data[14] & 0x40) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER, (data[14] & 0x80) ? SDL_PRESSED : SDL_RELEASED);
}
if (ctx->last_state[15] != data[15]) {
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_START, (data[15] & 0x08) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_LEFT_STICK, (data[15] & 0x20) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_RIGHT_STICK, (data[15] & 0x40) ? SDL_PRESSED : SDL_RELEASED);
}
if (ctx->last_state[16] != data[16]) {
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_BACK, (data[16] & 0x01) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_CONTROLLER_BUTTON_LUNA_MIC, (data[16] & 0x02) ? SDL_PRESSED : SDL_RELEASED);
}
#define READ_STICK_AXIS(offset) \
(data[offset] == 0x7f ? 0 : (Sint16)HIDAPI_RemapVal((float)data[offset], 0x00, 0xff, SDL_MIN_SINT16, SDL_MAX_SINT16))
{
Sint16 axis = READ_STICK_AXIS(2);
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFTX, axis);
axis = READ_STICK_AXIS(4);
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFTY, axis);
axis = READ_STICK_AXIS(6);
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTX, axis);
axis = READ_STICK_AXIS(8);
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTY, axis);
}
#undef READ_STICK_AXIS
#define READ_TRIGGER_AXIS(offset) \
(Sint16) HIDAPI_RemapVal((float)((int)(((data[offset] | (data[offset + 1] << 8)) & 0x3ff) - 0x200)), 0x00 - 0x200, 0x3ff - 0x200, SDL_MIN_SINT16, SDL_MAX_SINT16)
{
Sint16 axis = READ_TRIGGER_AXIS(9);
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFT_TRIGGER, axis);
axis = READ_TRIGGER_AXIS(11);
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHT_TRIGGER, axis);
}
#undef READ_TRIGGER_AXIS
SDL_memcpy(ctx->last_state, data, SDL_min(size, sizeof(ctx->last_state)));
}
static SDL_bool HIDAPI_DriverLuna_UpdateDevice(SDL_HIDAPI_Device *device)
{
SDL_DriverLuna_Context *ctx = (SDL_DriverLuna_Context *)device->context;
SDL_Joystick *joystick = NULL;
Uint8 data[USB_PACKET_LENGTH];
int size = 0;
if (device->num_joysticks > 0) {
joystick = SDL_GetJoystickFromInstanceID(device->joysticks[0]);
} else {
return SDL_FALSE;
}
while ((size = SDL_hid_read_timeout(device->dev, data, sizeof(data), 0)) > 0) {
#ifdef DEBUG_LUNA_PROTOCOL
HIDAPI_DumpPacket("Amazon Luna packet: size = %d", data, size);
#endif
if (joystick == NULL) {
continue;
}
switch (size) {
case 10:
HIDAPI_DriverLuna_HandleUSBStatePacket(joystick, ctx, data, size);
break;
default:
HIDAPI_DriverLuna_HandleBluetoothStatePacket(joystick, ctx, data, size);
break;
}
}
if (size < 0) {
/* Read error, device is disconnected */
HIDAPI_JoystickDisconnected(device, device->joysticks[0]);
}
return size >= 0;
}
static void HIDAPI_DriverLuna_CloseJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
{
}
static void HIDAPI_DriverLuna_FreeDevice(SDL_HIDAPI_Device *device)
{
}
SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverLuna = {
SDL_HINT_JOYSTICK_HIDAPI_LUNA,
SDL_TRUE,
HIDAPI_DriverLuna_RegisterHints,
HIDAPI_DriverLuna_UnregisterHints,
HIDAPI_DriverLuna_IsEnabled,
HIDAPI_DriverLuna_IsSupportedDevice,
HIDAPI_DriverLuna_InitDevice,
HIDAPI_DriverLuna_GetDevicePlayerIndex,
HIDAPI_DriverLuna_SetDevicePlayerIndex,
HIDAPI_DriverLuna_UpdateDevice,
HIDAPI_DriverLuna_OpenJoystick,
HIDAPI_DriverLuna_RumbleJoystick,
HIDAPI_DriverLuna_RumbleJoystickTriggers,
HIDAPI_DriverLuna_GetJoystickCapabilities,
HIDAPI_DriverLuna_SetJoystickLED,
HIDAPI_DriverLuna_SendJoystickEffect,
HIDAPI_DriverLuna_SetJoystickSensorsEnabled,
HIDAPI_DriverLuna_CloseJoystick,
HIDAPI_DriverLuna_FreeDevice,
};
#endif /* SDL_JOYSTICK_HIDAPI_LUNA */
#endif /* SDL_JOYSTICK_HIDAPI */

View File

@@ -0,0 +1,49 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 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.
*/
/* These are values used in the controller type byte of the controller GUID */
/* These values come directly out of the hardware, so don't change them */
typedef enum
{
k_eSwitchDeviceInfoControllerType_Unknown = 0,
k_eSwitchDeviceInfoControllerType_JoyConLeft = 1,
k_eSwitchDeviceInfoControllerType_JoyConRight = 2,
k_eSwitchDeviceInfoControllerType_ProController = 3,
k_eSwitchDeviceInfoControllerType_LicProController = 6,
k_eSwitchDeviceInfoControllerType_HVCLeft = 7,
k_eSwitchDeviceInfoControllerType_HVCRight = 8,
k_eSwitchDeviceInfoControllerType_NESLeft = 9,
k_eSwitchDeviceInfoControllerType_NESRight = 10,
k_eSwitchDeviceInfoControllerType_SNES = 11,
k_eSwitchDeviceInfoControllerType_N64 = 12,
k_eSwitchDeviceInfoControllerType_SEGA_Genesis = 13,
} ESwitchDeviceInfoControllerType;
/* These values are used internally but can be updated as needed */
typedef enum
{
k_eWiiExtensionControllerType_Unknown = 0,
k_eWiiExtensionControllerType_None = 128,
k_eWiiExtensionControllerType_Nunchuk = 129,
k_eWiiExtensionControllerType_Gamepad = 130,
k_eWiiExtensionControllerType_WiiUPro = 131,
} EWiiExtensionControllerType;

View File

@@ -0,0 +1,993 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 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_HIDAPI
#include "../../SDL_hints_c.h"
#include "../SDL_sysjoystick.h"
#include "SDL_hidapijoystick_c.h"
#include "SDL_hidapi_rumble.h"
#ifdef SDL_JOYSTICK_HIDAPI_PS3
/* Define this if you want to log all packets from the controller */
/*#define DEBUG_PS3_PROTOCOL*/
#define LOAD16(A, B) (Sint16)((Uint16)(A) | (((Uint16)(B)) << 8))
typedef enum
{
k_EPS3ReportIdState = 1,
k_EPS3ReportIdEffects = 1,
} EPS3ReportId;
typedef struct
{
SDL_HIDAPI_Device *device;
SDL_Joystick *joystick;
SDL_bool is_shanwan;
SDL_bool report_sensors;
SDL_bool effects_updated;
int player_index;
Uint8 rumble_left;
Uint8 rumble_right;
Uint8 last_state[USB_PACKET_LENGTH];
} SDL_DriverPS3_Context;
static int HIDAPI_DriverPS3_SendJoystickEffect(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, const void *effect, int size);
static void HIDAPI_DriverPS3_RegisterHints(SDL_HintCallback callback, void *userdata)
{
SDL_AddHintCallback(SDL_HINT_JOYSTICK_HIDAPI_PS3, callback, userdata);
}
static void HIDAPI_DriverPS3_UnregisterHints(SDL_HintCallback callback, void *userdata)
{
SDL_DelHintCallback(SDL_HINT_JOYSTICK_HIDAPI_PS3, callback, userdata);
}
static SDL_bool HIDAPI_DriverPS3_IsEnabled(void)
{
SDL_bool default_value;
#ifdef __MACOS__
/* This works well on macOS */
default_value = SDL_TRUE;
#elif defined(__WINDOWS__)
/* You can't initialize the controller with the stock Windows drivers
* See https://github.com/ViGEm/DsHidMini as an alternative driver
*/
default_value = SDL_FALSE;
#elif defined(__LINUX__)
/* Linux drivers do a better job of managing the transition between
* USB and Bluetooth. There are also some quirks in communicating
* with PS3 controllers that have been implemented in SDL's hidapi
* for libusb, but are not possible to support using hidraw if the
* kernel doesn't already know about them.
*/
default_value = SDL_FALSE;
#else
/* Untested, default off */
default_value = SDL_FALSE;
#endif
if (default_value) {
default_value = SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI, SDL_HIDAPI_DEFAULT);
}
return SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI_PS3, default_value);
}
static SDL_bool HIDAPI_DriverPS3_IsSupportedDevice(SDL_HIDAPI_Device *device, const char *name, SDL_GamepadType type, Uint16 vendor_id, Uint16 product_id, Uint16 version, int interface_number, int interface_class, int interface_subclass, int interface_protocol)
{
if (vendor_id == USB_VENDOR_SONY && product_id == USB_PRODUCT_SONY_DS3) {
return SDL_TRUE;
}
if (vendor_id == USB_VENDOR_SHANWAN && product_id == USB_PRODUCT_SHANWAN_DS3) {
return SDL_TRUE;
}
return SDL_FALSE;
}
static int ReadFeatureReport(SDL_hid_device *dev, Uint8 report_id, Uint8 *report, size_t length)
{
SDL_memset(report, 0, length);
report[0] = report_id;
return SDL_hid_get_feature_report(dev, report, length);
}
static int SendFeatureReport(SDL_hid_device *dev, Uint8 *report, size_t length)
{
return SDL_hid_send_feature_report(dev, report, length);
}
static SDL_bool HIDAPI_DriverPS3_InitDevice(SDL_HIDAPI_Device *device)
{
SDL_DriverPS3_Context *ctx;
SDL_bool is_shanwan = SDL_FALSE;
if (device->vendor_id == USB_VENDOR_SONY &&
SDL_strncasecmp(device->name, "ShanWan", 7) == 0) {
is_shanwan = SDL_TRUE;
}
if (device->vendor_id == USB_VENDOR_SHANWAN ||
device->vendor_id == USB_VENDOR_SHANWAN_ALT) {
is_shanwan = SDL_TRUE;
}
ctx = (SDL_DriverPS3_Context *)SDL_calloc(1, sizeof(*ctx));
if (ctx == NULL) {
SDL_OutOfMemory();
return SDL_FALSE;
}
ctx->device = device;
ctx->is_shanwan = is_shanwan;
device->context = ctx;
/* Set the controller into report mode over Bluetooth */
if (device->is_bluetooth) {
Uint8 data[] = { 0xf4, 0x42, 0x03, 0x00, 0x00 };
SendFeatureReport(device->dev, data, sizeof(data));
}
/* Set the controller into report mode over USB */
if (!device->is_bluetooth) {
Uint8 data[USB_PACKET_LENGTH];
int size = ReadFeatureReport(device->dev, 0xf2, data, 17);
if (size < 0) {
SDL_LogDebug(SDL_LOG_CATEGORY_INPUT,
"HIDAPI_DriverPS3_InitDevice(): Couldn't read feature report 0xf2");
return SDL_FALSE;
}
#ifdef DEBUG_PS3_PROTOCOL
HIDAPI_DumpPacket("PS3 0xF2 packet: size = %d", data, size);
#endif
size = ReadFeatureReport(device->dev, 0xf5, data, 8);
if (size < 0) {
SDL_LogDebug(SDL_LOG_CATEGORY_INPUT,
"HIDAPI_DriverPS3_InitDevice(): Couldn't read feature report 0xf5");
return SDL_FALSE;
}
#ifdef DEBUG_PS3_PROTOCOL
HIDAPI_DumpPacket("PS3 0xF5 packet: size = %d", data, size);
#endif
if (!ctx->is_shanwan) {
/* An output report could cause ShanWan controllers to rumble non-stop */
SDL_hid_write(device->dev, data, 1);
}
}
device->type = SDL_GAMEPAD_TYPE_PS3;
HIDAPI_SetDeviceName(device, "PS3 Controller");
return HIDAPI_JoystickConnected(device, NULL);
}
static int HIDAPI_DriverPS3_GetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id)
{
return -1;
}
static int HIDAPI_DriverPS3_UpdateEffects(SDL_HIDAPI_Device *device)
{
SDL_DriverPS3_Context *ctx = (SDL_DriverPS3_Context *)device->context;
Uint8 effects[] = {
0x01, 0xff, 0x00, 0xff, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0x27, 0x10, 0x00, 0x32,
0xff, 0x27, 0x10, 0x00, 0x32,
0xff, 0x27, 0x10, 0x00, 0x32,
0xff, 0x27, 0x10, 0x00, 0x32,
0x00, 0x00, 0x00, 0x00, 0x00
};
effects[2] = ctx->rumble_right ? 1 : 0;
effects[4] = ctx->rumble_left;
effects[9] = (0x01 << (1 + (ctx->player_index % 4)));
return HIDAPI_DriverPS3_SendJoystickEffect(device, ctx->joystick, effects, sizeof(effects));
}
static void HIDAPI_DriverPS3_SetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id, int player_index)
{
SDL_DriverPS3_Context *ctx = (SDL_DriverPS3_Context *)device->context;
if (ctx == NULL) {
return;
}
ctx->player_index = player_index;
/* This will set the new LED state based on the new player index */
HIDAPI_DriverPS3_UpdateEffects(device);
}
static SDL_bool HIDAPI_DriverPS3_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
{
SDL_DriverPS3_Context *ctx = (SDL_DriverPS3_Context *)device->context;
SDL_AssertJoysticksLocked();
ctx->joystick = joystick;
ctx->effects_updated = SDL_FALSE;
ctx->rumble_left = 0;
ctx->rumble_right = 0;
SDL_zeroa(ctx->last_state);
/* Initialize player index (needed for setting LEDs) */
ctx->player_index = SDL_GetJoystickPlayerIndex(joystick);
/* Initialize the joystick capabilities */
joystick->nbuttons = 15;
joystick->naxes = 16;
joystick->epowerlevel = SDL_JOYSTICK_POWER_WIRED;
SDL_PrivateJoystickAddSensor(joystick, SDL_SENSOR_ACCEL, 100.0f);
return SDL_TRUE;
}
static int HIDAPI_DriverPS3_RumbleJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble)
{
SDL_DriverPS3_Context *ctx = (SDL_DriverPS3_Context *)device->context;
ctx->rumble_left = (low_frequency_rumble >> 8);
ctx->rumble_right = (high_frequency_rumble >> 8);
return HIDAPI_DriverPS3_UpdateEffects(device);
}
static int HIDAPI_DriverPS3_RumbleJoystickTriggers(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint16 left_rumble, Uint16 right_rumble)
{
return SDL_Unsupported();
}
static Uint32 HIDAPI_DriverPS3_GetJoystickCapabilities(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
{
return SDL_JOYCAP_RUMBLE;
}
static int HIDAPI_DriverPS3_SetJoystickLED(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue)
{
return SDL_Unsupported();
}
static int HIDAPI_DriverPS3_SendJoystickEffect(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, const void *effect, int size)
{
Uint8 data[49];
int report_size, offset;
SDL_zeroa(data);
data[0] = k_EPS3ReportIdEffects;
report_size = sizeof(data);
offset = 1;
SDL_memcpy(&data[offset], effect, SDL_min((sizeof(data) - offset), (size_t)size));
if (SDL_HIDAPI_SendRumble(device, data, report_size) != report_size) {
return SDL_SetError("Couldn't send rumble packet");
}
return 0;
}
static int HIDAPI_DriverPS3_SetJoystickSensorsEnabled(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, SDL_bool enabled)
{
SDL_DriverPS3_Context *ctx = (SDL_DriverPS3_Context *)device->context;
ctx->report_sensors = enabled;
return 0;
}
static float HIDAPI_DriverPS3_ScaleAccel(Sint16 value)
{
/* Accelerometer values are in big endian order */
value = SDL_SwapBE16(value);
return ((float)(value - 511) / 113.0f) * SDL_STANDARD_GRAVITY;
}
static void HIDAPI_DriverPS3_HandleMiniStatePacket(SDL_Joystick *joystick, SDL_DriverPS3_Context *ctx, Uint8 *data, int size)
{
Sint16 axis;
Uint64 timestamp = SDL_GetTicksNS();
if (ctx->last_state[4] != data[4]) {
SDL_bool dpad_up = SDL_FALSE;
SDL_bool dpad_down = SDL_FALSE;
SDL_bool dpad_left = SDL_FALSE;
SDL_bool dpad_right = SDL_FALSE;
switch (data[4] & 0x0f) {
case 0:
dpad_up = SDL_TRUE;
break;
case 1:
dpad_up = SDL_TRUE;
dpad_right = SDL_TRUE;
break;
case 2:
dpad_right = SDL_TRUE;
break;
case 3:
dpad_right = SDL_TRUE;
dpad_down = SDL_TRUE;
break;
case 4:
dpad_down = SDL_TRUE;
break;
case 5:
dpad_left = SDL_TRUE;
dpad_down = SDL_TRUE;
break;
case 6:
dpad_left = SDL_TRUE;
break;
case 7:
dpad_up = SDL_TRUE;
dpad_left = SDL_TRUE;
break;
default:
break;
}
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_DPAD_DOWN, dpad_down);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_DPAD_UP, dpad_up);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_DPAD_RIGHT, dpad_right);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_DPAD_LEFT, dpad_left);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_Y, (data[4] & 0x10) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_B, (data[4] & 0x20) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_A, (data[4] & 0x40) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_X, (data[4] & 0x80) ? SDL_PRESSED : SDL_RELEASED);
}
if (ctx->last_state[5] != data[5]) {
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_LEFT_SHOULDER, (data[5] & 0x01) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER, (data[5] & 0x02) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFT_TRIGGER, (data[5] & 0x04) ? SDL_JOYSTICK_AXIS_MAX : SDL_JOYSTICK_AXIS_MIN);
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHT_TRIGGER, (data[5] & 0x08) ? SDL_JOYSTICK_AXIS_MAX : SDL_JOYSTICK_AXIS_MIN);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_BACK, (data[5] & 0x10) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_START, (data[5] & 0x20) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_LEFT_STICK, (data[5] & 0x40) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_RIGHT_STICK, (data[5] & 0x80) ? SDL_PRESSED : SDL_RELEASED);
}
axis = ((int)data[2] * 257) - 32768;
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFTX, axis);
axis = ((int)data[3] * 257) - 32768;
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFTY, axis);
axis = ((int)data[0] * 257) - 32768;
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTX, axis);
axis = ((int)data[1] * 257) - 32768;
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTY, axis);
SDL_memcpy(ctx->last_state, data, SDL_min(size, sizeof(ctx->last_state)));
}
static void HIDAPI_DriverPS3_HandleStatePacket(SDL_Joystick *joystick, SDL_DriverPS3_Context *ctx, Uint8 *data, int size)
{
Sint16 axis;
Uint64 timestamp = SDL_GetTicksNS();
if (ctx->last_state[2] != data[2]) {
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_BACK, (data[2] & 0x01) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_LEFT_STICK, (data[2] & 0x02) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_RIGHT_STICK, (data[2] & 0x04) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_START, (data[2] & 0x08) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_DPAD_UP, (data[2] & 0x10) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_DPAD_RIGHT, (data[2] & 0x20) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_DPAD_DOWN, (data[2] & 0x40) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_DPAD_LEFT, (data[2] & 0x80) ? SDL_PRESSED : SDL_RELEASED);
}
if (ctx->last_state[3] != data[3]) {
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_LEFT_SHOULDER, (data[3] & 0x04) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER, (data[3] & 0x08) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_Y, (data[3] & 0x10) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_B, (data[3] & 0x20) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_A, (data[3] & 0x40) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_X, (data[3] & 0x80) ? SDL_PRESSED : SDL_RELEASED);
}
if (ctx->last_state[4] != data[4]) {
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_GUIDE, (data[4] & 0x01) ? SDL_PRESSED : SDL_RELEASED);
}
axis = ((int)data[18] * 257) - 32768;
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFT_TRIGGER, axis);
axis = ((int)data[19] * 257) - 32768;
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHT_TRIGGER, axis);
axis = ((int)data[6] * 257) - 32768;
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFTX, axis);
axis = ((int)data[7] * 257) - 32768;
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFTY, axis);
axis = ((int)data[8] * 257) - 32768;
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTX, axis);
axis = ((int)data[9] * 257) - 32768;
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTY, axis);
/* Buttons are mapped as axes in the order they appear in the button enumeration */
{
static int button_axis_offsets[] = {
24, /* SDL_GAMEPAD_BUTTON_A */
23, /* SDL_GAMEPAD_BUTTON_B */
25, /* SDL_GAMEPAD_BUTTON_X */
22, /* SDL_GAMEPAD_BUTTON_Y */
0, /* SDL_GAMEPAD_BUTTON_BACK */
0, /* SDL_GAMEPAD_BUTTON_GUIDE */
0, /* SDL_GAMEPAD_BUTTON_START */
0, /* SDL_GAMEPAD_BUTTON_LEFT_STICK */
0, /* SDL_GAMEPAD_BUTTON_RIGHT_STICK */
20, /* SDL_GAMEPAD_BUTTON_LEFT_SHOULDER */
21, /* SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER */
14, /* SDL_GAMEPAD_BUTTON_DPAD_UP */
16, /* SDL_GAMEPAD_BUTTON_DPAD_DOWN */
17, /* SDL_GAMEPAD_BUTTON_DPAD_LEFT */
15, /* SDL_GAMEPAD_BUTTON_DPAD_RIGHT */
};
Uint8 i, axis_index = 6;
for (i = 0; i < SDL_arraysize(button_axis_offsets); ++i) {
int offset = button_axis_offsets[i];
if (!offset) {
/* This button doesn't report as an axis */
continue;
}
axis = ((int)data[offset] * 257) - 32768;
SDL_SendJoystickAxis(timestamp, joystick, axis_index, axis);
++axis_index;
}
}
if (ctx->report_sensors) {
float sensor_data[3];
sensor_data[0] = HIDAPI_DriverPS3_ScaleAccel(LOAD16(data[41], data[42]));
sensor_data[1] = -HIDAPI_DriverPS3_ScaleAccel(LOAD16(data[45], data[46]));
sensor_data[2] = -HIDAPI_DriverPS3_ScaleAccel(LOAD16(data[43], data[44]));
SDL_SendJoystickSensor(timestamp, joystick, SDL_SENSOR_ACCEL, timestamp, sensor_data, SDL_arraysize(sensor_data));
}
SDL_memcpy(ctx->last_state, data, SDL_min(size, sizeof(ctx->last_state)));
}
static SDL_bool HIDAPI_DriverPS3_UpdateDevice(SDL_HIDAPI_Device *device)
{
SDL_DriverPS3_Context *ctx = (SDL_DriverPS3_Context *)device->context;
SDL_Joystick *joystick = NULL;
Uint8 data[USB_PACKET_LENGTH];
int size;
if (device->num_joysticks > 0) {
joystick = SDL_GetJoystickFromInstanceID(device->joysticks[0]);
} else {
return SDL_FALSE;
}
while ((size = SDL_hid_read_timeout(device->dev, data, sizeof(data), 0)) > 0) {
#ifdef DEBUG_PS3_PROTOCOL
HIDAPI_DumpPacket("PS3 packet: size = %d", data, size);
#endif
if (joystick == NULL) {
continue;
}
if (size == 7) {
/* Seen on a ShanWan PS2 -> PS3 USB converter */
HIDAPI_DriverPS3_HandleMiniStatePacket(joystick, ctx, data, size);
/* Wait for the first report to set the LED state after the controller stops blinking */
if (!ctx->effects_updated) {
HIDAPI_DriverPS3_UpdateEffects(device);
ctx->effects_updated = SDL_TRUE;
}
continue;
}
switch (data[0]) {
case k_EPS3ReportIdState:
if (data[1] == 0xFF) {
/* Invalid data packet, ignore */
break;
}
HIDAPI_DriverPS3_HandleStatePacket(joystick, ctx, data, size);
/* Wait for the first report to set the LED state after the controller stops blinking */
if (!ctx->effects_updated) {
HIDAPI_DriverPS3_UpdateEffects(device);
ctx->effects_updated = SDL_TRUE;
}
break;
default:
#ifdef DEBUG_JOYSTICK
SDL_Log("Unknown PS3 packet: 0x%.2x\n", data[0]);
#endif
break;
}
}
if (size < 0) {
/* Read error, device is disconnected */
HIDAPI_JoystickDisconnected(device, device->joysticks[0]);
}
return size >= 0;
}
static void HIDAPI_DriverPS3_CloseJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
{
SDL_DriverPS3_Context *ctx = (SDL_DriverPS3_Context *)device->context;
ctx->joystick = NULL;
}
static void HIDAPI_DriverPS3_FreeDevice(SDL_HIDAPI_Device *device)
{
}
SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverPS3 = {
SDL_HINT_JOYSTICK_HIDAPI_PS3,
SDL_TRUE,
HIDAPI_DriverPS3_RegisterHints,
HIDAPI_DriverPS3_UnregisterHints,
HIDAPI_DriverPS3_IsEnabled,
HIDAPI_DriverPS3_IsSupportedDevice,
HIDAPI_DriverPS3_InitDevice,
HIDAPI_DriverPS3_GetDevicePlayerIndex,
HIDAPI_DriverPS3_SetDevicePlayerIndex,
HIDAPI_DriverPS3_UpdateDevice,
HIDAPI_DriverPS3_OpenJoystick,
HIDAPI_DriverPS3_RumbleJoystick,
HIDAPI_DriverPS3_RumbleJoystickTriggers,
HIDAPI_DriverPS3_GetJoystickCapabilities,
HIDAPI_DriverPS3_SetJoystickLED,
HIDAPI_DriverPS3_SendJoystickEffect,
HIDAPI_DriverPS3_SetJoystickSensorsEnabled,
HIDAPI_DriverPS3_CloseJoystick,
HIDAPI_DriverPS3_FreeDevice,
};
static SDL_bool HIDAPI_DriverPS3ThirdParty_IsEnabled(void)
{
return SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI_PS3,
SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI,
SDL_HIDAPI_DEFAULT));
}
static SDL_bool HIDAPI_DriverPS3ThirdParty_IsSupportedDevice(SDL_HIDAPI_Device *device, const char *name, SDL_GamepadType type, Uint16 vendor_id, Uint16 product_id, Uint16 version, int interface_number, int interface_class, int interface_subclass, int interface_protocol)
{
Uint8 data[USB_PACKET_LENGTH];
int size;
if ((type == SDL_GAMEPAD_TYPE_PS3 && vendor_id != USB_VENDOR_SONY) ||
HIDAPI_SupportsPlaystationDetection(vendor_id, product_id)) {
if (device && device->dev) {
size = ReadFeatureReport(device->dev, 0x03, data, sizeof(data));
if (size == 8 && data[2] == 0x26) {
/* Supported third party controller */
return SDL_TRUE;
} else {
return SDL_FALSE;
}
} else {
/* Might be supported by this driver, enumerate and find out */
return SDL_TRUE;
}
}
return SDL_FALSE;
}
static SDL_bool HIDAPI_DriverPS3ThirdParty_InitDevice(SDL_HIDAPI_Device *device)
{
SDL_DriverPS3_Context *ctx;
ctx = (SDL_DriverPS3_Context *)SDL_calloc(1, sizeof(*ctx));
if (ctx == NULL) {
SDL_OutOfMemory();
return SDL_FALSE;
}
ctx->device = device;
device->context = ctx;
device->type = SDL_GAMEPAD_TYPE_PS3;
if (device->vendor_id == USB_VENDOR_LOGITECH &&
device->product_id == USB_PRODUCT_LOGITECH_CHILLSTREAM) {
HIDAPI_SetDeviceName(device, "Logitech ChillStream");
}
return HIDAPI_JoystickConnected(device, NULL);
}
static int HIDAPI_DriverPS3ThirdParty_GetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id)
{
return -1;
}
static void HIDAPI_DriverPS3ThirdParty_SetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id, int player_index)
{
}
static SDL_bool HIDAPI_DriverPS3ThirdParty_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
{
SDL_DriverPS3_Context *ctx = (SDL_DriverPS3_Context *)device->context;
SDL_AssertJoysticksLocked();
ctx->joystick = joystick;
SDL_zeroa(ctx->last_state);
/* Initialize the joystick capabilities */
joystick->nbuttons = 15;
joystick->naxes = 16;
joystick->epowerlevel = SDL_JOYSTICK_POWER_WIRED;
return SDL_TRUE;
}
static int HIDAPI_DriverPS3ThirdParty_RumbleJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble)
{
return SDL_Unsupported();
}
static int HIDAPI_DriverPS3ThirdParty_RumbleJoystickTriggers(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint16 left_rumble, Uint16 right_rumble)
{
return SDL_Unsupported();
}
static Uint32 HIDAPI_DriverPS3ThirdParty_GetJoystickCapabilities(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
{
return 0;
}
static int HIDAPI_DriverPS3ThirdParty_SetJoystickLED(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue)
{
return SDL_Unsupported();
}
static int HIDAPI_DriverPS3ThirdParty_SendJoystickEffect(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, const void *effect, int size)
{
return SDL_Unsupported();
}
static int HIDAPI_DriverPS3ThirdParty_SetJoystickSensorsEnabled(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, SDL_bool enabled)
{
return SDL_Unsupported();
}
static void HIDAPI_DriverPS3ThirdParty_HandleStatePacket18(SDL_Joystick *joystick, SDL_DriverPS3_Context *ctx, Uint8 *data, int size)
{
Sint16 axis;
Uint64 timestamp = SDL_GetTicksNS();
if (ctx->last_state[0] != data[0]) {
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_X, (data[0] & 0x01) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_A, (data[0] & 0x02) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_B, (data[0] & 0x04) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_Y, (data[0] & 0x08) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_LEFT_SHOULDER, (data[0] & 0x10) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER, (data[0] & 0x20) ? SDL_PRESSED : SDL_RELEASED);
}
if (ctx->last_state[1] != data[1]) {
SDL_bool dpad_up = SDL_FALSE;
SDL_bool dpad_down = SDL_FALSE;
SDL_bool dpad_left = SDL_FALSE;
SDL_bool dpad_right = SDL_FALSE;
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_BACK, (data[1] & 0x01) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_START, (data[1] & 0x02) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_LEFT_STICK, (data[1] & 0x04) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_RIGHT_STICK, (data[1] & 0x08) ? SDL_PRESSED : SDL_RELEASED);
switch (data[1] >> 4) {
case 0:
dpad_up = SDL_TRUE;
break;
case 1:
dpad_up = SDL_TRUE;
dpad_right = SDL_TRUE;
break;
case 2:
dpad_right = SDL_TRUE;
break;
case 3:
dpad_right = SDL_TRUE;
dpad_down = SDL_TRUE;
break;
case 4:
dpad_down = SDL_TRUE;
break;
case 5:
dpad_left = SDL_TRUE;
dpad_down = SDL_TRUE;
break;
case 6:
dpad_left = SDL_TRUE;
break;
case 7:
dpad_up = SDL_TRUE;
dpad_left = SDL_TRUE;
break;
default:
break;
}
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_DPAD_DOWN, dpad_down);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_DPAD_UP, dpad_up);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_DPAD_RIGHT, dpad_right);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_DPAD_LEFT, dpad_left);
}
axis = ((int)data[16] * 257) - 32768;
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFT_TRIGGER, axis);
axis = ((int)data[17] * 257) - 32768;
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHT_TRIGGER, axis);
axis = ((int)data[2] * 257) - 32768;
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFTX, axis);
axis = ((int)data[3] * 257) - 32768;
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFTY, axis);
axis = ((int)data[4] * 257) - 32768;
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTX, axis);
axis = ((int)data[5] * 257) - 32768;
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTY, axis);
/* Buttons are mapped as axes in the order they appear in the button enumeration */
{
static int button_axis_offsets[] = {
12, /* SDL_GAMEPAD_BUTTON_A */
11, /* SDL_GAMEPAD_BUTTON_B */
13, /* SDL_GAMEPAD_BUTTON_X */
10, /* SDL_GAMEPAD_BUTTON_Y */
0, /* SDL_GAMEPAD_BUTTON_BACK */
0, /* SDL_GAMEPAD_BUTTON_GUIDE */
0, /* SDL_GAMEPAD_BUTTON_START */
0, /* SDL_GAMEPAD_BUTTON_LEFT_STICK */
0, /* SDL_GAMEPAD_BUTTON_RIGHT_STICK */
14, /* SDL_GAMEPAD_BUTTON_LEFT_SHOULDER */
16, /* SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER */
8, /* SDL_GAMEPAD_BUTTON_DPAD_UP */
9, /* SDL_GAMEPAD_BUTTON_DPAD_DOWN */
7, /* SDL_GAMEPAD_BUTTON_DPAD_LEFT */
6, /* SDL_GAMEPAD_BUTTON_DPAD_RIGHT */
};
Uint8 i, axis_index = 6;
for (i = 0; i < SDL_arraysize(button_axis_offsets); ++i) {
int offset = button_axis_offsets[i];
if (!offset) {
/* This button doesn't report as an axis */
continue;
}
axis = ((int)data[offset] * 257) - 32768;
SDL_SendJoystickAxis(timestamp, joystick, axis_index, axis);
++axis_index;
}
}
SDL_memcpy(ctx->last_state, data, SDL_min(size, sizeof(ctx->last_state)));
}
static void HIDAPI_DriverPS3ThirdParty_HandleStatePacket19(SDL_Joystick *joystick, SDL_DriverPS3_Context *ctx, Uint8 *data, int size)
{
Sint16 axis;
Uint64 timestamp = SDL_GetTicksNS();
if (ctx->last_state[0] != data[0]) {
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_X, (data[0] & 0x01) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_A, (data[0] & 0x02) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_B, (data[0] & 0x04) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_Y, (data[0] & 0x08) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_LEFT_SHOULDER, (data[0] & 0x10) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER, (data[0] & 0x20) ? SDL_PRESSED : SDL_RELEASED);
}
if (ctx->last_state[1] != data[1]) {
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_BACK, (data[1] & 0x01) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_START, (data[1] & 0x02) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_LEFT_STICK, (data[1] & 0x04) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_RIGHT_STICK, (data[1] & 0x08) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_GUIDE, (data[1] & 0x10) ? SDL_PRESSED : SDL_RELEASED);
}
if (ctx->device->vendor_id == USB_VENDOR_SAITEK && ctx->device->product_id == USB_PRODUCT_SAITEK_CYBORG_V3) {
/* Cyborg V.3 Rumble Pad doesn't set the dpad bits as expected, so use the axes instead */
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_DPAD_DOWN, data[10] ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_DPAD_UP, data[9] ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_DPAD_RIGHT, data[7] ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_DPAD_LEFT, data[8] ? SDL_PRESSED : SDL_RELEASED);
} else {
if (ctx->last_state[2] != data[2]) {
SDL_bool dpad_up = SDL_FALSE;
SDL_bool dpad_down = SDL_FALSE;
SDL_bool dpad_left = SDL_FALSE;
SDL_bool dpad_right = SDL_FALSE;
switch (data[2] & 0x0f) {
case 0:
dpad_up = SDL_TRUE;
break;
case 1:
dpad_up = SDL_TRUE;
dpad_right = SDL_TRUE;
break;
case 2:
dpad_right = SDL_TRUE;
break;
case 3:
dpad_right = SDL_TRUE;
dpad_down = SDL_TRUE;
break;
case 4:
dpad_down = SDL_TRUE;
break;
case 5:
dpad_left = SDL_TRUE;
dpad_down = SDL_TRUE;
break;
case 6:
dpad_left = SDL_TRUE;
break;
case 7:
dpad_up = SDL_TRUE;
dpad_left = SDL_TRUE;
break;
default:
break;
}
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_DPAD_DOWN, dpad_down);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_DPAD_UP, dpad_up);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_DPAD_RIGHT, dpad_right);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_DPAD_LEFT, dpad_left);
}
}
axis = ((int)data[17] * 257) - 32768;
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFT_TRIGGER, axis);
axis = ((int)data[18] * 257) - 32768;
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHT_TRIGGER, axis);
axis = ((int)data[3] * 257) - 32768;
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFTX, axis);
axis = ((int)data[4] * 257) - 32768;
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFTY, axis);
axis = ((int)data[5] * 257) - 32768;
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTX, axis);
axis = ((int)data[6] * 257) - 32768;
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTY, axis);
/* Buttons are mapped as axes in the order they appear in the button enumeration */
{
static int button_axis_offsets[] = {
13, /* SDL_GAMEPAD_BUTTON_A */
12, /* SDL_GAMEPAD_BUTTON_B */
14, /* SDL_GAMEPAD_BUTTON_X */
11, /* SDL_GAMEPAD_BUTTON_Y */
0, /* SDL_GAMEPAD_BUTTON_BACK */
0, /* SDL_GAMEPAD_BUTTON_GUIDE */
0, /* SDL_GAMEPAD_BUTTON_START */
0, /* SDL_GAMEPAD_BUTTON_LEFT_STICK */
0, /* SDL_GAMEPAD_BUTTON_RIGHT_STICK */
15, /* SDL_GAMEPAD_BUTTON_LEFT_SHOULDER */
16, /* SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER */
9, /* SDL_GAMEPAD_BUTTON_DPAD_UP */
10, /* SDL_GAMEPAD_BUTTON_DPAD_DOWN */
8, /* SDL_GAMEPAD_BUTTON_DPAD_LEFT */
7, /* SDL_GAMEPAD_BUTTON_DPAD_RIGHT */
};
Uint8 i, axis_index = 6;
for (i = 0; i < SDL_arraysize(button_axis_offsets); ++i) {
int offset = button_axis_offsets[i];
if (!offset) {
/* This button doesn't report as an axis */
continue;
}
axis = ((int)data[offset] * 257) - 32768;
SDL_SendJoystickAxis(timestamp, joystick, axis_index, axis);
++axis_index;
}
}
SDL_memcpy(ctx->last_state, data, SDL_min(size, sizeof(ctx->last_state)));
}
static SDL_bool HIDAPI_DriverPS3ThirdParty_UpdateDevice(SDL_HIDAPI_Device *device)
{
SDL_DriverPS3_Context *ctx = (SDL_DriverPS3_Context *)device->context;
SDL_Joystick *joystick = NULL;
Uint8 data[USB_PACKET_LENGTH];
int size;
if (device->num_joysticks > 0) {
joystick = SDL_GetJoystickFromInstanceID(device->joysticks[0]);
} else {
return SDL_FALSE;
}
while ((size = SDL_hid_read_timeout(device->dev, data, sizeof(data), 0)) > 0) {
#ifdef DEBUG_PS3_PROTOCOL
HIDAPI_DumpPacket("PS3 packet: size = %d", data, size);
#endif
if (joystick == NULL) {
continue;
}
if (size >= 19) {
HIDAPI_DriverPS3ThirdParty_HandleStatePacket19(joystick, ctx, data, size);
} else if (size == 18) {
/* This packet format was seen with the Logitech ChillStream */
HIDAPI_DriverPS3ThirdParty_HandleStatePacket18(joystick, ctx, data, size);
} else {
#ifdef DEBUG_JOYSTICK
SDL_Log("Unknown PS3 packet, size %d\n", size);
#endif
}
}
if (size < 0) {
/* Read error, device is disconnected */
HIDAPI_JoystickDisconnected(device, device->joysticks[0]);
}
return size >= 0;
}
static void HIDAPI_DriverPS3ThirdParty_CloseJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
{
SDL_DriverPS3_Context *ctx = (SDL_DriverPS3_Context *)device->context;
ctx->joystick = NULL;
}
static void HIDAPI_DriverPS3ThirdParty_FreeDevice(SDL_HIDAPI_Device *device)
{
}
SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverPS3ThirdParty = {
SDL_HINT_JOYSTICK_HIDAPI_PS3,
SDL_TRUE,
HIDAPI_DriverPS3_RegisterHints,
HIDAPI_DriverPS3_UnregisterHints,
HIDAPI_DriverPS3ThirdParty_IsEnabled,
HIDAPI_DriverPS3ThirdParty_IsSupportedDevice,
HIDAPI_DriverPS3ThirdParty_InitDevice,
HIDAPI_DriverPS3ThirdParty_GetDevicePlayerIndex,
HIDAPI_DriverPS3ThirdParty_SetDevicePlayerIndex,
HIDAPI_DriverPS3ThirdParty_UpdateDevice,
HIDAPI_DriverPS3ThirdParty_OpenJoystick,
HIDAPI_DriverPS3ThirdParty_RumbleJoystick,
HIDAPI_DriverPS3ThirdParty_RumbleJoystickTriggers,
HIDAPI_DriverPS3ThirdParty_GetJoystickCapabilities,
HIDAPI_DriverPS3ThirdParty_SetJoystickLED,
HIDAPI_DriverPS3ThirdParty_SendJoystickEffect,
HIDAPI_DriverPS3ThirdParty_SetJoystickSensorsEnabled,
HIDAPI_DriverPS3ThirdParty_CloseJoystick,
HIDAPI_DriverPS3ThirdParty_FreeDevice,
};
#endif /* SDL_JOYSTICK_HIDAPI_PS3 */
#endif /* SDL_JOYSTICK_HIDAPI */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,283 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 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_HIDAPI
/* Handle rumble on a separate thread so it doesn't block the application */
#include "SDL_hidapijoystick_c.h"
#include "SDL_hidapi_rumble.h"
#include "../../thread/SDL_systhread.h"
typedef struct SDL_HIDAPI_RumbleRequest
{
SDL_HIDAPI_Device *device;
Uint8 data[2 * USB_PACKET_LENGTH]; /* need enough space for the biggest report: dualshock4 is 78 bytes */
int size;
SDL_HIDAPI_RumbleSentCallback callback;
void *userdata;
struct SDL_HIDAPI_RumbleRequest *prev;
} SDL_HIDAPI_RumbleRequest;
typedef struct SDL_HIDAPI_RumbleContext
{
SDL_AtomicInt initialized;
SDL_AtomicInt running;
SDL_Thread *thread;
SDL_Semaphore *request_sem;
SDL_HIDAPI_RumbleRequest *requests_head;
SDL_HIDAPI_RumbleRequest *requests_tail;
} SDL_HIDAPI_RumbleContext;
#ifndef SDL_THREAD_SAFETY_ANALYSIS
static
#endif
SDL_Mutex *SDL_HIDAPI_rumble_lock;
static SDL_HIDAPI_RumbleContext rumble_context SDL_GUARDED_BY(SDL_HIDAPI_rumble_lock);
static int SDLCALL SDL_HIDAPI_RumbleThread(void *data)
{
SDL_HIDAPI_RumbleContext *ctx = (SDL_HIDAPI_RumbleContext *)data;
SDL_SetThreadPriority(SDL_THREAD_PRIORITY_HIGH);
while (SDL_AtomicGet(&ctx->running)) {
SDL_HIDAPI_RumbleRequest *request = NULL;
SDL_WaitSemaphore(ctx->request_sem);
SDL_LockMutex(SDL_HIDAPI_rumble_lock);
request = ctx->requests_tail;
if (request) {
if (request == ctx->requests_head) {
ctx->requests_head = NULL;
}
ctx->requests_tail = request->prev;
}
SDL_UnlockMutex(SDL_HIDAPI_rumble_lock);
if (request) {
SDL_LockMutex(request->device->dev_lock);
if (request->device->dev) {
#ifdef DEBUG_RUMBLE
HIDAPI_DumpPacket("Rumble packet: size = %d", request->data, request->size);
#endif
SDL_hid_write(request->device->dev, request->data, request->size);
}
SDL_UnlockMutex(request->device->dev_lock);
if (request->callback) {
request->callback(request->userdata);
}
(void)SDL_AtomicDecRef(&request->device->rumble_pending);
SDL_free(request);
/* Make sure we're not starving report reads when there's lots of rumble */
SDL_Delay(10);
}
}
return 0;
}
static void SDL_HIDAPI_StopRumbleThread(SDL_HIDAPI_RumbleContext *ctx)
{
SDL_HIDAPI_RumbleRequest *request;
SDL_AtomicSet(&ctx->running, SDL_FALSE);
if (ctx->thread) {
int result;
SDL_PostSemaphore(ctx->request_sem);
SDL_WaitThread(ctx->thread, &result);
ctx->thread = NULL;
}
SDL_LockMutex(SDL_HIDAPI_rumble_lock);
while (ctx->requests_tail) {
request = ctx->requests_tail;
if (request == ctx->requests_head) {
ctx->requests_head = NULL;
}
ctx->requests_tail = request->prev;
if (request->callback) {
request->callback(request->userdata);
}
(void)SDL_AtomicDecRef(&request->device->rumble_pending);
SDL_free(request);
}
SDL_UnlockMutex(SDL_HIDAPI_rumble_lock);
if (ctx->request_sem) {
SDL_DestroySemaphore(ctx->request_sem);
ctx->request_sem = NULL;
}
if (SDL_HIDAPI_rumble_lock) {
SDL_DestroyMutex(SDL_HIDAPI_rumble_lock);
SDL_HIDAPI_rumble_lock = NULL;
}
SDL_AtomicSet(&ctx->initialized, SDL_FALSE);
}
static int SDL_HIDAPI_StartRumbleThread(SDL_HIDAPI_RumbleContext *ctx)
{
SDL_HIDAPI_rumble_lock = SDL_CreateMutex();
if (!SDL_HIDAPI_rumble_lock) {
SDL_HIDAPI_StopRumbleThread(ctx);
return -1;
}
ctx->request_sem = SDL_CreateSemaphore(0);
if (!ctx->request_sem) {
SDL_HIDAPI_StopRumbleThread(ctx);
return -1;
}
SDL_AtomicSet(&ctx->running, SDL_TRUE);
ctx->thread = SDL_CreateThreadInternal(SDL_HIDAPI_RumbleThread, "HIDAPI Rumble", 0, ctx);
if (!ctx->thread) {
SDL_HIDAPI_StopRumbleThread(ctx);
return -1;
}
return 0;
}
int SDL_HIDAPI_LockRumble(void)
{
SDL_HIDAPI_RumbleContext *ctx = &rumble_context;
if (SDL_AtomicCAS(&ctx->initialized, SDL_FALSE, SDL_TRUE)) {
if (SDL_HIDAPI_StartRumbleThread(ctx) < 0) {
return -1;
}
}
SDL_LockMutex(SDL_HIDAPI_rumble_lock);
return 0;
}
SDL_bool SDL_HIDAPI_GetPendingRumbleLocked(SDL_HIDAPI_Device *device, Uint8 **data, int **size, int *maximum_size)
{
SDL_HIDAPI_RumbleContext *ctx = &rumble_context;
SDL_HIDAPI_RumbleRequest *request, *found;
found = NULL;
for (request = ctx->requests_tail; request; request = request->prev) {
if (request->device == device) {
found = request;
}
}
if (found) {
*data = found->data;
*size = &found->size;
*maximum_size = sizeof(found->data);
return SDL_TRUE;
}
return SDL_FALSE;
}
int SDL_HIDAPI_SendRumbleAndUnlock(SDL_HIDAPI_Device *device, const Uint8 *data, int size)
{
return SDL_HIDAPI_SendRumbleWithCallbackAndUnlock(device, data, size, NULL, NULL);
}
int SDL_HIDAPI_SendRumbleWithCallbackAndUnlock(SDL_HIDAPI_Device *device, const Uint8 *data, int size, SDL_HIDAPI_RumbleSentCallback callback, void *userdata)
{
SDL_HIDAPI_RumbleContext *ctx = &rumble_context;
SDL_HIDAPI_RumbleRequest *request;
if (size > sizeof(request->data)) {
SDL_HIDAPI_UnlockRumble();
return SDL_SetError("Couldn't send rumble, size %d is greater than %d", size, (int)sizeof(request->data));
}
request = (SDL_HIDAPI_RumbleRequest *)SDL_calloc(1, sizeof(*request));
if (request == NULL) {
SDL_HIDAPI_UnlockRumble();
return SDL_OutOfMemory();
}
request->device = device;
SDL_memcpy(request->data, data, size);
request->size = size;
request->callback = callback;
request->userdata = userdata;
SDL_AtomicIncRef(&device->rumble_pending);
if (ctx->requests_head) {
ctx->requests_head->prev = request;
} else {
ctx->requests_tail = request;
}
ctx->requests_head = request;
/* Make sure we unlock before posting the semaphore so the rumble thread can run immediately */
SDL_HIDAPI_UnlockRumble();
SDL_PostSemaphore(ctx->request_sem);
return size;
}
void SDL_HIDAPI_UnlockRumble(void)
{
SDL_UnlockMutex(SDL_HIDAPI_rumble_lock);
}
int SDL_HIDAPI_SendRumble(SDL_HIDAPI_Device *device, const Uint8 *data, int size)
{
Uint8 *pending_data;
int *pending_size;
int maximum_size;
if (size <= 0) {
return SDL_SetError("Tried to send rumble with invalid size");
}
if (SDL_HIDAPI_LockRumble() != 0) {
return -1;
}
/* check if there is a pending request for the device and update it */
if (SDL_HIDAPI_GetPendingRumbleLocked(device, &pending_data, &pending_size, &maximum_size) &&
size == *pending_size && data[0] == pending_data[0]) {
SDL_memcpy(pending_data, data, size);
SDL_HIDAPI_UnlockRumble();
return size;
}
return SDL_HIDAPI_SendRumbleAndUnlock(device, data, size);
}
void SDL_HIDAPI_QuitRumble(void)
{
SDL_HIDAPI_RumbleContext *ctx = &rumble_context;
if (SDL_AtomicGet(&ctx->running)) {
SDL_HIDAPI_StopRumbleThread(ctx);
}
}
#endif /* SDL_JOYSTICK_HIDAPI */

View File

@@ -0,0 +1,42 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 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_HIDAPI
/* Handle rumble on a separate thread so it doesn't block the application */
/* Advanced API */
#ifdef SDL_THREAD_SAFETY_ANALYSIS
extern SDL_Mutex *SDL_HIDAPI_rumble_lock;
#endif
int SDL_HIDAPI_LockRumble(void) SDL_TRY_ACQUIRE(0, SDL_HIDAPI_rumble_lock);
SDL_bool SDL_HIDAPI_GetPendingRumbleLocked(SDL_HIDAPI_Device *device, Uint8 **data, int **size, int *maximum_size);
int SDL_HIDAPI_SendRumbleAndUnlock(SDL_HIDAPI_Device *device, const Uint8 *data, int size) SDL_RELEASE(SDL_HIDAPI_rumble_lock);
typedef void (*SDL_HIDAPI_RumbleSentCallback)(void *userdata);
int SDL_HIDAPI_SendRumbleWithCallbackAndUnlock(SDL_HIDAPI_Device *device, const Uint8 *data, int size, SDL_HIDAPI_RumbleSentCallback callback, void *userdata) SDL_RELEASE(SDL_HIDAPI_rumble_lock);
void SDL_HIDAPI_UnlockRumble(void) SDL_RELEASE(SDL_HIDAPI_rumble_lock);
/* Simple API, will replace any pending rumble with the new data */
int SDL_HIDAPI_SendRumble(SDL_HIDAPI_Device *device, const Uint8 *data, int size);
void SDL_HIDAPI_QuitRumble(void);
#endif /* SDL_JOYSTICK_HIDAPI */

View File

@@ -0,0 +1,601 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 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_HIDAPI
#include "../SDL_sysjoystick.h"
#include "SDL_hidapijoystick_c.h"
#include "SDL_hidapi_rumble.h"
#ifdef SDL_JOYSTICK_HIDAPI_SHIELD
/* Define this if you want to log all packets from the controller */
/*#define DEBUG_SHIELD_PROTOCOL*/
#define CMD_BATTERY_STATE 0x07
#define CMD_RUMBLE 0x39
#define CMD_CHARGE_STATE 0x3A
/* Milliseconds between polls of battery state */
#define BATTERY_POLL_INTERVAL_MS 60000
/* Milliseconds between retransmission of rumble to keep motors running */
#define RUMBLE_REFRESH_INTERVAL_MS 500
/* Reports that are too small are dropped over Bluetooth */
#define HID_REPORT_SIZE 33
enum
{
SDL_CONTROLLER_BUTTON_SHIELD_V103_TOUCHPAD = SDL_GAMEPAD_BUTTON_MISC1 + 1,
SDL_CONTROLLER_BUTTON_SHIELD_V103_MINUS,
SDL_CONTROLLER_BUTTON_SHIELD_V103_PLUS,
SDL_CONTROLLER_NUM_SHIELD_V103_BUTTONS,
SDL_CONTROLLER_NUM_SHIELD_V104_BUTTONS = SDL_GAMEPAD_BUTTON_MISC1 + 1,
};
typedef enum
{
k_ShieldReportIdControllerState = 0x01,
k_ShieldReportIdControllerTouch = 0x02,
k_ShieldReportIdCommandResponse = 0x03,
k_ShieldReportIdCommandRequest = 0x04,
} EShieldReportId;
/* This same report structure is used for both requests and responses */
typedef struct
{
Uint8 report_id;
Uint8 cmd;
Uint8 seq_num;
Uint8 payload[HID_REPORT_SIZE - 3];
} ShieldCommandReport_t;
SDL_COMPILE_TIME_ASSERT(ShieldCommandReport_t, sizeof(ShieldCommandReport_t) == HID_REPORT_SIZE);
typedef struct
{
Uint8 seq_num;
SDL_JoystickPowerLevel battery_level;
SDL_bool charging;
Uint64 last_battery_query_time;
SDL_bool rumble_report_pending;
SDL_bool rumble_update_pending;
Uint8 left_motor_amplitude;
Uint8 right_motor_amplitude;
Uint64 last_rumble_time;
Uint8 last_state[USB_PACKET_LENGTH];
} SDL_DriverShield_Context;
static void HIDAPI_DriverShield_RegisterHints(SDL_HintCallback callback, void *userdata)
{
SDL_AddHintCallback(SDL_HINT_JOYSTICK_HIDAPI_SHIELD, callback, userdata);
}
static void HIDAPI_DriverShield_UnregisterHints(SDL_HintCallback callback, void *userdata)
{
SDL_DelHintCallback(SDL_HINT_JOYSTICK_HIDAPI_SHIELD, callback, userdata);
}
static SDL_bool HIDAPI_DriverShield_IsEnabled(void)
{
return SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI_SHIELD, SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI, SDL_HIDAPI_DEFAULT));
}
static SDL_bool HIDAPI_DriverShield_IsSupportedDevice(SDL_HIDAPI_Device *device, const char *name, SDL_GamepadType type, Uint16 vendor_id, Uint16 product_id, Uint16 version, int interface_number, int interface_class, int interface_subclass, int interface_protocol)
{
return SDL_IsJoystickNVIDIASHIELDController(vendor_id, product_id);
}
static SDL_bool HIDAPI_DriverShield_InitDevice(SDL_HIDAPI_Device *device)
{
SDL_DriverShield_Context *ctx;
ctx = (SDL_DriverShield_Context *)SDL_calloc(1, sizeof(*ctx));
if (ctx == NULL) {
SDL_OutOfMemory();
return SDL_FALSE;
}
device->context = ctx;
HIDAPI_SetDeviceName(device, "NVIDIA SHIELD Controller");
return HIDAPI_JoystickConnected(device, NULL);
}
static int HIDAPI_DriverShield_GetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id)
{
return -1;
}
static void HIDAPI_DriverShield_SetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id, int player_index)
{
}
static int HIDAPI_DriverShield_SendCommand(SDL_HIDAPI_Device *device, Uint8 cmd, const void *data, int size)
{
SDL_DriverShield_Context *ctx = (SDL_DriverShield_Context *)device->context;
ShieldCommandReport_t cmd_pkt;
if (size > sizeof(cmd_pkt.payload)) {
return SDL_SetError("Command data exceeds HID report size");
}
if (SDL_HIDAPI_LockRumble() != 0) {
return -1;
}
cmd_pkt.report_id = k_ShieldReportIdCommandRequest;
cmd_pkt.cmd = cmd;
cmd_pkt.seq_num = ctx->seq_num++;
if (data) {
SDL_memcpy(cmd_pkt.payload, data, size);
}
/* Zero unused data in the payload */
if (size != sizeof(cmd_pkt.payload)) {
SDL_memset(&cmd_pkt.payload[size], 0, sizeof(cmd_pkt.payload) - size);
}
if (SDL_HIDAPI_SendRumbleAndUnlock(device, (Uint8 *)&cmd_pkt, sizeof(cmd_pkt)) != sizeof(cmd_pkt)) {
return SDL_SetError("Couldn't send command packet");
}
return 0;
}
static SDL_bool HIDAPI_DriverShield_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
{
SDL_DriverShield_Context *ctx = (SDL_DriverShield_Context *)device->context;
SDL_AssertJoysticksLocked();
ctx->rumble_report_pending = SDL_FALSE;
ctx->rumble_update_pending = SDL_FALSE;
ctx->left_motor_amplitude = 0;
ctx->right_motor_amplitude = 0;
ctx->last_rumble_time = 0;
SDL_zeroa(ctx->last_state);
/* Initialize the joystick capabilities */
if (device->product_id == USB_PRODUCT_NVIDIA_SHIELD_CONTROLLER_V103) {
joystick->nbuttons = SDL_CONTROLLER_NUM_SHIELD_V103_BUTTONS;
joystick->naxes = SDL_GAMEPAD_AXIS_MAX;
joystick->epowerlevel = SDL_JOYSTICK_POWER_WIRED;
SDL_PrivateJoystickAddTouchpad(joystick, 1);
} else {
joystick->nbuttons = SDL_CONTROLLER_NUM_SHIELD_V104_BUTTONS;
joystick->naxes = SDL_GAMEPAD_AXIS_MAX;
joystick->epowerlevel = SDL_JOYSTICK_POWER_UNKNOWN;
}
/* Request battery and charging info */
ctx->last_battery_query_time = SDL_GetTicks();
HIDAPI_DriverShield_SendCommand(device, CMD_CHARGE_STATE, NULL, 0);
HIDAPI_DriverShield_SendCommand(device, CMD_BATTERY_STATE, NULL, 0);
return SDL_TRUE;
}
static int HIDAPI_DriverShield_SendNextRumble(SDL_HIDAPI_Device *device)
{
SDL_DriverShield_Context *ctx = device->context;
Uint8 rumble_data[3];
if (!ctx->rumble_update_pending) {
return 0;
}
rumble_data[0] = 0x01; /* enable */
rumble_data[1] = ctx->left_motor_amplitude;
rumble_data[2] = ctx->right_motor_amplitude;
ctx->rumble_update_pending = SDL_FALSE;
ctx->last_rumble_time = SDL_GetTicks();
return HIDAPI_DriverShield_SendCommand(device, CMD_RUMBLE, rumble_data, sizeof(rumble_data));
}
static int HIDAPI_DriverShield_RumbleJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble)
{
if (device->product_id == USB_PRODUCT_NVIDIA_SHIELD_CONTROLLER_V103) {
Uint8 rumble_packet[] = { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
rumble_packet[2] = (low_frequency_rumble >> 8);
rumble_packet[4] = (high_frequency_rumble >> 8);
if (SDL_HIDAPI_SendRumble(device, rumble_packet, sizeof(rumble_packet)) != sizeof(rumble_packet)) {
return SDL_SetError("Couldn't send rumble packet");
}
return 0;
} else {
SDL_DriverShield_Context *ctx = device->context;
/* The rumble motors are quite intense, so tone down the intensity like the official driver does */
ctx->left_motor_amplitude = low_frequency_rumble >> 11;
ctx->right_motor_amplitude = high_frequency_rumble >> 11;
ctx->rumble_update_pending = SDL_TRUE;
if (ctx->rumble_report_pending) {
/* We will service this after the hardware acknowledges the previous request */
return 0;
}
return HIDAPI_DriverShield_SendNextRumble(device);
}
}
static int HIDAPI_DriverShield_RumbleJoystickTriggers(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint16 left_rumble, Uint16 right_rumble)
{
return SDL_Unsupported();
}
static Uint32 HIDAPI_DriverShield_GetJoystickCapabilities(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
{
return SDL_JOYCAP_RUMBLE;
}
static int HIDAPI_DriverShield_SetJoystickLED(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue)
{
return SDL_Unsupported();
}
static int HIDAPI_DriverShield_SendJoystickEffect(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, const void *data, int size)
{
const Uint8 *data_bytes = data;
if (size > 1) {
/* Single command byte followed by a variable length payload */
return HIDAPI_DriverShield_SendCommand(device, data_bytes[0], &data_bytes[1], size - 1);
} else if (size == 1) {
/* Single command byte with no payload */
return HIDAPI_DriverShield_SendCommand(device, data_bytes[0], NULL, 0);
} else {
return SDL_SetError("Effect data must at least contain a command byte");
}
}
static int HIDAPI_DriverShield_SetJoystickSensorsEnabled(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, SDL_bool enabled)
{
return SDL_Unsupported();
}
static void HIDAPI_DriverShield_HandleStatePacketV103(SDL_Joystick *joystick, SDL_DriverShield_Context *ctx, Uint8 *data, int size)
{
Uint64 timestamp = SDL_GetTicksNS();
if (ctx->last_state[3] != data[3]) {
SDL_bool dpad_up = SDL_FALSE;
SDL_bool dpad_down = SDL_FALSE;
SDL_bool dpad_left = SDL_FALSE;
SDL_bool dpad_right = SDL_FALSE;
switch (data[3]) {
case 0:
dpad_up = SDL_TRUE;
break;
case 1:
dpad_up = SDL_TRUE;
dpad_right = SDL_TRUE;
break;
case 2:
dpad_right = SDL_TRUE;
break;
case 3:
dpad_right = SDL_TRUE;
dpad_down = SDL_TRUE;
break;
case 4:
dpad_down = SDL_TRUE;
break;
case 5:
dpad_left = SDL_TRUE;
dpad_down = SDL_TRUE;
break;
case 6:
dpad_left = SDL_TRUE;
break;
case 7:
dpad_up = SDL_TRUE;
dpad_left = SDL_TRUE;
break;
default:
break;
}
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_DPAD_DOWN, dpad_down);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_DPAD_UP, dpad_up);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_DPAD_RIGHT, dpad_right);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_DPAD_LEFT, dpad_left);
}
if (ctx->last_state[1] != data[1]) {
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_A, (data[1] & 0x01) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_B, (data[1] & 0x02) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_X, (data[1] & 0x04) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_Y, (data[1] & 0x08) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_LEFT_SHOULDER, (data[1] & 0x10) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER, (data[1] & 0x20) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_LEFT_STICK, (data[1] & 0x40) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_RIGHT_STICK, (data[1] & 0x80) ? SDL_PRESSED : SDL_RELEASED);
}
if (ctx->last_state[2] != data[2]) {
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_START, (data[2] & 0x02) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_CONTROLLER_BUTTON_SHIELD_V103_PLUS, (data[2] & 0x08) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_CONTROLLER_BUTTON_SHIELD_V103_MINUS, (data[2] & 0x10) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_GUIDE, (data[2] & 0x20) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_BACK, (data[2] & 0x40) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_MISC1, (data[2] & 0x80) ? SDL_PRESSED : SDL_RELEASED);
}
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFTX, SDL_SwapLE16(*(Sint16 *)&data[4]) - 0x8000);
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFTY, SDL_SwapLE16(*(Sint16 *)&data[6]) - 0x8000);
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTX, SDL_SwapLE16(*(Sint16 *)&data[8]) - 0x8000);
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTY, SDL_SwapLE16(*(Sint16 *)&data[10]) - 0x8000);
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFT_TRIGGER, SDL_SwapLE16(*(Sint16 *)&data[12]) - 0x8000);
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHT_TRIGGER, SDL_SwapLE16(*(Sint16 *)&data[14]) - 0x8000);
SDL_memcpy(ctx->last_state, data, SDL_min(size, sizeof(ctx->last_state)));
}
#undef clamp
#define clamp(val, min, max) (((val) > (max)) ? (max) : (((val) < (min)) ? (min) : (val)))
static void HIDAPI_DriverShield_HandleTouchPacketV103(SDL_Joystick *joystick, SDL_DriverShield_Context *ctx, const Uint8 *data, int size)
{
Uint8 touchpad_state;
float touchpad_x, touchpad_y;
Uint64 timestamp = SDL_GetTicksNS();
SDL_SendJoystickButton(timestamp, joystick, SDL_CONTROLLER_BUTTON_SHIELD_V103_TOUCHPAD, (data[1] & 0x01) ? SDL_PRESSED : SDL_RELEASED);
/* It's a triangular pad, but just use the center as the usable touch area */
touchpad_state = !(data[1] & 0x80) ? SDL_PRESSED : SDL_RELEASED;
touchpad_x = clamp((float)(data[2] - 0x70) / 0x50, 0.0f, 1.0f);
touchpad_y = clamp((float)(data[4] - 0x40) / 0x15, 0.0f, 1.0f);
SDL_SendJoystickTouchpad(timestamp, joystick, 0, 0, touchpad_state, touchpad_x, touchpad_y, touchpad_state ? 1.0f : 0.0f);
}
static void HIDAPI_DriverShield_HandleStatePacketV104(SDL_Joystick *joystick, SDL_DriverShield_Context *ctx, Uint8 *data, int size)
{
Uint64 timestamp = SDL_GetTicksNS();
if (size < 23) {
return;
}
if (ctx->last_state[2] != data[2]) {
SDL_bool dpad_up = SDL_FALSE;
SDL_bool dpad_down = SDL_FALSE;
SDL_bool dpad_left = SDL_FALSE;
SDL_bool dpad_right = SDL_FALSE;
switch (data[2]) {
case 0:
dpad_up = SDL_TRUE;
break;
case 1:
dpad_up = SDL_TRUE;
dpad_right = SDL_TRUE;
break;
case 2:
dpad_right = SDL_TRUE;
break;
case 3:
dpad_right = SDL_TRUE;
dpad_down = SDL_TRUE;
break;
case 4:
dpad_down = SDL_TRUE;
break;
case 5:
dpad_left = SDL_TRUE;
dpad_down = SDL_TRUE;
break;
case 6:
dpad_left = SDL_TRUE;
break;
case 7:
dpad_up = SDL_TRUE;
dpad_left = SDL_TRUE;
break;
default:
break;
}
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_DPAD_DOWN, dpad_down);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_DPAD_UP, dpad_up);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_DPAD_RIGHT, dpad_right);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_DPAD_LEFT, dpad_left);
}
if (ctx->last_state[3] != data[3]) {
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_A, (data[3] & 0x01) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_B, (data[3] & 0x02) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_X, (data[3] & 0x04) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_Y, (data[3] & 0x08) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_LEFT_SHOULDER, (data[3] & 0x10) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER, (data[3] & 0x20) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_LEFT_STICK, (data[3] & 0x40) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_RIGHT_STICK, (data[3] & 0x80) ? SDL_PRESSED : SDL_RELEASED);
}
if (ctx->last_state[4] != data[4]) {
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_START, (data[4] & 0x01) ? SDL_PRESSED : SDL_RELEASED);
}
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFTX, SDL_SwapLE16(*(Sint16 *)&data[9]) - 0x8000);
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFTY, SDL_SwapLE16(*(Sint16 *)&data[11]) - 0x8000);
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTX, SDL_SwapLE16(*(Sint16 *)&data[13]) - 0x8000);
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTY, SDL_SwapLE16(*(Sint16 *)&data[15]) - 0x8000);
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFT_TRIGGER, SDL_SwapLE16(*(Sint16 *)&data[19]) - 0x8000);
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHT_TRIGGER, SDL_SwapLE16(*(Sint16 *)&data[21]) - 0x8000);
if (ctx->last_state[17] != data[17]) {
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_MISC1, (data[17] & 0x01) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_BACK, (data[17] & 0x02) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_GUIDE, (data[17] & 0x04) ? SDL_PRESSED : SDL_RELEASED);
}
SDL_memcpy(ctx->last_state, data, SDL_min(size, sizeof(ctx->last_state)));
}
static SDL_bool HIDAPI_DriverShield_UpdateDevice(SDL_HIDAPI_Device *device)
{
SDL_DriverShield_Context *ctx = (SDL_DriverShield_Context *)device->context;
SDL_Joystick *joystick = NULL;
Uint8 data[USB_PACKET_LENGTH];
int size = 0;
ShieldCommandReport_t *cmd_resp_report;
if (device->num_joysticks > 0) {
joystick = SDL_GetJoystickFromInstanceID(device->joysticks[0]);
} else {
return SDL_FALSE;
}
while ((size = SDL_hid_read_timeout(device->dev, data, sizeof(data), 0)) > 0) {
#ifdef DEBUG_SHIELD_PROTOCOL
HIDAPI_DumpPacket("NVIDIA SHIELD packet: size = %d", data, size);
#endif
/* Byte 0 is HID report ID */
switch (data[0]) {
case k_ShieldReportIdControllerState:
if (joystick == NULL) {
break;
}
if (size == 16) {
HIDAPI_DriverShield_HandleStatePacketV103(joystick, ctx, data, size);
} else {
HIDAPI_DriverShield_HandleStatePacketV104(joystick, ctx, data, size);
}
break;
case k_ShieldReportIdControllerTouch:
if (joystick == NULL) {
break;
}
HIDAPI_DriverShield_HandleTouchPacketV103(joystick, ctx, data, size);
break;
case k_ShieldReportIdCommandResponse:
cmd_resp_report = (ShieldCommandReport_t *)data;
switch (cmd_resp_report->cmd) {
case CMD_RUMBLE:
ctx->rumble_report_pending = SDL_FALSE;
HIDAPI_DriverShield_SendNextRumble(device);
break;
case CMD_CHARGE_STATE:
ctx->charging = cmd_resp_report->payload[0] != 0;
if (joystick) {
SDL_SendJoystickBatteryLevel(joystick, ctx->charging ? SDL_JOYSTICK_POWER_WIRED : ctx->battery_level);
}
break;
case CMD_BATTERY_STATE:
switch (cmd_resp_report->payload[2]) {
case 0:
ctx->battery_level = SDL_JOYSTICK_POWER_EMPTY;
break;
case 1:
ctx->battery_level = SDL_JOYSTICK_POWER_LOW;
break;
case 2: /* 40% */
case 3: /* 60% */
case 4: /* 80% */
ctx->battery_level = SDL_JOYSTICK_POWER_MEDIUM;
break;
case 5:
ctx->battery_level = SDL_JOYSTICK_POWER_FULL;
break;
default:
ctx->battery_level = SDL_JOYSTICK_POWER_UNKNOWN;
break;
}
if (joystick) {
SDL_SendJoystickBatteryLevel(joystick, ctx->charging ? SDL_JOYSTICK_POWER_WIRED : ctx->battery_level);
}
break;
}
break;
}
}
/* Ask for battery state again if we're due for an update */
if (joystick && SDL_GetTicks() >= (ctx->last_battery_query_time + BATTERY_POLL_INTERVAL_MS)) {
ctx->last_battery_query_time = SDL_GetTicks();
HIDAPI_DriverShield_SendCommand(device, CMD_BATTERY_STATE, NULL, 0);
}
/* Retransmit rumble packets if they've lasted longer than the hardware supports */
if ((ctx->left_motor_amplitude != 0 || ctx->right_motor_amplitude != 0) &&
SDL_GetTicks() >= (ctx->last_rumble_time + RUMBLE_REFRESH_INTERVAL_MS)) {
ctx->rumble_update_pending = SDL_TRUE;
HIDAPI_DriverShield_SendNextRumble(device);
}
if (size < 0) {
/* Read error, device is disconnected */
HIDAPI_JoystickDisconnected(device, device->joysticks[0]);
}
return size >= 0;
}
static void HIDAPI_DriverShield_CloseJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
{
}
static void HIDAPI_DriverShield_FreeDevice(SDL_HIDAPI_Device *device)
{
}
SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverShield = {
SDL_HINT_JOYSTICK_HIDAPI_SHIELD,
SDL_TRUE,
HIDAPI_DriverShield_RegisterHints,
HIDAPI_DriverShield_UnregisterHints,
HIDAPI_DriverShield_IsEnabled,
HIDAPI_DriverShield_IsSupportedDevice,
HIDAPI_DriverShield_InitDevice,
HIDAPI_DriverShield_GetDevicePlayerIndex,
HIDAPI_DriverShield_SetDevicePlayerIndex,
HIDAPI_DriverShield_UpdateDevice,
HIDAPI_DriverShield_OpenJoystick,
HIDAPI_DriverShield_RumbleJoystick,
HIDAPI_DriverShield_RumbleJoystickTriggers,
HIDAPI_DriverShield_GetJoystickCapabilities,
HIDAPI_DriverShield_SetJoystickLED,
HIDAPI_DriverShield_SendJoystickEffect,
HIDAPI_DriverShield_SetJoystickSensorsEnabled,
HIDAPI_DriverShield_CloseJoystick,
HIDAPI_DriverShield_FreeDevice,
};
#endif /* SDL_JOYSTICK_HIDAPI_SHIELD */
#endif /* SDL_JOYSTICK_HIDAPI */

View File

@@ -0,0 +1,334 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 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_HIDAPI
#include "../SDL_sysjoystick.h"
#include "SDL_hidapijoystick_c.h"
#include "SDL_hidapi_rumble.h"
#ifdef SDL_JOYSTICK_HIDAPI_STADIA
/* Define this if you want to log all packets from the controller */
/*#define DEBUG_STADIA_PROTOCOL*/
enum
{
SDL_CONTROLLER_BUTTON_STADIA_SHARE = 15,
SDL_CONTROLLER_BUTTON_STADIA_GOOGLE_ASSISTANT,
SDL_CONTROLLER_NUM_STADIA_BUTTONS,
};
typedef struct
{
SDL_bool rumble_supported;
Uint8 last_state[USB_PACKET_LENGTH];
} SDL_DriverStadia_Context;
static void HIDAPI_DriverStadia_RegisterHints(SDL_HintCallback callback, void *userdata)
{
SDL_AddHintCallback(SDL_HINT_JOYSTICK_HIDAPI_STADIA, callback, userdata);
}
static void HIDAPI_DriverStadia_UnregisterHints(SDL_HintCallback callback, void *userdata)
{
SDL_DelHintCallback(SDL_HINT_JOYSTICK_HIDAPI_STADIA, callback, userdata);
}
static SDL_bool HIDAPI_DriverStadia_IsEnabled(void)
{
return SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI_STADIA, SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI, SDL_HIDAPI_DEFAULT));
}
static SDL_bool HIDAPI_DriverStadia_IsSupportedDevice(SDL_HIDAPI_Device *device, const char *name, SDL_GamepadType type, Uint16 vendor_id, Uint16 product_id, Uint16 version, int interface_number, int interface_class, int interface_subclass, int interface_protocol)
{
return SDL_IsJoystickGoogleStadiaController(vendor_id, product_id);
}
static SDL_bool HIDAPI_DriverStadia_InitDevice(SDL_HIDAPI_Device *device)
{
SDL_DriverStadia_Context *ctx;
ctx = (SDL_DriverStadia_Context *)SDL_calloc(1, sizeof(*ctx));
if (ctx == NULL) {
SDL_OutOfMemory();
return SDL_FALSE;
}
device->context = ctx;
/* Check whether rumble is supported */
{
Uint8 rumble_packet[] = { 0x05, 0x00, 0x00, 0x00, 0x00 };
if (SDL_hid_write(device->dev, rumble_packet, sizeof(rumble_packet)) >= 0) {
ctx->rumble_supported = SDL_TRUE;
}
}
HIDAPI_SetDeviceName(device, "Google Stadia Controller");
return HIDAPI_JoystickConnected(device, NULL);
}
static int HIDAPI_DriverStadia_GetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id)
{
return -1;
}
static void HIDAPI_DriverStadia_SetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id, int player_index)
{
}
static SDL_bool HIDAPI_DriverStadia_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
{
SDL_DriverStadia_Context *ctx = (SDL_DriverStadia_Context *)device->context;
SDL_AssertJoysticksLocked();
SDL_zeroa(ctx->last_state);
/* Initialize the joystick capabilities */
joystick->nbuttons = SDL_CONTROLLER_NUM_STADIA_BUTTONS;
joystick->naxes = SDL_GAMEPAD_AXIS_MAX;
joystick->epowerlevel = SDL_JOYSTICK_POWER_WIRED;
return SDL_TRUE;
}
static int HIDAPI_DriverStadia_RumbleJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble)
{
SDL_DriverStadia_Context *ctx = (SDL_DriverStadia_Context *)device->context;
if (ctx->rumble_supported) {
Uint8 rumble_packet[] = { 0x05, 0x00, 0x00, 0x00, 0x00 };
rumble_packet[1] = (low_frequency_rumble & 0xFF);
rumble_packet[2] = (low_frequency_rumble >> 8);
rumble_packet[3] = (high_frequency_rumble & 0xFF);
rumble_packet[4] = (high_frequency_rumble >> 8);
if (SDL_HIDAPI_SendRumble(device, rumble_packet, sizeof(rumble_packet)) != sizeof(rumble_packet)) {
return SDL_SetError("Couldn't send rumble packet");
}
return 0;
} else {
return SDL_Unsupported();
}
}
static int HIDAPI_DriverStadia_RumbleJoystickTriggers(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint16 left_rumble, Uint16 right_rumble)
{
return SDL_Unsupported();
}
static Uint32 HIDAPI_DriverStadia_GetJoystickCapabilities(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
{
SDL_DriverStadia_Context *ctx = (SDL_DriverStadia_Context *)device->context;
Uint32 caps = 0;
if (ctx->rumble_supported) {
caps |= SDL_JOYCAP_RUMBLE;
}
return caps;
}
static int HIDAPI_DriverStadia_SetJoystickLED(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue)
{
return SDL_Unsupported();
}
static int HIDAPI_DriverStadia_SendJoystickEffect(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, const void *data, int size)
{
return SDL_Unsupported();
}
static int HIDAPI_DriverStadia_SetJoystickSensorsEnabled(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, SDL_bool enabled)
{
return SDL_Unsupported();
}
static void HIDAPI_DriverStadia_HandleStatePacket(SDL_Joystick *joystick, SDL_DriverStadia_Context *ctx, Uint8 *data, int size)
{
Sint16 axis;
Uint64 timestamp = SDL_GetTicksNS();
// The format is the same but the original FW will send 10 bytes and January '21 FW update will send 11
if (size < 10 || data[0] != 0x03) {
/* We don't know how to handle this report */
return;
}
if (ctx->last_state[1] != data[1]) {
SDL_bool dpad_up = SDL_FALSE;
SDL_bool dpad_down = SDL_FALSE;
SDL_bool dpad_left = SDL_FALSE;
SDL_bool dpad_right = SDL_FALSE;
switch (data[1]) {
case 0:
dpad_up = SDL_TRUE;
break;
case 1:
dpad_up = SDL_TRUE;
dpad_right = SDL_TRUE;
break;
case 2:
dpad_right = SDL_TRUE;
break;
case 3:
dpad_right = SDL_TRUE;
dpad_down = SDL_TRUE;
break;
case 4:
dpad_down = SDL_TRUE;
break;
case 5:
dpad_left = SDL_TRUE;
dpad_down = SDL_TRUE;
break;
case 6:
dpad_left = SDL_TRUE;
break;
case 7:
dpad_up = SDL_TRUE;
dpad_left = SDL_TRUE;
break;
default:
break;
}
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_DPAD_DOWN, dpad_down);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_DPAD_UP, dpad_up);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_DPAD_RIGHT, dpad_right);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_DPAD_LEFT, dpad_left);
}
if (ctx->last_state[2] != data[2]) {
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_BACK, (data[2] & 0x40) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_GUIDE, (data[2] & 0x10) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_START, (data[2] & 0x20) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_RIGHT_STICK, (data[2] & 0x80) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_CONTROLLER_BUTTON_STADIA_SHARE, (data[2] & 0x01) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_CONTROLLER_BUTTON_STADIA_GOOGLE_ASSISTANT, (data[2] & 0x02) ? SDL_PRESSED : SDL_RELEASED);
}
if (ctx->last_state[3] != data[3]) {
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_A, (data[3] & 0x40) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_B, (data[3] & 0x20) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_X, (data[3] & 0x10) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_Y, (data[3] & 0x08) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_LEFT_SHOULDER, (data[3] & 0x04) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER, (data[3] & 0x02) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_LEFT_STICK, (data[3] & 0x01) ? SDL_PRESSED : SDL_RELEASED);
}
#define READ_STICK_AXIS(offset) \
(data[offset] == 0x80 ? 0 : (Sint16)HIDAPI_RemapVal((float)((int)data[offset] - 0x80), 0x01 - 0x80, 0xff - 0x80, SDL_MIN_SINT16, SDL_MAX_SINT16))
{
axis = READ_STICK_AXIS(4);
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFTX, axis);
axis = READ_STICK_AXIS(5);
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFTY, axis);
axis = READ_STICK_AXIS(6);
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTX, axis);
axis = READ_STICK_AXIS(7);
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTY, axis);
}
#undef READ_STICK_AXIS
#define READ_TRIGGER_AXIS(offset) \
(Sint16)(((int)data[offset] * 257) - 32768)
{
axis = READ_TRIGGER_AXIS(8);
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFT_TRIGGER, axis);
axis = READ_TRIGGER_AXIS(9);
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHT_TRIGGER, axis);
}
#undef READ_TRIGGER_AXIS
SDL_memcpy(ctx->last_state, data, SDL_min(size, sizeof(ctx->last_state)));
}
static SDL_bool HIDAPI_DriverStadia_UpdateDevice(SDL_HIDAPI_Device *device)
{
SDL_DriverStadia_Context *ctx = (SDL_DriverStadia_Context *)device->context;
SDL_Joystick *joystick = NULL;
Uint8 data[USB_PACKET_LENGTH];
int size = 0;
if (device->num_joysticks > 0) {
joystick = SDL_GetJoystickFromInstanceID(device->joysticks[0]);
} else {
return SDL_FALSE;
}
while ((size = SDL_hid_read_timeout(device->dev, data, sizeof(data), 0)) > 0) {
#ifdef DEBUG_STADIA_PROTOCOL
HIDAPI_DumpPacket("Google Stadia packet: size = %d", data, size);
#endif
if (joystick == NULL) {
continue;
}
HIDAPI_DriverStadia_HandleStatePacket(joystick, ctx, data, size);
}
if (size < 0) {
/* Read error, device is disconnected */
HIDAPI_JoystickDisconnected(device, device->joysticks[0]);
}
return size >= 0;
}
static void HIDAPI_DriverStadia_CloseJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
{
}
static void HIDAPI_DriverStadia_FreeDevice(SDL_HIDAPI_Device *device)
{
}
SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverStadia = {
SDL_HINT_JOYSTICK_HIDAPI_STADIA,
SDL_TRUE,
HIDAPI_DriverStadia_RegisterHints,
HIDAPI_DriverStadia_UnregisterHints,
HIDAPI_DriverStadia_IsEnabled,
HIDAPI_DriverStadia_IsSupportedDevice,
HIDAPI_DriverStadia_InitDevice,
HIDAPI_DriverStadia_GetDevicePlayerIndex,
HIDAPI_DriverStadia_SetDevicePlayerIndex,
HIDAPI_DriverStadia_UpdateDevice,
HIDAPI_DriverStadia_OpenJoystick,
HIDAPI_DriverStadia_RumbleJoystick,
HIDAPI_DriverStadia_RumbleJoystickTriggers,
HIDAPI_DriverStadia_GetJoystickCapabilities,
HIDAPI_DriverStadia_SetJoystickLED,
HIDAPI_DriverStadia_SendJoystickEffect,
HIDAPI_DriverStadia_SetJoystickSensorsEnabled,
HIDAPI_DriverStadia_CloseJoystick,
HIDAPI_DriverStadia_FreeDevice,
};
#endif /* SDL_JOYSTICK_HIDAPI_STADIA */
#endif /* SDL_JOYSTICK_HIDAPI */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,386 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 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_HIDAPI
#include "../../SDL_hints_c.h"
#include "../SDL_sysjoystick.h"
#include "SDL_hidapijoystick_c.h"
#include "SDL_hidapi_rumble.h"
#ifdef SDL_JOYSTICK_HIDAPI_XBOX360
/* Define this if you want to log all packets from the controller */
/*#define DEBUG_XBOX_PROTOCOL*/
typedef struct
{
SDL_HIDAPI_Device *device;
SDL_Joystick *joystick;
int player_index;
SDL_bool player_lights;
Uint8 last_state[USB_PACKET_LENGTH];
} SDL_DriverXbox360_Context;
static void HIDAPI_DriverXbox360_RegisterHints(SDL_HintCallback callback, void *userdata)
{
SDL_AddHintCallback(SDL_HINT_JOYSTICK_HIDAPI_XBOX, callback, userdata);
SDL_AddHintCallback(SDL_HINT_JOYSTICK_HIDAPI_XBOX_360, callback, userdata);
}
static void HIDAPI_DriverXbox360_UnregisterHints(SDL_HintCallback callback, void *userdata)
{
SDL_DelHintCallback(SDL_HINT_JOYSTICK_HIDAPI_XBOX, callback, userdata);
SDL_DelHintCallback(SDL_HINT_JOYSTICK_HIDAPI_XBOX_360, callback, userdata);
}
static SDL_bool HIDAPI_DriverXbox360_IsEnabled(void)
{
return SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI_XBOX_360,
SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI_XBOX, SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI, SDL_HIDAPI_DEFAULT)));
}
static SDL_bool HIDAPI_DriverXbox360_IsSupportedDevice(SDL_HIDAPI_Device *device, const char *name, SDL_GamepadType type, Uint16 vendor_id, Uint16 product_id, Uint16 version, int interface_number, int interface_class, int interface_subclass, int interface_protocol)
{
const int XB360W_IFACE_PROTOCOL = 129; /* Wireless */
if (vendor_id == USB_VENDOR_ASTRO && product_id == USB_PRODUCT_ASTRO_C40_XBOX360) {
/* This is the ASTRO C40 in Xbox 360 mode */
return SDL_TRUE;
}
if (vendor_id == USB_VENDOR_NVIDIA) {
/* This is the NVIDIA Shield controller which doesn't talk Xbox controller protocol */
return SDL_FALSE;
}
if ((vendor_id == USB_VENDOR_MICROSOFT && (product_id == 0x0291 || product_id == 0x0719)) ||
(type == SDL_GAMEPAD_TYPE_XBOX360 && interface_protocol == XB360W_IFACE_PROTOCOL)) {
/* This is the wireless dongle, which talks a different protocol */
return SDL_FALSE;
}
if (interface_number > 0) {
/* This is the chatpad or other input interface, not the Xbox 360 interface */
return SDL_FALSE;
}
#ifdef __MACOS__
if (vendor_id == USB_VENDOR_MICROSOFT && product_id == USB_PRODUCT_XBOX360_WIRED_CONTROLLER && version == 0) {
/* This is the Steam Virtual Gamepad, which isn't supported by this driver */
return SDL_FALSE;
}
/* Wired Xbox One controllers are handled by this driver, interfacing with
the 360Controller driver available from:
https://github.com/360Controller/360Controller/releases
Bluetooth Xbox One controllers are handled by the SDL Xbox One driver
*/
if (SDL_IsJoystickBluetoothXboxOne(vendor_id, product_id)) {
return SDL_FALSE;
}
return (type == SDL_GAMEPAD_TYPE_XBOX360 || type == SDL_GAMEPAD_TYPE_XBOXONE) ? SDL_TRUE : SDL_FALSE;
#else
return (type == SDL_GAMEPAD_TYPE_XBOX360) ? SDL_TRUE : SDL_FALSE;
#endif
}
static SDL_bool SetSlotLED(SDL_hid_device *dev, Uint8 slot, SDL_bool on)
{
const SDL_bool blink = SDL_FALSE;
Uint8 mode = on ? ((blink ? 0x02 : 0x06) + slot) : 0;
Uint8 led_packet[] = { 0x01, 0x03, 0x00 };
led_packet[2] = mode;
if (SDL_hid_write(dev, led_packet, sizeof(led_packet)) != sizeof(led_packet)) {
return SDL_FALSE;
}
return SDL_TRUE;
}
static void UpdateSlotLED(SDL_DriverXbox360_Context *ctx)
{
if (ctx->player_lights) {
SetSlotLED(ctx->device->dev, (ctx->player_index % 4), SDL_TRUE);
} else {
SetSlotLED(ctx->device->dev, 0, SDL_FALSE);
}
}
static void SDLCALL SDL_PlayerLEDHintChanged(void *userdata, const char *name, const char *oldValue, const char *hint)
{
SDL_DriverXbox360_Context *ctx = (SDL_DriverXbox360_Context *)userdata;
SDL_bool player_lights = SDL_GetStringBoolean(hint, SDL_TRUE);
if (player_lights != ctx->player_lights) {
ctx->player_lights = player_lights;
UpdateSlotLED(ctx);
}
}
static SDL_bool HIDAPI_DriverXbox360_InitDevice(SDL_HIDAPI_Device *device)
{
SDL_DriverXbox360_Context *ctx;
ctx = (SDL_DriverXbox360_Context *)SDL_calloc(1, sizeof(*ctx));
if (ctx == NULL) {
SDL_OutOfMemory();
return SDL_FALSE;
}
ctx->device = device;
device->context = ctx;
device->type = SDL_GAMEPAD_TYPE_XBOX360;
return HIDAPI_JoystickConnected(device, NULL);
}
static int HIDAPI_DriverXbox360_GetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id)
{
return -1;
}
static void HIDAPI_DriverXbox360_SetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id, int player_index)
{
SDL_DriverXbox360_Context *ctx = (SDL_DriverXbox360_Context *)device->context;
if (!ctx->joystick) {
return;
}
ctx->player_index = player_index;
UpdateSlotLED(ctx);
}
static SDL_bool HIDAPI_DriverXbox360_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
{
SDL_DriverXbox360_Context *ctx = (SDL_DriverXbox360_Context *)device->context;
SDL_AssertJoysticksLocked();
ctx->joystick = joystick;
SDL_zeroa(ctx->last_state);
/* Initialize player index (needed for setting LEDs) */
ctx->player_index = SDL_GetJoystickPlayerIndex(joystick);
ctx->player_lights = SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI_XBOX_360_PLAYER_LED, SDL_TRUE);
UpdateSlotLED(ctx);
SDL_AddHintCallback(SDL_HINT_JOYSTICK_HIDAPI_XBOX_360_PLAYER_LED,
SDL_PlayerLEDHintChanged, ctx);
/* Initialize the joystick capabilities */
joystick->nbuttons = 15;
joystick->naxes = SDL_GAMEPAD_AXIS_MAX;
joystick->epowerlevel = SDL_JOYSTICK_POWER_WIRED;
return SDL_TRUE;
}
static int HIDAPI_DriverXbox360_RumbleJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble)
{
#ifdef __MACOS__
if (SDL_IsJoystickBluetoothXboxOne(device->vendor_id, device->product_id)) {
Uint8 rumble_packet[] = { 0x03, 0x0F, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00 };
rumble_packet[4] = (low_frequency_rumble >> 8);
rumble_packet[5] = (high_frequency_rumble >> 8);
if (SDL_HIDAPI_SendRumble(device, rumble_packet, sizeof(rumble_packet)) != sizeof(rumble_packet)) {
return SDL_SetError("Couldn't send rumble packet");
}
} else {
/* On macOS the 360Controller driver uses this short report,
and we need to prefix it with a magic token so hidapi passes it through untouched
*/
Uint8 rumble_packet[] = { 'M', 'A', 'G', 'I', 'C', '0', 0x00, 0x04, 0x00, 0x00 };
rumble_packet[6 + 2] = (low_frequency_rumble >> 8);
rumble_packet[6 + 3] = (high_frequency_rumble >> 8);
if (SDL_HIDAPI_SendRumble(device, rumble_packet, sizeof(rumble_packet)) != sizeof(rumble_packet)) {
return SDL_SetError("Couldn't send rumble packet");
}
}
#else
Uint8 rumble_packet[] = { 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
rumble_packet[3] = (low_frequency_rumble >> 8);
rumble_packet[4] = (high_frequency_rumble >> 8);
if (SDL_HIDAPI_SendRumble(device, rumble_packet, sizeof(rumble_packet)) != sizeof(rumble_packet)) {
return SDL_SetError("Couldn't send rumble packet");
}
#endif
return 0;
}
static int HIDAPI_DriverXbox360_RumbleJoystickTriggers(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint16 left_rumble, Uint16 right_rumble)
{
return SDL_Unsupported();
}
static Uint32 HIDAPI_DriverXbox360_GetJoystickCapabilities(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
{
/* Doesn't have an RGB LED, so don't return SDL_JOYCAP_LED here */
return SDL_JOYCAP_RUMBLE;
}
static int HIDAPI_DriverXbox360_SetJoystickLED(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue)
{
return SDL_Unsupported();
}
static int HIDAPI_DriverXbox360_SendJoystickEffect(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, const void *data, int size)
{
return SDL_Unsupported();
}
static int HIDAPI_DriverXbox360_SetJoystickSensorsEnabled(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, SDL_bool enabled)
{
return SDL_Unsupported();
}
static void HIDAPI_DriverXbox360_HandleStatePacket(SDL_Joystick *joystick, SDL_DriverXbox360_Context *ctx, Uint8 *data, int size)
{
Sint16 axis;
#ifdef __MACOS__
const SDL_bool invert_y_axes = SDL_FALSE;
#else
const SDL_bool invert_y_axes = SDL_TRUE;
#endif
Uint64 timestamp = SDL_GetTicksNS();
if (ctx->last_state[2] != data[2]) {
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_DPAD_UP, (data[2] & 0x01) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_DPAD_DOWN, (data[2] & 0x02) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_DPAD_LEFT, (data[2] & 0x04) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_DPAD_RIGHT, (data[2] & 0x08) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_START, (data[2] & 0x10) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_BACK, (data[2] & 0x20) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_LEFT_STICK, (data[2] & 0x40) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_RIGHT_STICK, (data[2] & 0x80) ? SDL_PRESSED : SDL_RELEASED);
}
if (ctx->last_state[3] != data[3]) {
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_LEFT_SHOULDER, (data[3] & 0x01) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER, (data[3] & 0x02) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_GUIDE, (data[3] & 0x04) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_A, (data[3] & 0x10) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_B, (data[3] & 0x20) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_X, (data[3] & 0x40) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_Y, (data[3] & 0x80) ? SDL_PRESSED : SDL_RELEASED);
}
axis = ((int)data[4] * 257) - 32768;
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFT_TRIGGER, axis);
axis = ((int)data[5] * 257) - 32768;
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHT_TRIGGER, axis);
axis = SDL_SwapLE16(*(Sint16 *)(&data[6]));
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFTX, axis);
axis = SDL_SwapLE16(*(Sint16 *)(&data[8]));
if (invert_y_axes) {
axis = ~axis;
}
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFTY, axis);
axis = SDL_SwapLE16(*(Sint16 *)(&data[10]));
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTX, axis);
axis = SDL_SwapLE16(*(Sint16 *)(&data[12]));
if (invert_y_axes) {
axis = ~axis;
}
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTY, axis);
SDL_memcpy(ctx->last_state, data, SDL_min((size_t)size, sizeof(ctx->last_state)));
}
static SDL_bool HIDAPI_DriverXbox360_UpdateDevice(SDL_HIDAPI_Device *device)
{
SDL_DriverXbox360_Context *ctx = (SDL_DriverXbox360_Context *)device->context;
SDL_Joystick *joystick = NULL;
Uint8 data[USB_PACKET_LENGTH];
int size = 0;
if (device->num_joysticks > 0) {
joystick = SDL_GetJoystickFromInstanceID(device->joysticks[0]);
} else {
return SDL_FALSE;
}
while ((size = SDL_hid_read_timeout(device->dev, data, sizeof(data), 0)) > 0) {
#ifdef DEBUG_XBOX_PROTOCOL
HIDAPI_DumpPacket("Xbox 360 packet: size = %d", data, size);
#endif
if (joystick == NULL) {
continue;
}
if (data[0] == 0x00) {
HIDAPI_DriverXbox360_HandleStatePacket(joystick, ctx, data, size);
}
}
if (size < 0) {
/* Read error, device is disconnected */
HIDAPI_JoystickDisconnected(device, device->joysticks[0]);
}
return size >= 0;
}
static void HIDAPI_DriverXbox360_CloseJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
{
SDL_DriverXbox360_Context *ctx = (SDL_DriverXbox360_Context *)device->context;
SDL_DelHintCallback(SDL_HINT_JOYSTICK_HIDAPI_XBOX_360_PLAYER_LED,
SDL_PlayerLEDHintChanged, ctx);
ctx->joystick = NULL;
}
static void HIDAPI_DriverXbox360_FreeDevice(SDL_HIDAPI_Device *device)
{
}
SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverXbox360 = {
SDL_HINT_JOYSTICK_HIDAPI_XBOX_360,
SDL_TRUE,
HIDAPI_DriverXbox360_RegisterHints,
HIDAPI_DriverXbox360_UnregisterHints,
HIDAPI_DriverXbox360_IsEnabled,
HIDAPI_DriverXbox360_IsSupportedDevice,
HIDAPI_DriverXbox360_InitDevice,
HIDAPI_DriverXbox360_GetDevicePlayerIndex,
HIDAPI_DriverXbox360_SetDevicePlayerIndex,
HIDAPI_DriverXbox360_UpdateDevice,
HIDAPI_DriverXbox360_OpenJoystick,
HIDAPI_DriverXbox360_RumbleJoystick,
HIDAPI_DriverXbox360_RumbleJoystickTriggers,
HIDAPI_DriverXbox360_GetJoystickCapabilities,
HIDAPI_DriverXbox360_SetJoystickLED,
HIDAPI_DriverXbox360_SendJoystickEffect,
HIDAPI_DriverXbox360_SetJoystickSensorsEnabled,
HIDAPI_DriverXbox360_CloseJoystick,
HIDAPI_DriverXbox360_FreeDevice,
};
#endif /* SDL_JOYSTICK_HIDAPI_XBOX360 */
#endif /* SDL_JOYSTICK_HIDAPI */

View File

@@ -0,0 +1,379 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 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_HIDAPI
#include "../../SDL_hints_c.h"
#include "../SDL_sysjoystick.h"
#include "SDL_hidapijoystick_c.h"
#include "SDL_hidapi_rumble.h"
#ifdef SDL_JOYSTICK_HIDAPI_XBOX360
/* Define this if you want to log all packets from the controller */
/*#define DEBUG_XBOX_PROTOCOL*/
typedef struct
{
SDL_HIDAPI_Device *device;
SDL_bool connected;
int player_index;
SDL_bool player_lights;
Uint8 last_state[USB_PACKET_LENGTH];
} SDL_DriverXbox360W_Context;
static void HIDAPI_DriverXbox360W_RegisterHints(SDL_HintCallback callback, void *userdata)
{
SDL_AddHintCallback(SDL_HINT_JOYSTICK_HIDAPI_XBOX, callback, userdata);
SDL_AddHintCallback(SDL_HINT_JOYSTICK_HIDAPI_XBOX_360, callback, userdata);
SDL_AddHintCallback(SDL_HINT_JOYSTICK_HIDAPI_XBOX_360_WIRELESS, callback, userdata);
}
static void HIDAPI_DriverXbox360W_UnregisterHints(SDL_HintCallback callback, void *userdata)
{
SDL_DelHintCallback(SDL_HINT_JOYSTICK_HIDAPI_XBOX, callback, userdata);
SDL_DelHintCallback(SDL_HINT_JOYSTICK_HIDAPI_XBOX_360, callback, userdata);
SDL_DelHintCallback(SDL_HINT_JOYSTICK_HIDAPI_XBOX_360_WIRELESS, callback, userdata);
}
static SDL_bool HIDAPI_DriverXbox360W_IsEnabled(void)
{
return SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI_XBOX_360_WIRELESS,
SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI_XBOX_360, SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI_XBOX, SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI, SDL_HIDAPI_DEFAULT))));
}
static SDL_bool HIDAPI_DriverXbox360W_IsSupportedDevice(SDL_HIDAPI_Device *device, const char *name, SDL_GamepadType type, Uint16 vendor_id, Uint16 product_id, Uint16 version, int interface_number, int interface_class, int interface_subclass, int interface_protocol)
{
const int XB360W_IFACE_PROTOCOL = 129; /* Wireless */
if ((vendor_id == USB_VENDOR_MICROSOFT && (product_id == 0x0291 || product_id == 0x02a9 || product_id == 0x0719) && interface_protocol == 0) ||
(type == SDL_GAMEPAD_TYPE_XBOX360 && interface_protocol == XB360W_IFACE_PROTOCOL)) {
return SDL_TRUE;
}
return SDL_FALSE;
}
static SDL_bool SetSlotLED(SDL_hid_device *dev, Uint8 slot, SDL_bool on)
{
const SDL_bool blink = SDL_FALSE;
Uint8 mode = on ? ((blink ? 0x02 : 0x06) + slot) : 0;
Uint8 led_packet[] = { 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
led_packet[3] = 0x40 + (mode % 0x0e);
if (SDL_hid_write(dev, led_packet, sizeof(led_packet)) != sizeof(led_packet)) {
return SDL_FALSE;
}
return SDL_TRUE;
}
static void UpdateSlotLED(SDL_DriverXbox360W_Context *ctx)
{
if (ctx->player_lights) {
SetSlotLED(ctx->device->dev, (ctx->player_index % 4), SDL_TRUE);
} else {
SetSlotLED(ctx->device->dev, 0, SDL_FALSE);
}
}
static void SDLCALL SDL_PlayerLEDHintChanged(void *userdata, const char *name, const char *oldValue, const char *hint)
{
SDL_DriverXbox360W_Context *ctx = (SDL_DriverXbox360W_Context *)userdata;
SDL_bool player_lights = SDL_GetStringBoolean(hint, SDL_TRUE);
if (player_lights != ctx->player_lights) {
ctx->player_lights = player_lights;
UpdateSlotLED(ctx);
}
}
static void UpdatePowerLevel(SDL_Joystick *joystick, Uint8 level)
{
float normalized_level = (float)level / 255.0f;
if (normalized_level <= 0.05f) {
SDL_SendJoystickBatteryLevel(joystick, SDL_JOYSTICK_POWER_EMPTY);
} else if (normalized_level <= 0.20f) {
SDL_SendJoystickBatteryLevel(joystick, SDL_JOYSTICK_POWER_LOW);
} else if (normalized_level <= 0.70f) {
SDL_SendJoystickBatteryLevel(joystick, SDL_JOYSTICK_POWER_MEDIUM);
} else {
SDL_SendJoystickBatteryLevel(joystick, SDL_JOYSTICK_POWER_FULL);
}
}
static SDL_bool HIDAPI_DriverXbox360W_InitDevice(SDL_HIDAPI_Device *device)
{
SDL_DriverXbox360W_Context *ctx;
/* Requests controller presence information from the wireless dongle */
const Uint8 init_packet[] = { 0x08, 0x00, 0x0F, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
HIDAPI_SetDeviceName(device, "Xbox 360 Wireless Controller");
ctx = (SDL_DriverXbox360W_Context *)SDL_calloc(1, sizeof(*ctx));
if (ctx == NULL) {
SDL_OutOfMemory();
return SDL_FALSE;
}
ctx->device = device;
device->context = ctx;
if (SDL_hid_write(device->dev, init_packet, sizeof(init_packet)) != sizeof(init_packet)) {
SDL_SetError("Couldn't write init packet");
return SDL_FALSE;
}
device->type = SDL_GAMEPAD_TYPE_XBOX360;
return SDL_TRUE;
}
static int HIDAPI_DriverXbox360W_GetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id)
{
return -1;
}
static void HIDAPI_DriverXbox360W_SetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id, int player_index)
{
SDL_DriverXbox360W_Context *ctx = (SDL_DriverXbox360W_Context *)device->context;
if (ctx == NULL) {
return;
}
ctx->player_index = player_index;
UpdateSlotLED(ctx);
}
static SDL_bool HIDAPI_DriverXbox360W_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
{
SDL_DriverXbox360W_Context *ctx = (SDL_DriverXbox360W_Context *)device->context;
SDL_AssertJoysticksLocked();
SDL_zeroa(ctx->last_state);
/* Initialize player index (needed for setting LEDs) */
ctx->player_index = SDL_GetJoystickPlayerIndex(joystick);
ctx->player_lights = SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI_XBOX_360_PLAYER_LED, SDL_TRUE);
UpdateSlotLED(ctx);
SDL_AddHintCallback(SDL_HINT_JOYSTICK_HIDAPI_XBOX_360_PLAYER_LED,
SDL_PlayerLEDHintChanged, ctx);
/* Initialize the joystick capabilities */
joystick->nbuttons = 15;
joystick->naxes = SDL_GAMEPAD_AXIS_MAX;
joystick->epowerlevel = SDL_JOYSTICK_POWER_UNKNOWN;
return SDL_TRUE;
}
static int HIDAPI_DriverXbox360W_RumbleJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble)
{
Uint8 rumble_packet[] = { 0x00, 0x01, 0x0f, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
rumble_packet[5] = (low_frequency_rumble >> 8);
rumble_packet[6] = (high_frequency_rumble >> 8);
if (SDL_HIDAPI_SendRumble(device, rumble_packet, sizeof(rumble_packet)) != sizeof(rumble_packet)) {
return SDL_SetError("Couldn't send rumble packet");
}
return 0;
}
static int HIDAPI_DriverXbox360W_RumbleJoystickTriggers(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint16 left_rumble, Uint16 right_rumble)
{
return SDL_Unsupported();
}
static Uint32 HIDAPI_DriverXbox360W_GetJoystickCapabilities(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
{
/* Doesn't have an RGB LED, so don't return SDL_JOYCAP_LED here */
return SDL_JOYCAP_RUMBLE;
}
static int HIDAPI_DriverXbox360W_SetJoystickLED(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue)
{
return SDL_Unsupported();
}
static int HIDAPI_DriverXbox360W_SendJoystickEffect(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, const void *data, int size)
{
return SDL_Unsupported();
}
static int HIDAPI_DriverXbox360W_SetJoystickSensorsEnabled(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, SDL_bool enabled)
{
return SDL_Unsupported();
}
static void HIDAPI_DriverXbox360W_HandleStatePacket(SDL_Joystick *joystick, SDL_hid_device *dev, SDL_DriverXbox360W_Context *ctx, Uint8 *data, int size)
{
Sint16 axis;
const SDL_bool invert_y_axes = SDL_TRUE;
Uint64 timestamp = SDL_GetTicksNS();
if (ctx->last_state[2] != data[2]) {
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_DPAD_UP, (data[2] & 0x01) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_DPAD_DOWN, (data[2] & 0x02) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_DPAD_LEFT, (data[2] & 0x04) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_DPAD_RIGHT, (data[2] & 0x08) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_START, (data[2] & 0x10) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_BACK, (data[2] & 0x20) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_LEFT_STICK, (data[2] & 0x40) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_RIGHT_STICK, (data[2] & 0x80) ? SDL_PRESSED : SDL_RELEASED);
}
if (ctx->last_state[3] != data[3]) {
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_LEFT_SHOULDER, (data[3] & 0x01) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER, (data[3] & 0x02) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_GUIDE, (data[3] & 0x04) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_A, (data[3] & 0x10) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_B, (data[3] & 0x20) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_X, (data[3] & 0x40) ? SDL_PRESSED : SDL_RELEASED);
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_Y, (data[3] & 0x80) ? SDL_PRESSED : SDL_RELEASED);
}
axis = ((int)data[4] * 257) - 32768;
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFT_TRIGGER, axis);
axis = ((int)data[5] * 257) - 32768;
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHT_TRIGGER, axis);
axis = SDL_SwapLE16(*(Sint16 *)(&data[6]));
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFTX, axis);
axis = SDL_SwapLE16(*(Sint16 *)(&data[8]));
if (invert_y_axes) {
axis = ~axis;
}
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFTY, axis);
axis = SDL_SwapLE16(*(Sint16 *)(&data[10]));
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTX, axis);
axis = SDL_SwapLE16(*(Sint16 *)(&data[12]));
if (invert_y_axes) {
axis = ~axis;
}
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTY, axis);
SDL_memcpy(ctx->last_state, data, SDL_min(size, sizeof(ctx->last_state)));
}
static SDL_bool HIDAPI_DriverXbox360W_UpdateDevice(SDL_HIDAPI_Device *device)
{
SDL_DriverXbox360W_Context *ctx = (SDL_DriverXbox360W_Context *)device->context;
SDL_Joystick *joystick = NULL;
Uint8 data[USB_PACKET_LENGTH];
int size;
if (device->num_joysticks > 0) {
joystick = SDL_GetJoystickFromInstanceID(device->joysticks[0]);
}
while ((size = SDL_hid_read_timeout(device->dev, data, sizeof(data), 0)) > 0) {
#ifdef DEBUG_XBOX_PROTOCOL
HIDAPI_DumpPacket("Xbox 360 wireless packet: size = %d", data, size);
#endif
if (size == 2 && data[0] == 0x08) {
SDL_bool connected = (data[1] & 0x80) ? SDL_TRUE : SDL_FALSE;
#ifdef DEBUG_JOYSTICK
SDL_Log("Connected = %s\n", connected ? "TRUE" : "FALSE");
#endif
if (connected != ctx->connected) {
ctx->connected = connected;
if (connected) {
SDL_JoystickID joystickID;
HIDAPI_JoystickConnected(device, &joystickID);
} else if (device->num_joysticks > 0) {
HIDAPI_JoystickDisconnected(device, device->joysticks[0]);
}
}
} else if (size == 29 && data[0] == 0x00 && data[1] == 0x0f && data[2] == 0x00 && data[3] == 0xf0) {
/* Serial number is data[7-13] */
#ifdef DEBUG_JOYSTICK
SDL_Log("Battery status (initial): %d\n", data[17]);
#endif
if (joystick) {
UpdatePowerLevel(joystick, data[17]);
}
} else if (size == 29 && data[0] == 0x00 && data[1] == 0x00 && data[2] == 0x00 && data[3] == 0x13) {
#ifdef DEBUG_JOYSTICK
SDL_Log("Battery status: %d\n", data[4]);
#endif
if (joystick) {
UpdatePowerLevel(joystick, data[4]);
}
} else if (size == 29 && data[0] == 0x00 && (data[1] & 0x01) == 0x01) {
if (joystick) {
HIDAPI_DriverXbox360W_HandleStatePacket(joystick, device->dev, ctx, data + 4, size - 4);
}
}
}
if (size < 0 && device->num_joysticks > 0) {
/* Read error, device is disconnected */
HIDAPI_JoystickDisconnected(device, device->joysticks[0]);
}
return size >= 0;
}
static void HIDAPI_DriverXbox360W_CloseJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
{
SDL_DriverXbox360W_Context *ctx = (SDL_DriverXbox360W_Context *)device->context;
SDL_DelHintCallback(SDL_HINT_JOYSTICK_HIDAPI_XBOX_360_PLAYER_LED,
SDL_PlayerLEDHintChanged, ctx);
}
static void HIDAPI_DriverXbox360W_FreeDevice(SDL_HIDAPI_Device *device)
{
}
SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverXbox360W = {
SDL_HINT_JOYSTICK_HIDAPI_XBOX_360_WIRELESS,
SDL_TRUE,
HIDAPI_DriverXbox360W_RegisterHints,
HIDAPI_DriverXbox360W_UnregisterHints,
HIDAPI_DriverXbox360W_IsEnabled,
HIDAPI_DriverXbox360W_IsSupportedDevice,
HIDAPI_DriverXbox360W_InitDevice,
HIDAPI_DriverXbox360W_GetDevicePlayerIndex,
HIDAPI_DriverXbox360W_SetDevicePlayerIndex,
HIDAPI_DriverXbox360W_UpdateDevice,
HIDAPI_DriverXbox360W_OpenJoystick,
HIDAPI_DriverXbox360W_RumbleJoystick,
HIDAPI_DriverXbox360W_RumbleJoystickTriggers,
HIDAPI_DriverXbox360W_GetJoystickCapabilities,
HIDAPI_DriverXbox360W_SetJoystickLED,
HIDAPI_DriverXbox360W_SendJoystickEffect,
HIDAPI_DriverXbox360W_SetJoystickSensorsEnabled,
HIDAPI_DriverXbox360W_CloseJoystick,
HIDAPI_DriverXbox360W_FreeDevice,
};
#endif /* SDL_JOYSTICK_HIDAPI_XBOX360 */
#endif /* SDL_JOYSTICK_HIDAPI */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,162 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 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"
#ifndef SDL_JOYSTICK_HIDAPI_H
#define SDL_JOYSTICK_HIDAPI_H
#include "../usb_ids.h"
/* This is the full set of HIDAPI drivers available */
#define SDL_JOYSTICK_HIDAPI_GAMECUBE
#define SDL_JOYSTICK_HIDAPI_LUNA
#define SDL_JOYSTICK_HIDAPI_PS3
#define SDL_JOYSTICK_HIDAPI_PS4
#define SDL_JOYSTICK_HIDAPI_PS5
#define SDL_JOYSTICK_HIDAPI_STADIA
#define SDL_JOYSTICK_HIDAPI_STEAM /* Simple support for BLE Steam Controller, hint is disabled by default */
#define SDL_JOYSTICK_HIDAPI_SWITCH
#define SDL_JOYSTICK_HIDAPI_WII
#define SDL_JOYSTICK_HIDAPI_XBOX360
#define SDL_JOYSTICK_HIDAPI_XBOXONE
#define SDL_JOYSTICK_HIDAPI_SHIELD
/* Whether HIDAPI is enabled by default */
#define SDL_HIDAPI_DEFAULT SDL_TRUE
/* The maximum size of a USB packet for HID devices */
#define USB_PACKET_LENGTH 64
/* Forward declaration */
struct SDL_HIDAPI_DeviceDriver;
typedef struct SDL_HIDAPI_Device
{
const void *magic;
char *name;
char *path;
Uint16 vendor_id;
Uint16 product_id;
Uint16 version;
char *serial;
SDL_JoystickGUID guid;
int interface_number; /* Available on Windows and Linux */
int interface_class;
int interface_subclass;
int interface_protocol;
Uint16 usage_page; /* Available on Windows and macOS */
Uint16 usage; /* Available on Windows and macOS */
SDL_bool is_bluetooth;
SDL_JoystickType joystick_type;
SDL_GamepadType type;
struct SDL_HIDAPI_DeviceDriver *driver;
void *context;
SDL_Mutex *dev_lock;
SDL_hid_device *dev;
SDL_AtomicInt rumble_pending;
int num_joysticks;
SDL_JoystickID *joysticks;
/* Used during scanning for device changes */
SDL_bool seen;
/* Used to flag that the device is being updated */
SDL_bool updating;
struct SDL_HIDAPI_Device *parent;
int num_children;
struct SDL_HIDAPI_Device **children;
struct SDL_HIDAPI_Device *next;
} SDL_HIDAPI_Device;
typedef struct SDL_HIDAPI_DeviceDriver
{
const char *name;
SDL_bool enabled;
void (*RegisterHints)(SDL_HintCallback callback, void *userdata);
void (*UnregisterHints)(SDL_HintCallback callback, void *userdata);
SDL_bool (*IsEnabled)(void);
SDL_bool (*IsSupportedDevice)(SDL_HIDAPI_Device *device, const char *name, SDL_GamepadType type, Uint16 vendor_id, Uint16 product_id, Uint16 version, int interface_number, int interface_class, int interface_subclass, int interface_protocol);
SDL_bool (*InitDevice)(SDL_HIDAPI_Device *device);
int (*GetDevicePlayerIndex)(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id);
void (*SetDevicePlayerIndex)(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id, int player_index);
SDL_bool (*UpdateDevice)(SDL_HIDAPI_Device *device);
SDL_bool (*OpenJoystick)(SDL_HIDAPI_Device *device, SDL_Joystick *joystick);
int (*RumbleJoystick)(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble);
int (*RumbleJoystickTriggers)(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint16 left_rumble, Uint16 right_rumble);
Uint32 (*GetJoystickCapabilities)(SDL_HIDAPI_Device *device, SDL_Joystick *joystick);
int (*SetJoystickLED)(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue);
int (*SendJoystickEffect)(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, const void *data, int size);
int (*SetJoystickSensorsEnabled)(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, SDL_bool enabled);
void (*CloseJoystick)(SDL_HIDAPI_Device *device, SDL_Joystick *joystick);
void (*FreeDevice)(SDL_HIDAPI_Device *device);
} SDL_HIDAPI_DeviceDriver;
/* HIDAPI device support */
extern SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverCombined;
extern SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverGameCube;
extern SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverJoyCons;
extern SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverLuna;
extern SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverNintendoClassic;
extern SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverPS3;
extern SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverPS3ThirdParty;
extern SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverPS4;
extern SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverPS5;
extern SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverShield;
extern SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverStadia;
extern SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverSteam;
extern SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverSwitch;
extern SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverWii;
extern SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverXbox360;
extern SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverXbox360W;
extern SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverXboxOne;
/* Return true if a HID device is present and supported as a joystick of the given type */
extern SDL_bool HIDAPI_IsDeviceTypePresent(SDL_GamepadType type);
/* Return true if a HID device is present and supported as a joystick */
extern SDL_bool HIDAPI_IsDevicePresent(Uint16 vendor_id, Uint16 product_id, Uint16 version, const char *name);
/* Return the type of a joystick if it's present and supported */
extern SDL_JoystickType HIDAPI_GetJoystickTypeFromGUID(SDL_JoystickGUID guid);
/* Return the type of a game controller if it's present and supported */
extern SDL_GamepadType HIDAPI_GetGamepadTypeFromGUID(SDL_JoystickGUID guid);
extern void HIDAPI_UpdateDevices(void);
extern void HIDAPI_SetDeviceName(SDL_HIDAPI_Device *device, const char *name);
extern void HIDAPI_SetDeviceProduct(SDL_HIDAPI_Device *device, Uint16 vendor_id, Uint16 product_id);
extern void HIDAPI_SetDeviceSerial(SDL_HIDAPI_Device *device, const char *serial);
extern SDL_bool HIDAPI_HasConnectedUSBDevice(const char *serial);
extern void HIDAPI_DisconnectBluetoothDevice(const char *serial);
extern SDL_bool HIDAPI_JoystickConnected(SDL_HIDAPI_Device *device, SDL_JoystickID *pJoystickID);
extern void HIDAPI_JoystickDisconnected(SDL_HIDAPI_Device *device, SDL_JoystickID joystickID);
extern void HIDAPI_DumpPacket(const char *prefix, const Uint8 *data, int size);
extern SDL_bool HIDAPI_SupportsPlaystationDetection(Uint16 vendor, Uint16 product);
extern float HIDAPI_RemapVal(float val, float val_min, float val_max, float output_min, float output_max);
#endif /* SDL_JOYSTICK_HIDAPI_H */

View File

@@ -0,0 +1,499 @@
/*
Simple DirectMedia Layer
Copyright (C) 2021 Valve Corporation
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.
*/
#ifndef _CONTROLLER_CONSTANTS_
#define _CONTROLLER_CONSTANTS_
#include "controller_structs.h"
#ifdef __cplusplus
extern "C" {
#endif
#define FEATURE_REPORT_SIZE 64
#define VALVE_USB_VID 0x28DE
// Frame update rate (in ms).
#define FAST_SCAN_INTERVAL 6
#define SLOW_SCAN_INTERVAL 9
// Contains each of the USB PIDs for Valve controllers (only add to this enum and never change the order)
enum ValveControllerPID
{
BASTILLE_PID = 0x2202,
CHELL_PID = 0x1101,
D0G_PID = 0x1102,
ELI_PID = 0x1103,
FREEMAN_PID = 0x1104,
D0G_BLE_PID = 0x1105,
D0G_BLE2_PID = 0x1106,
D0GGLE_PID = 0x1142,
};
// This enum contains all of the messages exchanged between the host and the target (only add to this enum and never change the order)
enum FeatureReportMessageIDs
{
ID_SET_DIGITAL_MAPPINGS = 0x80,
ID_CLEAR_DIGITAL_MAPPINGS = 0x81,
ID_GET_DIGITAL_MAPPINGS = 0x82,
ID_GET_ATTRIBUTES_VALUES = 0x83,
ID_GET_ATTRIBUTE_LABEL = 0x84,
ID_SET_DEFAULT_DIGITAL_MAPPINGS = 0x85,
ID_FACTORY_RESET = 0x86,
ID_SET_SETTINGS_VALUES = 0x87,
ID_CLEAR_SETTINGS_VALUES = 0x88,
ID_GET_SETTINGS_VALUES = 0x89,
ID_GET_SETTING_LABEL = 0x8A,
ID_GET_SETTINGS_MAXS = 0x8B,
ID_GET_SETTINGS_DEFAULTS = 0x8C,
ID_SET_CONTROLLER_MODE = 0x8D,
ID_LOAD_DEFAULT_SETTINGS = 0x8E,
ID_TRIGGER_HAPTIC_PULSE = 0x8F,
ID_TURN_OFF_CONTROLLER = 0x9F,
ID_GET_DEVICE_INFO = 0xA1,
ID_CALIBRATE_TRACKPADS = 0xA7,
ID_RESERVED_0 = 0xA8,
ID_SET_SERIAL_NUMBER = 0xA9,
ID_GET_TRACKPAD_CALIBRATION = 0xAA,
ID_GET_TRACKPAD_FACTORY_CALIBRATION = 0xAB,
ID_GET_TRACKPAD_RAW_DATA = 0xAC,
ID_ENABLE_PAIRING = 0xAD,
ID_GET_STRING_ATTRIBUTE = 0xAE,
ID_RADIO_ERASE_RECORDS = 0xAF,
ID_RADIO_WRITE_RECORD = 0xB0,
ID_SET_DONGLE_SETTING = 0xB1,
ID_DONGLE_DISCONNECT_DEVICE = 0xB2,
ID_DONGLE_COMMIT_DEVICE = 0xB3,
ID_DONGLE_GET_WIRELESS_STATE = 0xB4,
ID_CALIBRATE_GYRO = 0xB5,
ID_PLAY_AUDIO = 0xB6,
ID_AUDIO_UPDATE_START = 0xB7,
ID_AUDIO_UPDATE_DATA = 0xB8,
ID_AUDIO_UPDATE_COMPLETE = 0xB9,
ID_GET_CHIPID = 0xBA,
ID_CALIBRATE_JOYSTICK = 0xBF,
ID_CALIBRATE_ANALOG_TRIGGERS = 0xC0,
ID_SET_AUDIO_MAPPING = 0xC1,
ID_CHECK_GYRO_FW_LOAD = 0xC2,
ID_CALIBRATE_ANALOG = 0xC3,
ID_DONGLE_GET_CONNECTED_SLOTS = 0xC4,
};
// Enumeration of all wireless dongle events
typedef enum WirelessEventTypes
{
WIRELESS_EVENT_DISCONNECT = 1,
WIRELESS_EVENT_CONNECT = 2,
WIRELESS_EVENT_PAIR = 3,
} EWirelessEventType;
// Enumeration of generic digital inputs - not all of these will be supported on all controllers (only add to this enum and never change the order)
typedef enum
{
IO_DIGITAL_BUTTON_NONE = -1,
IO_DIGITAL_BUTTON_RIGHT_TRIGGER,
IO_DIGITAL_BUTTON_LEFT_TRIGGER,
IO_DIGITAL_BUTTON_1,
IO_DIGITAL_BUTTON_Y=IO_DIGITAL_BUTTON_1,
IO_DIGITAL_BUTTON_2,
IO_DIGITAL_BUTTON_B=IO_DIGITAL_BUTTON_2,
IO_DIGITAL_BUTTON_3,
IO_DIGITAL_BUTTON_X=IO_DIGITAL_BUTTON_3,
IO_DIGITAL_BUTTON_4,
IO_DIGITAL_BUTTON_A=IO_DIGITAL_BUTTON_4,
IO_DIGITAL_BUTTON_RIGHT_BUMPER,
IO_DIGITAL_BUTTON_LEFT_BUMPER,
IO_DIGITAL_BUTTON_LEFT_JOYSTICK_CLICK,
IO_DIGITAL_BUTTON_ESCAPE,
IO_DIGITAL_BUTTON_STEAM,
IO_DIGITAL_BUTTON_MENU,
IO_DIGITAL_STICK_UP,
IO_DIGITAL_STICK_DOWN,
IO_DIGITAL_STICK_LEFT,
IO_DIGITAL_STICK_RIGHT,
IO_DIGITAL_TOUCH_1,
IO_DIGITAL_BUTTON_UP=IO_DIGITAL_TOUCH_1,
IO_DIGITAL_TOUCH_2,
IO_DIGITAL_BUTTON_RIGHT=IO_DIGITAL_TOUCH_2,
IO_DIGITAL_TOUCH_3,
IO_DIGITAL_BUTTON_LEFT=IO_DIGITAL_TOUCH_3,
IO_DIGITAL_TOUCH_4,
IO_DIGITAL_BUTTON_DOWN=IO_DIGITAL_TOUCH_4,
IO_DIGITAL_BUTTON_BACK_LEFT,
IO_DIGITAL_BUTTON_BACK_RIGHT,
IO_DIGITAL_LEFT_TRACKPAD_N,
IO_DIGITAL_LEFT_TRACKPAD_NE,
IO_DIGITAL_LEFT_TRACKPAD_E,
IO_DIGITAL_LEFT_TRACKPAD_SE,
IO_DIGITAL_LEFT_TRACKPAD_S,
IO_DIGITAL_LEFT_TRACKPAD_SW,
IO_DIGITAL_LEFT_TRACKPAD_W,
IO_DIGITAL_LEFT_TRACKPAD_NW,
IO_DIGITAL_RIGHT_TRACKPAD_N,
IO_DIGITAL_RIGHT_TRACKPAD_NE,
IO_DIGITAL_RIGHT_TRACKPAD_E,
IO_DIGITAL_RIGHT_TRACKPAD_SE,
IO_DIGITAL_RIGHT_TRACKPAD_S,
IO_DIGITAL_RIGHT_TRACKPAD_SW,
IO_DIGITAL_RIGHT_TRACKPAD_W,
IO_DIGITAL_RIGHT_TRACKPAD_NW,
IO_DIGITAL_LEFT_TRACKPAD_DOUBLE_TAP,
IO_DIGITAL_RIGHT_TRACKPAD_DOUBLE_TAP,
IO_DIGITAL_LEFT_TRACKPAD_OUTER_RADIUS,
IO_DIGITAL_RIGHT_TRACKPAD_OUTER_RADIUS,
IO_DIGITAL_LEFT_TRACKPAD_CLICK,
IO_DIGITAL_RIGHT_TRACKPAD_CLICK,
IO_DIGITAL_BATTERY_LOW,
IO_DIGITAL_LEFT_TRIGGER_THRESHOLD,
IO_DIGITAL_RIGHT_TRIGGER_THRESHOLD,
IO_DIGITAL_BUTTON_BACK_LEFT2,
IO_DIGITAL_BUTTON_BACK_RIGHT2,
IO_DIGITAL_BUTTON_ALWAYS_ON,
IO_DIGITAL_BUTTON_ANCILLARY_1,
IO_DIGITAL_BUTTON_MACRO_0,
IO_DIGITAL_BUTTON_MACRO_1,
IO_DIGITAL_BUTTON_MACRO_2,
IO_DIGITAL_BUTTON_MACRO_3,
IO_DIGITAL_BUTTON_MACRO_4,
IO_DIGITAL_BUTTON_MACRO_5,
IO_DIGITAL_BUTTON_MACRO_6,
IO_DIGITAL_BUTTON_MACRO_7,
IO_DIGITAL_BUTTON_MACRO_1FINGER,
IO_DIGITAL_BUTTON_MACRO_2FINGER,
IO_DIGITAL_COUNT
} DigitalIO ;
// Enumeration of generic analog inputs - not all of these will be supported on all controllers (only add to this enum and never change the order)
typedef enum
{
IO_ANALOG_LEFT_STICK_X,
IO_ANALOG_LEFT_STICK_Y,
IO_ANALOG_RIGHT_STICK_X,
IO_ANALOG_RIGHT_STICK_Y,
IO_ANALOG_LEFT_TRIGGER,
IO_ANALOG_RIGHT_TRIGGER,
IO_MOUSE1_X,
IO_MOUSE1_Y,
IO_MOUSE1_Z,
IO_ACCEL_X,
IO_ACCEL_Y,
IO_ACCEL_Z,
IO_GYRO_X,
IO_GYRO_Y,
IO_GYRO_Z,
IO_GYRO_QUAT_W,
IO_GYRO_QUAT_X,
IO_GYRO_QUAT_Y,
IO_GYRO_QUAT_Z,
IO_GYRO_STEERING_VEC,
IO_RAW_TRIGGER_LEFT,
IO_RAW_TRIGGER_RIGHT,
IO_RAW_JOYSTICK_X,
IO_RAW_JOYSTICK_Y,
IO_GYRO_TILT_VEC,
IO_ANALOG_COUNT
} AnalogIO;
// Contains list of all types of devices that the controller emulates (only add to this enum and never change the order)
enum DeviceTypes
{
DEVICE_KEYBOARD,
DEVICE_MOUSE,
DEVICE_GAMEPAD,
DEVICE_MODE_ADJUST,
DEVICE_COUNT
};
// Scan codes for HID keyboards
enum HIDKeyboardKeys
{
KEY_INVALID,
KEY_FIRST = 0x04,
KEY_A = KEY_FIRST, KEY_B, KEY_C, KEY_D, KEY_E, KEY_F, KEY_G, KEY_H, KEY_I, KEY_J, KEY_K, KEY_L,
KEY_M, KEY_N, KEY_O, KEY_P, KEY_Q, KEY_R, KEY_S, KEY_T, KEY_U, KEY_V, KEY_W, KEY_X, KEY_Y, KEY_Z, KEY_1, KEY_2,
KEY_3, KEY_4, KEY_5, KEY_6, KEY_7, KEY_8, KEY_9, KEY_0, KEY_RETURN, KEY_ESCAPE, KEY_BACKSPACE, KEY_TAB, KEY_SPACE, KEY_DASH, KEY_EQUALS, KEY_LEFT_BRACKET,
KEY_RIGHT_BRACKET, KEY_BACKSLASH, KEY_UNUSED1, KEY_SEMICOLON, KEY_SINGLE_QUOTE, KEY_BACK_TICK, KEY_COMMA, KEY_PERIOD, KEY_FORWARD_SLASH, KEY_CAPSLOCK, KEY_F1, KEY_F2, KEY_F3, KEY_F4, KEY_F5, KEY_F6,
KEY_F7, KEY_F8, KEY_F9, KEY_F10, KEY_F11, KEY_F12, KEY_PRINT_SCREEN, KEY_SCROLL_LOCK, KEY_BREAK, KEY_INSERT, KEY_HOME, KEY_PAGE_UP, KEY_DELETE, KEY_END, KEY_PAGE_DOWN, KEY_RIGHT_ARROW,
KEY_LEFT_ARROW, KEY_DOWN_ARROW, KEY_UP_ARROW, KEY_NUM_LOCK, KEY_KEYPAD_FORWARD_SLASH, KEY_KEYPAD_ASTERISK, KEY_KEYPAD_DASH, KEY_KEYPAD_PLUS, KEY_KEYPAD_ENTER, KEY_KEYPAD_1, KEY_KEYPAD_2, KEY_KEYPAD_3, KEY_KEYPAD_4, KEY_KEYPAD_5, KEY_KEYPAD_6, KEY_KEYPAD_7,
KEY_KEYPAD_8, KEY_KEYPAD_9, KEY_KEYPAD_0, KEY_KEYPAD_PERIOD,
KEY_LALT,
KEY_LSHIFT,
KEY_LWIN,
KEY_LCONTROL,
KEY_RALT,
KEY_RSHIFT,
KEY_RWIN,
KEY_RCONTROL,
KEY_VOLUP,
KEY_VOLDOWN,
KEY_MUTE,
KEY_PLAY,
KEY_STOP,
KEY_NEXT,
KEY_PREV,
KEY_LAST = KEY_PREV
};
enum ModifierMasks
{
KEY_LCONTROL_MASK = (1<<0),
KEY_LSHIFT_MASK = (1<<1),
KEY_LALT_MASK = (1<<2),
KEY_LWIN_MASK = (1<<3),
KEY_RCONTROL_MASK = (1<<4),
KEY_RSHIFT_MASK = (1<<5),
KEY_RALT_MASK = (1<<6),
KEY_RWIN_MASK = (1<<7)
};
// Standard mouse buttons as specified in the HID mouse spec
enum MouseButtons
{
MOUSE_BTN_LEFT,
MOUSE_BTN_RIGHT,
MOUSE_BTN_MIDDLE,
MOUSE_BTN_BACK,
MOUSE_BTN_FORWARD,
MOUSE_SCROLL_UP,
MOUSE_SCROLL_DOWN,
MOUSE_BTN_COUNT
};
// Gamepad buttons
enum GamepadButtons
{
GAMEPAD_BTN_TRIGGER_LEFT=1,
GAMEPAD_BTN_TRIGGER_RIGHT,
GAMEPAD_BTN_A,
GAMEPAD_BTN_B,
GAMEPAD_BTN_Y,
GAMEPAD_BTN_X,
GAMEPAD_BTN_SHOULDER_LEFT,
GAMEPAD_BTN_SHOULDER_RIGHT,
GAMEPAD_BTN_LEFT_JOYSTICK,
GAMEPAD_BTN_RIGHT_JOYSTICK,
GAMEPAD_BTN_START,
GAMEPAD_BTN_SELECT,
GAMEPAD_BTN_STEAM,
GAMEPAD_BTN_DPAD_UP,
GAMEPAD_BTN_DPAD_DOWN,
GAMEPAD_BTN_DPAD_LEFT,
GAMEPAD_BTN_DPAD_RIGHT,
GAMEPAD_BTN_LSTICK_UP,
GAMEPAD_BTN_LSTICK_DOWN,
GAMEPAD_BTN_LSTICK_LEFT,
GAMEPAD_BTN_LSTICK_RIGHT,
GAMEPAD_BTN_RSTICK_UP,
GAMEPAD_BTN_RSTICK_DOWN,
GAMEPAD_BTN_RSTICK_LEFT,
GAMEPAD_BTN_RSTICK_RIGHT,
GAMEPAD_BTN_COUNT
};
// Mode adjust
enum ModeAdjustModes
{
MODE_ADJUST_SENSITITY=1,
MODE_ADJUST_LEFT_PAD_SECONDARY_MODE,
MODE_ADJUST_RIGHT_PAD_SECONDARY_MODE,
MODE_ADJUST_COUNT
};
// Read-only attributes of controllers (only add to this enum and never change the order)
typedef enum
{
ATTRIB_UNIQUE_ID,
ATTRIB_PRODUCT_ID,
ATTRIB_PRODUCT_REVISON, // deprecated
ATTRIB_CAPABILITIES = ATTRIB_PRODUCT_REVISON, // intentional aliasing
ATTRIB_FIRMWARE_VERSION, // deprecated
ATTRIB_FIRMWARE_BUILD_TIME,
ATTRIB_RADIO_FIRMWARE_BUILD_TIME,
ATTRIB_RADIO_DEVICE_ID0,
ATTRIB_RADIO_DEVICE_ID1,
ATTRIB_DONGLE_FIRMWARE_BUILD_TIME,
ATTRIB_BOARD_REVISION,
ATTRIB_BOOTLOADER_BUILD_TIME,
ATTRIB_CONNECTION_INTERVAL_IN_US,
ATTRIB_COUNT
} ControllerAttributes;
// Read-only string attributes of controllers (only add to this enum and never change the order)
typedef enum
{
ATTRIB_STR_BOARD_SERIAL,
ATTRIB_STR_UNIT_SERIAL,
ATTRIB_STR_COUNT
} ControllerStringAttributes;
typedef enum
{
STATUS_CODE_NORMAL,
STATUS_CODE_CRITICAL_BATTERY,
STATUS_CODE_GYRO_INIT_ERROR,
} ControllerStatusEventCodes;
typedef enum
{
STATUS_STATE_LOW_BATTERY=0,
} ControllerStatusStateFlags;
typedef enum {
TRACKPAD_ABSOLUTE_MOUSE,
TRACKPAD_RELATIVE_MOUSE,
TRACKPAD_DPAD_FOUR_WAY_DISCRETE,
TRACKPAD_DPAD_FOUR_WAY_OVERLAP,
TRACKPAD_DPAD_EIGHT_WAY,
TRACKPAD_RADIAL_MODE,
TRACKPAD_ABSOLUTE_DPAD,
TRACKPAD_NONE,
TRACKPAD_GESTURE_KEYBOARD,
TRACKPAD_NUM_MODES
} TrackpadDPadMode;
// Read-write controller settings (only add to this enum and never change the order)
typedef enum
{
SETTING_MOUSE_SENSITIVITY,
SETTING_MOUSE_ACCELERATION,
SETTING_TRACKBALL_ROTATION_ANGLE,
SETTING_HAPTIC_INTENSITY,
SETTING_LEFT_GAMEPAD_STICK_ENABLED,
SETTING_RIGHT_GAMEPAD_STICK_ENABLED,
SETTING_USB_DEBUG_MODE,
SETTING_LEFT_TRACKPAD_MODE,
SETTING_RIGHT_TRACKPAD_MODE,
SETTING_MOUSE_POINTER_ENABLED,
SETTING_DPAD_DEADZONE,
SETTING_MINIMUM_MOMENTUM_VEL,
SETTING_MOMENTUM_DECAY_AMMOUNT,
SETTING_TRACKPAD_RELATIVE_MODE_TICKS_PER_PIXEL,
SETTING_HAPTIC_INCREMENT,
SETTING_DPAD_ANGLE_SIN,
SETTING_DPAD_ANGLE_COS,
SETTING_MOMENTUM_VERTICAL_DIVISOR,
SETTING_MOMENTUM_MAXIMUM_VELOCITY,
SETTING_TRACKPAD_Z_ON,
SETTING_TRACKPAD_Z_OFF,
SETTING_SENSITIVY_SCALE_AMMOUNT,
SETTING_LEFT_TRACKPAD_SECONDARY_MODE,
SETTING_RIGHT_TRACKPAD_SECONDARY_MODE,
SETTING_SMOOTH_ABSOLUTE_MOUSE,
SETTING_STEAMBUTTON_POWEROFF_TIME,
SETTING_UNUSED_1,
SETTING_TRACKPAD_OUTER_RADIUS,
SETTING_TRACKPAD_Z_ON_LEFT,
SETTING_TRACKPAD_Z_OFF_LEFT,
SETTING_TRACKPAD_OUTER_SPIN_VEL,
SETTING_TRACKPAD_OUTER_SPIN_RADIUS,
SETTING_TRACKPAD_OUTER_SPIN_HORIZONTAL_ONLY,
SETTING_TRACKPAD_RELATIVE_MODE_DEADZONE,
SETTING_TRACKPAD_RELATIVE_MODE_MAX_VEL,
SETTING_TRACKPAD_RELATIVE_MODE_INVERT_Y,
SETTING_TRACKPAD_DOUBLE_TAP_BEEP_ENABLED,
SETTING_TRACKPAD_DOUBLE_TAP_BEEP_PERIOD,
SETTING_TRACKPAD_DOUBLE_TAP_BEEP_COUNT,
SETTING_TRACKPAD_OUTER_RADIUS_RELEASE_ON_TRANSITION,
SETTING_RADIAL_MODE_ANGLE,
SETTING_HAPTIC_INTENSITY_MOUSE_MODE,
SETTING_LEFT_DPAD_REQUIRES_CLICK,
SETTING_RIGHT_DPAD_REQUIRES_CLICK,
SETTING_LED_BASELINE_BRIGHTNESS,
SETTING_LED_USER_BRIGHTNESS,
SETTING_ENABLE_RAW_JOYSTICK,
SETTING_ENABLE_FAST_SCAN,
SETTING_GYRO_MODE,
SETTING_WIRELESS_PACKET_VERSION,
SETTING_SLEEP_INACTIVITY_TIMEOUT,
SETTING_COUNT,
// This is a special setting value use for callbacks and should not be set/get explicitly.
SETTING_ALL=0xFF
} ControllerSettings;
typedef enum
{
SETTING_DEFAULT,
SETTING_MIN,
SETTING_MAX,
SETTING_DEFAULTMINMAXCOUNT
} SettingDefaultMinMax;
// Bitmask that define which IMU features to enable.
typedef enum
{
SETTING_GYRO_MODE_OFF = 0x0000,
SETTING_GYRO_MODE_STEERING = 0x0001,
SETTING_GYRO_MODE_TILT = 0x0002,
SETTING_GYRO_MODE_SEND_ORIENTATION = 0x0004,
SETTING_GYRO_MODE_SEND_RAW_ACCEL = 0x0008,
SETTING_GYRO_MODE_SEND_RAW_GYRO = 0x0010,
} SettingGyroMode;
// Bitmask for haptic pulse flags
typedef enum
{
HAPTIC_PULSE_NORMAL = 0x0000,
HAPTIC_PULSE_HIGH_PRIORITY = 0x0001,
HAPTIC_PULSE_VERY_HIGH_PRIORITY = 0x0002,
} SettingHapticPulseFlags;
typedef struct
{
// default,min,max in this array in that order
short defaultminmax[SETTING_DEFAULTMINMAXCOUNT];
} SettingValueRange_t;
// below is from controller_constants.c which should be compiled into any code that uses this
extern const SettingValueRange_t g_DefaultSettingValues[SETTING_COUNT];
// Read-write settings for dongle (only add to this enum and never change the order)
typedef enum
{
DONGLE_SETTING_MOUSE_KEYBOARD_ENABLED,
DONGLE_SETTING_COUNT,
} DongleSettings;
typedef enum
{
AUDIO_STARTUP = 0,
AUDIO_SHUTDOWN = 1,
AUDIO_PAIR = 2,
AUDIO_PAIR_SUCCESS = 3,
AUDIO_IDENTIFY = 4,
AUDIO_LIZARDMODE = 5,
AUDIO_NORMALMODE = 6,
AUDIO_MAX_SLOT = 15
} ControllerAudio;
#ifdef __cplusplus
}
#endif
#endif // _CONTROLLER_CONSTANTS_H

View File

@@ -0,0 +1,307 @@
/*
Simple DirectMedia Layer
Copyright (C) 2020 Valve Corporation
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.
*/
#ifndef _CONTROLLER_STRUCTS_
#define _CONTROLLER_STRUCTS_
#pragma pack(1)
#define HID_FEATURE_REPORT_BYTES 64
// Header for all host <==> target messages
typedef struct
{
unsigned char type;
unsigned char length;
} FeatureReportHeader;
// Generic controller attribute structure
typedef struct
{
unsigned char attributeTag;
uint32_t attributeValue;
} ControllerAttribute;
// Generic controller settings structure
typedef struct
{
ControllerAttribute attributes[ ( HID_FEATURE_REPORT_BYTES - sizeof( FeatureReportHeader ) ) / sizeof( ControllerAttribute ) ];
} MsgGetAttributes;
// This is the only message struct that application code should use to interact with feature request messages. Any new
// messages should be added to the union. The structures defined here should correspond to the ones defined in
// ValveDeviceCore.cpp.
//
typedef struct
{
FeatureReportHeader header;
union
{
MsgGetAttributes getAttributes;
} payload;
} FeatureReportMsg;
// Roll this version forward anytime that you are breaking compatibility of existing
// message types within ValveInReport_t or the header itself. Hopefully this should
// be super rare and instead you should just add new message payloads to the union,
// or just add fields to the end of existing payload structs which is expected to be
// safe in all code consuming these as they should just consume/copy upto the prior size
// they were aware of when processing.
#define k_ValveInReportMsgVersion 0x01
typedef enum
{
ID_CONTROLLER_STATE = 1,
ID_CONTROLLER_DEBUG = 2,
ID_CONTROLLER_WIRELESS = 3,
ID_CONTROLLER_STATUS = 4,
ID_CONTROLLER_DEBUG2 = 5,
ID_CONTROLLER_SECONDARY_STATE = 6,
ID_CONTROLLER_BLE_STATE = 7,
ID_CONTROLLER_MSG_COUNT
} ValveInReportMessageIDs;
typedef struct
{
unsigned short unReportVersion;
unsigned char ucType;
unsigned char ucLength;
} ValveInReportHeader_t;
// State payload
typedef struct
{
// If packet num matches that on your prior call, then the controller state hasn't been changed since
// your last call and there is no need to process it
uint32 unPacketNum;
// Button bitmask and trigger data.
union
{
uint64 ulButtons;
struct
{
unsigned char _pad0[3];
unsigned char nLeft;
unsigned char nRight;
unsigned char _pad1[3];
} Triggers;
} ButtonTriggerData;
// Left pad coordinates
short sLeftPadX;
short sLeftPadY;
// Right pad coordinates
short sRightPadX;
short sRightPadY;
// This is redundant, packed above, but still sent over wired
unsigned short sTriggerL;
unsigned short sTriggerR;
// FIXME figure out a way to grab this stuff over wireless
short sAccelX;
short sAccelY;
short sAccelZ;
short sGyroX;
short sGyroY;
short sGyroZ;
short sGyroQuatW;
short sGyroQuatX;
short sGyroQuatY;
short sGyroQuatZ;
} ValveControllerStatePacket_t;
// BLE State payload this has to be re-formatted from the normal state because BLE controller shows up as
//a HID device and we don't want to send all the optional parts of the message. Keep in sync with struct above.
typedef struct
{
// If packet num matches that on your prior call, then the controller state hasn't been changed since
// your last call and there is no need to process it
uint32 unPacketNum;
// Button bitmask and trigger data.
union
{
uint64 ulButtons;
struct
{
unsigned char _pad0[3];
unsigned char nLeft;
unsigned char nRight;
unsigned char _pad1[3];
} Triggers;
} ButtonTriggerData;
// Left pad coordinates
short sLeftPadX;
short sLeftPadY;
// Right pad coordinates
short sRightPadX;
short sRightPadY;
//This mimcs how the dongle reconstitutes HID packets, there will be 0-4 shorts depending on gyro mode
unsigned char ucGyroDataType; //TODO could maybe find some unused bits in the button field for this info (is only 2bits)
short sGyro[4];
} ValveControllerBLEStatePacket_t;
// Define a payload for reporting debug information
typedef struct
{
// Left pad coordinates
short sLeftPadX;
short sLeftPadY;
// Right pad coordinates
short sRightPadX;
short sRightPadY;
// Left mouse deltas
short sLeftPadMouseDX;
short sLeftPadMouseDY;
// Right mouse deltas
short sRightPadMouseDX;
short sRightPadMouseDY;
// Left mouse filtered deltas
short sLeftPadMouseFilteredDX;
short sLeftPadMouseFilteredDY;
// Right mouse filtered deltas
short sRightPadMouseFilteredDX;
short sRightPadMouseFilteredDY;
// Pad Z values
unsigned char ucLeftZ;
unsigned char ucRightZ;
// FingerPresent
unsigned char ucLeftFingerPresent;
unsigned char ucRightFingerPresent;
// Timestamps
unsigned char ucLeftTimestamp;
unsigned char ucRightTimestamp;
// Double tap state
unsigned char ucLeftTapState;
unsigned char ucRightTapState;
unsigned int unDigitalIOStates0;
unsigned int unDigitalIOStates1;
} ValveControllerDebugPacket_t;
typedef struct
{
unsigned char ucPadNum;
unsigned char ucPad[3]; // need Data to be word aligned
short Data[20];
unsigned short unNoise;
} ValveControllerTrackpadImage_t;
typedef struct
{
unsigned char ucPadNum;
unsigned char ucOffset;
unsigned char ucPad[2]; // need Data to be word aligned
short rgData[28];
} ValveControllerRawTrackpadImage_t;
// Payload for wireless metadata
typedef struct
{
unsigned char ucEventType;
} SteamControllerWirelessEvent_t;
typedef struct
{
// Current packet number.
unsigned int unPacketNum;
// Event codes and state information.
unsigned short sEventCode;
unsigned short unStateFlags;
// Current battery voltage (mV).
unsigned short sBatteryVoltage;
// Current battery level (0-100).
unsigned char ucBatteryLevel;
} SteamControllerStatusEvent_t;
typedef struct
{
ValveInReportHeader_t header;
union
{
ValveControllerStatePacket_t controllerState;
ValveControllerBLEStatePacket_t controllerBLEState;
ValveControllerDebugPacket_t debugState;
ValveControllerTrackpadImage_t padImage;
ValveControllerRawTrackpadImage_t rawPadImage;
SteamControllerWirelessEvent_t wirelessEvent;
SteamControllerStatusEvent_t statusEvent;
} payload;
} ValveInReport_t;
// Enumeration for BLE packet protocol
enum EBLEPacketReportNums
{
// Skipping past 2-3 because they are escape characters in Uart protocol
k_EBLEReportState = 4,
k_EBLEReportStatus = 5,
};
// Enumeration of data chunks in BLE state packets
enum EBLEOptionDataChunksBitmask
{
// First byte upper nibble
k_EBLEButtonChunk1 = 0x10,
k_EBLEButtonChunk2 = 0x20,
k_EBLEButtonChunk3 = 0x40,
k_EBLELeftJoystickChunk = 0x80,
// Second full byte
k_EBLELeftTrackpadChunk = 0x100,
k_EBLERightTrackpadChunk = 0x200,
k_EBLEIMUAccelChunk = 0x400,
k_EBLEIMUGyroChunk = 0x800,
k_EBLEIMUQuatChunk = 0x1000,
};
#pragma pack()
#endif // _CONTROLLER_STRUCTS

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,111 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 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.
*/
#ifndef SDL_sysjoystick_c_h_
#define SDL_sysjoystick_c_h_
#include <linux/input.h>
struct SDL_joylist_item;
struct SDL_sensorlist_item;
/* The private structure used to keep track of a joystick */
struct joystick_hwdata
{
int fd;
/* linux driver creates a separate device for gyro/accelerometer */
int fd_sensor;
struct SDL_joylist_item *item;
struct SDL_sensorlist_item *item_sensor;
SDL_JoystickGUID guid;
char *fname; /* Used in haptic subsystem */
SDL_bool ff_rumble;
SDL_bool ff_sine;
struct ff_effect effect;
Uint32 effect_expiration;
/* The current Linux joystick driver maps hats to two axes */
struct hwdata_hat
{
int axis[2];
} *hats;
/* Support for the Linux 2.4 unified input interface */
Uint8 key_map[KEY_MAX];
Uint8 abs_map[ABS_MAX];
SDL_bool has_key[KEY_MAX];
SDL_bool has_abs[ABS_MAX];
SDL_bool has_accelerometer;
SDL_bool has_gyro;
/* Support for the classic joystick interface */
SDL_bool classic;
Uint16 *key_pam;
Uint8 *abs_pam;
struct axis_correct
{
SDL_bool use_deadzones;
/* Deadzone coefficients */
int coef[3];
/* Raw coordinate scale */
int minimum;
int maximum;
float scale;
} abs_correct[ABS_MAX];
float accelerometer_scale[3];
float gyro_scale[3];
/* Each axis is read independently, if we don't get all axis this call to
* LINUX_JoystickUpdateupdate(), store them for the next one */
float gyro_data[3];
float accel_data[3];
Uint64 sensor_tick;
Sint32 last_tick;
SDL_bool report_sensor;
SDL_bool fresh;
SDL_bool recovering_from_dropped;
SDL_bool recovering_from_dropped_sensor;
/* Steam Controller support */
SDL_bool m_bSteamController;
/* 4 = (ABS_HAT3X-ABS_HAT0X)/2 (see input-event-codes.h in kernel) */
int hats_indices[4];
SDL_bool has_hat[4];
struct hat_axis_correct
{
SDL_bool use_deadzones;
int minimum[2];
int maximum[2];
} hat_correct[4];
/* Set when gamepad is pending removal due to ENODEV read error */
SDL_bool gone;
SDL_bool sensor_gone;
};
#endif /* SDL_sysjoystick_c_h_ */

View File

@@ -0,0 +1,281 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 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_N3DS
/* This is the N3DS implementation of the SDL joystick API */
#include <3ds.h>
#include "../SDL_sysjoystick.h"
#define NB_BUTTONS 23
/*
N3DS sticks values are roughly within +/-160
which is too small to pass the jitter tolerance.
This correction is applied to axis values
so they fit better in SDL's value range.
*/
#define CORRECT_AXIS_X(X) ((X * SDL_JOYSTICK_AXIS_MAX) / 160)
/*
The Y axis needs to be flipped because SDL's "up"
is reversed compared to libctru's "up"
*/
#define CORRECT_AXIS_Y(Y) CORRECT_AXIS_X(-Y)
static void UpdateN3DSPressedButtons(Uint64 timestamp, SDL_Joystick *joystick);
static void UpdateN3DSReleasedButtons(Uint64 timestamp, SDL_Joystick *joystick);
static void UpdateN3DSCircle(Uint64 timestamp, SDL_Joystick *joystick);
static void UpdateN3DSCStick(Uint64 timestamp, SDL_Joystick *joystick);
static int N3DS_JoystickInit(void)
{
hidInit();
return 0;
}
static const char *N3DS_JoystickGetDeviceName(int device_index)
{
return "Nintendo 3DS";
}
static int N3DS_JoystickGetCount(void)
{
return 1;
}
static SDL_JoystickGUID N3DS_JoystickGetDeviceGUID(int device_index)
{
SDL_JoystickGUID guid = SDL_CreateJoystickGUIDForName("Nintendo 3DS");
return guid;
}
static SDL_JoystickID N3DS_JoystickGetDeviceInstanceID(int device_index)
{
return device_index;
}
static int N3DS_JoystickOpen(SDL_Joystick *joystick, int device_index)
{
joystick->nbuttons = NB_BUTTONS;
joystick->naxes = 4;
joystick->nhats = 0;
joystick->instance_id = device_index;
return 0;
}
static int N3DS_JoystickSetSensorsEnabled(SDL_Joystick *joystick, SDL_bool enabled)
{
return SDL_Unsupported();
}
static void N3DS_JoystickUpdate(SDL_Joystick *joystick)
{
Uint64 timestamp = SDL_GetTicksNS();
UpdateN3DSPressedButtons(timestamp, joystick);
UpdateN3DSReleasedButtons(timestamp, joystick);
UpdateN3DSCircle(timestamp, joystick);
UpdateN3DSCStick(timestamp, joystick);
}
static void UpdateN3DSPressedButtons(Uint64 timestamp, SDL_Joystick *joystick)
{
static u32 previous_state = 0;
u32 updated_down;
u32 current_state = hidKeysDown();
updated_down = previous_state ^ current_state;
if (updated_down) {
for (Uint8 i = 0; i < joystick->nbuttons; i++) {
if (current_state & BIT(i) & updated_down) {
SDL_SendJoystickButton(timestamp, joystick, i, SDL_PRESSED);
}
}
}
previous_state = current_state;
}
static void UpdateN3DSReleasedButtons(Uint64 timestamp, SDL_Joystick *joystick)
{
static u32 previous_state = 0;
u32 updated_up;
u32 current_state = hidKeysUp();
updated_up = previous_state ^ current_state;
if (updated_up) {
for (Uint8 i = 0; i < joystick->nbuttons; i++) {
if (current_state & BIT(i) & updated_up) {
SDL_SendJoystickButton(timestamp, joystick, i, SDL_RELEASED);
}
}
}
previous_state = current_state;
}
static void UpdateN3DSCircle(Uint64 timestamp, SDL_Joystick *joystick)
{
static circlePosition previous_state = { 0, 0 };
circlePosition current_state;
hidCircleRead(&current_state);
if (previous_state.dx != current_state.dx) {
SDL_SendJoystickAxis(timestamp, joystick,
0,
CORRECT_AXIS_X(current_state.dx));
}
if (previous_state.dy != current_state.dy) {
SDL_SendJoystickAxis(timestamp, joystick,
1,
CORRECT_AXIS_Y(current_state.dy));
}
previous_state = current_state;
}
static void UpdateN3DSCStick(Uint64 timestamp, SDL_Joystick *joystick)
{
static circlePosition previous_state = { 0, 0 };
circlePosition current_state;
hidCstickRead(&current_state);
if (previous_state.dx != current_state.dx) {
SDL_SendJoystickAxis(timestamp, joystick,
2,
CORRECT_AXIS_X(current_state.dx));
}
if (previous_state.dy != current_state.dy) {
SDL_SendJoystickAxis(timestamp, joystick,
3,
CORRECT_AXIS_Y(current_state.dy));
}
previous_state = current_state;
}
static void N3DS_JoystickClose(SDL_Joystick *joystick)
{
}
static void N3DS_JoystickQuit(void)
{
hidExit();
}
static SDL_bool N3DS_JoystickGetGamepadMapping(int device_index, SDL_GamepadMapping *out)
{
/* There is only one possible mapping. */
*out = (SDL_GamepadMapping){
.a = { EMappingKind_Button, 0 },
.b = { EMappingKind_Button, 1 },
.x = { EMappingKind_Button, 10 },
.y = { EMappingKind_Button, 11 },
.back = { EMappingKind_Button, 2 },
.guide = { EMappingKind_None, 255 },
.start = { EMappingKind_Button, 3 },
.leftstick = { EMappingKind_None, 255 },
.rightstick = { EMappingKind_None, 255 },
.leftshoulder = { EMappingKind_Button, 9 },
.rightshoulder = { EMappingKind_Button, 8 },
.dpup = { EMappingKind_Button, 6 },
.dpdown = { EMappingKind_Button, 7 },
.dpleft = { EMappingKind_Button, 5 },
.dpright = { EMappingKind_Button, 4 },
.misc1 = { EMappingKind_None, 255 },
.paddle1 = { EMappingKind_None, 255 },
.paddle2 = { EMappingKind_None, 255 },
.paddle3 = { EMappingKind_None, 255 },
.paddle4 = { EMappingKind_None, 255 },
.leftx = { EMappingKind_Axis, 0 },
.lefty = { EMappingKind_Axis, 1 },
.rightx = { EMappingKind_Axis, 2 },
.righty = { EMappingKind_Axis, 3 },
.lefttrigger = { EMappingKind_Button, 14 },
.righttrigger = { EMappingKind_Button, 15 },
};
return SDL_TRUE;
}
static void N3DS_JoystickDetect(void)
{
}
static const char *N3DS_JoystickGetDevicePath(int device_index)
{
return NULL;
}
static int N3DS_JoystickGetDevicePlayerIndex(int device_index)
{
return -1;
}
static void N3DS_JoystickSetDevicePlayerIndex(int device_index, int player_index)
{
}
static Uint32 N3DS_JoystickGetCapabilities(SDL_Joystick *joystick)
{
return 0;
}
static int N3DS_JoystickRumble(SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble)
{
return SDL_Unsupported();
}
static int N3DS_JoystickRumbleTriggers(SDL_Joystick *joystick, Uint16 left_rumble, Uint16 right_rumble)
{
return SDL_Unsupported();
}
static int N3DS_JoystickSetLED(SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue)
{
return SDL_Unsupported();
}
static int N3DS_JoystickSendEffect(SDL_Joystick *joystick, const void *data, int size)
{
return SDL_Unsupported();
}
SDL_JoystickDriver SDL_N3DS_JoystickDriver = {
.Init = N3DS_JoystickInit,
.GetCount = N3DS_JoystickGetCount,
.Detect = N3DS_JoystickDetect,
.GetDeviceName = N3DS_JoystickGetDeviceName,
.GetDevicePath = N3DS_JoystickGetDevicePath,
.GetDevicePlayerIndex = N3DS_JoystickGetDevicePlayerIndex,
.SetDevicePlayerIndex = N3DS_JoystickSetDevicePlayerIndex,
.GetDeviceGUID = N3DS_JoystickGetDeviceGUID,
.GetDeviceInstanceID = N3DS_JoystickGetDeviceInstanceID,
.Open = N3DS_JoystickOpen,
.Rumble = N3DS_JoystickRumble,
.RumbleTriggers = N3DS_JoystickRumbleTriggers,
.GetCapabilities = N3DS_JoystickGetCapabilities,
.SetLED = N3DS_JoystickSetLED,
.SendEffect = N3DS_JoystickSendEffect,
.SetSensorsEnabled = N3DS_JoystickSetSensorsEnabled,
.Update = N3DS_JoystickUpdate,
.Close = N3DS_JoystickClose,
.Quit = N3DS_JoystickQuit,
.GetGamepadMapping = N3DS_JoystickGetGamepadMapping
};
#endif /* SDL_JOYSTICK_N3DS */

View File

@@ -0,0 +1,361 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 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_PS2
/* This is the PS2 implementation of the SDL joystick API */
#include <libmtap.h>
#include <libpad.h>
#include <ps2_joystick_driver.h>
#include <stdio.h> /* For the definition of NULL */
#include <stdlib.h>
#include <stdbool.h>
#include "../SDL_sysjoystick.h"
#include "../SDL_joystick_c.h"
#define PS2_MAX_PORT 2 /* each ps2 has 2 ports */
#define PS2_MAX_SLOT 4 /* maximum - 4 slots in one multitap */
#define MAX_CONTROLLERS (PS2_MAX_PORT * PS2_MAX_SLOT)
#define PS2_ANALOG_STICKS 2
#define PS2_ANALOG_AXIS 2
#define PS2_BUTTONS 16
#define PS2_TOTAL_AXIS (PS2_ANALOG_STICKS * PS2_ANALOG_AXIS)
struct JoyInfo
{
uint8_t padBuf[256];
uint16_t btns;
uint8_t analog_state[PS2_TOTAL_AXIS];
uint8_t port;
uint8_t slot;
int8_t rumble_ready;
int8_t opened;
} __attribute__((aligned(64)));
static uint8_t enabled_pads = 0;
static struct JoyInfo joyInfo[MAX_CONTROLLERS];
static inline int16_t convert_u8_to_s16(uint8_t val)
{
if (val == 0) {
return -0x7fff;
}
return val * 0x0101 - 0x8000;
}
static inline uint8_t rumble_status(uint8_t index)
{
char actAlign[6];
int res;
struct JoyInfo *info = &joyInfo[index];
if (info->rumble_ready == 0) {
actAlign[0] = 0;
actAlign[1] = 1;
actAlign[2] = 0xff;
actAlign[3] = 0xff;
actAlign[4] = 0xff;
actAlign[5] = 0xff;
res = padSetActAlign(info->port, info->slot, actAlign);
info->rumble_ready = res <= 0 ? -1 : 1;
}
return info->rumble_ready == 1;
}
/* Function to scan the system for joysticks.
* Joystick 0 should be the system default joystick.
* This function should return 0, or -1 on an unrecoverable error.
*/
static int PS2_JoystickInit(void)
{
uint32_t port = 0;
uint32_t slot = 0;
if (init_joystick_driver(true) < 0) {
return -1;
}
for (port = 0; port < PS2_MAX_PORT; port++) {
mtapPortOpen(port);
}
/* it can fail - we dont care, we will check it more strictly when padPortOpen */
for (slot = 0; slot < PS2_MAX_SLOT; slot++) {
for (port = 0; port < PS2_MAX_PORT; port++) {
/* 2 main controller ports acts the same with and without multitap
Port 0,0 -> Connector 1 - the same as Port 0
Port 1,0 -> Connector 2 - the same as Port 1
Port 0,1 -> Connector 3
Port 1,1 -> Connector 4
Port 0,2 -> Connector 5
Port 1,2 -> Connector 6
Port 0,3 -> Connector 7
Port 1,3 -> Connector 8
*/
struct JoyInfo *info = &joyInfo[enabled_pads];
if (padPortOpen(port, slot, (void *)info->padBuf) > 0) {
info->port = (uint8_t)port;
info->slot = (uint8_t)slot;
info->opened = 1;
enabled_pads++;
}
}
}
return enabled_pads > 0 ? 0 : -1;
}
/* Function to return the number of joystick devices plugged in right now */
static int PS2_JoystickGetCount()
{
return (int)enabled_pads;
}
/* Function to cause any queued joystick insertions to be processed */
static void PS2_JoystickDetect()
{
}
/* Function to get the device-dependent name of a joystick */
static const char *PS2_JoystickGetDeviceName(int index)
{
if (index >= 0 && index < enabled_pads) {
return "PS2 Controller";
}
SDL_SetError("No joystick available with that index");
return NULL;
}
/* Function to get the device-dependent path of a joystick */
static const char *PS2_JoystickGetDevicePath(int index)
{
return NULL;
}
/* Function to get the player index of a joystick */
static int PS2_JoystickGetDevicePlayerIndex(int device_index)
{
return -1;
}
/* Function to set the player index of a joystick */
static void PS2_JoystickSetDevicePlayerIndex(int device_index, int player_index)
{
}
/* Function to return the stable GUID for a plugged in device */
static SDL_JoystickGUID PS2_JoystickGetDeviceGUID(int device_index)
{
/* the GUID is just the name for now */
const char *name = PS2_JoystickGetDeviceName(device_index);
return SDL_CreateJoystickGUIDForName(name);
}
/* Function to get the current instance id of the joystick located at device_index */
static SDL_JoystickID PS2_JoystickGetDeviceInstanceID(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.
*/
static int PS2_JoystickOpen(SDL_Joystick *joystick, int device_index)
{
int index = joystick->instance_id;
struct JoyInfo *info = &joyInfo[index];
if (!info->opened) {
if (padPortOpen(info->port, info->slot, (void *)info->padBuf) > 0) {
info->opened = 1;
} else {
return -1;
}
}
joystick->nbuttons = PS2_BUTTONS;
joystick->naxes = PS2_TOTAL_AXIS;
joystick->nhats = 0;
joystick->instance_id = device_index;
return 0;
}
/* Rumble functionality */
static int PS2_JoystickRumble(SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble)
{
char actAlign[6];
int res;
int index = joystick->instance_id;
struct JoyInfo *info = &joyInfo[index];
if (!rumble_status(index)) {
return -1;
}
// Initial value
actAlign[0] = low_frequency_rumble >> 8; // Enable small engine
actAlign[1] = high_frequency_rumble >> 8; // Enable big engine
actAlign[2] = 0xff;
actAlign[3] = 0xff;
actAlign[4] = 0xff;
actAlign[5] = 0xff;
res = padSetActDirect(info->port, info->slot, actAlign);
return res == 1 ? 0 : -1;
}
/* Rumble functionality */
static int PS2_JoystickRumbleTriggers(SDL_Joystick *joystick, Uint16 left, Uint16 right)
{
return -1;
}
/* Capability detection */
static Uint32 PS2_JoystickGetCapabilities(SDL_Joystick *joystick)
{
return SDL_JOYCAP_RUMBLE;
}
/* LED functionality */
static int PS2_JoystickSetLED(SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue)
{
return -1;
}
/* General effects */
static int PS2_JoystickSendEffect(SDL_Joystick *joystick, const void *data, int size)
{
return -1;
}
/* Sensor functionality */
static int PS2_JoystickSetSensorsEnabled(SDL_Joystick *joystick, SDL_bool enabled)
{
return -1;
}
/* 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 PS2_JoystickUpdate(SDL_Joystick *joystick)
{
uint8_t i;
uint8_t previous_axis, current_axis;
uint16_t mask, previous, current;
struct padButtonStatus buttons;
uint8_t all_axis[PS2_TOTAL_AXIS];
int index = joystick->instance_id;
struct JoyInfo *info = &joyInfo[index];
int state = padGetState(info->port, info->slot);
Uint64 timestamp = SDL_GetTicksNS();
if (state != PAD_STATE_DISCONN && state != PAD_STATE_EXECCMD && state != PAD_STATE_ERROR) {
int ret = padRead(info->port, info->slot, &buttons); /* port, slot, buttons */
if (ret != 0) {
/* Buttons */
int32_t pressed_buttons = 0xffff ^ buttons.btns;
;
if (info->btns != pressed_buttons) {
for (i = 0; i < PS2_BUTTONS; i++) {
mask = (1 << i);
previous = info->btns & mask;
current = pressed_buttons & mask;
if (previous != current) {
SDL_SendJoystickButton(timestamp, joystick, i, current ? SDL_PRESSED : SDL_RELEASED);
}
}
}
info->btns = pressed_buttons;
/* Analog */
all_axis[0] = buttons.ljoy_h;
all_axis[1] = buttons.ljoy_v;
all_axis[2] = buttons.rjoy_h;
all_axis[3] = buttons.rjoy_v;
for (i = 0; i < PS2_TOTAL_AXIS; i++) {
previous_axis = info->analog_state[i];
current_axis = all_axis[i];
if (previous_axis != current_axis) {
SDL_SendJoystickAxis(timestamp, joystick, i, convert_u8_to_s16(current_axis));
}
info->analog_state[i] = current_axis;
}
}
}
}
/* Function to close a joystick after use */
static void PS2_JoystickClose(SDL_Joystick *joystick)
{
int index = joystick->instance_id;
struct JoyInfo *info = &joyInfo[index];
padPortClose(info->port, info->slot);
info->opened = 0;
}
/* Function to perform any system-specific joystick related cleanup */
static void PS2_JoystickQuit(void)
{
deinit_joystick_driver(true);
}
static SDL_bool PS2_GetGamepadMapping(int device_index, SDL_GamepadMapping *out)
{
return SDL_FALSE;
}
SDL_JoystickDriver SDL_PS2_JoystickDriver = {
PS2_JoystickInit,
PS2_JoystickGetCount,
PS2_JoystickDetect,
PS2_JoystickGetDeviceName,
PS2_JoystickGetDevicePath,
PS2_JoystickGetDevicePlayerIndex,
PS2_JoystickSetDevicePlayerIndex,
PS2_JoystickGetDeviceGUID,
PS2_JoystickGetDeviceInstanceID,
PS2_JoystickOpen,
PS2_JoystickRumble,
PS2_JoystickRumbleTriggers,
PS2_JoystickGetCapabilities,
PS2_JoystickSetLED,
PS2_JoystickSendEffect,
PS2_JoystickSetSensorsEnabled,
PS2_JoystickUpdate,
PS2_JoystickClose,
PS2_JoystickQuit,
PS2_GetGamepadMapping,
};
#endif /* SDL_JOYSTICK_PS2 */

View File

@@ -0,0 +1,273 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 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_PSP
/* This is the PSP implementation of the SDL joystick API */
#include <pspctrl.h>
#include <stdio.h> /* For the definition of NULL */
#include <stdlib.h>
#include "../SDL_sysjoystick.h"
#include "../SDL_joystick_c.h"
/* Current pad state */
static SceCtrlData pad = { .Lx = 0, .Ly = 0, .Buttons = 0 };
static const enum PspCtrlButtons button_map[] = {
PSP_CTRL_TRIANGLE, PSP_CTRL_CIRCLE, PSP_CTRL_CROSS, PSP_CTRL_SQUARE,
PSP_CTRL_LTRIGGER, PSP_CTRL_RTRIGGER,
PSP_CTRL_DOWN, PSP_CTRL_LEFT, PSP_CTRL_UP, PSP_CTRL_RIGHT,
PSP_CTRL_SELECT, PSP_CTRL_START, PSP_CTRL_HOME, PSP_CTRL_HOLD
};
static int analog_map[256]; /* Map analog inputs to -32768 -> 32767 */
typedef struct
{
int x;
int y;
} point;
/* 4 points define the bezier-curve. */
static point a = { 0, 0 };
static point b = { 50, 0 };
static point c = { 78, 32767 };
static point d = { 128, 32767 };
/* simple linear interpolation between two points */
static SDL_INLINE void lerp(point *dest, point *pt_a, point *pt_b, float t)
{
dest->x = pt_a->x + (pt_b->x - pt_a->x) * t;
dest->y = pt_a->y + (pt_b->y - pt_a->y) * t;
}
/* evaluate a point on a bezier-curve. t goes from 0 to 1.0 */
static int calc_bezier_y(float t)
{
point ab, bc, cd, abbc, bccd, dest;
lerp(&ab, &a, &b, t); /* point between a and b */
lerp(&bc, &b, &c, t); /* point between b and c */
lerp(&cd, &c, &d, t); /* point between c and d */
lerp(&abbc, &ab, &bc, t); /* point between ab and bc */
lerp(&bccd, &bc, &cd, t); /* point between bc and cd */
lerp(&dest, &abbc, &bccd, t); /* point on the bezier-curve */
return dest.y;
}
/* Function to scan the system for joysticks.
* Joystick 0 should be the system default joystick.
* It should return number of joysticks, or -1 on an unrecoverable fatal error.
*/
static int PSP_JoystickInit(void)
{
int i;
/* Setup input */
sceCtrlSetSamplingCycle(0);
sceCtrlSetSamplingMode(PSP_CTRL_MODE_ANALOG);
/* Create an accurate map from analog inputs (0 to 255)
to SDL joystick positions (-32768 to 32767) */
for (i = 0; i < 128; i++) {
float t = (float)i / 127.0f;
analog_map[i + 128] = calc_bezier_y(t);
analog_map[127 - i] = -1 * analog_map[i + 128];
}
return 1;
}
static int PSP_JoystickGetCount(void)
{
return 1;
}
static void PSP_JoystickDetect(void)
{
}
/* Function to get the device-dependent name of a joystick */
static const char *PSP_JoystickGetDeviceName(int device_index)
{
if (device_index == 0) {
return "PSP builtin joypad";
}
SDL_SetError("No joystick available with that index");
return NULL;
}
static const char *PSP_JoystickGetDevicePath(int index)
{
return NULL;
}
static int PSP_JoystickGetDevicePlayerIndex(int device_index)
{
return -1;
}
static void PSP_JoystickSetDevicePlayerIndex(int device_index, int player_index)
{
}
static SDL_JoystickGUID PSP_JoystickGetDeviceGUID(int device_index)
{
/* the GUID is just the name for now */
const char *name = PSP_JoystickGetDeviceName(device_index);
return SDL_CreateJoystickGUIDForName(name);
}
/* Function to perform the mapping from device index to the instance id for this index */
static SDL_JoystickID PSP_JoystickGetDeviceInstanceID(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.
*/
static int PSP_JoystickOpen(SDL_Joystick *joystick, int device_index)
{
joystick->nbuttons = SDL_arraysize(button_map);
joystick->naxes = 2;
joystick->nhats = 0;
joystick->instance_id = device_index;
return 0;
}
static int PSP_JoystickRumble(SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble)
{
return SDL_Unsupported();
}
static int PSP_JoystickRumbleTriggers(SDL_Joystick *joystick, Uint16 left_rumble, Uint16 right_rumble)
{
return SDL_Unsupported();
}
static Uint32 PSP_JoystickGetCapabilities(SDL_Joystick *joystick)
{
return 0;
}
static int PSP_JoystickSetLED(SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue)
{
return SDL_Unsupported();
}
static int PSP_JoystickSendEffect(SDL_Joystick *joystick, const void *data, int size)
{
return SDL_Unsupported();
}
static int PSP_JoystickSetSensorsEnabled(SDL_Joystick *joystick, SDL_bool enabled)
{
return SDL_Unsupported();
}
/* 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 PSP_JoystickUpdate(SDL_Joystick *joystick)
{
int i;
enum PspCtrlButtons buttons;
enum PspCtrlButtons changed;
unsigned char x, y;
static enum PspCtrlButtons old_buttons = 0;
static unsigned char old_x = 0, old_y = 0;
Uint64 timestamp = SDL_GetTicksNS();
sceCtrlReadBufferPositive(&pad, 1);
buttons = pad.Buttons;
x = pad.Lx;
y = pad.Ly;
/* Axes */
if (old_x != x) {
SDL_SendJoystickAxis(timestamp, joystick, 0, analog_map[x]);
old_x = x;
}
if (old_y != y) {
SDL_SendJoystickAxis(timestamp, joystick, 1, analog_map[y]);
old_y = y;
}
/* Buttons */
changed = old_buttons ^ buttons;
old_buttons = buttons;
if (changed) {
for (i = 0; i < SDL_arraysize(button_map); i++) {
if (changed & button_map[i]) {
SDL_SendJoystickButton(timestamp,
joystick, i,
(buttons & button_map[i]) ? SDL_PRESSED : SDL_RELEASED);
}
}
}
}
/* Function to close a joystick after use */
static void PSP_JoystickClose(SDL_Joystick *joystick)
{
}
/* Function to perform any system-specific joystick related cleanup */
static void PSP_JoystickQuit(void)
{
}
static SDL_bool PSP_JoystickGetGamepadMapping(int device_index, SDL_GamepadMapping *out)
{
return SDL_FALSE;
}
SDL_JoystickDriver SDL_PSP_JoystickDriver = {
PSP_JoystickInit,
PSP_JoystickGetCount,
PSP_JoystickDetect,
PSP_JoystickGetDeviceName,
PSP_JoystickGetDevicePath,
PSP_JoystickGetDevicePlayerIndex,
PSP_JoystickSetDevicePlayerIndex,
PSP_JoystickGetDeviceGUID,
PSP_JoystickGetDeviceInstanceID,
PSP_JoystickOpen,
PSP_JoystickRumble,
PSP_JoystickRumbleTriggers,
PSP_JoystickGetCapabilities,
PSP_JoystickSetLED,
PSP_JoystickSendEffect,
PSP_JoystickSetSensorsEnabled,
PSP_JoystickUpdate,
PSP_JoystickClose,
PSP_JoystickQuit,
PSP_JoystickGetGamepadMapping
};
#endif /* SDL_JOYSTICK_PSP */

View File

@@ -0,0 +1,152 @@
#!/usr/bin/env python3
#
# Script to sort the game controller database entries in SDL_gamepad.c
import re
filename = "SDL_gamepad_db.h"
input = open(filename)
output = open(f"{filename}.new", "w")
parsing_controllers = False
controllers = []
controller_guids = {}
conditionals = []
split_pattern = re.compile(r'([^"]*")([^,]*,)([^,]*,)([^"]*)(".*)')
# BUS (1) CRC (3,2) VID (5,4) (6) PID (8,7) (9) VERSION (11,10) MISC (12)
standard_guid_pattern = re.compile(r'^([0-9a-fA-F]{4})([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})(0000)([0-9a-fA-F]{2})([0-9a-fA-F]{2})(0000)([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{4},)$')
# These chipsets are used in multiple controllers with different mappings,
# without enough unique information to differentiate them. e.g.
# https://github.com/gabomdq/SDL_GameControllerDB/issues/202
invalid_controllers = (
('0079', '0006', '0000'), # DragonRise Inc. Generic USB Joystick
('0079', '0006', '6120'), # DragonRise Inc. Generic USB Joystick
('04b4', '2412', 'c529'), # Flydigi Vader 2, Vader 2 Pro, Apex 2, Apex 3
('16c0', '05e1', '0000'), # Xinmotek Controller
)
def find_element(prefix, bindings):
i=0
for element in bindings:
if element.startswith(prefix):
return i
i=(i + 1)
return -1
def save_controller(line):
global controllers
match = split_pattern.match(line)
entry = [ match.group(1), match.group(2), match.group(3) ]
bindings = sorted(match.group(4).split(","))
if (bindings[0] == ""):
bindings.pop(0)
name = entry[2].rstrip(',')
crc = ""
pos = find_element("crc:", bindings)
if pos >= 0:
crc = bindings[pos] + ","
bindings.pop(pos)
guid_match = standard_guid_pattern.match(entry[1])
if guid_match:
groups = guid_match.groups()
crc_value = groups[2] + groups[1]
vid_value = groups[4] + groups[3]
pid_value = groups[7] + groups[6]
version_value = groups[10] + groups[9]
#print("CRC: %s, VID: %s, PID: %s, VERSION: %s" % (crc_value, vid_value, pid_value, version_value))
if crc_value == "0000":
if crc != "":
crc_value = crc[4:-1]
else:
print("Extracting CRC from GUID of " + name)
entry[1] = groups[0] + "0000" + "".join(groups[3:])
crc = "crc:" + crc_value + ","
if (vid_value, pid_value, crc_value) in invalid_controllers:
print("Controller '%s' not unique, skipping" % name)
return
pos = find_element("type", bindings)
if pos >= 0:
bindings.insert(0, bindings.pop(pos))
pos = find_element("platform", bindings)
if pos >= 0:
bindings.insert(0, bindings.pop(pos))
pos = find_element("sdk", bindings)
if pos >= 0:
bindings.append(bindings.pop(pos))
pos = find_element("hint:", bindings)
if pos >= 0:
bindings.append(bindings.pop(pos))
entry.extend(crc)
entry.extend(",".join(bindings) + ",")
entry.append(match.group(5))
controllers.append(entry)
entry_id = entry[1] + entry[3]
if ',sdk' in line or ',hint:' in line:
conditionals.append(entry_id)
def write_controllers():
global controllers
global controller_guids
# Check for duplicates
for entry in controllers:
entry_id = entry[1] + entry[3]
if (entry_id in controller_guids and entry_id not in conditionals):
current_name = entry[2]
existing_name = controller_guids[entry_id][2]
print("Warning: entry '%s' is duplicate of entry '%s'" % (current_name, existing_name))
if (not current_name.startswith("(DUPE)")):
entry[2] = f"(DUPE) {current_name}"
if (not existing_name.startswith("(DUPE)")):
controller_guids[entry_id][2] = f"(DUPE) {existing_name}"
controller_guids[entry_id] = entry
for entry in sorted(controllers, key=lambda entry: f"{entry[2]}-{entry[1]}"):
line = "".join(entry) + "\n"
line = line.replace("\t", " ")
if not line.endswith(",\n") and not line.endswith("*/\n") and not line.endswith(",\r\n") and not line.endswith("*/\r\n"):
print("Warning: '%s' is missing a comma at the end of the line" % (line))
output.write(line)
controllers = []
controller_guids = {}
for line in input:
if parsing_controllers:
if (line.startswith("{")):
output.write(line)
elif (line.startswith(" NULL")):
parsing_controllers = False
write_controllers()
output.write(line)
elif (line.startswith("#if")):
print(f"Parsing {line.strip()}")
output.write(line)
elif (line.startswith("#endif")):
write_controllers()
output.write(line)
else:
save_controller(line)
else:
if (line.startswith("static const char *")):
parsing_controllers = True
output.write(line)
output.close()
print(f"Finished writing {filename}.new")

View File

@@ -0,0 +1,49 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 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"
#include "../SDL_joystick_c.h"
#include "SDL_steamcontroller.h"
void SDL_InitSteamControllers(SteamControllerConnectedCallback_t connectedCallback,
SteamControllerDisconnectedCallback_t disconnectedCallback)
{
}
void SDL_GetSteamControllerInputs(int *nbuttons, int *naxes, int *nhats)
{
*nbuttons = 0;
*naxes = 0;
*nhats = 0;
}
void SDL_UpdateSteamControllers(void)
{
}
void SDL_UpdateSteamController(SDL_Joystick *joystick)
{
}
void SDL_QuitSteamControllers(void)
{
}

View File

@@ -0,0 +1,37 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 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.
*/
#ifndef SDL_steamcontroller_h_
#define SDL_steamcontroller_h_
#include "SDL_internal.h"
typedef SDL_bool (*SteamControllerConnectedCallback_t)(const char *name, SDL_JoystickGUID guid, SDL_JoystickID *device_instance);
typedef void (*SteamControllerDisconnectedCallback_t)(SDL_JoystickID device_instance);
void SDL_InitSteamControllers(SteamControllerConnectedCallback_t connectedCallback,
SteamControllerDisconnectedCallback_t disconnectedCallback);
void SDL_GetSteamControllerInputs(int *nbuttons, int *naxes, int *nhats);
void SDL_UpdateSteamControllers(void);
void SDL_UpdateSteamController(SDL_Joystick *joystick);
void SDL_QuitSteamControllers(void);
#endif /* SDL_steamcontroller_h_ */

167
external/sdl/SDL/src/joystick/usb_ids.h vendored Normal file
View File

@@ -0,0 +1,167 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 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.
*/
#ifndef usb_ids_h_
#define usb_ids_h_
/* Definitions of useful USB VID/PID values */
#define USB_VENDOR_8BITDO 0x2dc8
#define USB_VENDOR_AMAZON 0x1949
#define USB_VENDOR_APPLE 0x05ac
#define USB_VENDOR_ASTRO 0x9886
#define USB_VENDOR_BACKBONE 0x358a
#define USB_VENDOR_GAMESIR 0x3537
#define USB_VENDOR_DRAGONRISE 0x0079
#define USB_VENDOR_GOOGLE 0x18d1
#define USB_VENDOR_HORI 0x0f0d
#define USB_VENDOR_HYPERKIN 0x2e24
#define USB_VENDOR_LOGITECH 0x046d
#define USB_VENDOR_MADCATZ 0x0738
#define USB_VENDOR_MICROSOFT 0x045e
#define USB_VENDOR_NACON 0x146b
#define USB_VENDOR_NINTENDO 0x057e
#define USB_VENDOR_NVIDIA 0x0955
#define USB_VENDOR_PDP 0x0e6f
#define USB_VENDOR_POWERA 0x24c6
#define USB_VENDOR_POWERA_ALT 0x20d6
#define USB_VENDOR_QANBA 0x2c22
#define USB_VENDOR_RAZER 0x1532
#define USB_VENDOR_SAITEK 0x06a3
#define USB_VENDOR_SHANWAN 0x2563
#define USB_VENDOR_SHANWAN_ALT 0x20bc
#define USB_VENDOR_SONY 0x054c
#define USB_VENDOR_THRUSTMASTER 0x044f
#define USB_VENDOR_TURTLE_BEACH 0x10f5
#define USB_VENDOR_VALVE 0x28de
#define USB_VENDOR_ZEROPLUS 0x0c12
#define USB_PRODUCT_8BITDO_XBOX_CONTROLLER 0x2002
#define USB_PRODUCT_AMAZON_LUNA_CONTROLLER 0x0419
#define USB_PRODUCT_ASTRO_C40_XBOX360 0x0024
#define USB_PRODUCT_BACKBONE_ONE_IOS 0x0103
#define USB_PRODUCT_BACKBONE_ONE_IOS_PS5 0x0104
#define USB_PRODUCT_GAMESIR_G7 0x1001
#define USB_PRODUCT_GOOGLE_STADIA_CONTROLLER 0x9400
#define USB_PRODUCT_EVORETRO_GAMECUBE_ADAPTER 0x1846
#define USB_PRODUCT_HORI_FIGHTING_COMMANDER_OCTA_SERIES_X 0x0150
#define USB_PRODUCT_HORI_HORIPAD_PRO_SERIES_X 0x014f
#define USB_PRODUCT_HORI_FIGHTING_STICK_ALPHA_PS4 0x011c
#define USB_PRODUCT_HORI_FIGHTING_STICK_ALPHA_PS5 0x0184
#define USB_PRODUCT_LOGITECH_F310 0xc216
#define USB_PRODUCT_LOGITECH_CHILLSTREAM 0xcad1
#define USB_PRODUCT_NINTENDO_GAMECUBE_ADAPTER 0x0337
#define USB_PRODUCT_NINTENDO_N64_CONTROLLER 0x2019
#define USB_PRODUCT_NINTENDO_SEGA_GENESIS_CONTROLLER 0x201e
#define USB_PRODUCT_NINTENDO_SNES_CONTROLLER 0x2017
#define USB_PRODUCT_NINTENDO_SWITCH_JOYCON_GRIP 0x200e
#define USB_PRODUCT_NINTENDO_SWITCH_JOYCON_LEFT 0x2006
#define USB_PRODUCT_NINTENDO_SWITCH_JOYCON_PAIR 0x2008 /* Used by joycond */
#define USB_PRODUCT_NINTENDO_SWITCH_JOYCON_RIGHT 0x2007
#define USB_PRODUCT_NINTENDO_SWITCH_PRO 0x2009
#define USB_PRODUCT_NINTENDO_WII_REMOTE 0x0306
#define USB_PRODUCT_NINTENDO_WII_REMOTE2 0x0330
#define USB_PRODUCT_NVIDIA_SHIELD_CONTROLLER_V103 0x7210
#define USB_PRODUCT_NVIDIA_SHIELD_CONTROLLER_V104 0x7214
#define USB_PRODUCT_RAZER_ATROX 0x0a00
#define USB_PRODUCT_RAZER_PANTHERA 0x0401
#define USB_PRODUCT_RAZER_PANTHERA_EVO 0x1008
#define USB_PRODUCT_RAZER_RAIJU 0x1000
#define USB_PRODUCT_RAZER_TOURNAMENT_EDITION_USB 0x1007
#define USB_PRODUCT_RAZER_TOURNAMENT_EDITION_BLUETOOTH 0x100a
#define USB_PRODUCT_RAZER_ULTIMATE_EDITION_USB 0x1004
#define USB_PRODUCT_RAZER_ULTIMATE_EDITION_BLUETOOTH 0x1009
#define USB_PRODUCT_RAZER_WOLVERINE_V2 0x0a29
#define USB_PRODUCT_RAZER_WOLVERINE_V2_CHROMA 0x0a2e
#define USB_PRODUCT_RAZER_WOLVERINE_V2_PRO_PS5_WIRED 0x100b
#define USB_PRODUCT_RAZER_WOLVERINE_V2_PRO_PS5_WIRELESS 0x100c
#define USB_PRODUCT_RAZER_WOLVERINE_V2_PRO_XBOX_WIRED 0x1010
#define USB_PRODUCT_RAZER_WOLVERINE_V2_PRO_XBOX_WIRELESS 0x1011
#define USB_PRODUCT_SAITEK_CYBORG_V3 0xf622
#define USB_PRODUCT_SHANWAN_DS3 0x0523
#define USB_PRODUCT_SONY_DS3 0x0268
#define USB_PRODUCT_SONY_DS4 0x05c4
#define USB_PRODUCT_SONY_DS4_DONGLE 0x0ba0
#define USB_PRODUCT_SONY_DS4_SLIM 0x09cc
#define USB_PRODUCT_SONY_DS4_STRIKEPAD 0x05c5
#define USB_PRODUCT_SONY_DS5 0x0ce6
#define USB_PRODUCT_SONY_DS5_EDGE 0x0df2
#define USB_PRODUCT_THRUSTMASTER_ESWAPX_PRO 0xd012
#define USB_PRODUCT_TURTLE_BEACH_SERIES_X_REACT_R 0x7013
#define USB_PRODUCT_TURTLE_BEACH_SERIES_X_RECON 0x7009
#define USB_PRODUCT_VICTRIX_FS_PRO 0x0203
#define USB_PRODUCT_VICTRIX_FS_PRO_V2 0x0207
#define USB_PRODUCT_XBOX360_XUSB_CONTROLLER 0x02a1 /* XUSB driver software PID */
#define USB_PRODUCT_XBOX360_WIRED_CONTROLLER 0x028e
#define USB_PRODUCT_XBOX360_WIRELESS_RECEIVER 0x0719
#define USB_PRODUCT_XBOX_ONE_ADAPTIVE 0x0b0a
#define USB_PRODUCT_XBOX_ONE_ADAPTIVE_BLUETOOTH 0x0b0c
#define USB_PRODUCT_XBOX_ONE_ADAPTIVE_BLE 0x0b21
#define USB_PRODUCT_XBOX_ONE_ELITE_SERIES_1 0x02e3
#define USB_PRODUCT_XBOX_ONE_ELITE_SERIES_2 0x0b00
#define USB_PRODUCT_XBOX_ONE_ELITE_SERIES_2_BLUETOOTH 0x0b05
#define USB_PRODUCT_XBOX_ONE_ELITE_SERIES_2_BLE 0x0b22
#define USB_PRODUCT_XBOX_ONE_S 0x02ea
#define USB_PRODUCT_XBOX_ONE_S_REV1_BLUETOOTH 0x02e0
#define USB_PRODUCT_XBOX_ONE_S_REV2_BLUETOOTH 0x02fd
#define USB_PRODUCT_XBOX_ONE_S_REV2_BLE 0x0b20
#define USB_PRODUCT_XBOX_SERIES_X 0x0b12
#define USB_PRODUCT_XBOX_SERIES_X_BLE 0x0b13
#define USB_PRODUCT_XBOX_SERIES_X_VICTRIX_GAMBIT 0x02d6
#define USB_PRODUCT_XBOX_SERIES_X_PDP_BLUE 0x02d9
#define USB_PRODUCT_XBOX_SERIES_X_PDP_AFTERGLOW 0x02da
#define USB_PRODUCT_XBOX_SERIES_X_POWERA_FUSION_PRO2 0x4001
#define USB_PRODUCT_XBOX_SERIES_X_POWERA_MOGA_XP_ULTRA 0x890b
#define USB_PRODUCT_XBOX_SERIES_X_POWERA_SPECTRA 0x4002
#define USB_PRODUCT_XBOX_ONE_XBOXGIP_CONTROLLER 0x02ff /* XBOXGIP driver software PID */
#define USB_PRODUCT_XBOX_ONE_XINPUT_CONTROLLER 0x02fe /* Made up product ID for XInput */
#define USB_PRODUCT_STEAM_VIRTUAL_GAMEPAD 0x11ff
/* USB usage pages */
#define USB_USAGEPAGE_GENERIC_DESKTOP 0x0001
#define USB_USAGEPAGE_BUTTON 0x0009
/* USB usages for USAGE_PAGE_GENERIC_DESKTOP */
#define USB_USAGE_GENERIC_POINTER 0x0001
#define USB_USAGE_GENERIC_MOUSE 0x0002
#define USB_USAGE_GENERIC_JOYSTICK 0x0004
#define USB_USAGE_GENERIC_GAMEPAD 0x0005
#define USB_USAGE_GENERIC_KEYBOARD 0x0006
#define USB_USAGE_GENERIC_KEYPAD 0x0007
#define USB_USAGE_GENERIC_MULTIAXISCONTROLLER 0x0008
#define USB_USAGE_GENERIC_X 0x0030
#define USB_USAGE_GENERIC_Y 0x0031
#define USB_USAGE_GENERIC_Z 0x0032
#define USB_USAGE_GENERIC_RX 0x0033
#define USB_USAGE_GENERIC_RY 0x0034
#define USB_USAGE_GENERIC_RZ 0x0035
#define USB_USAGE_GENERIC_SLIDER 0x0036
#define USB_USAGE_GENERIC_DIAL 0x0037
#define USB_USAGE_GENERIC_WHEEL 0x0038
#define USB_USAGE_GENERIC_HAT 0x0039
/* Bluetooth SIG assigned Company Identifiers
https://www.bluetooth.com/specifications/assigned-numbers/company-identifiers/ */
#define BLUETOOTH_VENDOR_AMAZON 0x0171
#define BLUETOOTH_PRODUCT_LUNA_CONTROLLER 0x0419
#endif /* usb_ids_h_ */

View File

@@ -0,0 +1,748 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 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_VIRTUAL
/* This is the virtual implementation of the SDL joystick API */
#include "SDL_virtualjoystick_c.h"
#include "../SDL_sysjoystick.h"
#include "../SDL_joystick_c.h"
static joystick_hwdata *g_VJoys SDL_GUARDED_BY(SDL_joystick_lock) = NULL;
static joystick_hwdata *VIRTUAL_HWDataForInstance(SDL_JoystickID instance_id)
{
joystick_hwdata *vjoy;
SDL_AssertJoysticksLocked();
for (vjoy = g_VJoys; vjoy; vjoy = vjoy->next) {
if (instance_id == vjoy->instance_id) {
return vjoy;
}
}
return NULL;
}
static joystick_hwdata *VIRTUAL_HWDataForIndex(int device_index)
{
joystick_hwdata *vjoy;
SDL_AssertJoysticksLocked();
for (vjoy = g_VJoys; vjoy; vjoy = vjoy->next) {
if (device_index == 0) {
break;
}
--device_index;
}
return vjoy;
}
static void VIRTUAL_FreeHWData(joystick_hwdata *hwdata)
{
joystick_hwdata *cur;
joystick_hwdata *prev = NULL;
SDL_AssertJoysticksLocked();
if (hwdata == NULL) {
return;
}
/* Remove hwdata from SDL-global list */
for (cur = g_VJoys; cur; prev = cur, cur = cur->next) {
if (hwdata == cur) {
if (prev) {
prev->next = cur->next;
} else {
g_VJoys = cur->next;
}
break;
}
}
if (hwdata->joystick) {
hwdata->joystick->hwdata = NULL;
hwdata->joystick = NULL;
}
if (hwdata->name) {
SDL_free(hwdata->name);
hwdata->name = NULL;
}
if (hwdata->axes) {
SDL_free((void *)hwdata->axes);
hwdata->axes = NULL;
}
if (hwdata->buttons) {
SDL_free((void *)hwdata->buttons);
hwdata->buttons = NULL;
}
if (hwdata->hats) {
SDL_free(hwdata->hats);
hwdata->hats = NULL;
}
SDL_free(hwdata);
}
SDL_JoystickID SDL_JoystickAttachVirtualInner(const SDL_VirtualJoystickDesc *desc)
{
joystick_hwdata *hwdata = NULL;
const char *name = NULL;
int axis_triggerleft = -1;
int axis_triggerright = -1;
SDL_AssertJoysticksLocked();
if (desc == NULL) {
return SDL_InvalidParamError("desc");
}
if (desc->version != SDL_VIRTUAL_JOYSTICK_DESC_VERSION) {
/* Is this an old version that we can support? */
return SDL_SetError("Unsupported virtual joystick description version %d", desc->version);
}
hwdata = SDL_calloc(1, sizeof(joystick_hwdata));
if (hwdata == NULL) {
VIRTUAL_FreeHWData(hwdata);
return SDL_OutOfMemory();
}
SDL_memcpy(&hwdata->desc, desc, sizeof(*desc));
if (hwdata->desc.name) {
name = hwdata->desc.name;
} else {
switch (hwdata->desc.type) {
case SDL_JOYSTICK_TYPE_GAMEPAD:
name = "Virtual Controller";
break;
case SDL_JOYSTICK_TYPE_WHEEL:
name = "Virtual Wheel";
break;
case SDL_JOYSTICK_TYPE_ARCADE_STICK:
name = "Virtual Arcade Stick";
break;
case SDL_JOYSTICK_TYPE_FLIGHT_STICK:
name = "Virtual Flight Stick";
break;
case SDL_JOYSTICK_TYPE_DANCE_PAD:
name = "Virtual Dance Pad";
break;
case SDL_JOYSTICK_TYPE_GUITAR:
name = "Virtual Guitar";
break;
case SDL_JOYSTICK_TYPE_DRUM_KIT:
name = "Virtual Drum Kit";
break;
case SDL_JOYSTICK_TYPE_ARCADE_PAD:
name = "Virtual Arcade Pad";
break;
case SDL_JOYSTICK_TYPE_THROTTLE:
name = "Virtual Throttle";
break;
default:
name = "Virtual Joystick";
break;
}
}
hwdata->name = SDL_strdup(name);
if (hwdata->desc.type == SDL_JOYSTICK_TYPE_GAMEPAD) {
int i, axis;
if (hwdata->desc.button_mask == 0) {
for (i = 0; i < hwdata->desc.nbuttons && i < sizeof(hwdata->desc.button_mask) * 8; ++i) {
hwdata->desc.button_mask |= (1 << i);
}
}
if (hwdata->desc.axis_mask == 0) {
if (hwdata->desc.naxes >= 2) {
hwdata->desc.axis_mask |= ((1 << SDL_GAMEPAD_AXIS_LEFTX) | (1 << SDL_GAMEPAD_AXIS_LEFTY));
}
if (hwdata->desc.naxes >= 4) {
hwdata->desc.axis_mask |= ((1 << SDL_GAMEPAD_AXIS_RIGHTX) | (1 << SDL_GAMEPAD_AXIS_RIGHTY));
}
if (hwdata->desc.naxes >= 6) {
hwdata->desc.axis_mask |= ((1 << SDL_GAMEPAD_AXIS_LEFT_TRIGGER) | (1 << SDL_GAMEPAD_AXIS_RIGHT_TRIGGER));
}
}
/* Find the trigger axes */
axis = 0;
for (i = 0; axis < hwdata->desc.naxes && i < SDL_GAMEPAD_AXIS_MAX; ++i) {
if (hwdata->desc.axis_mask & (1 << i)) {
if (i == SDL_GAMEPAD_AXIS_LEFT_TRIGGER) {
axis_triggerleft = axis;
}
if (i == SDL_GAMEPAD_AXIS_RIGHT_TRIGGER) {
axis_triggerright = axis;
}
++axis;
}
}
}
hwdata->guid = SDL_CreateJoystickGUID(SDL_HARDWARE_BUS_VIRTUAL, hwdata->desc.vendor_id, hwdata->desc.product_id, 0, name, 'v', (Uint8)hwdata->desc.type);
/* Allocate fields for different control-types */
if (hwdata->desc.naxes > 0) {
hwdata->axes = SDL_calloc(hwdata->desc.naxes, sizeof(Sint16));
if (!hwdata->axes) {
VIRTUAL_FreeHWData(hwdata);
return SDL_OutOfMemory();
}
/* Trigger axes are at minimum value at rest */
if (axis_triggerleft >= 0) {
hwdata->axes[axis_triggerleft] = SDL_JOYSTICK_AXIS_MIN;
}
if (axis_triggerright >= 0) {
hwdata->axes[axis_triggerright] = SDL_JOYSTICK_AXIS_MIN;
}
}
if (hwdata->desc.nbuttons > 0) {
hwdata->buttons = SDL_calloc(hwdata->desc.nbuttons, sizeof(Uint8));
if (!hwdata->buttons) {
VIRTUAL_FreeHWData(hwdata);
return SDL_OutOfMemory();
}
}
if (hwdata->desc.nhats > 0) {
hwdata->hats = SDL_calloc(hwdata->desc.nhats, sizeof(Uint8));
if (!hwdata->hats) {
VIRTUAL_FreeHWData(hwdata);
return SDL_OutOfMemory();
}
}
/* Allocate an instance ID for this device */
hwdata->instance_id = SDL_GetNextJoystickInstanceID();
/* Add virtual joystick to SDL-global lists */
if (g_VJoys) {
joystick_hwdata *last;
for (last = g_VJoys; last->next; last = last->next) {
}
last->next = hwdata;
} else {
g_VJoys = hwdata;
}
SDL_PrivateJoystickAdded(hwdata->instance_id);
return hwdata->instance_id;
}
int SDL_JoystickDetachVirtualInner(SDL_JoystickID instance_id)
{
joystick_hwdata *hwdata = VIRTUAL_HWDataForInstance(instance_id);
if (hwdata == NULL) {
return SDL_SetError("Virtual joystick data not found");
}
VIRTUAL_FreeHWData(hwdata);
SDL_PrivateJoystickRemoved(instance_id);
return 0;
}
int SDL_SetJoystickVirtualAxisInner(SDL_Joystick *joystick, int axis, Sint16 value)
{
joystick_hwdata *hwdata;
SDL_AssertJoysticksLocked();
if (joystick == NULL || !joystick->hwdata) {
SDL_UnlockJoysticks();
return SDL_SetError("Invalid joystick");
}
hwdata = (joystick_hwdata *)joystick->hwdata;
if (axis < 0 || axis >= hwdata->desc.naxes) {
SDL_UnlockJoysticks();
return SDL_SetError("Invalid axis index");
}
hwdata->axes[axis] = value;
return 0;
}
int SDL_SetJoystickVirtualButtonInner(SDL_Joystick *joystick, int button, Uint8 value)
{
joystick_hwdata *hwdata;
SDL_AssertJoysticksLocked();
if (joystick == NULL || !joystick->hwdata) {
SDL_UnlockJoysticks();
return SDL_SetError("Invalid joystick");
}
hwdata = (joystick_hwdata *)joystick->hwdata;
if (button < 0 || button >= hwdata->desc.nbuttons) {
SDL_UnlockJoysticks();
return SDL_SetError("Invalid button index");
}
hwdata->buttons[button] = value;
return 0;
}
int SDL_SetJoystickVirtualHatInner(SDL_Joystick *joystick, int hat, Uint8 value)
{
joystick_hwdata *hwdata;
SDL_AssertJoysticksLocked();
if (joystick == NULL || !joystick->hwdata) {
SDL_UnlockJoysticks();
return SDL_SetError("Invalid joystick");
}
hwdata = (joystick_hwdata *)joystick->hwdata;
if (hat < 0 || hat >= hwdata->desc.nhats) {
SDL_UnlockJoysticks();
return SDL_SetError("Invalid hat index");
}
hwdata->hats[hat] = value;
return 0;
}
static int VIRTUAL_JoystickInit(void)
{
return 0;
}
static int VIRTUAL_JoystickGetCount(void)
{
joystick_hwdata *cur;
int count = 0;
SDL_AssertJoysticksLocked();
for (cur = g_VJoys; cur; cur = cur->next) {
++count;
}
return count;
}
static void VIRTUAL_JoystickDetect(void)
{
}
static const char *VIRTUAL_JoystickGetDeviceName(int device_index)
{
joystick_hwdata *hwdata = VIRTUAL_HWDataForIndex(device_index);
if (hwdata == NULL) {
return NULL;
}
return hwdata->name;
}
static const char *VIRTUAL_JoystickGetDevicePath(int device_index)
{
return NULL;
}
static int VIRTUAL_JoystickGetDevicePlayerIndex(int device_index)
{
return -1;
}
static void VIRTUAL_JoystickSetDevicePlayerIndex(int device_index, int player_index)
{
joystick_hwdata *hwdata = VIRTUAL_HWDataForIndex(device_index);
if (hwdata && hwdata->desc.SetPlayerIndex) {
hwdata->desc.SetPlayerIndex(hwdata->desc.userdata, player_index);
}
}
static SDL_JoystickGUID VIRTUAL_JoystickGetDeviceGUID(int device_index)
{
joystick_hwdata *hwdata = VIRTUAL_HWDataForIndex(device_index);
if (hwdata == NULL) {
SDL_JoystickGUID guid;
SDL_zero(guid);
return guid;
}
return hwdata->guid;
}
static SDL_JoystickID VIRTUAL_JoystickGetDeviceInstanceID(int device_index)
{
joystick_hwdata *hwdata = VIRTUAL_HWDataForIndex(device_index);
if (hwdata == NULL) {
return 0;
}
return hwdata->instance_id;
}
static int VIRTUAL_JoystickOpen(SDL_Joystick *joystick, int device_index)
{
joystick_hwdata *hwdata;
SDL_AssertJoysticksLocked();
hwdata = VIRTUAL_HWDataForIndex(device_index);
if (hwdata == NULL) {
return SDL_SetError("No such device");
}
joystick->instance_id = hwdata->instance_id;
joystick->hwdata = hwdata;
joystick->naxes = hwdata->desc.naxes;
joystick->nbuttons = hwdata->desc.nbuttons;
joystick->nhats = hwdata->desc.nhats;
hwdata->joystick = joystick;
return 0;
}
static int VIRTUAL_JoystickRumble(SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble)
{
int result;
SDL_AssertJoysticksLocked();
if (joystick->hwdata) {
joystick_hwdata *hwdata = joystick->hwdata;
if (hwdata->desc.Rumble) {
result = hwdata->desc.Rumble(hwdata->desc.userdata, low_frequency_rumble, high_frequency_rumble);
} else {
result = SDL_Unsupported();
}
} else {
result = SDL_SetError("Rumble failed, device disconnected");
}
return result;
}
static int VIRTUAL_JoystickRumbleTriggers(SDL_Joystick *joystick, Uint16 left_rumble, Uint16 right_rumble)
{
int result;
SDL_AssertJoysticksLocked();
if (joystick->hwdata) {
joystick_hwdata *hwdata = joystick->hwdata;
if (hwdata->desc.RumbleTriggers) {
result = hwdata->desc.RumbleTriggers(hwdata->desc.userdata, left_rumble, right_rumble);
} else {
result = SDL_Unsupported();
}
} else {
result = SDL_SetError("Rumble failed, device disconnected");
}
return result;
}
static Uint32 VIRTUAL_JoystickGetCapabilities(SDL_Joystick *joystick)
{
joystick_hwdata *hwdata;
Uint32 caps = 0;
SDL_AssertJoysticksLocked();
hwdata = joystick->hwdata;
if (hwdata) {
if (hwdata->desc.Rumble) {
caps |= SDL_JOYCAP_RUMBLE;
}
if (hwdata->desc.RumbleTriggers) {
caps |= SDL_JOYCAP_RUMBLE_TRIGGERS;
}
if (hwdata->desc.SetLED) {
caps |= SDL_JOYCAP_LED;
}
}
return caps;
}
static int VIRTUAL_JoystickSetLED(SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue)
{
int result;
SDL_AssertJoysticksLocked();
if (joystick->hwdata) {
joystick_hwdata *hwdata = joystick->hwdata;
if (hwdata->desc.SetLED) {
result = hwdata->desc.SetLED(hwdata->desc.userdata, red, green, blue);
} else {
result = SDL_Unsupported();
}
} else {
result = SDL_SetError("SetLED failed, device disconnected");
}
return result;
}
static int VIRTUAL_JoystickSendEffect(SDL_Joystick *joystick, const void *data, int size)
{
int result;
SDL_AssertJoysticksLocked();
if (joystick->hwdata) {
joystick_hwdata *hwdata = joystick->hwdata;
if (hwdata->desc.SendEffect) {
result = hwdata->desc.SendEffect(hwdata->desc.userdata, data, size);
} else {
result = SDL_Unsupported();
}
} else {
result = SDL_SetError("SendEffect failed, device disconnected");
}
return result;
}
static int VIRTUAL_JoystickSetSensorsEnabled(SDL_Joystick *joystick, SDL_bool enabled)
{
return SDL_Unsupported();
}
static void VIRTUAL_JoystickUpdate(SDL_Joystick *joystick)
{
joystick_hwdata *hwdata;
Uint8 i;
Uint64 timestamp = SDL_GetTicksNS();
SDL_AssertJoysticksLocked();
if (joystick == NULL) {
return;
}
if (!joystick->hwdata) {
return;
}
hwdata = (joystick_hwdata *)joystick->hwdata;
if (hwdata->desc.Update) {
hwdata->desc.Update(hwdata->desc.userdata);
}
for (i = 0; i < hwdata->desc.naxes; ++i) {
SDL_SendJoystickAxis(timestamp, joystick, i, hwdata->axes[i]);
}
for (i = 0; i < hwdata->desc.nbuttons; ++i) {
SDL_SendJoystickButton(timestamp, joystick, i, hwdata->buttons[i]);
}
for (i = 0; i < hwdata->desc.nhats; ++i) {
SDL_SendJoystickHat(timestamp, joystick, i, hwdata->hats[i]);
}
}
static void VIRTUAL_JoystickClose(SDL_Joystick *joystick)
{
SDL_AssertJoysticksLocked();
if (joystick->hwdata) {
joystick_hwdata *hwdata = joystick->hwdata;
hwdata->joystick = NULL;
joystick->hwdata = NULL;
}
}
static void VIRTUAL_JoystickQuit(void)
{
SDL_AssertJoysticksLocked();
while (g_VJoys) {
VIRTUAL_FreeHWData(g_VJoys);
}
}
static SDL_bool VIRTUAL_JoystickGetGamepadMapping(int device_index, SDL_GamepadMapping *out)
{
joystick_hwdata *hwdata = VIRTUAL_HWDataForIndex(device_index);
Uint8 current_button = 0;
Uint8 current_axis = 0;
if (!hwdata || hwdata->desc.type != SDL_JOYSTICK_TYPE_GAMEPAD) {
return SDL_FALSE;
}
if (current_button < hwdata->desc.nbuttons && (hwdata->desc.button_mask & (1 << SDL_GAMEPAD_BUTTON_A))) {
out->a.kind = EMappingKind_Button;
out->a.target = current_button++;
}
if (current_button < hwdata->desc.nbuttons && (hwdata->desc.button_mask & (1 << SDL_GAMEPAD_BUTTON_B))) {
out->b.kind = EMappingKind_Button;
out->b.target = current_button++;
}
if (current_button < hwdata->desc.nbuttons && (hwdata->desc.button_mask & (1 << SDL_GAMEPAD_BUTTON_X))) {
out->x.kind = EMappingKind_Button;
out->x.target = current_button++;
}
if (current_button < hwdata->desc.nbuttons && (hwdata->desc.button_mask & (1 << SDL_GAMEPAD_BUTTON_Y))) {
out->y.kind = EMappingKind_Button;
out->y.target = current_button++;
}
if (current_button < hwdata->desc.nbuttons && (hwdata->desc.button_mask & (1 << SDL_GAMEPAD_BUTTON_BACK))) {
out->back.kind = EMappingKind_Button;
out->back.target = current_button++;
}
if (current_button < hwdata->desc.nbuttons && (hwdata->desc.button_mask & (1 << SDL_GAMEPAD_BUTTON_GUIDE))) {
out->guide.kind = EMappingKind_Button;
out->guide.target = current_button++;
}
if (current_button < hwdata->desc.nbuttons && (hwdata->desc.button_mask & (1 << SDL_GAMEPAD_BUTTON_START))) {
out->start.kind = EMappingKind_Button;
out->start.target = current_button++;
}
if (current_button < hwdata->desc.nbuttons && (hwdata->desc.button_mask & (1 << SDL_GAMEPAD_BUTTON_LEFT_STICK))) {
out->leftstick.kind = EMappingKind_Button;
out->leftstick.target = current_button++;
}
if (current_button < hwdata->desc.nbuttons && (hwdata->desc.button_mask & (1 << SDL_GAMEPAD_BUTTON_RIGHT_STICK))) {
out->rightstick.kind = EMappingKind_Button;
out->rightstick.target = current_button++;
}
if (current_button < hwdata->desc.nbuttons && (hwdata->desc.button_mask & (1 << SDL_GAMEPAD_BUTTON_LEFT_SHOULDER))) {
out->leftshoulder.kind = EMappingKind_Button;
out->leftshoulder.target = current_button++;
}
if (current_button < hwdata->desc.nbuttons && (hwdata->desc.button_mask & (1 << SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER))) {
out->rightshoulder.kind = EMappingKind_Button;
out->rightshoulder.target = current_button++;
}
if (current_button < hwdata->desc.nbuttons && (hwdata->desc.button_mask & (1 << SDL_GAMEPAD_BUTTON_DPAD_UP))) {
out->dpup.kind = EMappingKind_Button;
out->dpup.target = current_button++;
}
if (current_button < hwdata->desc.nbuttons && (hwdata->desc.button_mask & (1 << SDL_GAMEPAD_BUTTON_DPAD_DOWN))) {
out->dpdown.kind = EMappingKind_Button;
out->dpdown.target = current_button++;
}
if (current_button < hwdata->desc.nbuttons && (hwdata->desc.button_mask & (1 << SDL_GAMEPAD_BUTTON_DPAD_LEFT))) {
out->dpleft.kind = EMappingKind_Button;
out->dpleft.target = current_button++;
}
if (current_button < hwdata->desc.nbuttons && (hwdata->desc.button_mask & (1 << SDL_GAMEPAD_BUTTON_DPAD_RIGHT))) {
out->dpright.kind = EMappingKind_Button;
out->dpright.target = current_button++;
}
if (current_button < hwdata->desc.nbuttons && (hwdata->desc.button_mask & (1 << SDL_GAMEPAD_BUTTON_MISC1))) {
out->misc1.kind = EMappingKind_Button;
out->misc1.target = current_button++;
}
if (current_button < hwdata->desc.nbuttons && (hwdata->desc.button_mask & (1 << SDL_GAMEPAD_BUTTON_PADDLE1))) {
out->paddle1.kind = EMappingKind_Button;
out->paddle1.target = current_button++;
}
if (current_button < hwdata->desc.nbuttons && (hwdata->desc.button_mask & (1 << SDL_GAMEPAD_BUTTON_PADDLE2))) {
out->paddle2.kind = EMappingKind_Button;
out->paddle2.target = current_button++;
}
if (current_button < hwdata->desc.nbuttons && (hwdata->desc.button_mask & (1 << SDL_GAMEPAD_BUTTON_PADDLE3))) {
out->paddle3.kind = EMappingKind_Button;
out->paddle3.target = current_button++;
}
if (current_button < hwdata->desc.nbuttons && (hwdata->desc.button_mask & (1 << SDL_GAMEPAD_BUTTON_PADDLE4))) {
out->paddle4.kind = EMappingKind_Button;
out->paddle4.target = current_button++;
}
if (current_axis < hwdata->desc.naxes && (hwdata->desc.axis_mask & (1 << SDL_GAMEPAD_AXIS_LEFTX))) {
out->leftx.kind = EMappingKind_Axis;
out->leftx.target = current_axis++;
}
if (current_axis < hwdata->desc.naxes && (hwdata->desc.axis_mask & (1 << SDL_GAMEPAD_AXIS_LEFTY))) {
out->lefty.kind = EMappingKind_Axis;
out->lefty.target = current_axis++;
}
if (current_axis < hwdata->desc.naxes && (hwdata->desc.axis_mask & (1 << SDL_GAMEPAD_AXIS_RIGHTX))) {
out->rightx.kind = EMappingKind_Axis;
out->rightx.target = current_axis++;
}
if (current_axis < hwdata->desc.naxes && (hwdata->desc.axis_mask & (1 << SDL_GAMEPAD_AXIS_RIGHTY))) {
out->righty.kind = EMappingKind_Axis;
out->righty.target = current_axis++;
}
if (current_axis < hwdata->desc.naxes && (hwdata->desc.axis_mask & (1 << SDL_GAMEPAD_AXIS_LEFT_TRIGGER))) {
out->lefttrigger.kind = EMappingKind_Axis;
out->lefttrigger.target = current_axis++;
}
if (current_axis < hwdata->desc.naxes && (hwdata->desc.axis_mask & (1 << SDL_GAMEPAD_AXIS_RIGHT_TRIGGER))) {
out->righttrigger.kind = EMappingKind_Axis;
out->righttrigger.target = current_axis++;
}
return SDL_TRUE;
}
SDL_JoystickDriver SDL_VIRTUAL_JoystickDriver = {
VIRTUAL_JoystickInit,
VIRTUAL_JoystickGetCount,
VIRTUAL_JoystickDetect,
VIRTUAL_JoystickGetDeviceName,
VIRTUAL_JoystickGetDevicePath,
VIRTUAL_JoystickGetDevicePlayerIndex,
VIRTUAL_JoystickSetDevicePlayerIndex,
VIRTUAL_JoystickGetDeviceGUID,
VIRTUAL_JoystickGetDeviceInstanceID,
VIRTUAL_JoystickOpen,
VIRTUAL_JoystickRumble,
VIRTUAL_JoystickRumbleTriggers,
VIRTUAL_JoystickGetCapabilities,
VIRTUAL_JoystickSetLED,
VIRTUAL_JoystickSendEffect,
VIRTUAL_JoystickSetSensorsEnabled,
VIRTUAL_JoystickUpdate,
VIRTUAL_JoystickClose,
VIRTUAL_JoystickQuit,
VIRTUAL_JoystickGetGamepadMapping
};
#endif /* SDL_JOYSTICK_VIRTUAL */

View File

@@ -0,0 +1,56 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 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"
#ifndef SDL_VIRTUALJOYSTICK_C_H
#define SDL_VIRTUALJOYSTICK_C_H
#ifdef SDL_JOYSTICK_VIRTUAL
/**
* Data for a virtual, software-only joystick.
*/
typedef struct joystick_hwdata
{
SDL_JoystickType type;
SDL_bool attached;
char *name;
SDL_JoystickGUID guid;
SDL_VirtualJoystickDesc desc;
Sint16 *axes;
Uint8 *buttons;
Uint8 *hats;
SDL_JoystickID instance_id;
SDL_Joystick *joystick;
struct joystick_hwdata *next;
} joystick_hwdata;
SDL_JoystickID SDL_JoystickAttachVirtualInner(const SDL_VirtualJoystickDesc *desc);
int SDL_JoystickDetachVirtualInner(SDL_JoystickID instance_id);
int SDL_SetJoystickVirtualAxisInner(SDL_Joystick *joystick, int axis, Sint16 value);
int SDL_SetJoystickVirtualButtonInner(SDL_Joystick *joystick, int button, Uint8 value);
int SDL_SetJoystickVirtualHatInner(SDL_Joystick *joystick, int hat, Uint8 value);
#endif /* SDL_JOYSTICK_VIRTUAL */
#endif /* SDL_VIRTUALJOYSTICK_C_H */

View File

@@ -0,0 +1,402 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 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_VITA
/* This is the PSVita implementation of the SDL joystick API */
#include <psp2/types.h>
#include <psp2/ctrl.h>
#include <psp2/kernel/threadmgr.h>
#include <stdio.h> /* For the definition of NULL */
#include <stdlib.h>
#include "../SDL_sysjoystick.h"
#include "../SDL_joystick_c.h"
/* Current pad state */
static SceCtrlData pad0 = { .lx = 0, .ly = 0, .rx = 0, .ry = 0, .lt = 0, .rt = 0, .buttons = 0 };
static SceCtrlData pad1 = { .lx = 0, .ly = 0, .rx = 0, .ry = 0, .lt = 0, .rt = 0, .buttons = 0 };
static SceCtrlData pad2 = { .lx = 0, .ly = 0, .rx = 0, .ry = 0, .lt = 0, .rt = 0, .buttons = 0 };
static SceCtrlData pad3 = { .lx = 0, .ly = 0, .rx = 0, .ry = 0, .lt = 0, .rt = 0, .buttons = 0 };
static int ext_port_map[4] = { 1, 2, 3, 4 }; // index: SDL joy number, entry: Vita port number. For external controllers
static int SDL_numjoysticks = 1;
static const unsigned int ext_button_map[] = {
SCE_CTRL_TRIANGLE,
SCE_CTRL_CIRCLE,
SCE_CTRL_CROSS,
SCE_CTRL_SQUARE,
SCE_CTRL_L1,
SCE_CTRL_R1,
SCE_CTRL_DOWN,
SCE_CTRL_LEFT,
SCE_CTRL_UP,
SCE_CTRL_RIGHT,
SCE_CTRL_SELECT,
SCE_CTRL_START,
SCE_CTRL_L2,
SCE_CTRL_R2,
SCE_CTRL_L3,
SCE_CTRL_R3
};
static int analog_map[256]; /* Map analog inputs to -32768 -> 32767 */
typedef struct
{
int x;
int y;
} point;
/* 4 points define the bezier-curve. */
/* The Vita has a good amount of analog travel, so use a linear curve */
static point a = { 0, 0 };
static point b = { 0, 0 };
static point c = { 128, 32767 };
static point d = { 128, 32767 };
/* simple linear interpolation between two points */
static SDL_INLINE void lerp(point *dest, point *first, point *second, float t)
{
dest->x = first->x + (second->x - first->x) * t;
dest->y = first->y + (second->y - first->y) * t;
}
/* evaluate a point on a bezier-curve. t goes from 0 to 1.0 */
static int calc_bezier_y(float t)
{
point ab, bc, cd, abbc, bccd, dest;
lerp(&ab, &a, &b, t); /* point between a and b */
lerp(&bc, &b, &c, t); /* point between b and c */
lerp(&cd, &c, &d, t); /* point between c and d */
lerp(&abbc, &ab, &bc, t); /* point between ab and bc */
lerp(&bccd, &bc, &cd, t); /* point between bc and cd */
lerp(&dest, &abbc, &bccd, t); /* point on the bezier-curve */
return dest.y;
}
/* Function to scan the system for joysticks.
* Joystick 0 should be the system default joystick.
* It should return number of joysticks, or -1 on an unrecoverable fatal error.
*/
int VITA_JoystickInit(void)
{
int i;
SceCtrlPortInfo myPortInfo;
/* Setup input */
sceCtrlSetSamplingMode(SCE_CTRL_MODE_ANALOG_WIDE);
sceCtrlSetSamplingModeExt(SCE_CTRL_MODE_ANALOG_WIDE);
/* Create an accurate map from analog inputs (0 to 255)
to SDL joystick positions (-32768 to 32767) */
for (i = 0; i < 128; i++) {
float t = (float)i / 127.0f;
analog_map[i + 128] = calc_bezier_y(t);
analog_map[127 - i] = -1 * analog_map[i + 128];
}
// Assume we have at least one controller, even when nothing is paired
// This way the user can jump in, pair a controller
// and control things immediately even if it is paired
// after the app has already started.
SDL_numjoysticks = 1;
SDL_PrivateJoystickAdded(0);
// How many additional paired controllers are there?
sceCtrlGetControllerPortInfo(&myPortInfo);
// On Vita TV, port 0 and 1 are the same controller
// and that is the first one, so start at port 2
for (i = 2; i <= 4; i++) {
if (myPortInfo.port[i] != SCE_CTRL_TYPE_UNPAIRED) {
SDL_PrivateJoystickAdded(SDL_numjoysticks);
SDL_numjoysticks++;
}
}
return SDL_numjoysticks;
}
int VITA_JoystickGetCount()
{
return SDL_numjoysticks;
}
void VITA_JoystickDetect()
{
}
/* Function to perform the mapping from device index to the instance id for this index */
SDL_JoystickID VITA_JoystickGetDeviceInstanceID(int device_index)
{
return device_index;
}
const char *VITA_JoystickGetDeviceName(int index)
{
if (index == 0) {
return "PSVita Controller";
}
if (index == 1) {
return "PSVita Controller";
}
if (index == 2) {
return "PSVita Controller";
}
if (index == 3) {
return "PSVita Controller";
}
SDL_SetError("No joystick available with that index");
return NULL;
}
const char *VITA_JoystickGetDevicePath(int index)
{
return NULL;
}
static int VITA_JoystickGetDevicePlayerIndex(int device_index)
{
return -1;
}
static void VITA_JoystickSetDevicePlayerIndex(int device_index, int player_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 VITA_JoystickOpen(SDL_Joystick *joystick, int device_index)
{
joystick->nbuttons = SDL_arraysize(ext_button_map);
joystick->naxes = 6;
joystick->nhats = 0;
joystick->instance_id = device_index;
return 0;
}
/* 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 VITA_JoystickUpdate(SDL_Joystick *joystick)
{
int i;
unsigned int buttons;
unsigned int changed;
unsigned char lx, ly, rx, ry, lt, rt;
static unsigned int old_buttons[] = { 0, 0, 0, 0 };
static unsigned char old_lx[] = { 0, 0, 0, 0 };
static unsigned char old_ly[] = { 0, 0, 0, 0 };
static unsigned char old_rx[] = { 0, 0, 0, 0 };
static unsigned char old_ry[] = { 0, 0, 0, 0 };
static unsigned char old_lt[] = { 0, 0, 0, 0 };
static unsigned char old_rt[] = { 0, 0, 0, 0 };
SceCtrlData *pad = NULL;
Uint64 timestamp = SDL_GetTicksNS();
int index = (int)SDL_GetJoystickInstanceID(joystick) - 1;
if (index == 0)
pad = &pad0;
else if (index == 1)
pad = &pad1;
else if (index == 2)
pad = &pad2;
else if (index == 3)
pad = &pad3;
else
return;
if (index == 0) {
if (sceCtrlPeekBufferPositive2(ext_port_map[index], pad, 1) < 0) {
// on vita fallback to port 0
sceCtrlPeekBufferPositive2(0, pad, 1);
}
} else {
sceCtrlPeekBufferPositive2(ext_port_map[index], pad, 1);
}
buttons = pad->buttons;
lx = pad->lx;
ly = pad->ly;
rx = pad->rx;
ry = pad->ry;
lt = pad->lt;
rt = pad->rt;
// Axes
if (old_lx[index] != lx) {
SDL_SendJoystickAxis(timestamp, joystick, 0, analog_map[lx]);
old_lx[index] = lx;
}
if (old_ly[index] != ly) {
SDL_SendJoystickAxis(timestamp, joystick, 1, analog_map[ly]);
old_ly[index] = ly;
}
if (old_rx[index] != rx) {
SDL_SendJoystickAxis(timestamp, joystick, 2, analog_map[rx]);
old_rx[index] = rx;
}
if (old_ry[index] != ry) {
SDL_SendJoystickAxis(timestamp, joystick, 3, analog_map[ry]);
old_ry[index] = ry;
}
if (old_lt[index] != lt) {
SDL_SendJoystickAxis(timestamp, joystick, 4, analog_map[lt]);
old_lt[index] = lt;
}
if (old_rt[index] != rt) {
SDL_SendJoystickAxis(timestamp, joystick, 5, analog_map[rt]);
old_rt[index] = rt;
}
// Buttons
changed = old_buttons[index] ^ buttons;
old_buttons[index] = buttons;
if (changed) {
for (i = 0; i < SDL_arraysize(ext_button_map); i++) {
if (changed & ext_button_map[i]) {
SDL_SendJoystickButton(timestamp,
joystick, i,
(buttons & ext_button_map[i]) ? SDL_PRESSED : SDL_RELEASED);
}
}
}
}
/* Function to close a joystick after use */
void VITA_JoystickClose(SDL_Joystick *joystick)
{
}
/* Function to perform any system-specific joystick related cleanup */
void VITA_JoystickQuit(void)
{
}
SDL_JoystickGUID VITA_JoystickGetDeviceGUID(int device_index)
{
/* the GUID is just the name for now */
const char *name = VITA_JoystickGetDeviceName(device_index);
return SDL_CreateJoystickGUIDForName(name);
}
static int VITA_JoystickRumble(SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble)
{
int index = (int)SDL_GetJoystickInstanceID(joystick) - 1;
SceCtrlActuator act;
if (index < 0 || index > 3) {
return -1;
}
SDL_zero(act);
act.small = high_frequency_rumble / 256;
act.large = low_frequency_rumble / 256;
if (sceCtrlSetActuator(ext_port_map[index], &act) < 0) {
return SDL_Unsupported();
}
return 0;
}
static int VITA_JoystickRumbleTriggers(SDL_Joystick *joystick, Uint16 left, Uint16 right)
{
return SDL_Unsupported();
}
static Uint32 VITA_JoystickGetCapabilities(SDL_Joystick *joystick)
{
// always return LED and rumble supported for now
return SDL_JOYCAP_LED | SDL_JOYCAP_RUMBLE;
}
static int VITA_JoystickSetLED(SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue)
{
int index = (int)SDL_GetJoystickInstanceID(joystick) - 1;
if (index < 0 || index > 3) {
return -1;
}
if (sceCtrlSetLightBar(ext_port_map[index], red, green, blue) < 0) {
return SDL_Unsupported();
}
return 0;
}
static int VITA_JoystickSendEffect(SDL_Joystick *joystick, const void *data, int size)
{
return SDL_Unsupported();
}
static int VITA_JoystickSetSensorsEnabled(SDL_Joystick *joystick, SDL_bool enabled)
{
return SDL_Unsupported();
}
static SDL_bool VITA_JoystickGetGamepadMapping(int device_index, SDL_GamepadMapping *out)
{
return SDL_FALSE;
}
SDL_JoystickDriver SDL_VITA_JoystickDriver = {
VITA_JoystickInit,
VITA_JoystickGetCount,
VITA_JoystickDetect,
VITA_JoystickGetDeviceName,
VITA_JoystickGetDevicePath,
VITA_JoystickGetDevicePlayerIndex,
VITA_JoystickSetDevicePlayerIndex,
VITA_JoystickGetDeviceGUID,
VITA_JoystickGetDeviceInstanceID,
VITA_JoystickOpen,
VITA_JoystickRumble,
VITA_JoystickRumbleTriggers,
VITA_JoystickGetCapabilities,
VITA_JoystickSetLED,
VITA_JoystickSendEffect,
VITA_JoystickSetSensorsEnabled,
VITA_JoystickUpdate,
VITA_JoystickClose,
VITA_JoystickQuit,
VITA_JoystickGetGamepadMapping,
};
#endif /* SDL_JOYSTICK_VITA */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,41 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 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"
/* Set up for C function definitions, even when using C++ */
#ifdef __cplusplus
extern "C" {
#endif
extern int SDL_DINPUT_JoystickInit(void);
extern void SDL_DINPUT_JoystickDetect(JoyStick_DeviceData **pContext);
extern SDL_bool SDL_DINPUT_JoystickPresent(Uint16 vendor, Uint16 product, Uint16 version);
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);
extern Uint32 SDL_DINPUT_JoystickGetCapabilities(SDL_Joystick *joystick);
extern void SDL_DINPUT_JoystickUpdate(SDL_Joystick *joystick);
extern void SDL_DINPUT_JoystickClose(SDL_Joystick *joystick);
extern void SDL_DINPUT_JoystickQuit(void);
/* Ends C function definitions when using C++ */
#ifdef __cplusplus
}
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,35 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 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_windows.h"
/* Return true if the RawInput driver is enabled */
extern SDL_bool RAWINPUT_IsEnabled();
/* Return true if a RawInput device is present and supported as a joystick */
extern SDL_bool RAWINPUT_IsDevicePresent(Uint16 vendor_id, Uint16 product_id, Uint16 version, const char *name);
/* Registers for input events */
extern int RAWINPUT_RegisterNotifications(HWND hWnd);
extern int RAWINPUT_UnregisterNotifications();
/* Returns 0 if message was handled */
extern LRESULT CALLBACK RAWINPUT_WindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,826 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 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 defined(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_sysjoystick.h"
#include "../../thread/SDL_systhread.h"
#include "../../core/windows/SDL_windows.h"
#if !defined(__WINRT__) && !defined(__XBOXONE__) && !defined(__XBOXSERIES__)
#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 "SDL_rawinputjoystick_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
/* CM_Register_Notification definitions */
#define CR_SUCCESS (0x00000000)
/* Set up for C function definitions, even when using C++ */
#ifdef __cplusplus
extern "C" {
#endif
DECLARE_HANDLE(HCMNOTIFICATION);
typedef HCMNOTIFICATION *PHCMNOTIFICATION;
typedef enum _CM_NOTIFY_FILTER_TYPE
{
CM_NOTIFY_FILTER_TYPE_DEVICEINTERFACE = 0,
CM_NOTIFY_FILTER_TYPE_DEVICEHANDLE,
CM_NOTIFY_FILTER_TYPE_DEVICEINSTANCE,
CM_NOTIFY_FILTER_TYPE_MAX
} CM_NOTIFY_FILTER_TYPE,
*PCM_NOTIFY_FILTER_TYPE;
typedef struct _CM_NOTIFY_FILTER
{
DWORD cbSize;
DWORD Flags;
CM_NOTIFY_FILTER_TYPE FilterType;
DWORD Reserved;
union
{
struct
{
GUID ClassGuid;
} DeviceInterface;
struct
{
HANDLE hTarget;
} DeviceHandle;
struct
{
WCHAR InstanceId[200];
} DeviceInstance;
} u;
} CM_NOTIFY_FILTER, *PCM_NOTIFY_FILTER;
typedef enum _CM_NOTIFY_ACTION
{
CM_NOTIFY_ACTION_DEVICEINTERFACEARRIVAL = 0,
CM_NOTIFY_ACTION_DEVICEINTERFACEREMOVAL,
CM_NOTIFY_ACTION_DEVICEQUERYREMOVE,
CM_NOTIFY_ACTION_DEVICEQUERYREMOVEFAILED,
CM_NOTIFY_ACTION_DEVICEREMOVEPENDING,
CM_NOTIFY_ACTION_DEVICEREMOVECOMPLETE,
CM_NOTIFY_ACTION_DEVICECUSTOMEVENT,
CM_NOTIFY_ACTION_DEVICEINSTANCEENUMERATED,
CM_NOTIFY_ACTION_DEVICEINSTANCESTARTED,
CM_NOTIFY_ACTION_DEVICEINSTANCEREMOVED,
CM_NOTIFY_ACTION_MAX
} CM_NOTIFY_ACTION,
*PCM_NOTIFY_ACTION;
typedef struct _CM_NOTIFY_EVENT_DATA
{
CM_NOTIFY_FILTER_TYPE FilterType;
DWORD Reserved;
union
{
struct
{
GUID ClassGuid;
WCHAR SymbolicLink[ANYSIZE_ARRAY];
} DeviceInterface;
struct
{
GUID EventGuid;
LONG NameOffset;
DWORD DataSize;
BYTE Data[ANYSIZE_ARRAY];
} DeviceHandle;
struct
{
WCHAR InstanceId[ANYSIZE_ARRAY];
} DeviceInstance;
} u;
} CM_NOTIFY_EVENT_DATA, *PCM_NOTIFY_EVENT_DATA;
typedef DWORD(CALLBACK *PCM_NOTIFY_CALLBACK)(HCMNOTIFICATION hNotify, PVOID Context, CM_NOTIFY_ACTION Action, PCM_NOTIFY_EVENT_DATA EventData, DWORD EventDataSize);
typedef DWORD(WINAPI *CM_Register_NotificationFunc)(PCM_NOTIFY_FILTER pFilter, PVOID pContext, PCM_NOTIFY_CALLBACK pCallback, PHCMNOTIFICATION pNotifyContext);
typedef DWORD(WINAPI *CM_Unregister_NotificationFunc)(HCMNOTIFICATION NotifyContext);
/* local variables */
static SDL_bool s_bJoystickThread = SDL_FALSE;
static SDL_bool s_bWindowsDeviceChanged = SDL_FALSE;
static SDL_Condition *s_condJoystickThread = NULL;
static SDL_Mutex *s_mutexJoyStickEnum = NULL;
static SDL_Thread *s_joystickThread = NULL;
static SDL_bool s_bJoystickThreadQuit = SDL_FALSE;
static GUID GUID_DEVINTERFACE_HID = { 0x4D1E55B2L, 0xF16F, 0x11CF, { 0x88, 0xCB, 0x00, 0x11, 0x11, 0x00, 0x00, 0x30 } };
JoyStick_DeviceData *SYS_Joystick; /* array to hold joystick ID values */
#if !defined(__WINRT__) && !defined(__XBOXONE__) && !defined(__XBOXSERIES__)
static HMODULE cfgmgr32_lib_handle;
static CM_Register_NotificationFunc CM_Register_Notification;
static CM_Unregister_NotificationFunc CM_Unregister_Notification;
static HCMNOTIFICATION s_DeviceNotificationFuncHandle;
void WINDOWS_RAWINPUTEnabledChanged(void)
{
s_bWindowsDeviceChanged = SDL_TRUE;
}
static DWORD CALLBACK SDL_DeviceNotificationFunc(HCMNOTIFICATION hNotify, PVOID context, CM_NOTIFY_ACTION action, PCM_NOTIFY_EVENT_DATA eventData, DWORD event_data_size)
{
if (action == CM_NOTIFY_ACTION_DEVICEINTERFACEARRIVAL ||
action == CM_NOTIFY_ACTION_DEVICEINTERFACEREMOVAL) {
s_bWindowsDeviceChanged = SDL_TRUE;
}
return ERROR_SUCCESS;
}
static void SDL_CleanupDeviceNotificationFunc(void)
{
if (cfgmgr32_lib_handle) {
if (s_DeviceNotificationFuncHandle != NULL && CM_Unregister_Notification != NULL) {
CM_Unregister_Notification(s_DeviceNotificationFuncHandle);
s_DeviceNotificationFuncHandle = NULL;
}
FreeLibrary(cfgmgr32_lib_handle);
cfgmgr32_lib_handle = NULL;
}
}
static SDL_bool SDL_CreateDeviceNotificationFunc(void)
{
cfgmgr32_lib_handle = LoadLibraryA("cfgmgr32.dll");
if (cfgmgr32_lib_handle) {
CM_Register_Notification = (CM_Register_NotificationFunc)GetProcAddress(cfgmgr32_lib_handle, "CM_Register_Notification");
CM_Unregister_Notification = (CM_Unregister_NotificationFunc)GetProcAddress(cfgmgr32_lib_handle, "CM_Unregister_Notification");
if (CM_Register_Notification && CM_Unregister_Notification) {
CM_NOTIFY_FILTER notify_filter;
SDL_zero(notify_filter);
notify_filter.cbSize = sizeof(notify_filter);
notify_filter.FilterType = CM_NOTIFY_FILTER_TYPE_DEVICEINTERFACE;
notify_filter.u.DeviceInterface.ClassGuid = GUID_DEVINTERFACE_HID;
if (CM_Register_Notification(&notify_filter, NULL, SDL_DeviceNotificationFunc, &s_DeviceNotificationFuncHandle) == CR_SUCCESS) {
return SDL_TRUE;
}
}
}
SDL_CleanupDeviceNotificationFunc();
return SDL_FALSE;
}
typedef struct
{
HRESULT coinitialized;
WNDCLASSEX wincl;
HWND messageWindow;
HDEVNOTIFY hNotify;
} SDL_DeviceNotificationData;
#define IDT_SDL_DEVICE_CHANGE_TIMER_1 1200
#define IDT_SDL_DEVICE_CHANGE_TIMER_2 1201
/* windowproc for our joystick detect thread message only window, to detect any USB device addition/removal */
static LRESULT CALLBACK SDL_PrivateJoystickDetectProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg) {
case WM_DEVICECHANGE:
switch (wParam) {
case DBT_DEVICEARRIVAL:
case DBT_DEVICEREMOVECOMPLETE:
if (((DEV_BROADCAST_HDR *)lParam)->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE) {
/* notify 300ms and 2 seconds later to ensure all APIs have updated status */
SetTimer(hwnd, IDT_SDL_DEVICE_CHANGE_TIMER_1, 300, NULL);
SetTimer(hwnd, IDT_SDL_DEVICE_CHANGE_TIMER_2, 2000, NULL);
}
break;
}
return 0;
case WM_TIMER:
if (wParam == IDT_SDL_DEVICE_CHANGE_TIMER_1 ||
wParam == IDT_SDL_DEVICE_CHANGE_TIMER_2) {
KillTimer(hwnd, wParam);
s_bWindowsDeviceChanged = SDL_TRUE;
return 0;
}
break;
}
#ifdef SDL_JOYSTICK_RAWINPUT
return CallWindowProc(RAWINPUT_WindowProc, hwnd, msg, wParam, lParam);
#else
return CallWindowProc(DefWindowProc, hwnd, msg, wParam, lParam);
#endif
}
static void SDL_CleanupDeviceNotification(SDL_DeviceNotificationData *data)
{
#ifdef SDL_JOYSTICK_RAWINPUT
RAWINPUT_UnregisterNotifications();
#endif
if (data->hNotify) {
UnregisterDeviceNotification(data->hNotify);
}
if (data->messageWindow) {
DestroyWindow(data->messageWindow);
}
UnregisterClass(data->wincl.lpszClassName, data->wincl.hInstance);
if (data->coinitialized == S_OK) {
WIN_CoUninitialize();
}
}
static int SDL_CreateDeviceNotification(SDL_DeviceNotificationData *data)
{
DEV_BROADCAST_DEVICEINTERFACE dbh;
SDL_zerop(data);
data->coinitialized = WIN_CoInitialize();
data->wincl.hInstance = GetModuleHandle(NULL);
data->wincl.lpszClassName = TEXT("Message");
data->wincl.lpfnWndProc = SDL_PrivateJoystickDetectProc; /* This function is called by windows */
data->wincl.cbSize = sizeof(WNDCLASSEX);
if (!RegisterClassEx(&data->wincl)) {
WIN_SetError("Failed to create register class for joystick autodetect");
SDL_CleanupDeviceNotification(data);
return -1;
}
data->messageWindow = CreateWindowEx(0, TEXT("Message"), NULL, 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, NULL, NULL);
if (data->messageWindow == NULL) {
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;
}
#ifdef SDL_JOYSTICK_RAWINPUT
RAWINPUT_RegisterNotifications(data->messageWindow);
#endif
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 /* !defined(__WINRT__) && !defined(__XBOXONE__) && !defined(__XBOXSERIES__) */
#ifndef __WINRT__
#if !defined(__XBOXONE__) && !defined(__XBOXSERIES__)
static SDL_DeviceNotificationData s_notification_data;
#endif
/* Function/thread to scan the system for joysticks. */
static int SDLCALL SDL_JoystickThread(void *_data)
{
#ifdef SDL_JOYSTICK_XINPUT
SDL_bool bOpenedXInputDevices[XUSER_MAX_COUNT];
SDL_zeroa(bOpenedXInputDevices);
#endif
#if !defined(__XBOXONE__) && !defined(__XBOXSERIES__)
if (SDL_CreateDeviceNotification(&s_notification_data) < 0) {
return -1;
}
#endif
SDL_LockMutex(s_mutexJoyStickEnum);
while (s_bJoystickThreadQuit == SDL_FALSE) {
#if !defined(__XBOXONE__) && !defined(__XBOXSERIES__)
if (SDL_WaitForDeviceNotification(&s_notification_data, s_mutexJoyStickEnum) == SDL_FALSE) {
#else
{
#endif
#ifdef SDL_JOYSTICK_XINPUT
/* WM_DEVICECHANGE not working, poll for new XINPUT controllers */
SDL_WaitConditionTimeout(s_condJoystickThread, s_mutexJoyStickEnum, 1000);
if (SDL_XINPUT_Enabled() && 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) ? SDL_TRUE : SDL_FALSE;
if (bOpenedXInputDevices[userId] != available) {
s_bWindowsDeviceChanged = SDL_TRUE;
bOpenedXInputDevices[userId] = available;
}
}
}
#else
/* WM_DEVICECHANGE not working, no XINPUT, no point in keeping thread alive */
break;
#endif /* SDL_JOYSTICK_XINPUT */
}
}
SDL_UnlockMutex(s_mutexJoyStickEnum);
#if !defined(__XBOXONE__) && !defined(__XBOXSERIES__)
SDL_CleanupDeviceNotification(&s_notification_data);
#endif
return 1;
}
/* spin up the thread to detect hotplug of devices */
static int SDL_StartJoystickThread(void)
{
s_mutexJoyStickEnum = SDL_CreateMutex();
if (s_mutexJoyStickEnum == NULL) {
return -1;
}
s_condJoystickThread = SDL_CreateCondition();
if (s_condJoystickThread == NULL) {
return -1;
}
s_bJoystickThreadQuit = SDL_FALSE;
s_joystickThread = SDL_CreateThreadInternal(SDL_JoystickThread, "SDL_joystick", 64 * 1024, NULL);
if (s_joystickThread == NULL) {
return -1;
}
return 0;
}
static void SDL_StopJoystickThread(void)
{
if (s_joystickThread == NULL) {
return;
}
SDL_LockMutex(s_mutexJoyStickEnum);
s_bJoystickThreadQuit = SDL_TRUE;
SDL_BroadcastCondition(s_condJoystickThread); /* signal the joystick thread to quit */
SDL_UnlockMutex(s_mutexJoyStickEnum);
PostThreadMessage(SDL_GetThreadID(s_joystickThread), WM_QUIT, 0, 0);
/* Unlock joysticks while the joystick thread finishes processing messages */
SDL_AssertJoysticksLocked();
SDL_UnlockJoysticks();
SDL_WaitThread(s_joystickThread, NULL); /* wait for it to bugger off */
SDL_LockJoysticks();
SDL_DestroyCondition(s_condJoystickThread);
s_condJoystickThread = NULL;
SDL_DestroyMutex(s_mutexJoyStickEnum);
s_mutexJoyStickEnum = NULL;
s_joystickThread = NULL;
}
#endif /* !defined(__WINRT__) */
void WINDOWS_AddJoystickDevice(JoyStick_DeviceData *device)
{
device->send_add_event = SDL_TRUE;
device->nInstanceID = SDL_GetNextJoystickInstanceID();
device->pNext = SYS_Joystick;
SYS_Joystick = device;
}
void WINDOWS_JoystickDetect(void);
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_bWindowsDeviceChanged = SDL_TRUE; /* force a scan of the system for joysticks this first time */
WINDOWS_JoystickDetect();
#if !defined(__WINRT__) && !defined(__XBOXONE__) && !defined(__XBOXSERIES__)
SDL_CreateDeviceNotificationFunc();
s_bJoystickThread = SDL_GetHintBoolean(SDL_HINT_JOYSTICK_THREAD, SDL_FALSE);
if (s_bJoystickThread) {
if (SDL_StartJoystickThread() < 0) {
return -1;
}
} else {
if (SDL_CreateDeviceNotification(&s_notification_data) < 0) {
return -1;
}
}
#endif
#if defined(__XBOXONE__) || defined(__XBOXSERIES__)
/* On Xbox, force create the joystick thread for device detection (since other methods don't work */
s_bJoystickThread = SDL_TRUE;
if (SDL_StartJoystickThread() < 0) {
return -1;
}
#endif
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 */
void WINDOWS_JoystickDetect(void)
{
JoyStick_DeviceData *pCurList = NULL;
/* only enum the devices if the joystick thread told us something changed */
if (!s_bWindowsDeviceChanged) {
return; /* thread hasn't signaled, nothing to do right now. */
}
if (s_mutexJoyStickEnum) {
SDL_LockMutex(s_mutexJoyStickEnum);
}
s_bWindowsDeviceChanged = 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);
if (s_mutexJoyStickEnum) {
SDL_UnlockMutex(s_mutexJoyStickEnum);
}
while (pCurList) {
JoyStick_DeviceData *pListNext = NULL;
if (pCurList->bXInputDevice) {
#ifdef SDL_HAPTIC_XINPUT
SDL_XINPUT_HapticMaybeRemoveDevice(pCurList->XInputUserId);
#endif
} else {
#ifdef SDL_HAPTIC_DINPUT
SDL_DINPUT_HapticMaybeRemoveDevice(&pCurList->dxdevice);
#endif
}
SDL_PrivateJoystickRemoved(pCurList->nInstanceID);
pListNext = pCurList->pNext;
SDL_free(pCurList->joystickname);
SDL_free(pCurList);
pCurList = pListNext;
}
for (pCurList = SYS_Joystick; pCurList; pCurList = pCurList->pNext) {
if (pCurList->send_add_event) {
if (pCurList->bXInputDevice) {
#ifdef SDL_HAPTIC_XINPUT
SDL_XINPUT_HapticMaybeAddDevice(pCurList->XInputUserId);
#endif
} else {
#ifdef SDL_HAPTIC_DINPUT
SDL_DINPUT_HapticMaybeAddDevice(&pCurList->dxdevice);
#endif
}
SDL_PrivateJoystickAdded(pCurList->nInstanceID);
pCurList->send_add_event = SDL_FALSE;
}
}
}
static const char *WINDOWS_JoystickGetDeviceName(int device_index)
{
JoyStick_DeviceData *device = SYS_Joystick;
int index;
for (index = device_index; index > 0; index--) {
device = device->pNext;
}
return device->joystickname;
}
static const char *WINDOWS_JoystickGetDevicePath(int device_index)
{
JoyStick_DeviceData *device = SYS_Joystick;
int index;
for (index = device_index; index > 0; index--) {
device = device->pNext;
}
return device->path;
}
static int WINDOWS_JoystickGetDevicePlayerIndex(int device_index)
{
JoyStick_DeviceData *device = SYS_Joystick;
int index;
for (index = device_index; index > 0; index--) {
device = device->pNext;
}
return device->bXInputDevice ? (int)device->XInputUserId : -1;
}
static void WINDOWS_JoystickSetDevicePlayerIndex(int device_index, int player_index)
{
}
/* return the stable device guid for this device index */
static SDL_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 *device = SYS_Joystick;
int index;
for (index = device_index; index > 0; index--) {
device = device->pNext;
}
/* allocate memory for system specific hardware data */
joystick->instance_id = device->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 = device->guid;
if (device->bXInputDevice) {
return SDL_XINPUT_JoystickOpen(joystick, device);
} else {
return SDL_DINPUT_JoystickOpen(joystick, device);
}
}
static int WINDOWS_JoystickRumble(SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble)
{
if (joystick->hwdata->bXInputDevice) {
return SDL_XINPUT_JoystickRumble(joystick, low_frequency_rumble, high_frequency_rumble);
} else {
return SDL_DINPUT_JoystickRumble(joystick, low_frequency_rumble, high_frequency_rumble);
}
}
static int WINDOWS_JoystickRumbleTriggers(SDL_Joystick *joystick, Uint16 left_rumble, Uint16 right_rumble)
{
return SDL_Unsupported();
}
static Uint32 WINDOWS_JoystickGetCapabilities(SDL_Joystick *joystick)
{
if (joystick->hwdata->bXInputDevice) {
return SDL_XINPUT_JoystickGetCapabilities(joystick);
} else {
return SDL_DINPUT_JoystickGetCapabilities(joystick);
}
}
static int WINDOWS_JoystickSetLED(SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue)
{
return SDL_Unsupported();
}
static int WINDOWS_JoystickSendEffect(SDL_Joystick *joystick, const void *data, int size)
{
return SDL_Unsupported();
}
static int WINDOWS_JoystickSetSensorsEnabled(SDL_Joystick *joystick, SDL_bool enabled)
{
return SDL_Unsupported();
}
static void WINDOWS_JoystickUpdate(SDL_Joystick *joystick)
{
if (!joystick->hwdata) {
return;
}
if (joystick->hwdata->bXInputDevice) {
SDL_XINPUT_JoystickUpdate(joystick);
} else {
SDL_DINPUT_JoystickUpdate(joystick);
}
}
/* Function to close a joystick after use */
static void WINDOWS_JoystickClose(SDL_Joystick *joystick)
{
if (joystick->hwdata->bXInputDevice) {
SDL_XINPUT_JoystickClose(joystick);
} else {
SDL_DINPUT_JoystickClose(joystick);
}
SDL_free(joystick->hwdata);
}
/* Function to perform any system-specific joystick related cleanup */
void WINDOWS_JoystickQuit(void)
{
JoyStick_DeviceData *device = SYS_Joystick;
while (device) {
JoyStick_DeviceData *device_next = device->pNext;
SDL_free(device->joystickname);
SDL_free(device);
device = device_next;
}
SYS_Joystick = NULL;
#if !defined(__WINRT__) && !defined(__XBOXONE__) && !defined(__XBOXSERIES__)
if (s_bJoystickThread) {
SDL_StopJoystickThread();
} else {
SDL_CleanupDeviceNotification(&s_notification_data);
}
SDL_CleanupDeviceNotificationFunc();
#endif
#if defined(__XBOXONE__) || defined(__XBOXSERIES__)
if (s_bJoystickThread) {
SDL_StopJoystickThread();
}
#endif
SDL_DINPUT_JoystickQuit();
SDL_XINPUT_JoystickQuit();
s_bWindowsDeviceChanged = SDL_FALSE;
}
static SDL_bool WINDOWS_JoystickGetGamepadMapping(int device_index, SDL_GamepadMapping *out)
{
return SDL_FALSE;
}
SDL_JoystickDriver SDL_WINDOWS_JoystickDriver = {
WINDOWS_JoystickInit,
WINDOWS_JoystickGetCount,
WINDOWS_JoystickDetect,
WINDOWS_JoystickGetDeviceName,
WINDOWS_JoystickGetDevicePath,
WINDOWS_JoystickGetDevicePlayerIndex,
WINDOWS_JoystickSetDevicePlayerIndex,
WINDOWS_JoystickGetDeviceGUID,
WINDOWS_JoystickGetDeviceInstanceID,
WINDOWS_JoystickOpen,
WINDOWS_JoystickRumble,
WINDOWS_JoystickRumbleTriggers,
WINDOWS_JoystickGetCapabilities,
WINDOWS_JoystickSetLED,
WINDOWS_JoystickSendEffect,
WINDOWS_JoystickSetSensorsEnabled,
WINDOWS_JoystickUpdate,
WINDOWS_JoystickClose,
WINDOWS_JoystickQuit,
WINDOWS_JoystickGetGamepadMapping
};
/* Ends C function definitions when using C++ */
#ifdef __cplusplus
}
#endif
#else
#ifdef SDL_JOYSTICK_RAWINPUT
/* The RAWINPUT driver needs the device notification setup above */
#error SDL_JOYSTICK_RAWINPUT requires SDL_JOYSTICK_DINPUT || SDL_JOYSTICK_XINPUT
#endif
#endif /* SDL_JOYSTICK_DINPUT || SDL_JOYSTICK_XINPUT */

View File

@@ -0,0 +1,101 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 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"
#include "../../core/windows/SDL_windows.h"
#include "../../core/windows/SDL_directx.h"
#define MAX_INPUTS 256 /* each joystick can have up to 256 inputs */
/* Set up for C function definitions, even when using C++ */
#ifdef __cplusplus
extern "C" {
#endif
typedef struct JoyStick_DeviceData
{
SDL_JoystickGUID guid;
char *joystickname;
Uint8 send_add_event;
SDL_JoystickID nInstanceID;
SDL_bool bXInputDevice;
BYTE SubType;
Uint8 XInputUserId;
DIDEVICEINSTANCE dxdevice;
char path[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;
#ifdef 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;
};
#ifdef SDL_JOYSTICK_DINPUT
extern const DIDATAFORMAT SDL_c_dfDIJoystick2;
#endif
extern void WINDOWS_AddJoystickDevice(JoyStick_DeviceData *device);
/* Ends C function definitions when using C++ */
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,609 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 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"
#ifdef SDL_JOYSTICK_XINPUT
#include "SDL_windowsjoystick_c.h"
#include "SDL_xinputjoystick_c.h"
#include "SDL_rawinputjoystick_c.h"
#include "../hidapi/SDL_hidapijoystick_c.h"
/* Set up for C function definitions, even when using C++ */
#ifdef __cplusplus
extern "C" {
#endif
/*
* Internal stuff.
*/
static 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;
#elif defined(__XBOXONE__) || defined(__XBOXSERIES__)
return SDL_FALSE;
#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 const char *GetXInputName(const Uint8 userid, BYTE SubType)
{
static char name[32];
if (SDL_XInputUseOldJoystickMapping()) {
(void)SDL_snprintf(name, sizeof(name), "X360 Controller #%u", 1 + userid);
} else {
switch (SubType) {
case XINPUT_DEVSUBTYPE_GAMEPAD:
(void)SDL_snprintf(name, sizeof(name), "XInput Controller #%u", 1 + userid);
break;
case XINPUT_DEVSUBTYPE_WHEEL:
(void)SDL_snprintf(name, sizeof(name), "XInput Wheel #%u", 1 + userid);
break;
case XINPUT_DEVSUBTYPE_ARCADE_STICK:
(void)SDL_snprintf(name, sizeof(name), "XInput ArcadeStick #%u", 1 + userid);
break;
case XINPUT_DEVSUBTYPE_FLIGHT_STICK:
(void)SDL_snprintf(name, sizeof(name), "XInput FlightStick #%u", 1 + userid);
break;
case XINPUT_DEVSUBTYPE_DANCE_PAD:
(void)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:
(void)SDL_snprintf(name, sizeof(name), "XInput Guitar #%u", 1 + userid);
break;
case XINPUT_DEVSUBTYPE_DRUM_KIT:
(void)SDL_snprintf(name, sizeof(name), "XInput DrumKit #%u", 1 + userid);
break;
case XINPUT_DEVSUBTYPE_ARCADE_PAD:
(void)SDL_snprintf(name, sizeof(name), "XInput ArcadePad #%u", 1 + userid);
break;
default:
(void)SDL_snprintf(name, sizeof(name), "XInput Device #%u", 1 + userid);
break;
}
}
return 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)
{
#if !defined(__WINRT__) && !defined(__XBOXONE__) && !defined(__XBOXSERIES__) /* 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. */
}
/* First see if we have a cached entry for this index */
if (s_arrXInputDevicePath[userid]) {
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) {
if (SDL_strcmp(devName, s_arrXInputDevicePath[userid]) == 0) {
*pVID = (Uint16)rdi.hid.dwVendorId;
*pPID = (Uint16)rdi.hid.dwProductId;
*pVersion = (Uint16)rdi.hid.dwVersionNumber;
SDL_free(devices);
return;
}
}
}
}
for (i = 0; i < device_count; i++) {
RID_DEVICE_INFO rdi;
char devName[MAX_PATH];
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) {
#ifdef DEBUG_JOYSTICK
SDL_Log("Raw input device: VID = 0x%x, PID = 0x%x, %s\n", rdi.hid.dwVendorId, rdi.hid.dwProductId, devName);
#endif
if (SDL_strstr(devName, "IG_") != NULL) {
SDL_bool found = SDL_FALSE;
for (j = 0; j < SDL_arraysize(s_arrXInputDevicePath); ++j) {
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.
*/
if (rdi.hid.dwVendorId == USB_VENDOR_VALVE &&
rdi.hid.dwProductId == USB_PRODUCT_STEAM_VIRTUAL_GAMEPAD) {
/* Steam encodes the real device in the path */
int realVID = rdi.hid.dwVendorId;
int realPID = rdi.hid.dwProductId;
(void)SDL_sscanf(devName, "\\\\.\\pipe\\HID#VID_045E&PID_028E&IG_00#%x&%x&", &realVID, &realPID);
*pVID = (Uint16)realVID;
*pPID = (Uint16)realPID;
*pVersion = 0;
} else {
*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);
SDL_free(devices);
return;
}
}
}
SDL_free(devices);
#endif /* !__WINRT__ */
/* The device wasn't in the raw HID device list, it's probably Bluetooth */
*pVID = 0x045e; /* Microsoft */
*pPID = 0x02fd; /* XBox One S Bluetooth */
*pVersion = 0;
}
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;
#ifdef SDL_JOYSTICK_RAWINPUT
if (RAWINPUT_IsEnabled()) {
/* The raw input driver handles more than 4 controllers, so prefer that when available */
/* We do this check here rather than at the top of SDL_XINPUT_JoystickDetect() because
we need to check XInput state before RAWINPUT gets a hold of the device, otherwise
when a controller is connected via the wireless adapter, it will shut down at the
first subsequent XInput call. This seems like a driver stack bug?
Reference: https://github.com/libsdl-org/SDL/issues/3468
*/
return;
}
#endif
if (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_calloc(1, sizeof(JoyStick_DeviceData));
if (pNewJoystick == NULL) {
return; /* better luck next time? */
}
pNewJoystick->bXInputDevice = SDL_TRUE;
pNewJoystick->joystickname = SDL_CreateJoystickName(vendor, product, NULL, GetXInputName(userid, SubType));
if (!pNewJoystick->joystickname) {
SDL_free(pNewJoystick);
return; /* better luck next time? */
}
(void)SDL_snprintf(pNewJoystick->path, sizeof(pNewJoystick->path), "XInput#%d", userid);
if (!SDL_XInputUseOldJoystickMapping()) {
GuessXInputDevice(userid, &vendor, &product, &version);
pNewJoystick->guid = SDL_CreateJoystickGUID(SDL_HARDWARE_BUS_USB, vendor, product, version, pNewJoystick->joystickname, 'x', SubType);
}
pNewJoystick->SubType = SubType;
pNewJoystick->XInputUserId = userid;
if (SDL_ShouldIgnoreJoystick(pNewJoystick->joystickname, pNewJoystick->guid)) {
SDL_free(pNewJoystick);
return;
}
#ifdef SDL_JOYSTICK_HIDAPI
/* Since we're guessing about the VID/PID, use a hard-coded VID/PID to represent XInput */
if (HIDAPI_IsDevicePresent(USB_VENDOR_MICROSOFT, USB_PRODUCT_XBOX_ONE_XINPUT_CONTROLLER, version, pNewJoystick->joystickname)) {
/* The HIDAPI driver is taking care of this device */
SDL_free(pNewJoystick);
return;
}
#endif
#ifdef SDL_JOYSTICK_RAWINPUT
if (RAWINPUT_IsDevicePresent(vendor, product, version, pNewJoystick->joystickname)) {
/* The RAWINPUT 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) {
/* Adding a new device, must handle all removes first, or GuessXInputDevice goes terribly wrong (returns
a product/vendor ID that is not even attached to the system) when we get a remove and add on the same tick
(e.g. when disconnecting a device and the OS reassigns which userid an already-attached controller is)
*/
int iuserid2;
for (iuserid2 = iuserid - 1; iuserid2 >= 0; iuserid2--) {
const Uint8 userid2 = (Uint8)iuserid2;
XINPUT_CAPABILITIES capabilities2;
if (XINPUTGETCAPABILITIES(userid2, XINPUT_FLAG_GAMEPAD, &capabilities2) != ERROR_SUCCESS) {
DelXInputDevice(userid2);
}
}
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->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) ? SDL_TRUE : SDL_FALSE;
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_SendJoystickBatteryLevel(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;
Uint64 timestamp = SDL_GetTicksNS();
SDL_SendJoystickAxis(timestamp, joystick, 0, (Sint16)pXInputState->Gamepad.sThumbLX);
SDL_SendJoystickAxis(timestamp, joystick, 1, (Sint16)(-SDL_max(-32767, pXInputState->Gamepad.sThumbLY)));
SDL_SendJoystickAxis(timestamp, joystick, 2, (Sint16)pXInputState->Gamepad.sThumbRX);
SDL_SendJoystickAxis(timestamp, joystick, 3, (Sint16)(-SDL_max(-32767, pXInputState->Gamepad.sThumbRY)));
SDL_SendJoystickAxis(timestamp, joystick, 4, (Sint16)(((int)pXInputState->Gamepad.bLeftTrigger * 65535 / 255) - 32768));
SDL_SendJoystickAxis(timestamp, joystick, 5, (Sint16)(((int)pXInputState->Gamepad.bRightTrigger * 65535 / 255) - 32768));
for (button = 0; button < (Uint8)SDL_arraysize(s_XInputButtons); ++button) {
SDL_SendJoystickButton(timestamp, 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;
Uint64 timestamp = SDL_GetTicksNS();
SDL_SendJoystickAxis(timestamp, joystick, 0, pXInputState->Gamepad.sThumbLX);
SDL_SendJoystickAxis(timestamp, joystick, 1, ~pXInputState->Gamepad.sThumbLY);
SDL_SendJoystickAxis(timestamp, joystick, 2, ((int)pXInputState->Gamepad.bLeftTrigger * 257) - 32768);
SDL_SendJoystickAxis(timestamp, joystick, 3, pXInputState->Gamepad.sThumbRX);
SDL_SendJoystickAxis(timestamp, joystick, 4, ~pXInputState->Gamepad.sThumbRY);
SDL_SendJoystickAxis(timestamp, joystick, 5, ((int)pXInputState->Gamepad.bRightTrigger * 257) - 32768);
for (button = 0; button < (Uint8)SDL_arraysize(s_XInputButtons); ++button) {
SDL_SendJoystickButton(timestamp, 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_SendJoystickHat(timestamp, joystick, 0, hat);
UpdateXInputJoystickBatteryInformation(joystick, pBatteryInformation);
}
int SDL_XINPUT_JoystickRumble(SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble)
{
XINPUT_VIBRATION XVibration;
if (!XINPUTSETSTATE) {
return SDL_Unsupported();
}
XVibration.wLeftMotorSpeed = low_frequency_rumble;
XVibration.wRightMotorSpeed = high_frequency_rumble;
if (XINPUTSETSTATE(joystick->hwdata->userid, &XVibration) != ERROR_SUCCESS) {
return SDL_SetError("XInputSetState() failed");
}
return 0;
}
Uint32 SDL_XINPUT_JoystickGetCapabilities(SDL_Joystick *joystick)
{
return SDL_JOYCAP_RUMBLE;
}
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);
}
#if defined(__XBOXONE__) || defined(__XBOXSERIES__)
/* XInputOnGameInput doesn't ever change dwPacketNumber, so have to just update every frame */
UpdateXInputJoystickState(joystick, &XInputState, &XBatteryInformation);
#else
/* only fire events if the data changed from last time */
if (XInputState.dwPacketNumber && XInputState.dwPacketNumber != joystick->hwdata->dwPacketNumber) {
if (SDL_XInputUseOldJoystickMapping()) {
UpdateXInputJoystickState_OLD(joystick, &XInputState, &XBatteryInformation);
} else {
UpdateXInputJoystickState(joystick, &XInputState, &XBatteryInformation);
}
joystick->hwdata->dwPacketNumber = XInputState.dwPacketNumber;
}
#endif
}
void SDL_XINPUT_JoystickClose(SDL_Joystick *joystick)
{
}
void SDL_XINPUT_JoystickQuit(void)
{
if (s_bXInputEnabled) {
WIN_UnloadXInputDLL();
}
}
/* Ends C function definitions when using C++ */
#ifdef __cplusplus
}
#endif
#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)
{
return SDL_Unsupported();
}
Uint32 SDL_XINPUT_JoystickGetCapabilities(SDL_Joystick *joystick)
{
return 0;
}
void SDL_XINPUT_JoystickUpdate(SDL_Joystick *joystick)
{
}
void SDL_XINPUT_JoystickClose(SDL_Joystick *joystick)
{
}
void SDL_XINPUT_JoystickQuit(void)
{
}
#endif /* SDL_JOYSTICK_XINPUT */

View File

@@ -0,0 +1,43 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 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"
/* Set up for C function definitions, even when using C++ */
#ifdef __cplusplus
extern "C" {
#endif
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);
extern Uint32 SDL_XINPUT_JoystickGetCapabilities(SDL_Joystick *joystick);
extern void SDL_XINPUT_JoystickUpdate(SDL_Joystick *joystick);
extern void SDL_XINPUT_JoystickClose(SDL_Joystick *joystick);
extern void SDL_XINPUT_JoystickQuit(void);
/* Ends C function definitions when using C++ */
#ifdef __cplusplus
}
#endif