mirror of https://github.com/PCSX2/pcsx2.git
onepad: plug SDL2 API game controller
This commit is contained in:
parent
35b162adbf
commit
9da843c994
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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) {
|
||||
if (haptic != nullptr) {
|
||||
SDL_HapticClose(haptic);
|
||||
haptic = NULL;
|
||||
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();
|
||||
|
||||
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 == NULL) {
|
||||
PAD_LOG("failed to open joystick %d\n", 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 {
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
//PAD_LOG("There are %d buttons, %d axises, and %d hats.\n", numbuttons, numaxes, numhats);
|
||||
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();
|
||||
}
|
||||
|
|
|
@ -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];
|
||||
|
|
Loading…
Reference in New Issue