Commit 2cceec76 authored by Robert Menzel's avatar Robert Menzel

full xbox360 gamepad support including the buttons that are internally analog

parent e43bb19e
......@@ -15,6 +15,10 @@ namespace HardwareSupport{
/**
* NOTE: Will not work unless ACGL_COMPILE_WITH_GLFW or ACGL_COMPILE_WITH_QT (linux only) is defined!
*
*
* For the known gamepads, all axes start at 0.0f. All trigger go from 0..1 and all joystick-like
* analog sticks go from -1..1 while -1 is on the left or bottom / 1 is right or top.
*/
class GamePad {
public:
......@@ -39,15 +43,20 @@ public:
};
enum GamePadAxis {
LEFT_ANALOG_TRIGGER = 0,
RIGHT_ANALOG_TRIGGER = 1,
LEFT_ANALOG_STICK_X = 2, // aka left-right
LEFT_ANALOG_STICK_Y = 3, // aka up-down / front-back
RIGHT_ANALOG_STICK_X = 4, // aka left-right
RIGHT_ANALOG_STICK_Y = 5, // aka up-down / front-back
LEFT_ANALOG_TRIGGER = 0, // 0..1
RIGHT_ANALOG_TRIGGER = 1, // 0..1
LEFT_ANALOG_STICK_X = 2, // -1..1 aka left-right
LEFT_ANALOG_STICK_Y = 3, // -1..1 aka up-down / front-back
RIGHT_ANALOG_STICK_X = 4, // -1..1 aka left-right
RIGHT_ANALOG_STICK_Y = 5, // -1..1 aka up-down / front-back
LEFT_ANALOG_STICK_X_INVERSE = 6, // 1..-1
LEFT_ANALOG_STICK_Y_INVERSE = 7, // 1..-1
RIGHT_ANALOG_STICK_X_INVERSE = 8, // 1..-1
RIGHT_ANALOG_STICK_Y_INVERSE = 9, // 1..-1
// number of elements in this enum (itself not included):
GAMEPAD_AXIS_ENUM_SIZE = 6
GAMEPAD_AXIS_ENUM_SIZE = 10
};
......@@ -72,6 +81,9 @@ public:
//! true if the button was just pressed or released
bool buttonStateChanged( GamePadButton _button );
//! true if the axis is >
//bool isPressed( GamePadAxis _axis );
//! define the mapping of one button
void setButtonMapping( GamePadButton _button, unsigned int _rawButtonNumber );
......@@ -98,6 +110,9 @@ public:
//! print the button and axes state for debugging:
void printState();
//! print the names of all mapped buttons, in all caps if pressed
void printPressedButtons();
//! fetches the current device state, will do nothing if the joystick is not ok
void update();
......@@ -109,8 +124,9 @@ private:
int mAxisMap[GAMEPAD_AXIS_ENUM_SIZE];
unsigned char *mButtonState; // 0 = released, 1 = pressed
unsigned char *mLastButtonState;
float *mAxes; // -1 .. 1 per axis
float *mAxes; // -1..1 (e.g. analog sticks) or 0..1 (analog trigger) per axis - untouched should be 0
float *mAxesMultiplier; // used for scaling from the used API to -1..1
float *mAxesAdd; // also used for scaling
float mMinSensitivity; // a minimal axis value that has to be exceeded before it is evaluated
std::string mJoystickName;
......@@ -133,6 +149,9 @@ private:
#ifdef ACGL_OWN_LINUX_JOYSTICK
Joystick mLinuxGamePad;
#endif
bool isMapped( GamePadButton _button );
void printPressedButtonHelper( GamePadButton _b, const char *_TRUE, const char *_false );
};
ACGL_SMARTPOINTER_TYPEDEFS(GamePad)
......
......@@ -34,10 +34,11 @@ GamePad::GamePad( int _n )
#endif
mGamePadOK = false;
mAxes = NULL;
mAxesMultiplier = NULL;
mMinSensitivity = 0.0f;
mButtonState = NULL;
mAxes = NULL;
mAxesMultiplier = NULL;
mAxesAdd = NULL;
mMinSensitivity = 0.0f;
mButtonState = NULL;
mLastButtonState = NULL;
#if defined( ACGL_COMPILE_WITH_GLFW )
......@@ -81,6 +82,24 @@ GamePad::GamePad( int _n )
#endif
}
//
// init state arrays:
//
mLastButtonState = new unsigned char[mNumberOfButtons];
mButtonState = new unsigned char[mNumberOfButtons];
mAxes = new float[mNumberOfAxes];
mAxesMultiplier = new float[mNumberOfAxes];
mAxesAdd = new float[mNumberOfAxes];
for (int i = 0; i < mNumberOfButtons; ++i) {
mButtonState[i] = 0;
}
for (int i = 0; i < mNumberOfAxes; ++i) {
mAxesMultiplier[i] = 1.0f;
mAxesAdd[i] = 0.0f;
mAxes[i] = 0.0f;
}
//
// prepare button mapping
//
......@@ -129,29 +148,36 @@ GamePad::GamePad( int _n )
setMinAxisSensitivity( 0.05f );
} else if (mJoystickName == "Microsoft X-Box 360 pad") {
// real buttons:
setButtonMapping( SELECT, 6);
setButtonMapping( START, 7);
//setButtonMapping( LEFT_PAD_NORTH , 0);
//setButtonMapping( LEFT_PAD_EAST , 0);
//setButtonMapping( LEFT_PAD_SOUTH , 0);
//setButtonMapping( LEFT_PAD_WEST , 0);
setButtonMapping( RIGHT_PAD_NORTH , 3);
setButtonMapping( RIGHT_PAD_EAST , 1);
setButtonMapping( RIGHT_PAD_SOUTH , 0);
setButtonMapping( RIGHT_PAD_WEST , 2);
setButtonMapping( LEFT_SHOULDER , 4);
setButtonMapping( RIGHT_SHOULDER , 5);
//setButtonMapping( LEFT_TRIGGER , 0);
//setButtonMapping( RIGHT_TRIGGER , 0);
setAxisMapping( LEFT_ANALOG_TRIGGER , 2);
setAxisMapping( RIGHT_ANALOG_TRIGGER , 5);
// virtual buttons (analog axis values interpreted as buttons):
// (some buttons on the xbox controller are actually analog axes)
setButtonMapping( LEFT_PAD_NORTH , 7+mNumberOfButtons); // axis 7
setButtonMapping( LEFT_PAD_EAST , 6+mNumberOfButtons); // axis 6
setButtonMapping( LEFT_PAD_SOUTH , 7+mNumberOfButtons+mNumberOfAxes); // axis 7 inverse
setButtonMapping( LEFT_PAD_WEST , 6+mNumberOfButtons+mNumberOfAxes); // axis 6 inverse
setButtonMapping( LEFT_TRIGGER , 2+mNumberOfButtons); // axis 2
setButtonMapping( RIGHT_TRIGGER , 5+mNumberOfButtons); // axis 5
setAxisMapping( LEFT_ANALOG_TRIGGER , 2); mAxesMultiplier[2] = 0.5f; mAxesAdd[2] = 0.5f;
setAxisMapping( RIGHT_ANALOG_TRIGGER , 5); mAxesMultiplier[5] = -0.5f; mAxesAdd[5] = 0.5f;
setAxisMapping( LEFT_ANALOG_STICK_X , 0);
setAxisMapping( LEFT_ANALOG_STICK_Y , 1);
setAxisMapping( RIGHT_ANALOG_STICK_X , 3);
setAxisMapping( RIGHT_ANALOG_STICK_Y , 4);
setAxisMapping( RIGHT_ANALOG_STICK_X , 3); mAxesMultiplier[3] = -1.0f;
setAxisMapping( RIGHT_ANALOG_STICK_Y , 4); mAxesMultiplier[4] = -1.0f;
setMinAxisSensitivity( 0.2f );
} else {
debug() << "unknown gamepad: " << mJoystickName << " can't configure buttons" << endl;
}
......@@ -167,15 +193,31 @@ GamePad::~GamePad()
#endif
delete[] mAxes;
delete[] mAxesMultiplier;
delete[] mAxesAdd;
delete[] mButtonState;
delete[] mLastButtonState;
}
bool GamePad::isPressedRaw( unsigned int _button )
{
if ( (int)_button > mNumberOfButtons) return false;
return ( mButtonState[_button] == 1 );
if ( (int)_button < mNumberOfButtons) {
// it's a button:
return ( mButtonState[_button] == 1 );
}
// "buttons" from mNumberOfButtons to (mNumberOfButtons+mNumberOfAxes-1) are
// pushed if the axis value is >= 0.5.
int axis = (int)_button - mNumberOfButtons;
if (axis < mNumberOfAxes) {
return (mAxes[axis] >= 0.5f);
}
// "buttons" from (mNumberOfButtons+mNumberOfAxes) to (mNumberOfButtons+2*mNumberOfAxes-1) are
// pushed if the axis value is <= -0.5.
axis = axis - mNumberOfAxes;
if (axis < mNumberOfAxes) {
return (mAxes[axis] <= -0.5f);
}
// else the input was just too high, so return false
return false;
}
bool GamePad::isPressed( GamePadButton _button )
......@@ -270,29 +312,16 @@ void GamePad::getAxisAndButtonValues()
mAxes[i] = 0.0f;
}
#endif
for (int i = 0; i < mNumberOfAxes; ++i) {
mAxes[i] = mAxes[i] * mAxesMultiplier[i] + mAxesAdd[i];
}
}
void GamePad::update()
{
if (!ok()) return;
//
// if needed create state arrays
if (!mLastButtonState) {
mLastButtonState = new unsigned char[mNumberOfButtons];
mButtonState = new unsigned char[mNumberOfButtons];
mAxes = new float[mNumberOfAxes];
mAxesMultiplier = new float[mNumberOfAxes];
for (int i = 0; i < mNumberOfButtons; ++i) {
mButtonState[i] = 0;
}
for (int i = 0; i < mNumberOfAxes; ++i) {
mAxesMultiplier[i] = 1.0f;
mAxes[i] = 0.0f; // TODO: depending on the controller, the neutral state can also be -1!
}
}
//
// store old button state
// old axis state is not stored as this changes nearly constantly anyway
......@@ -327,17 +356,55 @@ void GamePad::printState()
return;
}
if (!mLastButtonState) {
// uninitialized, update() will initialize the buttons
update();
}
for (int i = 0; i < mNumberOfButtons; ++i) {
debug() << (int) mButtonState[i] << " ";
}
debug() << "| ";
std::stringstream axes;
axes.precision(2);
axes.setf( std::ios::fixed );
for (int i = 0; i < mNumberOfAxes; ++i) {
debug() << mAxes[i] << " ";
axes << mAxes[i] << " ";
}
debug() << axes.str() << endl;
}
bool GamePad::isMapped( GamePadButton _button )
{
for (int i = 0; i < GAMEPAD_BUTTON_ENUM_SIZE; ++i)
{
if (mButtonMap[i] != GAMEPAD_BUTTON_ENUM_SIZE) return true;
}
return false;
}
void GamePad::printPressedButtonHelper( GamePadButton _b, const char *_TRUE, const char *_false )
{
if (isMapped( _b )) {
if (isPressed( _b )) {
debug() << _TRUE << " ";
} else {
debug() << _false << " ";
}
}
}
void GamePad::printPressedButtons()
{
printPressedButtonHelper( SELECT, "SELECT", "select" );
printPressedButtonHelper( START, "START", "start" );
printPressedButtonHelper( LEFT_PAD_NORTH, "L_PAD_N", "l_pad_n");
printPressedButtonHelper( LEFT_PAD_EAST, "L_PAD_E", "l_pad_e");
printPressedButtonHelper( LEFT_PAD_SOUTH, "L_PAD_S", "l_pad_s");
printPressedButtonHelper( LEFT_PAD_WEST, "L_PAD_W", "l_pad_w");
printPressedButtonHelper( RIGHT_PAD_NORTH, "R_PAD_N", "r_pad_n");
printPressedButtonHelper( RIGHT_PAD_EAST, "R_PAD_E", "r_pad_e");
printPressedButtonHelper( RIGHT_PAD_SOUTH, "R_PAD_S", "r_pad_s");
printPressedButtonHelper( RIGHT_PAD_WEST, "R_PAD_W", "r_pad_w");
printPressedButtonHelper( LEFT_SHOULDER, "L_SHOULDER", "l_shoulder");
printPressedButtonHelper( RIGHT_SHOULDER, "R_SHOULDER", "r_shoulder");
printPressedButtonHelper( LEFT_TRIGGER, "L_TRIGGER", "l_trigger");
printPressedButtonHelper( RIGHT_TRIGGER, "R_TRIGGER", "r_trigger");
debug() << endl;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment