onepad: Move init/destroy code to constructor/destructor

* prefix remaining member with m_
* Use array for m_effect_id
* Properly Destroy/Close Haptic/Joystick/Game Controller
 (except on older SDL versions which are buggy)
This commit is contained in:
Gregory Hainaut 2017-04-14 20:14:42 +02:00
parent 4b24cfa5ea
commit 2e09c7faf3
7 changed files with 118 additions and 134 deletions

View File

@ -28,7 +28,7 @@ void GamePad::EnumerateGamePads(std::vector<std::unique_ptr<GamePad>> &vgamePad)
/** /**
* Safely dispatch to the Rumble method above * Safely dispatch to the Rumble method above
**/ **/
void GamePad::DoRumble(int type, int pad) void GamePad::DoRumble(unsigned type, unsigned pad)
{ {
u32 id = conf->get_joyid(pad); u32 id = conf->get_joyid(pad);
if (GamePadIdWithinBounds(id)) { if (GamePadIdWithinBounds(id)) {

View File

@ -36,13 +36,11 @@ public:
* Causes devices to rumble * Causes devices to rumble
* Rumble will differ according to type which is either 0(small motor) or 1(big motor) * Rumble will differ according to type which is either 0(small motor) or 1(big motor)
*/ */
virtual void Rumble(int type, int pad) { return; } virtual void Rumble(unsigned type, unsigned pad) { return; }
/* /*
* Safely dispatch to the Rumble method above * Safely dispatch to the Rumble method above
*/ */
static void DoRumble(int type, int pad); static void DoRumble(unsigned type, unsigned pad);
virtual bool Init(int id) { return false; } // opens a handle and gets information
/* /*
* Used for GUI checkbox to give feedback to the user * Used for GUI checkbox to give feedback to the user

View File

@ -70,8 +70,84 @@ void JoystickInfo::EnumerateJoysticks(std::vector<std::unique_ptr<GamePad>> &vjo
} }
} }
void JoystickInfo::GenerateDefaultEffect() void JoystickInfo::Rumble(unsigned type, unsigned pad)
{ {
if (type >= m_effects_id.size())
return;
if (!(conf->pad_options[pad].forcefeedback))
return;
if (m_haptic == nullptr)
return;
int id = m_effects_id[type];
if (SDL_HapticRunEffect(m_haptic, id, 1) != 0) {
fprintf(stderr, "ERROR: Effect is not working! %s, id is %d\n", SDL_GetError(), id);
}
}
JoystickInfo::~JoystickInfo()
{
// Haptic must be closed before the joystick
if (m_haptic != nullptr) {
for (const auto &eid : m_effects_id) {
if (eid >= 0)
SDL_HapticDestroyEffect(m_haptic, eid);
}
SDL_HapticClose(m_haptic);
}
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
}
}
JoystickInfo::JoystickInfo(int id)
: GamePad()
, m_controller(nullptr)
, m_haptic(nullptr)
{
SDL_Joystick *joy = nullptr;
m_effects_id.fill(-1);
if (SDL_IsGameController(id)) {
m_controller = SDL_GameControllerOpen(id);
joy = SDL_GameControllerGetJoystick(m_controller);
} else {
joy = SDL_JoystickOpen(id);
}
if (joy == nullptr) {
fprintf(stderr, "onepad:failed to open joystick %d\n", id);
return;
}
// Collect Device Information
char guid[64];
SDL_JoystickGetGUIDString(SDL_JoystickGetGUID(joy), guid, 64);
const char *devname = SDL_JoystickNameForIndex(id);
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);
#if SDL_MINOR_VERSION >= 4 // Version before 2.0.4 are bugged, JoystickClose crashes randomly
SDL_JoystickClose(joy);
#endif
return;
}
// Default haptic effect
SDL_HapticEffect effects[NB_EFFECT];
for (int i = 0; i < NB_EFFECT; i++) { for (int i = 0; i < NB_EFFECT; i++) {
SDL_HapticEffect effect; SDL_HapticEffect effect;
memset(&effect, 0, sizeof(SDL_HapticEffect)); // 0 is safe default memset(&effect, 0, sizeof(SDL_HapticEffect)); // 0 is safe default
@ -86,110 +162,37 @@ void JoystickInfo::GenerateDefaultEffect()
effect.periodic.length = 125; // 125ms feels quite near to original effect.periodic.length = 125; // 125ms feels quite near to original
effect.periodic.delay = 0; effect.periodic.delay = 0;
effect.periodic.attack_length = 0; effect.periodic.attack_length = 0;
effects[i] = effect;
}
}
void JoystickInfo::Rumble(int type, int pad)
{
if (type > 1)
return;
if (!(conf->pad_options[pad].forcefeedback))
return;
if (haptic == nullptr)
return;
if (first) { // If done multiple times, device memory will be filled
first = 0;
GenerateDefaultEffect();
/* Sine and triangle are quite probably the best, don't change that lightly and if you do /* Sine and triangle are quite probably the best, don't change that lightly and if you do
* keep effects ordered by type * keep effects ordered by type
*/ */
/* Effect for small motor */ if (i == 0) {
/* Sine seems to be the only effect making little motor from DS3/4 react /* Effect for small motor */
* Intensity has pretty much no effect either(which is coherent with what is explain in hid_sony driver /* Sine seems to be the only effect making little motor from DS3/4 react
*/ * Intensity has pretty much no effect either(which is coherent with what is explain in hid_sony driver
effects[0].type = SDL_HAPTIC_SINE; */
effects_id[0] = SDL_HapticNewEffect(haptic, &effects[0]); effect.type = SDL_HAPTIC_SINE;
if (effects_id[0] < 0) { } else {
fprintf(stderr, "ERROR: Effect is not uploaded! %s, id is %d\n", SDL_GetError(), effects_id[0]); /** Effect for big motor **/
effect.type = SDL_HAPTIC_TRIANGLE;
} }
/** Effect for big motor **/ effects[i] = effect;
effects[1].type = SDL_HAPTIC_TRIANGLE; }
effects_id[1] = SDL_HapticNewEffect(haptic, &effects[1]);
if (effects_id[1] < 0) { if (SDL_JoystickIsHaptic(joy)) {
fprintf(stderr, "ERROR: Effect is not uploaded! %s, id is %d\n", SDL_GetError(), effects_id[1]); m_haptic = SDL_HapticOpenFromJoystick(joy);
for (auto &eid : m_effects_id) {
eid = SDL_HapticNewEffect(m_haptic, &effects[0]);
if (eid < 0) {
fprintf(stderr, "ERROR: Effect is not uploaded! %s\n", SDL_GetError());
return;
}
} }
} }
int id;
id = effects_id[type];
if (SDL_HapticRunEffect(haptic, id, 1) != 0) {
fprintf(stderr, "ERROR: Effect is not working! %s, id is %d\n", SDL_GetError(), id);
}
}
void JoystickInfo::Destroy()
{
// Haptic must be closed before the joystick
if (haptic != nullptr) {
SDL_HapticClose(haptic);
haptic = nullptr;
}
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
m_controller = nullptr;
}
}
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 == nullptr) {
fprintf(stderr, "onepad:failed to open joystick %d\n", id);
return false;
}
// Collect Device Information
char guid[64];
SDL_JoystickGetGUIDString(SDL_JoystickGetGUID(joy), guid, 64);
const char *devname = SDL_JoystickNameForIndex(id);
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", fprintf(stdout, "onepad: controller (%s) detected%s, GUID:%s\n",
devname, haptic ? " with rumble support" : "", guid); devname, m_haptic ? " with rumble support" : "", guid);
return true;
} }
const char *JoystickInfo::GetName() const char *JoystickInfo::GetName()
@ -200,11 +203,13 @@ const char *JoystickInfo::GetName()
bool JoystickInfo::TestForce(float strength = 0.60) bool JoystickInfo::TestForce(float strength = 0.60)
{ {
// This code just use standard rumble to check that SDL handles the pad correctly! --3kinox // This code just use standard rumble to check that SDL handles the pad correctly! --3kinox
if (haptic == nullptr) if (m_haptic == nullptr)
return false; // Otherwise, core dump! return false; // Otherwise, core dump!
SDL_HapticRumbleInit(haptic);
SDL_HapticRumbleInit(m_haptic);
// Make the haptic pad rumble 60% strength for half a second, shoudld be enough for user to see if it works or not // Make the haptic pad rumble 60% strength for half a second, shoudld be enough for user to see if it works or not
if (SDL_HapticRumblePlay(haptic, strength, 400) != 0) { if (SDL_HapticRumblePlay(m_haptic, strength, 400) != 0) {
fprintf(stderr, "ERROR: Rumble is not working! %s\n", SDL_GetError()); fprintf(stderr, "ERROR: Rumble is not working! %s\n", SDL_GetError());
return false; return false;
} }

View File

@ -32,33 +32,17 @@
class JoystickInfo : GamePad class JoystickInfo : GamePad
{ {
public: public:
JoystickInfo(int id) JoystickInfo(int id);
: GamePad() ~JoystickInfo();
, m_controller(nullptr)
{
haptic = nullptr;
first = true;
memset(effects, 0, sizeof(effects));
memset(effects_id, 0, sizeof(effects_id));
Init(id);
}
~JoystickInfo()
{
Destroy();
}
JoystickInfo(const JoystickInfo &) = delete; // copy constructor JoystickInfo(const JoystickInfo &) = delete; // copy constructor
JoystickInfo &operator=(const JoystickInfo &) = delete; // assignment JoystickInfo &operator=(const JoystickInfo &) = delete; // assignment
void Destroy();
// opens handles to all possible joysticks // opens handles to all possible joysticks
static void EnumerateJoysticks(std::vector<std::unique_ptr<GamePad>> &vjoysticks); static void EnumerateJoysticks(std::vector<std::unique_ptr<GamePad>> &vjoysticks);
void Rumble(int type, int pad); void Rumble(unsigned type, unsigned pad);
bool Init(int id); // opens a handle and gets information
bool TestForce(float); bool TestForce(float);
@ -69,11 +53,7 @@ public:
virtual void UpdateGamePadState(); virtual void UpdateGamePadState();
private: private:
void GenerateDefaultEffect();
SDL_GameController *m_controller; SDL_GameController *m_controller;
SDL_Haptic *haptic; SDL_Haptic *m_haptic;
bool first; std::array<int, NB_EFFECT> m_effects_id;
SDL_HapticEffect effects[NB_EFFECT];
int effects_id[NB_EFFECT];
}; };

View File

@ -40,6 +40,7 @@
#endif #endif
#include <array>
#include <vector> #include <vector>
#include <map> #include <map>
#include <string> #include <string>

View File

@ -117,9 +117,9 @@ void Pad::reset()
reset_vibrate(); reset_vibrate();
} }
void Pad::rumble(int port) void Pad::rumble(unsigned port)
{ {
for (int motor = 0; motor < 2; motor++) { for (unsigned motor = 0; motor < 2; motor++) {
// TODO: Probably be better to send all of these at once. // TODO: Probably be better to send all of these at once.
if (nextVibrate[motor] | currentVibrate[motor]) { if (nextVibrate[motor] | currentVibrate[motor]) {
currentVibrate[motor] = nextVibrate[motor]; currentVibrate[motor] = nextVibrate[motor];
@ -152,8 +152,8 @@ void Pad::reset_all()
void Pad::rumble_all() void Pad::rumble_all()
{ {
for (int port = 0; port < 2; port++) for (unsigned port = 0; port < 2; port++)
for (int slot = 0; slot < 4; slot++) for (unsigned slot = 0; slot < 4; slot++)
pads[port][slot].rumble(port); pads[port][slot].rumble(port);
} }

View File

@ -88,7 +88,7 @@ class Pad : public PadFreezeData
public: public:
// Lilypad store here the state of PC pad // Lilypad store here the state of PC pad
void rumble(int port); void rumble(unsigned port);
void set_vibrate(int motor, u8 val); void set_vibrate(int motor, u8 val);
void reset_vibrate(); void reset_vibrate();
void reset(); void reset();