From 67425d7d477d1e95dfa3347df607806dc214c873 Mon Sep 17 00:00:00 2001 From: Neil Munday Date: Sun, 18 Sep 2016 00:33:28 +0100 Subject: [PATCH 1/5] Initial attempt at adding SDL's game controller database to PPSSPP. --- SDL/SDLJoystick.cpp | 78 +++++++++++++++--- SDL/SDLJoystick.h | 112 ++------------------------ assets/gamecontrollerdb.txt | 153 ++++++++++++++++++++++++++++++++++++ 3 files changed, 225 insertions(+), 118 deletions(-) create mode 100644 assets/gamecontrollerdb.txt diff --git a/SDL/SDLJoystick.cpp b/SDL/SDLJoystick.cpp index 9fca4a7b6..dec843a1c 100644 --- a/SDL/SDLJoystick.cpp +++ b/SDL/SDLJoystick.cpp @@ -15,24 +15,31 @@ SDLJoystick::SDLJoystick(bool init_SDL ): thread(NULL), running(true) { if (init_SDL) { SDL_setenv("SDL_JOYSTICK_ALLOW_BACKGROUND_EVENTS", "1", 0); - SDL_Init(SDL_INIT_JOYSTICK | SDL_INIT_VIDEO); + SDL_Init(SDL_INIT_JOYSTICK | SDL_INIT_VIDEO | SDL_INIT_GAMECONTROLLER); + } + + if (SDL_GameControllerAddMappingsFromFile("assets/gamecontrollerdb.txt") == -1) + { + printf("Failed to load control pad mappings, please place gamecontrollerdb.txt in your assets directory\n"); + } + else { + printf("Loaded game controller mappings for SDL2\n"); } int numjoys = SDL_NumJoysticks(); + int firstController = -1; SDL_JoystickEventState(SDL_ENABLE); for (int i = 0; i < numjoys; i++) { joys.push_back(SDL_JoystickOpen(i)); -// printf("Initialized joystick %d: %s",i,SDL_JoystickNameForIndex(i)); - if(strstr(SDL_JoystickNameForIndex(i),"PLAYSTATION(R)3 Controller")) - g_Config.bPS3Controller = true; + //printf("Initialized joystick %d: %s\n",i,SDL_JoystickNameForIndex(i)); + if (firstController == -1 && SDL_IsGameController(i)) + { + firstController = i; + } } - - if (g_Config.bPS3Controller) - fillMappingPS3(); - else - fillMapping(); - - + + printf("Player 1 will be using joystick %d, %s\n", firstController, SDL_JoystickNameForIndex(firstController)); + fillMapping(firstController); } SDLJoystick::~SDLJoystick(){ @@ -185,3 +192,52 @@ void SDLJoystick::runLoop(){ } } } + +void SDLJoystick::buttonMappingHelper(SDL_GameController* controller, SDL_GameControllerButton button, keycode_t buttonKeyCode) +{ + SDL_GameControllerButtonBind bind = SDL_GameControllerGetBindForButton(controller, button); + if (bind.bindType == SDL_CONTROLLER_BINDTYPE_BUTTON) + { + SDLJoyButtonMap[bind.value.button] = buttonKeyCode; + } +} + +void SDLJoystick::axisMappingHelper(SDL_GameController* controller, SDL_GameControllerAxis axis, keycode_t buttonKeyCode, AndroidJoystickAxis axisCode) +{ + SDL_GameControllerButtonBind bind = SDL_GameControllerGetBindForAxis(controller, axis); + if (bind.bindType == SDL_CONTROLLER_BINDTYPE_BUTTON && buttonKeyCode != NKCODE_UNKNOWN) + { + SDLJoyButtonMap[bind.value.button] = buttonKeyCode; + } + else if (bind.bindType == SDL_CONTROLLER_BINDTYPE_AXIS) + { + SDLJoyAxisMap[bind.value.axis] = axisCode; + } +} + +void SDLJoystick::fillMapping(int joyIndex) +{ + SDL_GameController *controller = SDL_GameControllerOpen(joyIndex); + printf("control pad mapping: %s\n", SDL_GameControllerMapping(controller)); + + buttonMappingHelper(controller, SDL_CONTROLLER_BUTTON_DPAD_UP, NKCODE_DPAD_UP); + buttonMappingHelper(controller, SDL_CONTROLLER_BUTTON_DPAD_DOWN, NKCODE_DPAD_DOWN); + buttonMappingHelper(controller, SDL_CONTROLLER_BUTTON_DPAD_LEFT, NKCODE_DPAD_LEFT); + buttonMappingHelper(controller, SDL_CONTROLLER_BUTTON_DPAD_RIGHT, NKCODE_DPAD_RIGHT); + buttonMappingHelper(controller, SDL_CONTROLLER_BUTTON_A, NKCODE_BUTTON_2); + buttonMappingHelper(controller, SDL_CONTROLLER_BUTTON_B, NKCODE_BUTTON_3); + buttonMappingHelper(controller, SDL_CONTROLLER_BUTTON_X, NKCODE_BUTTON_4); + buttonMappingHelper(controller, SDL_CONTROLLER_BUTTON_Y, NKCODE_BUTTON_1); + buttonMappingHelper(controller, SDL_CONTROLLER_BUTTON_START, NKCODE_BUTTON_10); + buttonMappingHelper(controller, SDL_CONTROLLER_BUTTON_BACK, NKCODE_BUTTON_9); // back == select + buttonMappingHelper(controller, SDL_CONTROLLER_BUTTON_LEFTSHOULDER, NKCODE_BUTTON_5); + buttonMappingHelper(controller, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER, NKCODE_BUTTON_6); + buttonMappingHelper(controller, SDL_CONTROLLER_BUTTON_GUIDE, NKCODE_BACK); // pause emulator + + axisMappingHelper(controller, SDL_CONTROLLER_AXIS_TRIGGERLEFT, NKCODE_BUTTON_7, JOYSTICK_AXIS_LTRIGGER); // L2 + axisMappingHelper(controller, SDL_CONTROLLER_AXIS_TRIGGERRIGHT, NKCODE_BUTTON_8, JOYSTICK_AXIS_RTRIGGER); // R2 + axisMappingHelper(controller, SDL_CONTROLLER_AXIS_LEFTX, NKCODE_UNKNOWN, JOYSTICK_AXIS_X); + axisMappingHelper(controller, SDL_CONTROLLER_AXIS_LEFTY, NKCODE_UNKNOWN, JOYSTICK_AXIS_Y); + axisMappingHelper(controller, SDL_CONTROLLER_AXIS_RIGHTX, NKCODE_UNKNOWN, JOYSTICK_AXIS_Z); + axisMappingHelper(controller, SDL_CONTROLLER_AXIS_RIGHTY, NKCODE_UNKNOWN, JOYSTICK_AXIS_RZ); +} diff --git a/SDL/SDLJoystick.h b/SDL/SDLJoystick.h index 9cbec8dc7..7e9d122dc 100644 --- a/SDL/SDLJoystick.h +++ b/SDL/SDLJoystick.h @@ -3,10 +3,12 @@ #ifdef _WIN32 #include "SDL/SDL.h" #include "SDL/SDL_joystick.h" +#include "SDL/SDL_gamecontroller.h" #include "SDL/SDL_thread.h" #else #include "SDL.h" #include "SDL_joystick.h" +#include "SDL_gamecontroller.h" #include "SDL_thread.h" #endif @@ -31,114 +33,10 @@ public: private: void runLoop(); - void fillMappingPS3() - { - SDLJoyButtonMap[14] = NKCODE_BUTTON_1; // Cross - SDLJoyButtonMap[13] = NKCODE_BUTTON_2; // Circle - SDLJoyButtonMap[15] = NKCODE_BUTTON_3; // Sqlare - SDLJoyButtonMap[12] = NKCODE_BUTTON_4; // Triangle - SDLJoyButtonMap[10] = NKCODE_BUTTON_5; // L1 - SDLJoyButtonMap[11] = NKCODE_BUTTON_6; // R1 - SDLJoyButtonMap[8] = NKCODE_BUTTON_7; // L2 - SDLJoyButtonMap[9] = NKCODE_BUTTON_8; // R2 - SDLJoyButtonMap[0] = NKCODE_BUTTON_9; // Select - SDLJoyButtonMap[3] = NKCODE_BUTTON_10; // Start - SDLJoyButtonMap[1] = NKCODE_BUTTON_11; // L3 - SDLJoyButtonMap[2] = NKCODE_BUTTON_12; // R3 - SDLJoyButtonMap[16] = NKCODE_BUTTON_13; // PS - SDLJoyButtonMap[4] = NKCODE_DPAD_UP; - SDLJoyButtonMap[6] = NKCODE_DPAD_DOWN; - SDLJoyButtonMap[7] = NKCODE_DPAD_LEFT; - SDLJoyButtonMap[5] = NKCODE_DPAD_RIGHT; - SDLJoyAxisMap[0] = JOYSTICK_AXIS_X; - SDLJoyAxisMap[1] = JOYSTICK_AXIS_Y; - SDLJoyAxisMap[2] = JOYSTICK_AXIS_Z; - SDLJoyAxisMap[3] = JOYSTICK_AXIS_RZ; - } - void fillMapping() - { - //TODO: C++11 aggregate initialization - //would remove runtime overhead completely - - // Mapping on Windows -#ifdef _WIN32 - SDLJoyButtonMap[0] = NKCODE_BUTTON_2; - SDLJoyButtonMap[1] = NKCODE_BUTTON_3; - SDLJoyButtonMap[2] = NKCODE_BUTTON_4; - SDLJoyButtonMap[3] = NKCODE_BUTTON_1; - SDLJoyButtonMap[4] = NKCODE_BUTTON_7; - SDLJoyButtonMap[5] = NKCODE_BUTTON_8; - SDLJoyButtonMap[6] = NKCODE_BUTTON_9; - SDLJoyButtonMap[7] = NKCODE_BUTTON_10; - SDLJoyButtonMap[8] = NKCODE_BUTTON_11; - SDLJoyButtonMap[9] = NKCODE_BUTTON_12; - SDLJoyButtonMap[10] = NKCODE_BUTTON_5; - SDLJoyButtonMap[11] = NKCODE_BUTTON_6; - SDLJoyButtonMap[12] = NKCODE_BUTTON_7; - SDLJoyButtonMap[13] = NKCODE_BUTTON_8; - SDLJoyButtonMap[14] = NKCODE_BUTTON_9; - - SDLJoyAxisMap[0] = JOYSTICK_AXIS_X; - SDLJoyAxisMap[1] = JOYSTICK_AXIS_Y; - SDLJoyAxisMap[2] = JOYSTICK_AXIS_Z; - SDLJoyAxisMap[3] = JOYSTICK_AXIS_RZ; - SDLJoyAxisMap[4] = JOYSTICK_AXIS_LTRIGGER; - SDLJoyAxisMap[5] = JOYSTICK_AXIS_RTRIGGER; - // Mapping on MacOSX to match X360 controller -#elif __APPLE__ - SDLJoyButtonMap[0] = NKCODE_DPAD_UP; - SDLJoyButtonMap[1] = NKCODE_DPAD_DOWN; - SDLJoyButtonMap[2] = NKCODE_DPAD_LEFT; - SDLJoyButtonMap[3] = NKCODE_DPAD_RIGHT; - SDLJoyButtonMap[4] = NKCODE_BUTTON_10; - SDLJoyButtonMap[5] = NKCODE_BUTTON_9; - SDLJoyButtonMap[6] = NKCODE_BUTTON_5; - SDLJoyButtonMap[7] = NKCODE_BUTTON_6; - SDLJoyButtonMap[8] = NKCODE_BUTTON_7; - SDLJoyButtonMap[9] = NKCODE_BUTTON_8; - SDLJoyButtonMap[10] = NKCODE_BUTTON_SELECT; - SDLJoyButtonMap[11] = NKCODE_BUTTON_2; - SDLJoyButtonMap[12] = NKCODE_BUTTON_3; - SDLJoyButtonMap[13] = NKCODE_BUTTON_4; - SDLJoyButtonMap[14] = NKCODE_BUTTON_1; - SDLJoyButtonMap[15] = NKCODE_BUTTON_11; - SDLJoyButtonMap[16] = NKCODE_BUTTON_12; - - SDLJoyAxisMap[0] = JOYSTICK_AXIS_X; - SDLJoyAxisMap[1] = JOYSTICK_AXIS_Y; - SDLJoyAxisMap[2] = JOYSTICK_AXIS_Z; - SDLJoyAxisMap[3] = JOYSTICK_AXIS_RZ; - SDLJoyAxisMap[4] = JOYSTICK_AXIS_LTRIGGER; - SDLJoyAxisMap[5] = JOYSTICK_AXIS_RTRIGGER; - // Mapping on Linux/Android/Other to match X360 and wii-u pro controller -#else - SDLJoyButtonMap[0] = NKCODE_BUTTON_1; - SDLJoyButtonMap[1] = NKCODE_BUTTON_2; - SDLJoyButtonMap[2] = NKCODE_BUTTON_3; - SDLJoyButtonMap[3] = NKCODE_BUTTON_4; - SDLJoyButtonMap[4] = NKCODE_BUTTON_5; - SDLJoyButtonMap[5] = NKCODE_BUTTON_6; - SDLJoyButtonMap[6] = NKCODE_BUTTON_7; - SDLJoyButtonMap[7] = NKCODE_BUTTON_8; - SDLJoyButtonMap[8] = NKCODE_BUTTON_9; - SDLJoyButtonMap[9] = NKCODE_BUTTON_10; - SDLJoyButtonMap[10] = NKCODE_BUTTON_11; - SDLJoyButtonMap[11] = NKCODE_BUTTON_12; - SDLJoyButtonMap[12] = NKCODE_BUTTON_13; - SDLJoyButtonMap[13] = NKCODE_DPAD_UP; - SDLJoyButtonMap[14] = NKCODE_DPAD_DOWN; - SDLJoyButtonMap[15] = NKCODE_DPAD_LEFT; - SDLJoyButtonMap[16] = NKCODE_DPAD_RIGHT; + void fillMapping(int joyIndex); + void axisMappingHelper(SDL_GameController* controller, SDL_GameControllerAxis axis, keycode_t buttonKeyCode, AndroidJoystickAxis axisCode); + void buttonMappingHelper(SDL_GameController* controller, SDL_GameControllerButton button, keycode_t buttonKeyCode); - SDLJoyAxisMap[0] = JOYSTICK_AXIS_X; - SDLJoyAxisMap[1] = JOYSTICK_AXIS_Y; - SDLJoyAxisMap[2] = JOYSTICK_AXIS_Z; - SDLJoyAxisMap[3] = JOYSTICK_AXIS_RZ; - SDLJoyAxisMap[4] = JOYSTICK_AXIS_LTRIGGER; - SDLJoyAxisMap[5] = JOYSTICK_AXIS_RTRIGGER; - -#endif - } std::map SDLJoyButtonMap; std::map SDLJoyAxisMap; diff --git a/assets/gamecontrollerdb.txt b/assets/gamecontrollerdb.txt new file mode 100644 index 000000000..9c964ede6 --- /dev/null +++ b/assets/gamecontrollerdb.txt @@ -0,0 +1,153 @@ +# Windows - DINPUT +8f0e1200000000000000504944564944,Acme,platform:Windows,x:b2,a:b0,b:b1,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b5,rightshoulder:b6,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2, +341a3608000000000000504944564944,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,platform:Windows, +ffff0000000000000000504944564944,GameStop Gamepad,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,platform:Windows, +6d0416c2000000000000504944564944,Generic DirectInput Controller,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,platform:Windows, +0d0f6e00000000000000504944564944,HORIPAD 4,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Windows, +6d0419c2000000000000504944564944,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,platform:Windows, +88880803000000000000504944564944,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,platform:Windows, +4c056802000000000000504944564944,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,platform:Windows, +25090500000000000000504944564944,PS3 DualShock,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,platform:Windows, +4c05c405000000000000504944564944,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,platform:Windows, +6d0418c2000000000000504944564944,Logitech RumblePad 2 USB,platform:Windows,x:b0,a:b1,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3, +36280100000000000000504944564944,OUYA Controller,platform:Windows,a:b0,b:b3,y:b2,x:b1,start:b14,guide:b15,leftstick:b6,rightstick:b7,leftshoulder:b4,rightshoulder:b5,dpup:b8,dpleft:b10,dpdown:b9,dpright:b11,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:b12,righttrigger:b13, +4f0400b3000000000000504944564944,Thrustmaster Firestorm Dual Power,a:b0,b:b2,y:b3,x:b1,start:b10,guide:b8,back:b9,leftstick:b11,rightstick:b12,leftshoulder:b4,rightshoulder:b6,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b5,righttrigger:b7,platform:Windows, +00f00300000000000000504944564944,RetroUSB.com RetroPad,a:b1,b:b5,x:b0,y:b4,back:b2,start:b3,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,platform:Windows, +00f0f100000000000000504944564944,RetroUSB.com Super RetroPort,a:b1,b:b5,x:b0,y:b4,back:b2,start:b3,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,platform:Windows, +28040140000000000000504944564944,GamePad Pro USB,platform:Windows,a:b1,b:b2,x:b0,y:b3,back:b8,start:b9,leftshoulder:b4,rightshoulder:b5,leftx:a0,lefty:a1,lefttrigger:b6,righttrigger:b7, +ff113133000000000000504944564944,SVEN X-PAD,platform:Windows,a:b2,b:b3,y:b1,x:b0,start:b5,back:b4,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a4,lefttrigger:b8,righttrigger:b9, +8f0e0300000000000000504944564944,Piranha xtreme,platform:Windows,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2, +8f0e0d31000000000000504944564944,Multilaser JS071 USB,platform:Windows,a:b1,b:b2,y:b3,x:b0,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7, +10080300000000000000504944564944,PS2 USB,platform:Windows,a:b2,b:b1,y:b0,x:b3,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a4,righty:a2,lefttrigger:b4,righttrigger:b5, +79000600000000000000504944564944,G-Shark GS-GP702,a:b2,b:b1,x:b3,y:b0,back:b8,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a4,lefttrigger:b6,righttrigger:b7,platform:Windows, +4b12014d000000000000504944564944,NYKO AIRFLO,a:b0,b:b1,x:b2,y:b3,back:b8,guide:b10,start:b9,leftstick:a0,rightstick:a2,leftshoulder:a3,rightshoulder:b5,dpup:h0.1,dpdown:h0.0,dpleft:h0.8,dpright:h0.2,leftx:h0.6,lefty:h0.12,rightx:h0.9,righty:h0.4,lefttrigger:b6,righttrigger:b7,platform:Windows, +d6206dca000000000000504944564944,PowerA Pro Ex,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.0,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Windows, +a3060cff000000000000504944564944,Saitek P2500,a:b2,b:b3,y:b1,x:b0,start:b4,guide:b10,back:b5,leftstick:b8,rightstick:b9,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,platform:Windows, +4f0415b3000000000000504944564944,Thrustmaster Dual Analog 3.2,platform:Windows,x:b1,a:b0,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b5,rightshoulder:b6,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3, +6f0e1e01000000000000504944564944,Rock Candy Gamepad for PS3,platform:Windows,a:b1,b:b2,x:b0,y:b3,back:b8,start:b9,guide:b12,leftshoulder:b4,rightshoulder:b5,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2, +83056020000000000000504944564944,iBuffalo USB 2-axis 8-button Gamepad,a:b1,b:b0,y:b2,x:b3,start:b7,back:b6,leftshoulder:b4,rightshoulder:b5,leftx:a0,lefty:a1,platform:Windows, +10080100000000000000504944564944,PS1 USB,platform:Windows,a:b2,b:b1,x:b3,y:b0,back:b8,start:b9,leftshoulder:b6,rightshoulder:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2,lefttrigger:b4,righttrigger:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2, +49190204000000000000504944564944,Ipega PG-9023,a:b0,b:b1,x:b3,y:b4,back:b10,start:b11,leftstick:b13,rightstick:b14,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:b8,righttrigger:b9,platform:Windows, +4f0423b3000000000000504944564944,Dual Trigger 3-in-1,a:b1,b:b2,x:b0,y:b3,back:b8,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:b6,righttrigger:b7,platform:Windows, +0d0f4900000000000000504944564944,Hatsune Miku Sho Controller,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Windows, +79004318000000000000504944564944,Mayflash GameCube Controller Adapter,platform:Windows,a:b1,b:b2,x:b0,y:b3,back:b0,start:b9,guide:b0,leftshoulder:b4,rightshoulder:b7,leftstick:b0,rightstick:b0,leftx:a0,lefty:a1,rightx:a5,righty:a2,lefttrigger:a3,righttrigger:a4,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2, +79000018000000000000504944564944,Mayflash WiiU Pro Game Controller Adapter (DInput),a:b1,b:b2,x:b0,y:b3,back:b8,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Windows, +2509e803000000000000504944564944,Mayflash Wii Classic Controller,a:b1,b:b0,x:b3,y:b2,back:b8,guide:b10,start:b9,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:b11,dpdown:b13,dpleft:b12,dpright:b14,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Windows, +300f1001000000000000504944564944,Saitek P480 Rumble Pad,a:b2,b:b3,x:b0,y:b1,back:b8,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b6,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a2,lefttrigger:b5,righttrigger:b7,platform:Windows, +10280900000000000000504944564944,8Bitdo SFC30 GamePad,a:b1,b:b0,y:b3,x:b4,start:b11,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,platform:Windows, +63252305000000000000504944564944,USB Vibration Joystick (BM),platform:Windows,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3, +20380900000000000000504944564944,8Bitdo NES30 PRO Wireless,platform:Windows,a:b0,b:b1,x:b3,y:b4,leftshoulder:b6,rightshoulder:b7,lefttrigger:b8,righttrigger:b9,back:b10,start:b11,leftstick:b13,rightstick:b14,leftx:a0,lefty:a1,rightx:a3,righty:a4,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8, +02200090000000000000504944564944,8Bitdo NES30 PRO USB,platform:Windows,a:b0,b:b1,x:b3,y:b4,leftshoulder:b6,rightshoulder:b7,lefttrigger:b8,righttrigger:b9,back:b10,start:b11,leftstick:b13,rightstick:b14,leftx:a0,lefty:a1,rightx:a3,righty:a4,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8, +ff113133000000000000504944564944,Gembird JPD-DualForce,platform:Windows,a:b2,b:b3,x:b0,y:b1,start:b9,back:b8,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a4,lefttrigger:b6,righttrigger:b7,leftstick:b10,rightstick:b11, +341a0108000000000000504944564944,EXEQ RF USB Gamepad 8206,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,leftstick:b8,rightstick:b7,back:b8,start:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,rightx:a2,righty:a3,platform:Windows, +c0111352000000000000504944564944,Battalife Joystick,platform:Windows,x:b4,a:b6,b:b7,y:b5,back:b2,start:b3,leftshoulder:b0,rightshoulder:b1,leftx:a0,lefty:a1, + +# OS X +0500000047532047616d657061640000,GameStop Gamepad,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,platform:Mac OS X, +6d0400000000000016c2000000000000,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,platform:Mac OS X, +6d0400000000000018c2000000000000,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,platform:Mac OS X, +6d040000000000001fc2000000000000,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,platform:Mac OS X, +6d0400000000000019c2000000000000,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,platform:Mac OS X, +4c050000000000006802000000000000,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,platform:Mac OS X, +4c05000000000000c405000000000000,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,platform:Mac OS X, +5e040000000000008e02000000000000,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,platform:Mac OS X, +891600000000000000fd000000000000,Razer Onza Tournament,a:b0,b:b1,y:b3,x:b2,start:b8,guide:b10,back:b9,leftstick:b6,rightstick:b7,leftshoulder:b4,rightshoulder:b5,dpup:b11,dpleft:b13,dpdown:b12,dpright:b14,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Mac OS X, +4f0400000000000000b3000000000000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,y:b3,x:b1,start:b10,guide:b8,back:b9,leftstick:b11,rightstick:,leftshoulder:b4,rightshoulder:b6,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b5,righttrigger:b7,platform:Mac OS X, +8f0e0000000000000300000000000000,Piranha xtreme,platform:Mac OS X,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2, +0d0f0000000000004d00000000000000,HORI Gem Pad 3,platform:Mac OS X,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7, +79000000000000000600000000000000,G-Shark GP-702,a:b2,b:b1,x:b3,y:b0,back:b8,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:b6,righttrigger:b7,platform:Mac OS X, +4f0400000000000015b3000000000000,Thrustmaster Dual Analog 3.2,platform:Mac OS X,x:b1,a:b0,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b5,rightshoulder:b6,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3, +AD1B00000000000001F9000000000000,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,platform:Mac OS X, +050000005769696d6f74652028303000,Wii Remote,a:b4,b:b5,y:b9,x:b10,start:b6,guide:b8,back:b7,dpup:b2,dpleft:b0,dpdown:b3,dpright:b1,leftx:a0,lefty:a1,lefttrigger:b12,righttrigger:,leftshoulder:b11,platform:Mac OS X, +83050000000000006020000000000000,iBuffalo USB 2-axis 8-button Gamepad,a:b1,b:b0,x:b3,y:b2,back:b6,start:b7,leftshoulder:b4,rightshoulder:b5,leftx:a0,lefty:a1,platform:Mac OS X, +5e04000000000000dd02000000000000,Xbox One Wired Controller,platform:Mac OS X,x:b2,a:b0,b:b1,y:b3,back:b9,guide:b10,start:b8,dpleft:b13,dpdown:b12,dpright:b14,dpup:b11,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b6,rightstick:b7,leftx:a0,lefty:a1,rightx:a3,righty:a4, +050000005769696d6f74652028313800,Wii U Pro Controller,a:b16,b:b15,x:b18,y:b17,back:b7,guide:b8,start:b6,leftstick:b23,rightstick:b24,leftshoulder:b19,rightshoulder:b20,dpup:b11,dpdown:b12,dpleft:b13,dpright:b14,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b21,righttrigger:b22,platform:Mac OS X, +79000000000000000018000000000000,Mayflash WiiU Pro Game Controller Adapter (DInput),a:b4,b:b8,x:b0,y:b12,back:b32,start:b36,leftstick:b40,rightstick:b44,leftshoulder:b16,rightshoulder:b20,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a4,rightx:a8,righty:a12,lefttrigger:b24,righttrigger:b28,platform:Mac OS X, +2509000000000000e803000000000000,Mayflash Wii Classic Controller,a:b1,b:b0,x:b3,y:b2,back:b8,guide:b10,start:b9,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:b11,dpdown:b13,dpleft:b12,dpright:b14,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Mac OS X, +351200000000000021ab000000000000,SFC30 Joystick,a:b1,b:b0,x:b4,y:b3,back:b10,start:b11,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,platform:Mac OS X, +b4040000000000000a01000000000000,Sega Saturn USB Gamepad,a:b0,b:b1,x:b3,y:b4,back:b5,guide:b2,start:b8,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,platform:Mac OS X, +10280000000000000900000000000000,8Bitdo SFC30 GamePad,a:b1,b:b0,x:b4,y:b3,back:b10,start:b11,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,platform:Mac OS X, +d814000000000000cecf000000000000,MC Cthulhu,platform:Mac OS X,leftx:,lefty:,rightx:,righty:,lefttrigger:b6,a:b1,b:b2,y:b3,x:b0,start:b9,back:b8,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,righttrigger:b7, +0d0f0000000000006600000000000000,HORIPAD FPS PLUS 4,platform:Mac OS X,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:b6,righttrigger:a4, + +# Linux +0500000047532047616d657061640000,GameStop Gamepad,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,platform:Linux, +03000000ba2200002010000001010000,Jess Technology USB Game Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Linux, +030000006d04000019c2000010010000,Logitech Cordless RumblePad 2,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:a3,start:b9,x:b0,y:b3,platform:Linux, +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,platform:Linux, +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,platform:Linux, +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,platform:Linux, +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,platform:Linux, +030000004c0500006802000011010000,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,platform:Linux, +030000004c050000c405000011010000,Sony DualShock 4,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:b6,righttrigger:b7,platform:Linux, +030000006f0e00003001000001010000,EA Sports PS3 Controller,platform:Linux,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7, +03000000de280000ff11000001000000,Valve Streaming 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,platform:Linux, +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,platform:Linux, +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,platform:Linux, +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,platform:Linux, +03000000100800000100000010010000,Twin USB PS2 Adapter,a:b2,b:b1,y:b0,x:b3,start:b9,guide:,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a2,lefttrigger:b4,righttrigger:b5,platform:Linux, +03000000a306000023f6000011010000,Saitek Cyborg V.1 Game Pad,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a4,lefttrigger:b6,righttrigger:b7,platform:Linux, +030000004f04000020b3000010010000,Thrustmaster 2 in 1 DT,a:b0,b:b2,y:b3,x:b1,start:b9,guide:,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b6,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b5,righttrigger:b7,platform:Linux, +030000004f04000023b3000000010000,Thrustmaster Dual Trigger 3-in-1,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a5, +030000008f0e00000300000010010000,GreenAsia Inc. USB Joystick ,platform:Linux,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2, +030000008f0e00001200000010010000,GreenAsia Inc. USB Joystick ,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b5,rightshoulder:b6,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2, +030000005e0400009102000007010000,X360 Wireless Controller,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:b13,dpleft:b11,dpdown:b14,dpright:b12,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Linux, +030000006d04000016c2000010010000,Logitech Logitech Dual Action,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3, +03000000260900008888000000010000,GameCube {WiseGroup USB box},a:b0,b:b2,y:b3,x:b1,start:b7,leftshoulder:,rightshoulder:b6,dpup:h0.1,dpleft:h0.8,rightstick:,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,platform:Linux, +030000006d04000011c2000010010000,Logitech WingMan Cordless RumblePad,a:b0,b:b1,y:b4,x:b3,start:b8,guide:b5,back:b2,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:b9,righttrigger:b10,platform:Linux, +030000006d04000018c2000010010000,Logitech Logitech RumblePad 2 USB,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3, +05000000d6200000ad0d000001000000,Moga Pro,platform:Linux,a:b0,b:b1,y:b3,x:b2,start:b6,leftstick:b7,rightstick:b8,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a5,righttrigger:a4, +030000004f04000009d0000000010000,Thrustmaster Run N Drive Wireless PS3,platform:Linux,a:b1,b:b2,x:b0,y:b3,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7, +030000004f04000008d0000000010000,Thrustmaster Run N Drive Wireless,platform:Linux,a:b1,b:b2,x:b0,y:b3,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:b6,righttrigger:b7, +0300000000f000000300000000010000,RetroUSB.com RetroPad,a:b1,b:b5,x:b0,y:b4,back:b2,start:b3,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,platform:Linux, +0300000000f00000f100000000010000,RetroUSB.com Super RetroPort,a:b1,b:b5,x:b0,y:b4,back:b2,start:b3,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,platform:Linux, +030000006f0e00001f01000000010000,Generic X-Box pad,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4, +03000000280400000140000000010000,Gravis GamePad Pro USB ,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,start:b9,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftx:a0,lefty:a1, +030000005e0400008902000021010000,Microsoft X-Box pad v2 (US),platform:Linux,x:b3,a:b0,b:b1,y:b4,back:b6,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b5,lefttrigger:a2,rightshoulder:b2,righttrigger:a5,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a3,righty:a4, +030000005e0400008502000000010000,Microsoft X-Box pad (Japan),platform:Linux,x:b3,a:b0,b:b1,y:b4,back:b6,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b5,lefttrigger:a2,rightshoulder:b2,righttrigger:a5,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a3,righty:a4, +030000006f0e00001e01000011010000,Rock Candy Gamepad for PS3,platform:Linux,a:b1,b:b2,x:b0,y:b3,back:b8,start:b9,guide:b12,leftshoulder:b4,rightshoulder:b5,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2, +03000000250900000500000000010000,Sony PS2 pad with SmartJoy adapter,platform:Linux,a:b2,b:b1,y:b0,x:b3,start:b8,back:b9,leftstick:b10,rightstick:b11,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b4,righttrigger:b5, +030000008916000000fd000024010000,Razer Onza Tournament,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:b13,dpleft:b11,dpdown:b14,dpright:b12,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Linux, +030000004f04000000b3000010010000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,y:b3,x:b1,start:b10,guide:b8,back:b9,leftstick:b11,rightstick:b12,leftshoulder:b4,rightshoulder:b6,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b5,righttrigger:b7,platform:Linux, +03000000ad1b000001f5000033050000,Hori Pad EX Turbo 2,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Linux, +050000004c050000c405000000010000,PS4 Controller (Bluetooth),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,platform:Linux, +060000004c0500006802000000010000,PS3 Controller (Bluetooth),a:b14,b:b13,y:b12,x:b15,start:b3,guide:b16,back:b0,leftstick:b1,rightstick:b2,leftshoulder:b10,rightshoulder:b11,dpup:b4,dpleft:b7,dpdown:b6,dpright:b5,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b8,righttrigger:b9,platform:Linux, +050000004c0500006802000000010000,PS3 Controller (Bluetooth),a:b14,b:b13,y:b12,x:b15,start:b3,guide:b16,back:b0,leftstick:b1,rightstick:b2,leftshoulder:b10,rightshoulder:b11,dpup:b4,dpleft:b7,dpdown:b6,dpright:b5,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b8,righttrigger:b9,platform:Linux, +03000000790000000600000010010000,DragonRise Inc. Generic USB Joystick ,platform:Linux,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a4, +03000000666600000488000000010000,Super Joy Box 5 Pro,platform:Linux,a:b2,b:b1,x:b3,y:b0,back:b9,start:b8,leftshoulder:b6,rightshoulder:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b4,righttrigger:b5,dpup:b12,dpleft:b15,dpdown:b14,dpright:b13, +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,platform:Linux,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,platform:Linux,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,x:b1,y:b2, +030000008916000001fd000024010000,Razer Onza Classic Edition,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:b11,dpdown:b14,dpright:b12,dpup:b13,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4, +030000005e040000d102000001010000,Microsoft X-Box One pad,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4, +030000005e040000dd02000003020000,Microsoft X-Box One pad v2,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,platform:Linux, +03000000790000001100000010010000,RetroLink Saturn Classic Controller,platform:Linux,x:b3,a:b0,b:b1,y:b4,back:b5,guide:b2,start:b8,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1, +050000007e0500003003000001000000,Nintendo Wii U Pro Controller,platform:Linux,a:b0,b:b1,x:b3,y:b2,back:b8,start:b9,guide:b10,leftshoulder:b4,rightshoulder:b5,leftstick:b11,rightstick:b12,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,dpup:b13,dpleft:b15,dpdown:b14,dpright:b16, +030000005e0400008e02000004010000,Microsoft X-Box 360 pad,platform:Linux,a:b0,b:b1,x:b2,y:b3,back:b6,start:b7,guide:b8,leftshoulder:b4,rightshoulder:b5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2, +030000000d0f00002200000011010000,HORI CO. LTD. REAL ARCADE Pro.V3,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,guide:b12,start:b9,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1, +030000000d0f00001000000011010000,HORI CO. LTD. FIGHTING STICK 3,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,guide:b12,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7 +03000000f0250000c183000010010000,Goodbetterbest Ltd USB Controller,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,guide:b12,start:b9,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3, +0000000058626f782047616d65706100,Xbox Gamepad (userspace driver),platform:Linux,a:b0,b:b1,x:b2,y:b3,start:b7,back:b6,guide:b8,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftshoulder:b4,rightshoulder:b5,lefttrigger:a5,righttrigger:a4,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a2,righty:a3, +03000000ff1100003133000010010000,PC Game Controller,a:b2,b:b1,y:b0,x:b3,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Linux, +030000005e0400008e02000020200000,SpeedLink XEOX Pro Analog Gamepad pad,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4, +030000006f0e00001304000000010000,Generic X-Box pad,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:a0,rightstick:a3,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4, +03000000a306000018f5000010010000,Saitek PLC Saitek P3200 Rumble Pad,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:a2,rightshoulder:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a4, +03000000830500006020000010010000,iBuffalo USB 2-axis 8-button Gamepad,a:b1,b:b0,x:b3,y:b2,back:b6,start:b7,leftshoulder:b4,rightshoulder:b5,leftx:a0,lefty:a1,platform:Linux, +03000000c9110000f055000011010000,HJC Game GAMEPAD,leftx:a0,lefty:a1,dpdown:h0.4,rightstick:b11,rightshoulder:b5,rightx:a2,start:b9,righty:a3,dpleft:h0.8,lefttrigger:b6,x:b2,dpup:h0.1,back:b8,leftstick:b10,leftshoulder:b4,y:b3,a:b0,dpright:h0.2,righttrigger:b7,b:b1,platform:Linux, +03000000a30600000c04000011010000,Saitek P2900 Wireless Pad,a:b1,b:b2,y:b3,x:b0,start:b12,guide:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a2,lefttrigger:b4,righttrigger:b5,platform:Linux, +03000000341a000005f7000010010000,GameCube {HuiJia USB box},a:b1,b:b2,y:b3,x:b0,start:b9,guide:,back:,leftstick:,rightstick:,leftshoulder:,dpleft:b15,dpdown:b14,dpright:b13,leftx:a0,lefty:a1,rightx:a5,righty:a2,lefttrigger:a3,righttrigger:a4,rightshoulder:b7,dpup:b12,platform:Linux, +030000006e0500000320000010010000,JC-U3613M - DirectInput Mode,platform:Linux,x:b0,a:b2,b:b3,y:b1,back:b10,guide:b12,start:b11,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3, +030000006f0e00004601000001010000,Rock Candy Wired Controller for Xbox One,platform:Linux,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,guide:b8,leftstick:b9,rightstick:b10,lefttrigger:a2,righttrigger:a5,leftx:a0,lefty:a1,rightx:a3,righty:a4, +03000000380700001647000010040000,Mad Catz Wired Xbox 360 Controller,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4, +030000006f0e00003901000020060000,Afterglow Wired Controller for Xbox One,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,platform:Linux, +030000004f04000015b3000010010000,Thrustmaster Dual Analog 4,platform:Linux,a:b0,b:b2,x:b1,y:b3,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b6,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b5,righttrigger:b7, +05000000102800000900000000010000,8Bitdo SFC30 GamePad,platform:Linux,x:b4,a:b1,b:b0,y:b3,back:b10,start:b11,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1, +03000000d81400000862000011010000,HitBox (PS3/PC) Analog Mode,platform:Linux,a:b1,b:b2,y:b3,x:b0,start:b12,guide:b9,back:b8,leftshoulder:b4,rightshoulder:b5,lefttrigger:b6,righttrigger:b7,leftx:a0,lefty:a1, +030000000d0f00000d00000000010000,hori,platform:Linux,a:b0,b:b6,y:b2,x:b1,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,start:b9,guide:b10,back:b8,leftshoulder:b3,rightshoulder:b7,leftx:b4,lefty:b5, +03000000ad1b000016f0000090040000,Mad Catz Xbox 360 Controller,platform:Linux,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5, +03000000d814000007cd000011010000,Toodles 2008 Chimp PC/PS3,platform:Linux,a:b0,b:b1,y:b2,x:b3,start:b9,back:b8,leftshoulder:b4,rightshoulder:b5,leftx:a0,lefty:a1,lefttrigger:b6,righttrigger:b7, +03000000fd0500000030000000010000,InterAct GoPad I-73000 (Fighting Game Layout),platform:Linux,a:b3,b:b4,y:b1,x:b0,start:b7,back:b6,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5, +05000000010000000100000003000000,Nintendo Wiimote,platform:Linux,a:b0,b:b1,y:b3,x:b2,start:b9,guide:b10,back:b8,leftstick:b11,rightstick:b12,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7, +030000005e0400008e02000062230000,Microsoft X-Box 360 pad,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4, +03000000a30600000901000000010000,Saitek P880,a:b2,b:b3,y:b1,x:b0,leftstick:b8,rightstick:b9,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a2,lefttrigger:b6,righttrigger:b7,platform:Linux, +030000006f0e00000103000000020000,Logic3 Controller,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4, +05000000380700006652000025010000,Mad Catz C.T.R.L.R ,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,guide:b12,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3, From db2cc49e0dd1b04d8b20ca4ccc52648e72f6b738 Mon Sep 17 00:00:00 2001 From: Neil Munday Date: Sun, 18 Sep 2016 23:23:36 +0100 Subject: [PATCH 2/5] Modified SDL2 code to make full use of SDL2's Game Controller API. --- SDL/README.TXT | 11 ++ SDL/SDLJoystick.cpp | 298 ++++++++++++++++++------------------- SDL/SDLJoystick.h | 20 +-- ext/native/base/PCMain.cpp | 2 +- 4 files changed, 160 insertions(+), 171 deletions(-) diff --git a/SDL/README.TXT b/SDL/README.TXT index 65d077a01..d553b1a4b 100644 --- a/SDL/README.TXT +++ b/SDL/README.TXT @@ -14,3 +14,14 @@ Open XCode, Preferences, Downloads, Components. Install the command line toools. Install MacPorts Using MacPorts, install libpng Do the above. + +SDL2 Game Controller Support Notes +================================== + +For SDL2 game controller support, at least SDL 2.0.4 is required. + +Under the assets directory is the SDL2 game controller database: gamecontrollerdb.txt. This file contains many known control pad mappings for Windows, Linux and MAC OS. PPSSPPSDL will load this file at start-up and work out how to assign control pad buttons for your control pad. + +Hot plugging of control pads is also supported. + +If you control pad has a "Guide" or "Home" button then when pressed, this will trigger the emulator pause menu, thus allowing you to exit the emulator if you wish or load another game from your library. diff --git a/SDL/SDLJoystick.cpp b/SDL/SDLJoystick.cpp index dec843a1c..c144f6b82 100644 --- a/SDL/SDLJoystick.cpp +++ b/SDL/SDLJoystick.cpp @@ -11,10 +11,10 @@ extern "C" { } } -SDLJoystick::SDLJoystick(bool init_SDL ): thread(NULL), running(true) { +SDLJoystick::SDLJoystick(bool init_SDL ): thread(NULL), running(true), player1Controller(NULL), player1JoyInstanceID(-1) { if (init_SDL) { - SDL_setenv("SDL_JOYSTICK_ALLOW_BACKGROUND_EVENTS", "1", 0); + SDL_SetHint(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, "1"); SDL_Init(SDL_INIT_JOYSTICK | SDL_INIT_VIDEO | SDL_INIT_GAMECONTROLLER); } @@ -24,149 +24,178 @@ SDLJoystick::SDLJoystick(bool init_SDL ): thread(NULL), running(true) { } else { printf("Loaded game controller mappings for SDL2\n"); + setUpPlayer1(); } +} +void SDLJoystick::setUpPlayer1() +{ int numjoys = SDL_NumJoysticks(); - int firstController = -1; - SDL_JoystickEventState(SDL_ENABLE); + int joyIndex = -1; for (int i = 0; i < numjoys; i++) { - joys.push_back(SDL_JoystickOpen(i)); - //printf("Initialized joystick %d: %s\n",i,SDL_JoystickNameForIndex(i)); - if (firstController == -1 && SDL_IsGameController(i)) + if (joyIndex == -1 && SDL_IsGameController(i)) { - firstController = i; + joyIndex = i; + break; + } + } + if (joyIndex != -1) + { + printf("Player 1 will be using joystick %d, %s\n", joyIndex, SDL_JoystickNameForIndex(joyIndex)); + player1Controller = SDL_GameControllerOpen(joyIndex); + if (player1Controller && SDL_GameControllerGetAttached(player1Controller)) + { + player1JoyInstanceID = SDL_JoystickInstanceID(SDL_GameControllerGetJoystick(player1Controller)); + char *mapping = SDL_GameControllerMapping(player1Controller); + if (mapping == NULL) + { + printf("control pad %s is not in the game controller database, unable to set mappings!\n", SDL_JoystickNameForIndex(joyIndex)); + } + else + { + printf("control pad mapping: %s\n", SDL_GameControllerMapping(player1Controller)); + } + } + else + { + printf("Error! Could not open controller\n"); } } - - printf("Player 1 will be using joystick %d, %s\n", firstController, SDL_JoystickNameForIndex(firstController)); - fillMapping(firstController); } SDLJoystick::~SDLJoystick(){ if (thread) { running = false; + if (player1Controller) + { + SDL_GameControllerClose(player1Controller); + } SDL_Event evt; evt.type = SDL_USEREVENT; SDL_PushEvent(&evt); SDL_WaitThread(thread,0); } - for (SDL_Joystick *joy : joys) - { - SDL_JoystickClose(joy); - } } void SDLJoystick::startEventLoop(){ thread = SDL_CreateThread(SDLJoystickThreadWrapper, "joystick",static_cast(this)); } +keycode_t SDLJoystick::getKeycodeForButton(SDL_GameControllerButton button) +{ + switch (button) + { + case SDL_CONTROLLER_BUTTON_DPAD_UP: return NKCODE_DPAD_UP; + case SDL_CONTROLLER_BUTTON_DPAD_DOWN: return NKCODE_DPAD_DOWN; + case SDL_CONTROLLER_BUTTON_DPAD_LEFT: return NKCODE_DPAD_LEFT; + case SDL_CONTROLLER_BUTTON_DPAD_RIGHT: return NKCODE_DPAD_RIGHT; + case SDL_CONTROLLER_BUTTON_A: return NKCODE_BUTTON_2; + case SDL_CONTROLLER_BUTTON_B: return NKCODE_BUTTON_3; + case SDL_CONTROLLER_BUTTON_X: return NKCODE_BUTTON_4; + case SDL_CONTROLLER_BUTTON_Y: return NKCODE_BUTTON_1; + case SDL_CONTROLLER_BUTTON_RIGHTSHOULDER: return NKCODE_BUTTON_5; + case SDL_CONTROLLER_BUTTON_LEFTSHOULDER: return NKCODE_BUTTON_6; + case SDL_CONTROLLER_BUTTON_START: return NKCODE_BUTTON_10; + case SDL_CONTROLLER_BUTTON_BACK: return NKCODE_BUTTON_9; // select button + case SDL_CONTROLLER_BUTTON_GUIDE: return NKCODE_BACK; // pause menu + } + return NKCODE_UNKNOWN; +} + void SDLJoystick::ProcessInput(SDL_Event &event){ switch (event.type) { - case SDL_JOYAXISMOTION: + case SDL_CONTROLLERBUTTONDOWN: { - std::map::const_iterator i = SDLJoyAxisMap.find(event.jaxis.axis); - int deviceIndex = getDeviceIndex(event.jaxis.which); - if (i != SDLJoyAxisMap.end() && deviceIndex >= 0) { + if (event.cbutton.which == player1JoyInstanceID && event.cbutton.state == SDL_PRESSED) + { + keycode_t code = getKeycodeForButton((SDL_GameControllerButton)event.cbutton.button); + if (code != NKCODE_UNKNOWN) + { + KeyInput key; + key.flags = KEY_DOWN; + key.keyCode = code; + key.deviceId = DEVICE_ID_PAD_0 + getDeviceIndex(event.cbutton.which); + NativeKey(key); + } + } + break; + } + case SDL_CONTROLLERBUTTONUP: + { + if (event.cbutton.which == player1JoyInstanceID && event.cbutton.state == SDL_RELEASED) + { + keycode_t code = getKeycodeForButton((SDL_GameControllerButton)event.cbutton.button); + if (code != NKCODE_UNKNOWN) + { + KeyInput key; + key.flags = KEY_UP; + key.keyCode = code; + key.deviceId = DEVICE_ID_PAD_0 + getDeviceIndex(event.cbutton.which); + NativeKey(key); + } + } + break; + } + case SDL_CONTROLLERAXISMOTION: + { + if (event.caxis.which == player1JoyInstanceID) + { AxisInput axis; - axis.axisId = i->second; + axis.axisId = event.caxis.axis; // 1.2 to try to approximate the PSP's clamped rectangular range. - axis.value = 1.2 * event.jaxis.value / 32767.0f; + axis.value = 1.2 * event.caxis.value / 32767.0f; if (axis.value > 1.0f) axis.value = 1.0f; if (axis.value < -1.0f) axis.value = -1.0f; - axis.deviceId = DEVICE_ID_PAD_0 + deviceIndex; + axis.deviceId = DEVICE_ID_PAD_0 + getDeviceIndex(event.caxis.which); axis.flags = 0; NativeAxis(axis); - } - break; - } - - case SDL_JOYBUTTONDOWN: - { - std::map::const_iterator i = SDLJoyButtonMap.find(event.jbutton.button); - int deviceIndex = getDeviceIndex(event.jbutton.which); - if (i != SDLJoyButtonMap.end() && deviceIndex >= 0) { - KeyInput key; - key.flags = KEY_DOWN; - key.keyCode = i->second; - key.deviceId = DEVICE_ID_PAD_0 + deviceIndex; - NativeKey(key); - } - break; - } - - case SDL_JOYBUTTONUP: - { - std::map::const_iterator i = SDLJoyButtonMap.find(event.jbutton.button); - int deviceIndex = getDeviceIndex(event.jbutton.which); - if (i != SDLJoyButtonMap.end() && deviceIndex >= 0) { - KeyInput key; - key.flags = KEY_UP; - key.keyCode = i->second; - key.deviceId = DEVICE_ID_PAD_0 + deviceIndex; - NativeKey(key); - } - break; - } - - case SDL_JOYHATMOTION: - { - int deviceIndex = getDeviceIndex(event.jhat.which); - if (deviceIndex < 0) { break; } -#ifdef _WIN32 - KeyInput key; - key.deviceId = DEVICE_ID_PAD_0 + deviceIndex; - - key.flags = (event.jhat.value & SDL_HAT_UP)?KEY_DOWN:KEY_UP; - key.keyCode = NKCODE_DPAD_UP; - NativeKey(key); - key.flags = (event.jhat.value & SDL_HAT_LEFT)?KEY_DOWN:KEY_UP; - key.keyCode = NKCODE_DPAD_LEFT; - NativeKey(key); - key.flags = (event.jhat.value & SDL_HAT_DOWN)?KEY_DOWN:KEY_UP; - key.keyCode = NKCODE_DPAD_DOWN; - NativeKey(key); - key.flags = (event.jhat.value & SDL_HAT_RIGHT)?KEY_DOWN:KEY_UP; - key.keyCode = NKCODE_DPAD_RIGHT; - NativeKey(key); -#else - AxisInput axisX; - AxisInput axisY; - axisX.axisId = JOYSTICK_AXIS_HAT_X; - axisY.axisId = JOYSTICK_AXIS_HAT_Y; - axisX.deviceId = DEVICE_ID_PAD_0 + deviceIndex; - axisY.deviceId = DEVICE_ID_PAD_0 + deviceIndex; - axisX.value = 0.0f; - axisY.value = 0.0f; - if (event.jhat.value & SDL_HAT_LEFT) axisX.value = -1.0f; - if (event.jhat.value & SDL_HAT_RIGHT) axisX.value = 1.0f; - if (event.jhat.value & SDL_HAT_DOWN) axisY.value = 1.0f; - if (event.jhat.value & SDL_HAT_UP) axisY.value = -1.0f; - NativeAxis(axisX); - NativeAxis(axisY); -#endif - break; } - - case SDL_JOYDEVICEADDED: + case SDL_CONTROLLERDEVICEREMOVED: { - int deviceIndex = event.jdevice.which; - if (deviceIndex >= joys.size()) { - joys.resize(deviceIndex+1); + // for removal events, "which" is the instance ID for SDL_CONTROLLERDEVICEREMOVED + if (event.cdevice.which == player1JoyInstanceID) + { + printf("control pad removed for player 1\n"); + if (player1Controller){ + SDL_GameControllerClose(player1Controller); + player1Controller = NULL; + } + // are there any other control pads we could use? + setUpPlayer1(); } - joys[deviceIndex] = SDL_JoystickOpen(deviceIndex); - SDL_JoystickEventState(SDL_ENABLE); break; } - - case SDL_JOYDEVICEREMOVED: + case SDL_CONTROLLERDEVICEADDED: { - int deviceIndex = getDeviceIndex(event.jdevice.which); - if (deviceIndex >= 0) { - SDL_JoystickClose(joys[deviceIndex]); - joys[deviceIndex] = 0; + // for add events, "which" is the device index! + if (!player1Controller) + { + if (SDL_IsGameController(event.cdevice.which)) + { + player1Controller = SDL_GameControllerOpen(event.cdevice.which); + SDL_GameControllerEventState(SDL_ENABLE); + if (player1Controller && SDL_GameControllerGetAttached(player1Controller)) + { + player1JoyInstanceID = SDL_JoystickInstanceID(SDL_GameControllerGetJoystick(player1Controller)); + printf("Player 1 will be using control pad: %s, instance ID: %d\n", SDL_GameControllerName(player1Controller), player1JoyInstanceID); + char *mapping = SDL_GameControllerMapping(player1Controller); + if (mapping == NULL) + { + printf("control pad %s is not in the game controller database, unable to set mappings!\n", SDL_GameControllerName(player1Controller)); + } + else + { + printf("control pad mapping: %s\n", SDL_GameControllerMapping(player1Controller)); + } + } + else + { + printf("Error! Could not open controller\n"); + } + } } break; } @@ -174,11 +203,17 @@ void SDLJoystick::ProcessInput(SDL_Event &event){ } int SDLJoystick::getDeviceIndex(int instanceId) { - for (int i = 0; i < joys.size(); i++) { - SDL_Joystick *joy = joys[i]; - if (SDL_JoystickInstanceID(joy) == instanceId) { + int numjoys = SDL_NumJoysticks(); + SDL_Joystick *joy; + for (int i = 0; i < numjoys; i++) + { + joy = SDL_JoystickOpen(i); + if (SDL_JoystickInstanceID(joy) == instanceId) + { + SDL_JoystickClose(joy); return i; } + SDL_JoystickClose(joy); } return -1; } @@ -192,52 +227,3 @@ void SDLJoystick::runLoop(){ } } } - -void SDLJoystick::buttonMappingHelper(SDL_GameController* controller, SDL_GameControllerButton button, keycode_t buttonKeyCode) -{ - SDL_GameControllerButtonBind bind = SDL_GameControllerGetBindForButton(controller, button); - if (bind.bindType == SDL_CONTROLLER_BINDTYPE_BUTTON) - { - SDLJoyButtonMap[bind.value.button] = buttonKeyCode; - } -} - -void SDLJoystick::axisMappingHelper(SDL_GameController* controller, SDL_GameControllerAxis axis, keycode_t buttonKeyCode, AndroidJoystickAxis axisCode) -{ - SDL_GameControllerButtonBind bind = SDL_GameControllerGetBindForAxis(controller, axis); - if (bind.bindType == SDL_CONTROLLER_BINDTYPE_BUTTON && buttonKeyCode != NKCODE_UNKNOWN) - { - SDLJoyButtonMap[bind.value.button] = buttonKeyCode; - } - else if (bind.bindType == SDL_CONTROLLER_BINDTYPE_AXIS) - { - SDLJoyAxisMap[bind.value.axis] = axisCode; - } -} - -void SDLJoystick::fillMapping(int joyIndex) -{ - SDL_GameController *controller = SDL_GameControllerOpen(joyIndex); - printf("control pad mapping: %s\n", SDL_GameControllerMapping(controller)); - - buttonMappingHelper(controller, SDL_CONTROLLER_BUTTON_DPAD_UP, NKCODE_DPAD_UP); - buttonMappingHelper(controller, SDL_CONTROLLER_BUTTON_DPAD_DOWN, NKCODE_DPAD_DOWN); - buttonMappingHelper(controller, SDL_CONTROLLER_BUTTON_DPAD_LEFT, NKCODE_DPAD_LEFT); - buttonMappingHelper(controller, SDL_CONTROLLER_BUTTON_DPAD_RIGHT, NKCODE_DPAD_RIGHT); - buttonMappingHelper(controller, SDL_CONTROLLER_BUTTON_A, NKCODE_BUTTON_2); - buttonMappingHelper(controller, SDL_CONTROLLER_BUTTON_B, NKCODE_BUTTON_3); - buttonMappingHelper(controller, SDL_CONTROLLER_BUTTON_X, NKCODE_BUTTON_4); - buttonMappingHelper(controller, SDL_CONTROLLER_BUTTON_Y, NKCODE_BUTTON_1); - buttonMappingHelper(controller, SDL_CONTROLLER_BUTTON_START, NKCODE_BUTTON_10); - buttonMappingHelper(controller, SDL_CONTROLLER_BUTTON_BACK, NKCODE_BUTTON_9); // back == select - buttonMappingHelper(controller, SDL_CONTROLLER_BUTTON_LEFTSHOULDER, NKCODE_BUTTON_5); - buttonMappingHelper(controller, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER, NKCODE_BUTTON_6); - buttonMappingHelper(controller, SDL_CONTROLLER_BUTTON_GUIDE, NKCODE_BACK); // pause emulator - - axisMappingHelper(controller, SDL_CONTROLLER_AXIS_TRIGGERLEFT, NKCODE_BUTTON_7, JOYSTICK_AXIS_LTRIGGER); // L2 - axisMappingHelper(controller, SDL_CONTROLLER_AXIS_TRIGGERRIGHT, NKCODE_BUTTON_8, JOYSTICK_AXIS_RTRIGGER); // R2 - axisMappingHelper(controller, SDL_CONTROLLER_AXIS_LEFTX, NKCODE_UNKNOWN, JOYSTICK_AXIS_X); - axisMappingHelper(controller, SDL_CONTROLLER_AXIS_LEFTY, NKCODE_UNKNOWN, JOYSTICK_AXIS_Y); - axisMappingHelper(controller, SDL_CONTROLLER_AXIS_RIGHTX, NKCODE_UNKNOWN, JOYSTICK_AXIS_Z); - axisMappingHelper(controller, SDL_CONTROLLER_AXIS_RIGHTY, NKCODE_UNKNOWN, JOYSTICK_AXIS_RZ); -} diff --git a/SDL/SDLJoystick.h b/SDL/SDLJoystick.h index 7e9d122dc..ed4227bc1 100644 --- a/SDL/SDLJoystick.h +++ b/SDL/SDLJoystick.h @@ -2,13 +2,9 @@ #ifdef _WIN32 #include "SDL/SDL.h" -#include "SDL/SDL_joystick.h" -#include "SDL/SDL_gamecontroller.h" #include "SDL/SDL_thread.h" #else #include "SDL.h" -#include "SDL_joystick.h" -#include "SDL_gamecontroller.h" #include "SDL_thread.h" #endif @@ -33,16 +29,12 @@ public: private: void runLoop(); - void fillMapping(int joyIndex); - void axisMappingHelper(SDL_GameController* controller, SDL_GameControllerAxis axis, keycode_t buttonKeyCode, AndroidJoystickAxis axisCode); - void buttonMappingHelper(SDL_GameController* controller, SDL_GameControllerButton button, keycode_t buttonKeyCode); - - std::map SDLJoyButtonMap; - std::map SDLJoyAxisMap; - - std::vector joys; + void setUpPlayer1(); + keycode_t getKeycodeForButton(SDL_GameControllerButton button); + int getDeviceIndex(int instanceId); SDL_Thread *thread ; bool running ; - - int getDeviceIndex(int instanceId); + SDL_GameController *player1Controller; + SDL_JoystickID player1JoyInstanceID; + }; diff --git a/ext/native/base/PCMain.cpp b/ext/native/base/PCMain.cpp index c3754b73e..726940d2a 100644 --- a/ext/native/base/PCMain.cpp +++ b/ext/native/base/PCMain.cpp @@ -427,7 +427,7 @@ int main(int argc, char *argv[]) { net::Init(); bool joystick_enabled = true; - if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK | SDL_INIT_AUDIO) < 0) { + if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER | SDL_INIT_AUDIO) < 0) { joystick_enabled = false; if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO) < 0) { fprintf(stderr, "Unable to initialize SDL: %s\n", SDL_GetError()); From e4a0a3cea3bc22f82a6d0760420116337c72ff78 Mon Sep 17 00:00:00 2001 From: Neil Munday Date: Tue, 20 Sep 2016 00:28:28 +0100 Subject: [PATCH 3/5] Updated SDL2 game controller mods following feedback from PPSSPP authors. --- SDL/SDLJoystick.cpp | 279 +++++++++++++++++++------------------------- SDL/SDLJoystick.h | 10 +- 2 files changed, 124 insertions(+), 165 deletions(-) diff --git a/SDL/SDLJoystick.cpp b/SDL/SDLJoystick.cpp index c144f6b82..5907da925 100644 --- a/SDL/SDLJoystick.cpp +++ b/SDL/SDLJoystick.cpp @@ -11,218 +11,177 @@ extern "C" { } } -SDLJoystick::SDLJoystick(bool init_SDL ): thread(NULL), running(true), player1Controller(NULL), player1JoyInstanceID(-1) { - if (init_SDL) - { +SDLJoystick::SDLJoystick(bool init_SDL ): thread(NULL), running(true) { + if (init_SDL) { SDL_SetHint(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, "1"); SDL_Init(SDL_INIT_JOYSTICK | SDL_INIT_VIDEO | SDL_INIT_GAMECONTROLLER); } - if (SDL_GameControllerAddMappingsFromFile("assets/gamecontrollerdb.txt") == -1) - { + if (SDL_GameControllerAddMappingsFromFile("assets/gamecontrollerdb.txt") == -1) { printf("Failed to load control pad mappings, please place gamecontrollerdb.txt in your assets directory\n"); - } - else { + } else { printf("Loaded game controller mappings for SDL2\n"); - setUpPlayer1(); + setUpControllers(); } } -void SDLJoystick::setUpPlayer1() -{ +void SDLJoystick::setUpControllers() { int numjoys = SDL_NumJoysticks(); - int joyIndex = -1; for (int i = 0; i < numjoys; i++) { - if (joyIndex == -1 && SDL_IsGameController(i)) - { - joyIndex = i; - break; - } + setUpController(i); } - if (joyIndex != -1) - { - printf("Player 1 will be using joystick %d, %s\n", joyIndex, SDL_JoystickNameForIndex(joyIndex)); - player1Controller = SDL_GameControllerOpen(joyIndex); - if (player1Controller && SDL_GameControllerGetAttached(player1Controller)) - { - player1JoyInstanceID = SDL_JoystickInstanceID(SDL_GameControllerGetJoystick(player1Controller)); - char *mapping = SDL_GameControllerMapping(player1Controller); - if (mapping == NULL) - { - printf("control pad %s is not in the game controller database, unable to set mappings!\n", SDL_JoystickNameForIndex(joyIndex)); + if (controllers.size() > 0) { + printf("Pad 1 has been assigned to control pad: %s\n", SDL_GameControllerName(controllers.front())); + } +} + +void SDLJoystick::setUpController(int deviceIndex) { + if (SDL_IsGameController(deviceIndex)) { + SDL_GameController *controller = SDL_GameControllerOpen(deviceIndex); + if (controller) { + if (SDL_GameControllerGetAttached(controller)) { + controllers.push_back(controller); + controllerDeviceMap[SDL_JoystickInstanceID(SDL_GameControllerGetJoystick(controller))] = deviceIndex; + printf("found control pad: %s, loading mapping: ", SDL_GameControllerName(controller)); + char *mapping = SDL_GameControllerMapping(controller); + if (mapping == NULL) { + printf("FAILED\n"); + } else { + printf("SUCCESS, mapping is:\n%s\n", mapping); + } + } else { + SDL_GameControllerClose(controller); } - else - { - printf("control pad mapping: %s\n", SDL_GameControllerMapping(player1Controller)); - } - } - else - { - printf("Error! Could not open controller\n"); } } } -SDLJoystick::~SDLJoystick(){ - if (thread) - { +SDLJoystick::~SDLJoystick() { + if (thread) { running = false; - if (player1Controller) - { - SDL_GameControllerClose(player1Controller); - } SDL_Event evt; evt.type = SDL_USEREVENT; SDL_PushEvent(&evt); SDL_WaitThread(thread,0); } + for (SDL_GameController *controller : controllers) { + SDL_GameControllerClose(controller); + } } -void SDLJoystick::startEventLoop(){ +void SDLJoystick::startEventLoop() { thread = SDL_CreateThread(SDLJoystickThreadWrapper, "joystick",static_cast(this)); } -keycode_t SDLJoystick::getKeycodeForButton(SDL_GameControllerButton button) -{ - switch (button) - { - case SDL_CONTROLLER_BUTTON_DPAD_UP: return NKCODE_DPAD_UP; - case SDL_CONTROLLER_BUTTON_DPAD_DOWN: return NKCODE_DPAD_DOWN; - case SDL_CONTROLLER_BUTTON_DPAD_LEFT: return NKCODE_DPAD_LEFT; - case SDL_CONTROLLER_BUTTON_DPAD_RIGHT: return NKCODE_DPAD_RIGHT; - case SDL_CONTROLLER_BUTTON_A: return NKCODE_BUTTON_2; - case SDL_CONTROLLER_BUTTON_B: return NKCODE_BUTTON_3; - case SDL_CONTROLLER_BUTTON_X: return NKCODE_BUTTON_4; - case SDL_CONTROLLER_BUTTON_Y: return NKCODE_BUTTON_1; - case SDL_CONTROLLER_BUTTON_RIGHTSHOULDER: return NKCODE_BUTTON_5; - case SDL_CONTROLLER_BUTTON_LEFTSHOULDER: return NKCODE_BUTTON_6; - case SDL_CONTROLLER_BUTTON_START: return NKCODE_BUTTON_10; - case SDL_CONTROLLER_BUTTON_BACK: return NKCODE_BUTTON_9; // select button - case SDL_CONTROLLER_BUTTON_GUIDE: return NKCODE_BACK; // pause menu +keycode_t SDLJoystick::getKeycodeForButton(SDL_GameControllerButton button) { + switch (button) { + case SDL_CONTROLLER_BUTTON_DPAD_UP: + return NKCODE_DPAD_UP; + case SDL_CONTROLLER_BUTTON_DPAD_DOWN: + return NKCODE_DPAD_DOWN; + case SDL_CONTROLLER_BUTTON_DPAD_LEFT: + return NKCODE_DPAD_LEFT; + case SDL_CONTROLLER_BUTTON_DPAD_RIGHT: + return NKCODE_DPAD_RIGHT; + case SDL_CONTROLLER_BUTTON_A: + return NKCODE_BUTTON_2; + case SDL_CONTROLLER_BUTTON_B: + return NKCODE_BUTTON_3; + case SDL_CONTROLLER_BUTTON_X: + return NKCODE_BUTTON_4; + case SDL_CONTROLLER_BUTTON_Y: + return NKCODE_BUTTON_1; + case SDL_CONTROLLER_BUTTON_RIGHTSHOULDER: + return NKCODE_BUTTON_5; + case SDL_CONTROLLER_BUTTON_LEFTSHOULDER: + return NKCODE_BUTTON_6; + case SDL_CONTROLLER_BUTTON_START: + return NKCODE_BUTTON_10; + case SDL_CONTROLLER_BUTTON_BACK: + return NKCODE_BUTTON_9; // select button + case SDL_CONTROLLER_BUTTON_GUIDE: + return NKCODE_BACK; // pause menu } return NKCODE_UNKNOWN; } void SDLJoystick::ProcessInput(SDL_Event &event){ switch (event.type) { - case SDL_CONTROLLERBUTTONDOWN: - { - if (event.cbutton.which == player1JoyInstanceID && event.cbutton.state == SDL_PRESSED) - { - keycode_t code = getKeycodeForButton((SDL_GameControllerButton)event.cbutton.button); - if (code != NKCODE_UNKNOWN) - { - KeyInput key; - key.flags = KEY_DOWN; - key.keyCode = code; - key.deviceId = DEVICE_ID_PAD_0 + getDeviceIndex(event.cbutton.which); - NativeKey(key); - } + case SDL_CONTROLLERBUTTONDOWN: + if (event.cbutton.state == SDL_PRESSED) { + keycode_t code = getKeycodeForButton((SDL_GameControllerButton)event.cbutton.button); + if (code != NKCODE_UNKNOWN) { + KeyInput key; + key.flags = KEY_DOWN; + key.keyCode = code; + key.deviceId = DEVICE_ID_PAD_0 + getDeviceIndex(event.cbutton.which); + NativeKey(key); } - break; } - case SDL_CONTROLLERBUTTONUP: - { - if (event.cbutton.which == player1JoyInstanceID && event.cbutton.state == SDL_RELEASED) - { - keycode_t code = getKeycodeForButton((SDL_GameControllerButton)event.cbutton.button); - if (code != NKCODE_UNKNOWN) - { - KeyInput key; - key.flags = KEY_UP; - key.keyCode = code; - key.deviceId = DEVICE_ID_PAD_0 + getDeviceIndex(event.cbutton.which); - NativeKey(key); - } + break; + case SDL_CONTROLLERBUTTONUP: + if (event.cbutton.state == SDL_RELEASED) { + keycode_t code = getKeycodeForButton((SDL_GameControllerButton)event.cbutton.button); + if (code != NKCODE_UNKNOWN) { + KeyInput key; + key.flags = KEY_UP; + key.keyCode = code; + key.deviceId = DEVICE_ID_PAD_0 + getDeviceIndex(event.cbutton.which); + NativeKey(key); } - break; } - case SDL_CONTROLLERAXISMOTION: - { - if (event.caxis.which == player1JoyInstanceID) - { - AxisInput axis; - axis.axisId = event.caxis.axis; - // 1.2 to try to approximate the PSP's clamped rectangular range. - axis.value = 1.2 * event.caxis.value / 32767.0f; - if (axis.value > 1.0f) axis.value = 1.0f; - if (axis.value < -1.0f) axis.value = -1.0f; - axis.deviceId = DEVICE_ID_PAD_0 + getDeviceIndex(event.caxis.which); - axis.flags = 0; - NativeAxis(axis); + break; + case SDL_CONTROLLERAXISMOTION: + AxisInput axis; + axis.axisId = event.caxis.axis; + // 1.2 to try to approximate the PSP's clamped rectangular range. + axis.value = 1.2 * event.caxis.value / 32767.0f; + if (axis.value > 1.0f) axis.value = 1.0f; + if (axis.value < -1.0f) axis.value = -1.0f; + axis.deviceId = DEVICE_ID_PAD_0 + getDeviceIndex(event.caxis.which); + axis.flags = 0; + NativeAxis(axis); + break; + case SDL_CONTROLLERDEVICEREMOVED: + // for removal events, "which" is the instance ID for SDL_CONTROLLERDEVICEREMOVED + SDL_GameController *removeThisController; + for (auto & controller : controllers) { + if (SDL_JoystickInstanceID(SDL_GameControllerGetJoystick(controller)) == event.cdevice.which) { + printf("control pad %s has been disconnected\n", SDL_GameControllerName(controller)); + removeThisController = controller; + SDL_GameControllerClose(controller); break; } } - case SDL_CONTROLLERDEVICEREMOVED: - { - // for removal events, "which" is the instance ID for SDL_CONTROLLERDEVICEREMOVED - if (event.cdevice.which == player1JoyInstanceID) - { - printf("control pad removed for player 1\n"); - if (player1Controller){ - SDL_GameControllerClose(player1Controller); - player1Controller = NULL; - } - // are there any other control pads we could use? - setUpPlayer1(); - } - break; + if (removeThisController) { + controllers.erase(std::remove(controllers.begin(), controllers.end(), removeThisController), controllers.end()); } - case SDL_CONTROLLERDEVICEADDED: - { - // for add events, "which" is the device index! - if (!player1Controller) - { - if (SDL_IsGameController(event.cdevice.which)) - { - player1Controller = SDL_GameControllerOpen(event.cdevice.which); - SDL_GameControllerEventState(SDL_ENABLE); - if (player1Controller && SDL_GameControllerGetAttached(player1Controller)) - { - player1JoyInstanceID = SDL_JoystickInstanceID(SDL_GameControllerGetJoystick(player1Controller)); - printf("Player 1 will be using control pad: %s, instance ID: %d\n", SDL_GameControllerName(player1Controller), player1JoyInstanceID); - char *mapping = SDL_GameControllerMapping(player1Controller); - if (mapping == NULL) - { - printf("control pad %s is not in the game controller database, unable to set mappings!\n", SDL_GameControllerName(player1Controller)); - } - else - { - printf("control pad mapping: %s\n", SDL_GameControllerMapping(player1Controller)); - } - } - else - { - printf("Error! Could not open controller\n"); - } - } - } - break; + break; + case SDL_CONTROLLERDEVICEADDED: + // for add events, "which" is the device index! + int prevNumControllers = controllers.size(); + setUpController(event.cdevice.which); + if (prevNumControllers == 0 && controllers.size() > 0) { + printf("Pad 1 has been assigned to control pad: %s\n", SDL_GameControllerName(controllers.front())); } + break; } } int SDLJoystick::getDeviceIndex(int instanceId) { - int numjoys = SDL_NumJoysticks(); - SDL_Joystick *joy; - for (int i = 0; i < numjoys; i++) - { - joy = SDL_JoystickOpen(i); - if (SDL_JoystickInstanceID(joy) == instanceId) - { - SDL_JoystickClose(joy); - return i; - } - SDL_JoystickClose(joy); + std::map::iterator it = controllerDeviceMap.find(instanceId); + if (it == controllerDeviceMap.end()) { + // could not find device + return -1; } - return -1; + return it->second; } -void SDLJoystick::runLoop(){ - while (running){ +void SDLJoystick::runLoop() { + while (running) { SDL_Event evt; int res = SDL_WaitEvent(&evt); - if (res){ + if (res) { ProcessInput(evt); } } diff --git a/SDL/SDLJoystick.h b/SDL/SDLJoystick.h index ed4227bc1..0fadc5bde 100644 --- a/SDL/SDLJoystick.h +++ b/SDL/SDLJoystick.h @@ -1,5 +1,4 @@ #pragma once - #ifdef _WIN32 #include "SDL/SDL.h" #include "SDL/SDL_thread.h" @@ -8,6 +7,7 @@ #include "SDL_thread.h" #endif +#include #include "input/input_state.h" #include "input/keycodes.h" #include "net/resolve.h" @@ -29,12 +29,12 @@ public: private: void runLoop(); - void setUpPlayer1(); + void setUpController(int deviceIndex); + void setUpControllers(); keycode_t getKeycodeForButton(SDL_GameControllerButton button); int getDeviceIndex(int instanceId); SDL_Thread *thread ; bool running ; - SDL_GameController *player1Controller; - SDL_JoystickID player1JoyInstanceID; - + std::vector controllers; + std::map controllerDeviceMap; }; From 182b9e0fdae35d801c526ff10769c69a9d88764f Mon Sep 17 00:00:00 2001 From: Neil Munday Date: Tue, 20 Sep 2016 21:50:45 +0100 Subject: [PATCH 4/5] Various improvements including finding the assets directory properly. --- SDL/SDLJoystick.cpp | 48 +++++++++++++++++++++++---------------------- SDL/SDLJoystick.h | 1 - 2 files changed, 25 insertions(+), 24 deletions(-) diff --git a/SDL/SDLJoystick.cpp b/SDL/SDLJoystick.cpp index 5907da925..1cde440ca 100644 --- a/SDL/SDLJoystick.cpp +++ b/SDL/SDLJoystick.cpp @@ -1,7 +1,11 @@ #include "SDL/SDLJoystick.h" #include "Core/Config.h" +#include "Common/FileUtil.h" #include +#include + +using namespace std; extern "C" { int SDLJoystickThreadWrapper(void *SDLJoy){ @@ -17,10 +21,13 @@ SDLJoystick::SDLJoystick(bool init_SDL ): thread(NULL), running(true) { SDL_Init(SDL_INIT_JOYSTICK | SDL_INIT_VIDEO | SDL_INIT_GAMECONTROLLER); } - if (SDL_GameControllerAddMappingsFromFile("assets/gamecontrollerdb.txt") == -1) { - printf("Failed to load control pad mappings, please place gamecontrollerdb.txt in your assets directory\n"); + auto dbPath = File::GetExeDirectory() + "assets/gamecontrollerdb.txt"; + cout << "loading control pad mappings from " << dbPath << ": "; + + if (SDL_GameControllerAddMappingsFromFile(dbPath.c_str()) == -1) { + cout << "FAILED! Please place gamecontrollerdb.txt in your assets directory." << endl; } else { - printf("Loaded game controller mappings for SDL2\n"); + cout << "SUCCESS!" << endl; setUpControllers(); } } @@ -31,7 +38,7 @@ void SDLJoystick::setUpControllers() { setUpController(i); } if (controllers.size() > 0) { - printf("Pad 1 has been assigned to control pad: %s\n", SDL_GameControllerName(controllers.front())); + cout << "pad 1 has been assigned to control pad: " << SDL_GameControllerName(controllers.front()) << endl; } } @@ -42,12 +49,12 @@ void SDLJoystick::setUpController(int deviceIndex) { if (SDL_GameControllerGetAttached(controller)) { controllers.push_back(controller); controllerDeviceMap[SDL_JoystickInstanceID(SDL_GameControllerGetJoystick(controller))] = deviceIndex; - printf("found control pad: %s, loading mapping: ", SDL_GameControllerName(controller)); - char *mapping = SDL_GameControllerMapping(controller); + cout << "found control pad: " << SDL_GameControllerName(controller) << ", loading mapping: "; + auto mapping = SDL_GameControllerMapping(controller); if (mapping == NULL) { - printf("FAILED\n"); + cout << "FAILED" << endl; } else { - printf("SUCCESS, mapping is:\n%s\n", mapping); + cout << "SUCCESS, mapping is:" << endl << mapping << endl; } } else { SDL_GameControllerClose(controller); @@ -64,7 +71,7 @@ SDLJoystick::~SDLJoystick() { SDL_PushEvent(&evt); SDL_WaitThread(thread,0); } - for (SDL_GameController *controller : controllers) { + for (auto & controller : controllers) { SDL_GameControllerClose(controller); } } @@ -109,7 +116,7 @@ void SDLJoystick::ProcessInput(SDL_Event &event){ switch (event.type) { case SDL_CONTROLLERBUTTONDOWN: if (event.cbutton.state == SDL_PRESSED) { - keycode_t code = getKeycodeForButton((SDL_GameControllerButton)event.cbutton.button); + auto code = getKeycodeForButton((SDL_GameControllerButton)event.cbutton.button); if (code != NKCODE_UNKNOWN) { KeyInput key; key.flags = KEY_DOWN; @@ -121,7 +128,7 @@ void SDLJoystick::ProcessInput(SDL_Event &event){ break; case SDL_CONTROLLERBUTTONUP: if (event.cbutton.state == SDL_RELEASED) { - keycode_t code = getKeycodeForButton((SDL_GameControllerButton)event.cbutton.button); + auto code = getKeycodeForButton((SDL_GameControllerButton)event.cbutton.button); if (code != NKCODE_UNKNOWN) { KeyInput key; key.flags = KEY_UP; @@ -143,33 +150,28 @@ void SDLJoystick::ProcessInput(SDL_Event &event){ NativeAxis(axis); break; case SDL_CONTROLLERDEVICEREMOVED: - // for removal events, "which" is the instance ID for SDL_CONTROLLERDEVICEREMOVED - SDL_GameController *removeThisController; - for (auto & controller : controllers) { - if (SDL_JoystickInstanceID(SDL_GameControllerGetJoystick(controller)) == event.cdevice.which) { - printf("control pad %s has been disconnected\n", SDL_GameControllerName(controller)); - removeThisController = controller; - SDL_GameControllerClose(controller); + // for removal events, "which" is the instance ID for SDL_CONTROLLERDEVICEREMOVED + for (auto it = controllers.begin(); it != controllers.end(); ++it) { + if (SDL_JoystickInstanceID(SDL_GameControllerGetJoystick(*it)) == event.cdevice.which) { + SDL_GameControllerClose(*it); + controllers.erase(it); break; } } - if (removeThisController) { - controllers.erase(std::remove(controllers.begin(), controllers.end(), removeThisController), controllers.end()); - } break; case SDL_CONTROLLERDEVICEADDED: // for add events, "which" is the device index! int prevNumControllers = controllers.size(); setUpController(event.cdevice.which); if (prevNumControllers == 0 && controllers.size() > 0) { - printf("Pad 1 has been assigned to control pad: %s\n", SDL_GameControllerName(controllers.front())); + cout << "pad 1 has been assigned to control pad: " << SDL_GameControllerName(controllers.front()) << endl; } break; } } int SDLJoystick::getDeviceIndex(int instanceId) { - std::map::iterator it = controllerDeviceMap.find(instanceId); + auto it = controllerDeviceMap.find(instanceId); if (it == controllerDeviceMap.end()) { // could not find device return -1; diff --git a/SDL/SDLJoystick.h b/SDL/SDLJoystick.h index 0fadc5bde..c91ac90bb 100644 --- a/SDL/SDLJoystick.h +++ b/SDL/SDLJoystick.h @@ -7,7 +7,6 @@ #include "SDL_thread.h" #endif -#include #include "input/input_state.h" #include "input/keycodes.h" #include "net/resolve.h" From 7d9eed90e8c07c2ccb1e48d69abf94a8f48e1eff Mon Sep 17 00:00:00 2001 From: Neil Munday Date: Tue, 20 Sep 2016 22:04:01 +0100 Subject: [PATCH 5/5] Added installation of the SDL game controller database to CMakeLists.txt --- CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 12b7b7874..eac01bcc0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1686,6 +1686,7 @@ set(NativeAssets assets/ppge_atlas.zim assets/compat.ini assets/langregion.ini + assets/gamecontrollerdb.txt assets/unknown.png) set(LinkCommon ${CoreLibName} ${CMAKE_THREAD_LIBS_INIT} ${nativeExtraLibs})