From 9da843c994a6d65fe4f205ec820ac03d3836cbfb Mon Sep 17 00:00:00 2001 From: Gregory Hainaut Date: Sun, 16 Apr 2017 14:57:23 +0200 Subject: [PATCH] onepad: plug SDL2 API game controller --- plugins/onepad/GamePad.cpp | 10 -- plugins/onepad/GamePad.h | 17 ++- plugins/onepad/Linux/linux.cpp | 12 ++ plugins/onepad/SDL/joystick.cpp | 198 +++++++++++++++++++++++++++----- plugins/onepad/SDL/joystick.h | 14 ++- 5 files changed, 196 insertions(+), 55 deletions(-) diff --git a/plugins/onepad/GamePad.cpp b/plugins/onepad/GamePad.cpp index 0582e82139..edb0b2f627 100644 --- a/plugins/onepad/GamePad.cpp +++ b/plugins/onepad/GamePad.cpp @@ -35,13 +35,3 @@ void GamePad::DoRumble(int type, int pad) s_vgamePad[id]->Rumble(type, pad); } } - -/** - * Update state of every attached devices - **/ -void GamePad::UpdateGamePadState() -{ -#ifdef SDL_BUILD - SDL_JoystickUpdate(); // No need to make yet another function call for that -#endif -} diff --git a/plugins/onepad/GamePad.h b/plugins/onepad/GamePad.h index bbc957140a..048e027640 100644 --- a/plugins/onepad/GamePad.h +++ b/plugins/onepad/GamePad.h @@ -10,8 +10,7 @@ class GamePad { public: GamePad() - : devname("") - , deadzone(1500) + : m_deadzone(1500) { } @@ -31,7 +30,7 @@ public: /* * Update state of every attached devices */ - static void UpdateGamePadState(); + virtual void UpdateGamePadState() = 0; /* * Causes devices to rumble @@ -50,19 +49,17 @@ public: */ virtual bool TestForce(float strength = 0.6) { return false; } - const string &GetName() - { - return devname; - } + virtual const char *GetName() = 0; + + virtual int GetInput(gamePadValues input) = 0; virtual int GetDeadzone() { - return deadzone; + return m_deadzone; } protected: - string devname; // pretty device name - int deadzone; + int m_deadzone; }; extern std::vector> s_vgamePad; diff --git a/plugins/onepad/Linux/linux.cpp b/plugins/onepad/Linux/linux.cpp index dce458b925..e729027b52 100644 --- a/plugins/onepad/Linux/linux.cpp +++ b/plugins/onepad/Linux/linux.cpp @@ -86,6 +86,18 @@ void PollForJoystickInput(int cpad) int joyid = conf->get_joyid(cpad); if (!GamePadIdWithinBounds(joyid)) return; + + auto &gamePad = s_vgamePad[joyid]; + + gamePad->UpdateGamePadState(); + + for (int i = 0; i < MAX_KEYS; i++) { + s32 value = gamePad->GetInput((gamePadValues)i); + if (value != 0) + key_status->press(cpad, i, value); + else + key_status->release(cpad, i); + } } EXPORT_C_(void) diff --git a/plugins/onepad/SDL/joystick.cpp b/plugins/onepad/SDL/joystick.cpp index 6b790986c6..f5a2cd90cc 100644 --- a/plugins/onepad/SDL/joystick.cpp +++ b/plugins/onepad/SDL/joystick.cpp @@ -29,20 +29,23 @@ // opens handles to all possible joysticks void JoystickInfo::EnumerateJoysticks(std::vector> &vjoysticks) { - if (!s_bSDLInit) { + uint32_t flag = SDL_INIT_JOYSTICK | SDL_INIT_HAPTIC | SDL_INIT_EVENTS | SDL_INIT_GAMECONTROLLER; + + if ((SDL_WasInit(0) & flag) != flag) { // Tell SDL to catch event even if the windows isn't focussed SDL_SetHint(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, "1"); - if (SDL_Init(SDL_INIT_JOYSTICK | SDL_INIT_HAPTIC | SDL_INIT_EVENTS) < 0) + + if (SDL_Init(flag) < 0) return; // WTF! Give me back the control of my system struct sigaction action = {0}; action.sa_handler = SIG_DFL; - sigaction(SIGINT, &action, NULL); - sigaction(SIGTERM, &action, NULL); + sigaction(SIGINT, &action, nullptr); + sigaction(SIGTERM, &action, nullptr); SDL_JoystickEventState(SDL_QUERY); - s_bSDLInit = true; + SDL_GameControllerEventState(SDL_QUERY); } vjoysticks.clear(); @@ -79,7 +82,7 @@ void JoystickInfo::Rumble(int type, int pad) if (!(conf->pad_options[pad].forcefeedback)) return; - if (haptic == NULL) + if (haptic == nullptr) return; if (first) { // If done multiple times, device memory will be filled @@ -115,18 +118,19 @@ void JoystickInfo::Rumble(int type, int pad) void JoystickInfo::Destroy() { - if (joy != NULL) { - // Haptic must be closed before the joystick - if (haptic != NULL) { - SDL_HapticClose(haptic); - haptic = NULL; - } + // Haptic must be closed before the joystick + if (haptic != nullptr) { + SDL_HapticClose(haptic); + haptic = nullptr; + } -#if SDL_MINOR_VERSION >= 4 // Version before 2.0.4 are bugged, JoystickClose crashes randomly - if (joy) - SDL_JoystickClose(joy); + if (m_controller != nullptr) { +#if SDL_MINOR_VERSION >= 4 + // Version before 2.0.4 are bugged, JoystickClose crashes randomly + // Note: GameControllerClose calls JoystickClose) + SDL_GameControllerClose(m_controller); #endif - joy = NULL; + m_controller = nullptr; } } @@ -134,31 +138,54 @@ bool JoystickInfo::Init(int id) { Destroy(); - joy = SDL_JoystickOpen(id); - if (joy == NULL) { - PAD_LOG("failed to open joystick %d\n", id); + SDL_Joystick *joy = nullptr; + + if (SDL_IsGameController(id)) { + m_controller = SDL_GameControllerOpen(id); + joy = SDL_GameControllerGetJoystick(m_controller); + } else { + m_controller = nullptr; + joy = SDL_JoystickOpen(id); + } + + if (joy == nullptr) { + fprintf(stderr, "onepad:failed to open joystick %d\n", id); return false; } - devname = SDL_JoystickName(joy); + // Collect Device Information + char guid[64]; + SDL_JoystickGetGUIDString(SDL_JoystickGetGUID(joy), guid, 64); + const char *devname = SDL_JoystickNameForIndex(id); - if (haptic == NULL) { - if (!SDL_JoystickIsHaptic(joy)) { - PAD_LOG("Haptic devices not supported!\n"); - } else { - haptic = SDL_HapticOpenFromJoystick(joy); - first = true; - } + if (m_controller == nullptr) { + fprintf(stderr, "onepad: Joystick (%s,GUID:%s) isn't yet supported by the SDL2 game controller API\n" + "Fortunately you can use AntiMicro (https://github.com/AntiMicro/antimicro) or Steam to configure your joystick\n" + "Please report it to us (https://github.com/PCSX2/pcsx2/issues) so we can add your joystick to our internal database.", + devname, guid); + return false; } - //PAD_LOG("There are %d buttons, %d axises, and %d hats.\n", numbuttons, numaxes, numhats); + if (haptic == nullptr && SDL_JoystickIsHaptic(joy)) { + haptic = SDL_HapticOpenFromJoystick(joy); + first = true; + } + + fprintf(stdout, "onepad: controller (%s) detected%s, GUID:%s\n", + devname, haptic ? " with rumble support" : "", guid); + return true; } +const char *JoystickInfo::GetName() +{ + return SDL_JoystickName(SDL_GameControllerGetJoystick(m_controller)); +} + bool JoystickInfo::TestForce(float strength = 0.60) { // This code just use standard rumble to check that SDL handles the pad correctly! --3kinox - if (haptic == NULL) + if (haptic == nullptr) return false; // Otherwise, core dump! SDL_HapticRumbleInit(haptic); // Make the haptic pad rumble 60% strength for half a second, shoudld be enough for user to see if it works or not @@ -169,3 +196,116 @@ bool JoystickInfo::TestForce(float strength = 0.60) return true; } + +int JoystickInfo::GetInput(gamePadValues input) +{ + int value = 0; + + // Handle standard button + switch (input) { + case PAD_L1: + value = SDL_GameControllerGetButton(m_controller, SDL_CONTROLLER_BUTTON_LEFTSHOULDER); + break; + case PAD_R1: + value = SDL_GameControllerGetButton(m_controller, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER); + break; + case PAD_TRIANGLE: + value = SDL_GameControllerGetButton(m_controller, SDL_CONTROLLER_BUTTON_Y); + break; + case PAD_CIRCLE: + value = SDL_GameControllerGetButton(m_controller, SDL_CONTROLLER_BUTTON_B); + break; + case PAD_CROSS: + value = SDL_GameControllerGetButton(m_controller, SDL_CONTROLLER_BUTTON_A); + break; + case PAD_SQUARE: + value = SDL_GameControllerGetButton(m_controller, SDL_CONTROLLER_BUTTON_X); + break; + case PAD_SELECT: + value = SDL_GameControllerGetButton(m_controller, SDL_CONTROLLER_BUTTON_BACK); + break; + case PAD_L3: + value = SDL_GameControllerGetButton(m_controller, SDL_CONTROLLER_BUTTON_LEFTSTICK); + break; + case PAD_R3: + value = SDL_GameControllerGetButton(m_controller, SDL_CONTROLLER_BUTTON_RIGHTSTICK); + break; + case PAD_START: + value = SDL_GameControllerGetButton(m_controller, SDL_CONTROLLER_BUTTON_START); + break; + case PAD_UP: + value = SDL_GameControllerGetButton(m_controller, SDL_CONTROLLER_BUTTON_DPAD_UP); + break; + case PAD_RIGHT: + value = SDL_GameControllerGetButton(m_controller, SDL_CONTROLLER_BUTTON_DPAD_RIGHT); + break; + case PAD_DOWN: + value = SDL_GameControllerGetButton(m_controller, SDL_CONTROLLER_BUTTON_DPAD_DOWN); + break; + case PAD_LEFT: + value = SDL_GameControllerGetButton(m_controller, SDL_CONTROLLER_BUTTON_DPAD_LEFT); + break; + default: + break; + } + + // Return max pressure for button + if (value) + return 0xFF; + + // Handle trigger + switch (input) { + case PAD_L2: + value = SDL_GameControllerGetAxis(m_controller, SDL_CONTROLLER_AXIS_TRIGGERLEFT); + break; + case PAD_R2: + value = SDL_GameControllerGetAxis(m_controller, SDL_CONTROLLER_AXIS_TRIGGERRIGHT); + break; + default: + break; + } + + // Note SDL values range from 0 to 32768 for trigger + if (value > m_deadzone) { + return value / 128; + } else { + value = 0; + } + + // Handle analog input + switch (input) { + case PAD_L_UP: + value = SDL_GameControllerGetAxis(m_controller, SDL_CONTROLLER_AXIS_LEFTY); + break; + case PAD_L_RIGHT: + value = SDL_GameControllerGetAxis(m_controller, SDL_CONTROLLER_AXIS_LEFTX); + break; + case PAD_L_DOWN: + value = SDL_GameControllerGetAxis(m_controller, SDL_CONTROLLER_AXIS_LEFTY); + break; + case PAD_L_LEFT: + value = SDL_GameControllerGetAxis(m_controller, SDL_CONTROLLER_AXIS_LEFTX); + break; + case PAD_R_UP: + value = SDL_GameControllerGetAxis(m_controller, SDL_CONTROLLER_AXIS_RIGHTY); + break; + case PAD_R_RIGHT: + value = SDL_GameControllerGetAxis(m_controller, SDL_CONTROLLER_AXIS_RIGHTX); + break; + case PAD_R_DOWN: + value = SDL_GameControllerGetAxis(m_controller, SDL_CONTROLLER_AXIS_RIGHTY); + break; + case PAD_R_LEFT: + value = SDL_GameControllerGetAxis(m_controller, SDL_CONTROLLER_AXIS_RIGHTX); + break; + default: + break; + } + + return (abs(value) > m_deadzone) ? value : 0; +} + +void JoystickInfo::UpdateGamePadState() +{ + SDL_GameControllerUpdate(); +} diff --git a/plugins/onepad/SDL/joystick.h b/plugins/onepad/SDL/joystick.h index 082cb5a5c6..1d7466f3e9 100644 --- a/plugins/onepad/SDL/joystick.h +++ b/plugins/onepad/SDL/joystick.h @@ -34,7 +34,7 @@ class JoystickInfo : GamePad public: JoystickInfo(int id) : GamePad() - , joy(nullptr) + , m_controller(nullptr) { haptic = nullptr; first = true; @@ -62,14 +62,16 @@ public: bool TestForce(float); + virtual const char *GetName(); + + virtual int GetInput(gamePadValues input); + + virtual void UpdateGamePadState(); + private: - SDL_Joystick *GetJoy() - { - return joy; - } void GenerateDefaultEffect(); - SDL_Joystick *joy; + SDL_GameController *m_controller; SDL_Haptic *haptic; bool first; SDL_HapticEffect effects[NB_EFFECT];