onepad: plug SDL2 API game controller

This commit is contained in:
Gregory Hainaut 2017-04-16 14:57:23 +02:00
parent 35b162adbf
commit 9da843c994
5 changed files with 196 additions and 55 deletions

View File

@ -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
}

View File

@ -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<std::unique_ptr<GamePad>> s_vgamePad;

View File

@ -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)

View File

@ -29,20 +29,23 @@
// opens handles to all possible joysticks
void JoystickInfo::EnumerateJoysticks(std::vector<std::unique_ptr<GamePad>> &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();
}

View File

@ -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];