Merge pull request #892 from 3kinox/rumble_onepad

Implement rumble and isolate SDL code path
This commit is contained in:
Gregory Hainaut 2015-10-17 11:00:06 +02:00
commit 9b796d0f27
14 changed files with 416 additions and 211 deletions

View File

@ -13,7 +13,8 @@ set(onepadFinalFlags "")
# onepad sources # onepad sources
set(onepadSources set(onepadSources
controller.cpp controller.cpp
joystick.cpp GamePad.cpp
SDL/joystick.cpp
keyboard.cpp keyboard.cpp
KeyStatus.cpp KeyStatus.cpp
onepad.cpp) onepad.cpp)
@ -22,7 +23,8 @@ set(onepadSources
set(onepadHeaders set(onepadHeaders
bitwise.h bitwise.h
controller.h controller.h
joystick.h GamePad.h
SDL/joystick.h
keyboard.h keyboard.h
KeyStatus.h KeyStatus.h
onepad.h) onepad.h)
@ -49,10 +51,12 @@ if (SDL2_API)
set(onepadFinalLibs set(onepadFinalLibs
${SDL2_LIBRARIES} ${SDL2_LIBRARIES}
) )
add_definitions(-DSDL_BUILD)
else() else()
set(onepadFinalLibs set(onepadFinalLibs
${SDL_LIBRARY} ${SDL_LIBRARY}
) )
add_definitions(-DSDL_BUILD)
endif() endif()
set(onepadFinalLibs set(onepadFinalLibs

View File

@ -0,0 +1,42 @@
#include "GamePad.h"
#ifdef SDL_BUILD
#include "SDL/joystick.h"
#endif
vector<GamePad*> s_vgamePad;
bool GamePadIdWithinBounds(int GamePadId)
{
return ((GamePadId >= 0) && (GamePadId < (int)s_vgamePad.size()));
}
/**
* Following static methods are just forwarders to their backend
* This is where link between agnostic and specific code is done
**/
/**
* Find every interesting devices and create right structure for them(depend on backend)
**/
void GamePad::EnumerateGamePads(vector<GamePad*>& vgamePad)
{
#ifdef SDL_BUILD
JoystickInfo::EnumerateJoysticks(vgamePad);
#endif
}
void GamePad::UpdateReleaseState()
{
#ifdef SDL_BUILD
JoystickInfo::UpdateReleaseState();
#endif
}
/**
* 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
}

139
plugins/onepad/GamePad.h Normal file
View File

@ -0,0 +1,139 @@
#pragma once
#include "onepad.h"
#include "controller.h"
#ifdef SDL_BUILD
#include <SDL.h>
#define HAT_UP SDL_HAT_UP
#define HAT_DOWN SDL_HAT_DOWN
#define HAT_RIGHT SDL_HAT_RIGHT
#define HAT_LEFT SDL_HAT_LEFT
#endif
class GamePad
{
public:
GamePad() : devname(""), _id(-1), numbuttons(0), numaxes(0), numhats(0),
deadzone(1500), pad(-1) {
vbuttonstate.clear();
vaxisstate.clear();
vhatstate.clear();
}
virtual ~GamePad()
{
return;
}
GamePad(const GamePad&); // copy constructor
GamePad& operator=(const GamePad&); // assignment
/**
* Find every interesting devices and create right structure for them(depend on backend)
**/
static void EnumerateGamePads(vector<GamePad*>& vgamePad);
static void UpdateReleaseState();
/**
* Update state of every attached devices
**/
static void UpdateGamePadState();
/**
* Causes devices to rumble
* 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 bool Init(int id){return false;} // opens a handle and gets information
/**
* Used for GUI checkbox to give feedback to the user
**/
virtual void TestForce(){return;}
virtual bool PollButtons(u32 &pkey){return false;}
virtual bool PollAxes(u32 &pkey){return false;}
virtual bool PollHats(u32 &pkey){return false;}
virtual int GetHat(int key_to_axis)
{
return 0;
}
virtual int GetButton(int key_to_button)
{
return 0;
}
virtual const string& GetName()
{
return devname;
}
virtual int GetNumButtons()
{
return numbuttons;
}
virtual int GetNumAxes()
{
return numaxes;
}
virtual int GetNumHats()
{
return numhats;
}
virtual int GetDeadzone()
{
return deadzone;
}
virtual void SaveState(){return;}
virtual int GetButtonState(int i)
{
return vbuttonstate[i];
}
virtual int GetAxisState(int i)
{
return vaxisstate[i];
}
virtual int GetHatState(int i)
{
//PAD_LOG("Getting POV State of %d.\n", i);
return vhatstate[i];
}
virtual void SetButtonState(int i, int state)
{
vbuttonstate[i] = state;
}
virtual void SetAxisState(int i, int value)
{
vaxisstate[i] = value;
}
virtual void SetHatState(int i, int value)
{
//PAD_LOG("We should set %d to %d.\n", i, value);
vhatstate[i] = value;
}
virtual int GetAxisFromKey(int pad, int index){return 0;}
// These fields need to be inherited by child classes
protected:
string devname; // pretty device name
int _id;
int numbuttons, numaxes, numhats;
int deadzone;
int pad;
vector<int> vbuttonstate, vaxisstate, vhatstate;
};
extern vector<GamePad*> s_vgamePad;
extern bool GamePadIdWithinBounds(int joyid);

View File

@ -69,7 +69,7 @@ void KeyStatus::press(u32 pad, u32 index, s32 value)
// Normal mode : expect value 0 -> 80 -> FF // Normal mode : expect value 0 -> 80 -> FF
// Reverse mode: expect value FF -> 7F -> 0 // Reverse mode: expect value FF -> 7F -> 0
u8 force = (value / 256); u8 force = (value / 256);
if (analog_is_reversed(index)) analog_set(pad, index, 0x7F - force); if (analog_is_reversed(pad,index)) analog_set(pad, index, 0x7F - force);
else analog_set(pad, index, 0x80 + force); else analog_set(pad, index, 0x80 + force);
} }
} }
@ -117,25 +117,25 @@ void KeyStatus::analog_set(u32 pad, u32 index, u8 value)
} }
} }
bool KeyStatus::analog_is_reversed(u32 index) bool KeyStatus::analog_is_reversed(u32 pad, u32 index)
{ {
switch (index) switch (index)
{ {
case PAD_L_RIGHT: case PAD_L_RIGHT:
case PAD_L_LEFT: case PAD_L_LEFT:
return ((conf->options & PADOPTION_REVERSELX) != 0); return (conf->pad_options[pad].reverse_lx);
case PAD_R_LEFT: case PAD_R_LEFT:
case PAD_R_RIGHT: case PAD_R_RIGHT:
return ((conf->options & PADOPTION_REVERSERX) != 0); return (conf->pad_options[pad].reverse_rx);
case PAD_L_UP: case PAD_L_UP:
case PAD_L_DOWN: case PAD_L_DOWN:
return ((conf->options & PADOPTION_REVERSELY) != 0); return (conf->pad_options[pad].reverse_ly);
case PAD_R_DOWN: case PAD_R_DOWN:
case PAD_R_UP: case PAD_R_UP:
return ((conf->options & PADOPTION_REVERSERY) != 0); return (conf->pad_options[pad].reverse_ry);
default: return false; default: return false;
} }

View File

@ -49,7 +49,7 @@ class KeyStatus
PADAnalog m_internal_analog_joy[2]; PADAnalog m_internal_analog_joy[2];
void analog_set(u32 pad, u32 index, u8 value); void analog_set(u32 pad, u32 index, u8 value);
bool analog_is_reversed(u32 index); bool analog_is_reversed(u32 pad, u32 index);
u8 analog_merge(u8 kbd, u8 joy); u8 analog_merge(u8 kbd, u8 joy);
public: public:

View File

@ -19,7 +19,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/ */
#include "joystick.h" #include "GamePad.h"
#include "keyboard.h" #include "keyboard.h"
#include "onepad.h" #include "onepad.h"
#include <gtk/gtk.h> #include <gtk/gtk.h>
@ -243,14 +243,14 @@ keys_tree *key_tree_manager;
void populate_new_joysticks(GtkComboBoxText *box) void populate_new_joysticks(GtkComboBoxText *box)
{ {
char str[255]; char str[255];
JoystickInfo::EnumerateJoysticks(s_vjoysticks); GamePad::EnumerateGamePads(s_vgamePad);
gtk_combo_box_text_append_text(box, "Keyboard/mouse only"); gtk_combo_box_text_append_text(box, "Keyboard/mouse only");
vector<JoystickInfo*>::iterator it = s_vjoysticks.begin(); vector<GamePad*>::iterator it = s_vgamePad.begin();
// Get everything in the vector vjoysticks. // Get everything in the vector vjoysticks.
while (it != s_vjoysticks.end()) while (it != s_vgamePad.end())
{ {
sprintf(str, "Keyboard/mouse and %s - but: %d, axes: %d, hats: %d", (*it)->GetName().c_str(), sprintf(str, "Keyboard/mouse and %s - but: %d, axes: %d, hats: %d", (*it)->GetName().c_str(),
(*it)->GetNumButtons(), (*it)->GetNumAxes(), (*it)->GetNumHats()); (*it)->GetNumButtons(), (*it)->GetNumAxes(), (*it)->GetNumHats());
@ -262,7 +262,7 @@ void populate_new_joysticks(GtkComboBoxText *box)
void set_current_joy() void set_current_joy()
{ {
u32 joyid = conf->get_joyid(current_pad); u32 joyid = conf->get_joyid(current_pad);
if (JoystickIdWithinBounds(joyid)) if (GamePadIdWithinBounds(joyid))
// 0 is special case for no gamepad. So you must increase of 1. // 0 is special case for no gamepad. So you must increase of 1.
gtk_combo_box_set_active(GTK_COMBO_BOX(joy_choose_cbox), joyid+1); gtk_combo_box_set_active(GTK_COMBO_BOX(joy_choose_cbox), joyid+1);
else else
@ -294,7 +294,7 @@ typedef struct
mask = mask_value; mask = mask_value;
gtk_fixed_put(GTK_FIXED(area), widget, x, y); gtk_fixed_put(GTK_FIXED(area), widget, x, y);
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), mask & conf->options); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), mask & conf->packed_options);
g_signal_connect(widget, "toggled", G_CALLBACK(on_toggle_option), this); g_signal_connect(widget, "toggled", G_CALLBACK(on_toggle_option), this);
} }
} dialog_checkbox; } dialog_checkbox;
@ -305,10 +305,10 @@ void config_key(int pad, int key)
u32 key_pressed = 0; u32 key_pressed = 0;
// I don't have any guarantee that not-yet-pressed state is egual to released state // I don't have any guarantee that not-yet-pressed state is egual to released state
JoystickInfo::UpdateReleaseState(); GamePad::UpdateReleaseState();
while (!captured) while (!captured)
{ {
vector<JoystickInfo*>::iterator itjoy; vector<GamePad*>::iterator itjoy;
if (PollX11KeyboardMouseEvent(key_pressed)) if (PollX11KeyboardMouseEvent(key_pressed))
{ {
@ -321,10 +321,10 @@ void config_key(int pad, int key)
break; break;
} }
SDL_JoystickUpdate(); GamePad::UpdateGamePadState();
itjoy = s_vjoysticks.begin(); itjoy = s_vgamePad.begin();
while ((itjoy != s_vjoysticks.end()) && (!captured)) while ((itjoy != s_vgamePad.end()) && (!captured))
{ {
if ((*itjoy)->PollButtons(key_pressed)) { if ((*itjoy)->PollButtons(key_pressed)) {
set_key(pad, key, key_pressed); set_key(pad, key, key_pressed);
@ -393,9 +393,13 @@ void on_toggle_option(GtkToggleButton *togglebutton, gpointer user_data)
dialog_checkbox *checkbox = (dialog_checkbox*)user_data; dialog_checkbox *checkbox = (dialog_checkbox*)user_data;
if (gtk_toggle_button_get_active(togglebutton)) if (gtk_toggle_button_get_active(togglebutton))
conf->options |= checkbox->mask; {
conf->packed_options |= checkbox->mask;
if(checkbox->mask == PADOPTION_FORCEFEEDBACK && (conf->get_joyid(current_pad)< s_vgamePad.size()))
s_vgamePad[conf->get_joyid(current_pad)]->TestForce();
}
else else
conf->options &= ~checkbox->mask; conf->packed_options &= ~checkbox->mask;
} }
void joy_changed(GtkComboBoxText *box, gpointer user_data) void joy_changed(GtkComboBoxText *box, gpointer user_data)
@ -427,23 +431,6 @@ void pad_changed(GtkNotebook *notebook, void *notebook_page, int page, void *dat
set_current_joy(); set_current_joy();
} }
//void on_forcefeedback_toggled(GtkToggleButton *togglebutton, gpointer user_data)
//{
// int mask = PADOPTION_REVERSELX << (16 * s_selectedpad);
//
// if (gtk_toggle_button_get_active(togglebutton))
// {
// conf->options |= mask;
//
// u32 joyid = conf->get_joyid(current_pad);
// if (JoystickIdWithinBounds(joyid)) s_vjoysticks[joyid]->TestForce();
// }
// else
// {
// conf->options &= ~mask;
// }
//}
struct button_positions struct button_positions
{ {
const char* label; const char* label;

View File

@ -22,7 +22,7 @@
#include <string.h> #include <string.h>
#include <gtk/gtk.h> #include <gtk/gtk.h>
#include "joystick.h" #include "GamePad.h"
#include "keyboard.h" #include "keyboard.h"
#include "onepad.h" #include "onepad.h"
#include "linux.h" #include "linux.h"
@ -73,19 +73,19 @@ string KeyName(int pad, int key, int keysym)
int axis = key_to_axis(pad, key); int axis = key_to_axis(pad, key);
switch(key_to_hat_dir(pad, key)) switch(key_to_hat_dir(pad, key))
{ {
case SDL_HAT_UP: case HAT_UP:
sprintf(&tmp[0], "JPOVU-%d", axis); sprintf(&tmp[0], "JPOVU-%d", axis);
break; break;
case SDL_HAT_RIGHT: case HAT_RIGHT:
sprintf(&tmp[0], "JPOVR-%d", axis); sprintf(&tmp[0], "JPOVR-%d", axis);
break; break;
case SDL_HAT_DOWN: case HAT_DOWN:
sprintf(&tmp[0], "JPOVD-%d", axis); sprintf(&tmp[0], "JPOVD-%d", axis);
break; break;
case SDL_HAT_LEFT: case HAT_LEFT:
sprintf(&tmp[0], "JPOVL-%d", axis); sprintf(&tmp[0], "JPOVL-%d", axis);
break; break;
} }
@ -129,10 +129,10 @@ void SaveConfig()
} }
fprintf(f, "log = %d\n", conf->log); fprintf(f, "log = %d\n", conf->log);
fprintf(f, "options = %d\n", conf->options); fprintf(f, "options = %d\n", conf->packed_options);
fprintf(f, "mouse_sensibility = %d\n", conf->sensibility); fprintf(f, "mouse_sensibility = %d\n", conf->get_sensibility());
fprintf(f, "joy_pad_map = %d\n", conf->joyid_map); fprintf(f, "joy_pad_map = %d\n", conf->joyid_map);
fprintf(f, "ff_intensity = %d\n", conf->ff_intensity); fprintf(f, "ff_intensity = %d\n", conf->get_ff_intensity());
for (int pad = 0; pad < 2; pad++) for (int pad = 0; pad < 2; pad++)
{ {
@ -174,13 +174,13 @@ void LoadConfig()
if (fscanf(f, "log = %d\n", &value) == 0) goto error; if (fscanf(f, "log = %d\n", &value) == 0) goto error;
conf->log = value; conf->log = value;
if (fscanf(f, "options = %d\n", &value) == 0) goto error; if (fscanf(f, "options = %d\n", &value) == 0) goto error;
conf->options = value; conf->packed_options = value;
if (fscanf(f, "mouse_sensibility = %d\n", &value) == 0) goto error; if (fscanf(f, "mouse_sensibility = %d\n", &value) == 0) goto error;
conf->sensibility = value; conf->set_sensibility(value);
if (fscanf(f, "joy_pad_map = %d\n", &value) == 0) goto error; if (fscanf(f, "joy_pad_map = %d\n", &value) == 0) goto error;
conf->joyid_map = value; conf->joyid_map = value;
if (fscanf(f, "ff_intensity = %d\n", &value) == 0) goto error; if (fscanf(f, "ff_intensity = %d\n", &value) == 0) goto error;
conf->ff_intensity = value; conf->set_ff_intensity(value);
for (int pad = 0; pad < 2; pad++) for (int pad = 0; pad < 2; pad++)
{ {

View File

@ -19,7 +19,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/ */
#include "joystick.h" #include "GamePad.h"
#include "onepad.h" #include "onepad.h"
#include "keyboard.h" #include "keyboard.h"
@ -74,34 +74,34 @@ void _PADclose()
{ {
SetAutoRepeat(true); SetAutoRepeat(true);
vector<JoystickInfo*>::iterator it = s_vjoysticks.begin(); vector<GamePad*>::iterator it = s_vgamePad.begin();
// Delete everything in the vector vjoysticks. // Delete everything in the vector vjoysticks.
while (it != s_vjoysticks.end()) while (it != s_vgamePad.end())
{ {
delete *it; delete *it;
it ++; it ++;
} }
s_vjoysticks.clear(); s_vgamePad.clear();
} }
void PollForJoystickInput(int cpad) void PollForJoystickInput(int cpad)
{ {
int joyid = conf->get_joyid(cpad); int joyid = conf->get_joyid(cpad);
if (!JoystickIdWithinBounds(joyid)) return; if (!GamePadIdWithinBounds(joyid)) return;
SDL_JoystickUpdate(); GamePad::UpdateGamePadState();
for (int i = 0; i < MAX_KEYS; i++) for (int i = 0; i < MAX_KEYS; i++)
{ {
JoystickInfo* pjoy = s_vjoysticks[joyid]; GamePad* gamePad = s_vgamePad[joyid];
switch (type_of_joykey(cpad, i)) switch (type_of_joykey(cpad, i))
{ {
case PAD_JOYBUTTONS: case PAD_JOYBUTTONS:
{ {
int value = SDL_JoystickGetButton((pjoy)->GetJoy(), key_to_button(cpad, i)); int value = gamePad->GetButton(key_to_button(cpad, i));
if (value) if (value)
key_status->press(cpad, i); key_status->press(cpad, i);
else else
@ -111,7 +111,7 @@ void PollForJoystickInput(int cpad)
} }
case PAD_HAT: case PAD_HAT:
{ {
int value = SDL_JoystickGetHat((pjoy)->GetJoy(), key_to_axis(cpad, i)); int value = gamePad->GetHat(key_to_axis(cpad, i));
// key_to_hat_dir and SDL_JoystickGetHat are a 4 bits bitmap, one for each directions. Only 1 bit can be high for // key_to_hat_dir and SDL_JoystickGetHat are a 4 bits bitmap, one for each directions. Only 1 bit can be high for
// key_to_hat_dir. SDL_JoystickGetHat handles diagonal too (2 bits) so you must check the intersection // key_to_hat_dir. SDL_JoystickGetHat handles diagonal too (2 bits) so you must check the intersection
@ -125,12 +125,12 @@ void PollForJoystickInput(int cpad)
} }
case PAD_AXIS: case PAD_AXIS:
{ {
int value = pjoy->GetAxisFromKey(cpad, i); int value = gamePad->GetAxisFromKey(cpad, i);
bool sign = key_to_axis_sign(cpad, i); bool sign = key_to_axis_sign(cpad, i);
bool full_axis = key_to_axis_type(cpad, i); bool full_axis = key_to_axis_type(cpad, i);
if (IsAnalogKey(i)) { if (IsAnalogKey(i)) {
if (abs(value) > pjoy->GetDeadzone()) if (abs(value) > gamePad->GetDeadzone())
key_status->press(cpad, i, value); key_status->press(cpad, i, value);
else else
key_status->release(cpad, i); key_status->release(cpad, i);
@ -138,15 +138,15 @@ void PollForJoystickInput(int cpad)
} else { } else {
if (full_axis) { if (full_axis) {
value += 0x8000; value += 0x8000;
if (value > pjoy->GetDeadzone()) if (value > gamePad->GetDeadzone())
key_status->press(cpad, i, min(value/256 , 0xFF)); key_status->press(cpad, i, min(value/256 , 0xFF));
else else
key_status->release(cpad, i); key_status->release(cpad, i);
} else { } else {
if (sign && (-value > pjoy->GetDeadzone())) if (sign && (-value > gamePad->GetDeadzone()))
key_status->press(cpad, i, min(-value /128, 0xFF)); key_status->press(cpad, i, min(-value /128, 0xFF));
else if (!sign && (value > pjoy->GetDeadzone())) else if (!sign && (value > gamePad->GetDeadzone()))
key_status->press(cpad, i, min(value /128, 0xFF)); key_status->press(cpad, i, min(value /128, 0xFF));
else else
key_status->release(cpad, i); key_status->release(cpad, i);

View File

@ -25,30 +25,24 @@
// Joystick definitions // // Joystick definitions //
////////////////////////// //////////////////////////
vector<JoystickInfo*> s_vjoysticks;
static u32 s_bSDLInit = false; static u32 s_bSDLInit = false;
void JoystickInfo::UpdateReleaseState() void JoystickInfo::UpdateReleaseState()
{ {
vector<JoystickInfo*>::iterator itjoy = s_vjoysticks.begin(); vector<GamePad*>::iterator itjoy = s_vgamePad.begin();
SDL_JoystickUpdate(); SDL_JoystickUpdate();
// Save everything in the vector s_vjoysticks. // Save everything in the vector s_vjoysticks.
while (itjoy != s_vjoysticks.end()) while (itjoy != s_vgamePad.end())
{ {
(*itjoy)->SaveState(); (*itjoy)->SaveState();
itjoy++; itjoy++;
} }
} }
bool JoystickIdWithinBounds(int joyid)
{
return ((joyid >= 0) && (joyid < (int)s_vjoysticks.size()));
}
// opens handles to all possible joysticks // opens handles to all possible joysticks
void JoystickInfo::EnumerateJoysticks(vector<JoystickInfo*>& vjoysticks) void JoystickInfo::EnumerateJoysticks(vector<GamePad*>& vjoysticks)
{ {
if (!s_bSDLInit) if (!s_bSDLInit)
@ -56,10 +50,7 @@ void JoystickInfo::EnumerateJoysticks(vector<JoystickInfo*>& vjoysticks)
#if SDL_MAJOR_VERSION >= 2 #if SDL_MAJOR_VERSION >= 2
// Tell SDL to catch event even if the windows isn't focussed // Tell SDL to catch event even if the windows isn't focussed
SDL_SetHint(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, "1"); SDL_SetHint(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, "1");
// SDL in 3rdparty wrap X11 call. In order to get x11 symbols loaded if (SDL_Init(SDL_INIT_JOYSTICK|SDL_INIT_HAPTIC|SDL_INIT_EVENTS) < 0) return;
// video must be loaded too.
// Example of X11 symbol are XAutoRepeatOn/XAutoRepeatOff
if (SDL_Init(SDL_INIT_JOYSTICK|SDL_INIT_VIDEO|SDL_INIT_HAPTIC|SDL_INIT_GAMECONTROLLER|SDL_INIT_EVENTS) < 0) return;
#else #else
if (SDL_Init(SDL_INIT_JOYSTICK) < 0) return; if (SDL_Init(SDL_INIT_JOYSTICK) < 0) return;
#endif #endif
@ -67,7 +58,7 @@ void JoystickInfo::EnumerateJoysticks(vector<JoystickInfo*>& vjoysticks)
s_bSDLInit = true; s_bSDLInit = true;
} }
vector<JoystickInfo*>::iterator it = vjoysticks.begin(); vector<GamePad*>::iterator it = vjoysticks.begin();
// Delete everything in the vector vjoysticks. // Delete everything in the vector vjoysticks.
while (it != vjoysticks.end()) while (it != vjoysticks.end())
@ -85,84 +76,68 @@ void JoystickInfo::EnumerateJoysticks(vector<JoystickInfo*>& vjoysticks)
} }
} }
void JoystickInfo::InitHapticEffect() void JoystickInfo::GenerateDefaultEffect()
{ {
for(int i=0;i<NB_EFFECT;i++)
{
SDL_HapticEffect effect;
memset( &effect, 0, sizeof(SDL_HapticEffect) ); // 0 is safe default
SDL_HapticDirection direction;
direction.type = SDL_HAPTIC_POLAR; // We'll be using polar direction encoding.
direction.dir[0] = 18000;
effect.periodic.direction = direction;
effect.periodic.period = 10;
effect.periodic.magnitude = (Sint16)(conf->get_ff_intensity()); // Effect at maximum instensity
effect.periodic.offset = 0;
effect.periodic.phase = 18000;
effect.periodic.length = 125; // 125ms feels quite near to original
effect.periodic.delay = 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 SDL_MAJOR_VERSION >= 2 #if SDL_MAJOR_VERSION >= 2
if (haptic == NULL) return; if (haptic == NULL) return;
#if 0 if(first)
additional field of the effect {// If done multiple times, device memory will be filled
/* Trigger */ first = 0;
Uint16 button; /**< Button that triggers the effect. */ GenerateDefaultEffect();
Uint16 interval; /**< How soon it can be triggered again after button. */ /** Sine and triangle are quite probably the best, don't change that lightly and if you do
* keep effects ordered by type
// periodic parameter **/
Sint16 offset; /**< Mean value of the wave. */ /** Effect for small motor **/
Uint16 phase; /**< Horizontal shift given by hundredth of a cycle. */ /** Sine seems to be the only effect making little motor from DS3/4 react
#endif * Intensity has pretty much no effect either(which is coherent with what is explain in hid_sony driver
**/
/*******************************************************************/ effects[0].type = SDL_HAPTIC_SINE;
/* Effect big & small */ effects_id[0] = SDL_HapticNewEffect(haptic, &effects[0]);
/*******************************************************************/ if(effects_id[0] < 0)
for (int new_effect = 0; new_effect < 2 ; new_effect++) { {
fprintf(stderr,"ERROR: Effect is not uploaded! %s, id is %d\n",SDL_GetError(),effects_id[0]);
// Direction of the effect SDL_HapticDirection
haptic_effect_data[new_effect].periodic.direction.type = SDL_HAPTIC_POLAR; // Polar coordinates
haptic_effect_data[new_effect].periodic.direction.dir[0] = 18000; // Force comes from south
// periodic parameter
haptic_effect_data[new_effect].periodic.period = 20; // 20 ms
haptic_effect_data[new_effect].periodic.magnitude = 2000; // 2000/32767 strength
// Replay
haptic_effect_data[new_effect].periodic.length = 60; // 60 ms long
haptic_effect_data[new_effect].periodic.delay = 0; // start 0 second after the upload
// enveloppe
haptic_effect_data[new_effect].periodic.attack_length = 5;// Takes 5 ms to get max strength
haptic_effect_data[new_effect].periodic.attack_level = 0; // start at 0
haptic_effect_data[new_effect].periodic.fade_length = 5; // Takes 5 ms to fade away
haptic_effect_data[new_effect].periodic.fade_level = 0; // finish at 0
} }
/*******************************************************************/ /** Effect for big motor **/
/* Effect small */ effects[1].type = SDL_HAPTIC_TRIANGLE;
/*******************************************************************/ effects_id[1] = SDL_HapticNewEffect(haptic, &effects[1]);
haptic_effect_data[0].type = SDL_HAPTIC_LEFTRIGHT; if(effects_id[1] < 0)
{
fprintf(stderr,"ERROR: Effect is not uploaded! %s, id is %d\n",SDL_GetError(),effects_id[1]);
}
}
/*******************************************************************/ int id;
/* Effect big */ id = effects_id[type];
/*******************************************************************/ if(SDL_HapticRunEffect(haptic, id, 1) != 0)
haptic_effect_data[1].type = SDL_HAPTIC_TRIANGLE; {
fprintf(stderr,"ERROR: Effect is not working! %s, id is %d\n",SDL_GetError(),id);
/*******************************************************************/ }
/* Upload effect to the device */
/*******************************************************************/
for (int i = 0 ; i < 2 ; i++)
haptic_effect_id[i] = SDL_HapticNewEffect(haptic, &haptic_effect_data[i]);
#endif
}
void JoystickInfo::DoHapticEffect(int type, int pad, int force)
{
if (type > 1) return;
if ( !(conf->options & (PADOPTION_FORCEFEEDBACK << 16 * pad)) ) return;
#if SDL_MAJOR_VERSION >= 2
int joyid = conf->get_joyid(pad);
if (!JoystickIdWithinBounds(joyid)) return;
JoystickInfo* pjoy = s_vjoysticks[joyid];
if (pjoy->haptic == NULL) return;
if (pjoy->haptic_effect_id[type] < 0) return;
// FIXME: might need to multiply force
pjoy->haptic_effect_data[type].periodic.magnitude = force * conf->ff_intensity ; // force/32767 strength
// Upload the new effect
SDL_HapticUpdateEffect(pjoy->haptic, pjoy->haptic_effect_id[type], &pjoy->haptic_effect_data[type]);
// run the effect once
SDL_HapticRunEffect( pjoy->haptic, pjoy->haptic_effect_id[type], 1 );
#endif #endif
} }
@ -179,7 +154,9 @@ void JoystickInfo::Destroy()
#endif #endif
#if SDL_MAJOR_VERSION >= 2 #if SDL_MAJOR_VERSION >= 2
#if SDL_MINOR_VERSION >= 4 // Version before 2.0.4 are bugged, JoystickClose crashes randomly
if (joy) SDL_JoystickClose(joy); if (joy) SDL_JoystickClose(joy);
#endif
#else #else
if (SDL_JoystickOpened(_id)) SDL_JoystickClose(joy); if (SDL_JoystickOpened(_id)) SDL_JoystickClose(joy);
#endif #endif
@ -230,8 +207,7 @@ bool JoystickInfo::Init(int id)
PAD_LOG("Haptic devices not supported!\n"); PAD_LOG("Haptic devices not supported!\n");
} else { } else {
haptic = SDL_HapticOpenFromJoystick(joy); haptic = SDL_HapticOpenFromJoystick(joy);
// upload some default effect first = true;
InitHapticEffect();
} }
} }
#endif #endif
@ -251,7 +227,14 @@ void JoystickInfo::SaveState()
} }
void JoystickInfo::TestForce() void JoystickInfo::TestForce()
{ { // This code just use standard rumble to check that SDL handles the pad correctly! --3kinox
if(haptic == NULL) return; // 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
if( SDL_HapticRumblePlay( haptic, 0.60, 400 ) != 0)
{
fprintf(stderr,"ERROR: Rumble is not working! %s\n",SDL_GetError());
}
} }
bool JoystickInfo::PollButtons(u32 &pkey) bool JoystickInfo::PollButtons(u32 &pkey)
@ -289,7 +272,7 @@ bool JoystickInfo::PollAxes(u32 &pkey)
if (found_hack != string::npos) { if (found_hack != string::npos) {
// The analog mode of the hat button is quite erratic. Values can be in half- axis // The analog mode of the hat button is quite erratic. Values can be in half- axis
// or full axis... So better keep them as button for the moment -- gregory // or full axis... So better keep them as button for the moment -- gregory
if (i >= 8 && i <= 11 && (conf->options & PADOPTION_SIXAXIS_USB)) if (i >= 8 && i <= 11 && (conf->pad_options[pad].sixaxis_usb))
continue; continue;
// Disable accelerometer // Disable accelerometer
if ((i >= 4 && i <= 6)) if ((i >= 4 && i <= 6))
@ -360,6 +343,16 @@ bool JoystickInfo::PollHats(u32 &pkey)
return false; return false;
} }
int JoystickInfo::GetHat(int key_to_axis)
{
return SDL_JoystickGetHat(GetJoy(),key_to_axis);
}
int JoystickInfo::GetButton(int key_to_button)
{
return SDL_JoystickGetButton(GetJoy(),key_to_button);
}
int JoystickInfo::GetAxisFromKey(int pad, int index) int JoystickInfo::GetAxisFromKey(int pad, int index)
{ {
return SDL_JoystickGetAxis(GetJoy(), key_to_axis(pad, index)); return SDL_JoystickGetAxis(GetJoy(), key_to_axis(pad, index));

View File

@ -19,20 +19,19 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/ */
#ifndef __JOYSTICK_H__ #pragma once
#define __JOYSTICK_H__
#include <SDL.h> #include <SDL.h>
#if SDL_MAJOR_VERSION >= 2 #if SDL_MAJOR_VERSION >= 2
#include <SDL_haptic.h> #include <SDL_haptic.h>
#endif #endif
#include "GamePad.h"
#include "onepad.h" #include "onepad.h"
#include "controller.h" #include "controller.h"
#define NB_EFFECT 2 // Don't use more than two, ps2 only has one for big motor and one for small(like most systems)
// holds all joystick info // holds all joystick info
class JoystickInfo class JoystickInfo : GamePad
{ {
public: public:
JoystickInfo() : devname(""), _id(-1), numbuttons(0), numaxes(0), numhats(0), JoystickInfo() : devname(""), _id(-1), numbuttons(0), numaxes(0), numhats(0),
@ -42,8 +41,7 @@ class JoystickInfo
vhatstate.clear(); vhatstate.clear();
#if SDL_MAJOR_VERSION >= 2 #if SDL_MAJOR_VERSION >= 2
haptic = NULL; haptic = NULL;
for (int i = 0 ; i < 2 ; i++) first = true;
haptic_effect_id[i] = -1;
#endif #endif
} }
@ -57,10 +55,9 @@ class JoystickInfo
void Destroy(); void Destroy();
// opens handles to all possible joysticks // opens handles to all possible joysticks
static void EnumerateJoysticks(vector<JoystickInfo*>& vjoysticks); static void EnumerateJoysticks(vector<GamePad*>& vjoysticks);
void InitHapticEffect(); void Rumble(int type,int pad);
static void DoHapticEffect(int type, int pad, int force);
bool Init(int id); // opens a handle and gets information bool Init(int id); // opens a handle and gets information
@ -70,6 +67,10 @@ class JoystickInfo
bool PollAxes(u32 &pkey); bool PollAxes(u32 &pkey);
bool PollHats(u32 &pkey); bool PollHats(u32 &pkey);
int GetHat(int key_to_axis);
int GetButton(int key_to_button);
const string& GetName() const string& GetName()
{ {
return devname; return devname;
@ -134,16 +135,16 @@ class JoystickInfo
vhatstate[i] = value; vhatstate[i] = value;
} }
SDL_Joystick* GetJoy()
{
return joy;
}
int GetAxisFromKey(int pad, int index); int GetAxisFromKey(int pad, int index);
static void UpdateReleaseState(); static void UpdateReleaseState();
private: private:
SDL_Joystick* GetJoy()
{
return joy;
}
void GenerateDefaultEffect();
string devname; // pretty device name string devname; // pretty device name
int _id; int _id;
int numbuttons, numaxes, numhats; int numbuttons, numaxes, numhats;
@ -155,13 +156,8 @@ class JoystickInfo
SDL_Joystick* joy; SDL_Joystick* joy;
#if SDL_MAJOR_VERSION >= 2 #if SDL_MAJOR_VERSION >= 2
SDL_Haptic* haptic; SDL_Haptic* haptic;
SDL_HapticEffect haptic_effect_data[2]; bool first;
int haptic_effect_id[2]; SDL_HapticEffect effects[NB_EFFECT];
int effects_id[NB_EFFECT];
#endif #endif
}; };
extern int s_selectedpad;
extern vector<JoystickInfo*> s_vjoysticks;
extern bool JoystickIdWithinBounds(int joyid);
#endif

View File

@ -19,9 +19,8 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/ */
#ifndef __CONTROLLER_H__ #pragma once
#define __CONTROLLER_H__ #include <string.h> // for memset
#ifdef __linux__ #ifdef __linux__
#define MAX_KEYS 24 #define MAX_KEYS 24
#else #else
@ -55,23 +54,37 @@ extern int hat_to_key(int dir, int axis_id);
extern int PadEnum[2][2]; extern int PadEnum[2][2];
struct PADconf class PADconf
{ {
u32 ff_intensity;
u32 sensibility;
public: public:
union {
struct {
u32 forcefeedback :1;
u32 reverse_lx :1;
u32 reverse_ly :1;
u32 reverse_rx :1;
u32 reverse_ry :1;
u32 mouse_l :1;
u32 mouse_r :1;
u32 sixaxis_usb :1;
u32 _free : 8; // The 8 remaining bits are unused, do what you wish with them ;)
} pad_options[2]; // One for each pads
u32 packed_options; // Only first 8 bits of each 16 bits series are really used, rest is padding
};
u32 keys[2][MAX_KEYS]; u32 keys[2][MAX_KEYS];
u32 log; u32 log;
u32 options; // upper 16 bits are for pad2
u32 sensibility;
u32 joyid_map; u32 joyid_map;
u32 ff_intensity;
map<u32,u32> keysym_map[2]; map<u32,u32> keysym_map[2];
PADconf() { init(); } PADconf() { init(); }
void init() { void init() {
memset(&keys, 0, sizeof(keys)); memset(&keys, 0, sizeof(keys));
log = options = joyid_map = 0; log = packed_options = joyid_map = 0;
ff_intensity = 100; ff_intensity = 0x7FFF; // set it at max value by default
sensibility = 500; sensibility = 500;
for (int pad = 0; pad < 2 ; pad++) for (int pad = 0; pad < 2 ; pad++)
keysym_map[pad].clear(); keysym_map[pad].clear();
@ -87,6 +100,43 @@ struct PADconf
int shift = 8 * pad; int shift = 8 * pad;
return ((joyid_map >> shift) & 0xFF); return ((joyid_map >> shift) & 0xFF);
} }
/**
* Return (a copy of) private memner ff_instensity
**/
u32 get_ff_intensity()
{
return ff_intensity;
}
/**
* Set intensity while checking that the new value is within
* valid range, more than 0x7FFF will cause pad not to rumble(and less than 0 is obviously bad)
**/
void set_ff_intensity(u32 new_intensity)
{
if(new_intensity < 0x7FFF && new_intensity >= 0)
{
ff_intensity = new_intensity;
}
}
/**
* Set sensibility value, sensibility is not yet implemented(and will probably be after evdev)
* However, there will be an upper range too, less than 0 is an obvious wrong
* Anyway, we are doing object oriented code, members are definitely not supposed to be public
**/
void set_sensibility(u32 new_sensibility)
{
if(sensibility > 0)
{
sensibility = new_sensibility;
}
}
u32 get_sensibility()
{
return sensibility;
}
}; };
extern PADconf *conf; extern PADconf *conf;
#endif

View File

@ -142,11 +142,11 @@ void AnalyzeKeyEvent(int pad, keyEvent &evt)
// 1/ small move == no move. Cons : can not do small movement // 1/ small move == no move. Cons : can not do small movement
// 2/ use a watchdog timer thread // 2/ use a watchdog timer thread
// 3/ ??? idea welcome ;) // 3/ ??? idea welcome ;)
if (conf->options & ((PADOPTION_MOUSE_L|PADOPTION_MOUSE_R) << 16 * pad )) { if (conf->pad_options[pad].mouse_l|conf->pad_options[pad].mouse_r) {
unsigned int pad_x; unsigned int pad_x;
unsigned int pad_y; unsigned int pad_y;
// Note when both PADOPTION_MOUSE_R and PADOPTION_MOUSE_L are set, take only the right one // Note when both PADOPTION_MOUSE_R and PADOPTION_MOUSE_L are set, take only the right one
if (conf->options & (PADOPTION_MOUSE_R << 16 * pad)) { if (conf->pad_options[pad].mouse_r) {
pad_x = PAD_R_RIGHT; pad_x = PAD_R_RIGHT;
pad_y = PAD_R_UP; pad_y = PAD_R_UP;
} else { } else {
@ -156,7 +156,7 @@ void AnalyzeKeyEvent(int pad, keyEvent &evt)
unsigned x = evt.key & 0xFFFF; unsigned x = evt.key & 0xFFFF;
unsigned int value = (s_previous_mouse_x > x) ? s_previous_mouse_x - x : x - s_previous_mouse_x; unsigned int value = (s_previous_mouse_x > x) ? s_previous_mouse_x - x : x - s_previous_mouse_x;
value *= conf->sensibility; value *= conf->get_sensibility();
if (x == 0) if (x == 0)
key_status->press(pad, pad_x, -MAX_ANALOG_VALUE); key_status->press(pad, pad_x, -MAX_ANALOG_VALUE);
@ -172,7 +172,7 @@ void AnalyzeKeyEvent(int pad, keyEvent &evt)
unsigned y = evt.key >> 16; unsigned y = evt.key >> 16;
value = (s_previous_mouse_y > y) ? s_previous_mouse_y - y : y - s_previous_mouse_y; value = (s_previous_mouse_y > y) ? s_previous_mouse_y - y : y - s_previous_mouse_y;
value *= conf->sensibility; value *= conf->get_sensibility();
if (y == 0) if (y == 0)
key_status->press(pad, pad_y, -MAX_ANALOG_VALUE); key_status->press(pad, pad_y, -MAX_ANALOG_VALUE);

View File

@ -263,7 +263,7 @@ EXPORT_C_(s32) PADopen(void *pDsp)
mutex_WasInit = true; mutex_WasInit = true;
#ifdef __linux__ #ifdef __linux__
JoystickInfo::EnumerateJoysticks(s_vjoysticks); GamePad::EnumerateGamePads(s_vgamePad);
#endif #endif
return _PADopen(pDsp); return _PADopen(pDsp);
} }
@ -300,7 +300,6 @@ EXPORT_C_(u32) PADquery()
void PADsetMode(int pad, int mode) void PADsetMode(int pad, int mode)
{ {
padMode[pad] = mode; padMode[pad] = mode;
// FIXME FEEDBACK
padVib0[pad] = 0; padVib0[pad] = 0;
padVib1[pad] = 0; padVib1[pad] = 0;
padVibF[pad][0] = 0; padVibF[pad][0] = 0;
@ -413,7 +412,6 @@ u8 _PADpoll(u8 value)
buf = stdpar[curPad]; buf = stdpar[curPad];
// FIXME FEEDBACK. Set effect here
/* Small Motor */ /* Small Motor */
vib_small = padVibF[curPad][0] ? 2000 : 0; vib_small = padVibF[curPad][0] ? 2000 : 0;
// if ((padVibF[curPad][2] != vib_small) && (padVibC[curPad] >= 0)) // if ((padVibF[curPad][2] != vib_small) && (padVibC[curPad] >= 0))
@ -421,7 +419,8 @@ u8 _PADpoll(u8 value)
{ {
padVibF[curPad][2] = vib_small; padVibF[curPad][2] = vib_small;
// SetDeviceForceS (padVibC[curPad], vib_small); // SetDeviceForceS (padVibC[curPad], vib_small);
JoystickInfo::DoHapticEffect(0, curPad, vib_small); GamePad* gamePad = s_vgamePad[conf->get_joyid(curPad)];
gamePad->Rumble(0,curPad);
} }
/* Big Motor */ /* Big Motor */
@ -431,7 +430,8 @@ u8 _PADpoll(u8 value)
{ {
padVibF[curPad][3] = vib_big; padVibF[curPad][3] = vib_big;
// SetDeviceForceB (padVibC[curPad], vib_big); // SetDeviceForceB (padVibC[curPad], vib_big);
JoystickInfo::DoHapticEffect(1, curPad, vib_big); GamePad* gamePad = s_vgamePad[conf->get_joyid(curPad)];
gamePad->Rumble(1,curPad);
} }
return padID[curPad]; return padID[curPad];
@ -491,7 +491,7 @@ u8 _PADpoll(u8 value)
switch (curCmd) switch (curCmd)
{ {
case CMD_READ_DATA_AND_VIBRATE: case CMD_READ_DATA_AND_VIBRATE:
// FIXME FEEDBACK
if (curByte == padVib0[curPad]) if (curByte == padVib0[curPad])
padVibF[curPad][0] = value; padVibF[curPad][0] = value;
if (curByte == padVib1[curPad]) if (curByte == padVib1[curPad])
@ -557,7 +557,7 @@ u8 _PADpoll(u8 value)
break; break;
case CMD_VIBRATION_TOGGLE: case CMD_VIBRATION_TOGGLE:
// FIXME FEEDBACK
if (curByte >= 2) if (curByte >= 2)
{ {
if (curByte == padVib0[curPad]) if (curByte == padVib0[curPad])
@ -567,16 +567,10 @@ u8 _PADpoll(u8 value)
if (value == 0x00) if (value == 0x00)
{ {
padVib0[curPad] = curByte; padVib0[curPad] = curByte;
// FIXME: code from SSSXPAD I'm not sure we need this part
// if ((padID[curPad] & 0x0f) < (curByte - 1) / 2)
// padID[curPad] = (padID[curPad] & 0xf0) + (curByte - 1) / 2;
} }
else if (value == 0x01) else if (value == 0x01)
{ {
padVib1[curPad] = curByte; padVib1[curPad] = curByte;
// FIXME: code from SSSXPAD I'm not sure we need this part
// if ((padID[curPad] & 0x0f) < (curByte - 1) / 2)
// padID[curPad] = (padID[curPad] & 0xf0) + (curByte - 1) / 2;
} }
} }
break; break;

View File

@ -48,7 +48,7 @@ using namespace std;
#include "PS2Edefs.h" #include "PS2Edefs.h"
#ifdef __linux__ #ifdef __linux__
#include "joystick.h" #include "GamePad.h"
#endif #endif
#include "bitwise.h" #include "bitwise.h"
#include "controller.h" #include "controller.h"