imported Löve GLES branch (changeset 1ba9037e558b)

This commit is contained in:
Martin Felis
2013-12-05 18:05:13 +01:00
parent 41b2db04a7
commit 2644d1ee18
615 changed files with 150300 additions and 0 deletions
+141
View File
@@ -0,0 +1,141 @@
/**
* Copyright (c) 2006-2013 LOVE Development Team
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
**/
// LOVE
#include "Joystick.h"
// STL
#include <cmath>
namespace love
{
namespace joystick
{
float Joystick::clampval(float x) const
{
if (fabsf(x) < 0.01)
return 0.0f;
if (x < -0.99f) return -1.0f;
if (x > 0.99f) return 1.0f;
return x;
}
bool Joystick::getConstant(const char *in, Joystick::Hat &out)
{
return hats.find(in, out);
}
bool Joystick::getConstant(Joystick::Hat in, const char *&out)
{
return hats.find(in, out);
}
bool Joystick::getConstant(const char *in, Joystick::GamepadAxis &out)
{
return gpAxes.find(in, out);
}
bool Joystick::getConstant(Joystick::GamepadAxis in, const char *&out)
{
return gpAxes.find(in, out);
}
bool Joystick::getConstant(const char *in, Joystick::GamepadButton &out)
{
return gpButtons.find(in, out);
}
bool Joystick::getConstant(Joystick::GamepadButton in, const char *&out)
{
return gpButtons.find(in, out);
}
bool Joystick::getConstant(const char *in, Joystick::InputType &out)
{
return inputTypes.find(in, out);
}
bool Joystick::getConstant(Joystick::InputType in, const char *&out)
{
return inputTypes.find(in, out);
}
StringMap<Joystick::Hat, Joystick::HAT_MAX_ENUM>::Entry Joystick::hatEntries[] =
{
{"c", Joystick::HAT_CENTERED},
{"u", Joystick::HAT_UP},
{"r", Joystick::HAT_RIGHT},
{"d", Joystick::HAT_DOWN},
{"l", Joystick::HAT_LEFT},
{"ru", Joystick::HAT_RIGHTUP},
{"rd", Joystick::HAT_RIGHTDOWN},
{"lu", Joystick::HAT_LEFTUP},
{"ld", Joystick::HAT_LEFTDOWN},
};
StringMap<Joystick::Hat, Joystick::HAT_MAX_ENUM> Joystick::hats(Joystick::hatEntries, sizeof(Joystick::hatEntries));
StringMap<Joystick::GamepadAxis, Joystick::GAMEPAD_AXIS_MAX_ENUM>::Entry Joystick::gpAxisEntries[] =
{
{"leftx", GAMEPAD_AXIS_LEFTX},
{"lefty", GAMEPAD_AXIS_LEFTY},
{"rightx", GAMEPAD_AXIS_RIGHTX},
{"righty", GAMEPAD_AXIS_RIGHTY},
{"triggerleft", GAMEPAD_AXIS_TRIGGERLEFT},
{"triggerright", GAMEPAD_AXIS_TRIGGERRIGHT},
};
StringMap<Joystick::GamepadAxis, Joystick::GAMEPAD_AXIS_MAX_ENUM> Joystick::gpAxes(Joystick::gpAxisEntries, sizeof(Joystick::gpAxisEntries));
StringMap<Joystick::GamepadButton, Joystick::GAMEPAD_BUTTON_MAX_ENUM>::Entry Joystick::gpButtonEntries[] =
{
{"a", GAMEPAD_BUTTON_A},
{"b", GAMEPAD_BUTTON_B},
{"x", GAMEPAD_BUTTON_X},
{"y", GAMEPAD_BUTTON_Y},
{"back", GAMEPAD_BUTTON_BACK},
{"guide", GAMEPAD_BUTTON_GUIDE},
{"start", GAMEPAD_BUTTON_START},
{"leftstick", GAMEPAD_BUTTON_LEFTSTICK},
{"rightstick", GAMEPAD_BUTTON_RIGHTSTICK},
{"leftshoulder", GAMEPAD_BUTTON_LEFTSHOULDER},
{"rightshoulder", GAMEPAD_BUTTON_RIGHTSHOULDER},
{"dpup", GAMEPAD_BUTTON_DPAD_UP},
{"dpdown", GAMEPAD_BUTTON_DPAD_DOWN},
{"dpleft", GAMEPAD_BUTTON_DPAD_LEFT},
{"dpright", GAMEPAD_BUTTON_DPAD_RIGHT},
};
StringMap<Joystick::GamepadButton, Joystick::GAMEPAD_BUTTON_MAX_ENUM> Joystick::gpButtons(Joystick::gpButtonEntries, sizeof(Joystick::gpButtonEntries));
StringMap<Joystick::InputType, Joystick::INPUT_TYPE_MAX_ENUM>::Entry Joystick::inputTypeEntries[] =
{
{"axis", Joystick::INPUT_TYPE_AXIS},
{"button", Joystick::INPUT_TYPE_BUTTON},
{"hat", Joystick::INPUT_TYPE_HAT},
};
StringMap<Joystick::InputType, Joystick::INPUT_TYPE_MAX_ENUM> Joystick::inputTypes(Joystick::inputTypeEntries, sizeof(Joystick::inputTypeEntries));
} // joystick
} // love
+200
View File
@@ -0,0 +1,200 @@
/**
* Copyright (c) 2006-2013 LOVE Development Team
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
**/
#ifndef LOVE_JOYSTICK_JOYSTICK_H
#define LOVE_JOYSTICK_JOYSTICK_H
// LOVE
#include "common/Object.h"
#include "common/StringMap.h"
// stdlib
#include <vector>
#include <string>
namespace love
{
namespace joystick
{
class Joystick : public Object
{
public:
// Joystick hat values.
enum Hat
{
HAT_INVALID,
HAT_CENTERED,
HAT_UP,
HAT_RIGHT,
HAT_DOWN,
HAT_LEFT,
HAT_RIGHTUP,
HAT_RIGHTDOWN,
HAT_LEFTUP,
HAT_LEFTDOWN,
HAT_MAX_ENUM = 16
};
// Valid Gamepad axes.
enum GamepadAxis
{
GAMEPAD_AXIS_INVALID,
GAMEPAD_AXIS_LEFTX,
GAMEPAD_AXIS_LEFTY,
GAMEPAD_AXIS_RIGHTX,
GAMEPAD_AXIS_RIGHTY,
GAMEPAD_AXIS_TRIGGERLEFT,
GAMEPAD_AXIS_TRIGGERRIGHT,
GAMEPAD_AXIS_MAX_ENUM
};
// Valid Gamepad buttons.
enum GamepadButton
{
GAMEPAD_BUTTON_INVALID,
GAMEPAD_BUTTON_A,
GAMEPAD_BUTTON_B,
GAMEPAD_BUTTON_X,
GAMEPAD_BUTTON_Y,
GAMEPAD_BUTTON_BACK,
GAMEPAD_BUTTON_GUIDE,
GAMEPAD_BUTTON_START,
GAMEPAD_BUTTON_LEFTSTICK,
GAMEPAD_BUTTON_RIGHTSTICK,
GAMEPAD_BUTTON_LEFTSHOULDER,
GAMEPAD_BUTTON_RIGHTSHOULDER,
GAMEPAD_BUTTON_DPAD_UP,
GAMEPAD_BUTTON_DPAD_DOWN,
GAMEPAD_BUTTON_DPAD_LEFT,
GAMEPAD_BUTTON_DPAD_RIGHT,
GAMEPAD_BUTTON_MAX_ENUM
};
// Different types of inputs for a joystick.
enum InputType
{
INPUT_TYPE_AXIS,
INPUT_TYPE_BUTTON,
INPUT_TYPE_HAT,
INPUT_TYPE_MAX_ENUM
};
// Represents a gamepad input value, e.g. the "x" button or the left trigger.
struct GamepadInput
{
InputType type;
union
{
GamepadAxis axis;
GamepadButton button;
};
};
// Represents a joystick input value, e.g. button 6 or axis 1.
struct JoystickInput
{
InputType type;
union
{
int axis;
int button;
struct
{
int index;
Hat value;
} hat;
};
};
virtual ~Joystick() {}
virtual bool open(int deviceindex) = 0;
virtual void close() = 0;
virtual bool isConnected() const = 0;
virtual const char *getName() const = 0;
virtual int getAxisCount() const = 0;
virtual int getButtonCount() const = 0;
virtual int getHatCount() const = 0;
virtual float getAxis(int axisindex) const = 0;
virtual std::vector<float> getAxes() const = 0;
virtual Hat getHat(int hatindex) const = 0;
virtual bool isDown(const std::vector<int> &buttonlist) const = 0;
virtual bool openGamepad(int deviceindex) = 0;
virtual bool isGamepad() const = 0;
virtual float getGamepadAxis(GamepadAxis axis) const = 0;
virtual bool isGamepadDown(const std::vector<GamepadButton> &blist) const = 0;
virtual void *getHandle() const = 0;
virtual std::string getGUID() const = 0;
virtual int getInstanceID() const = 0;
virtual int getID() const = 0;
virtual bool isVibrationSupported() = 0;
virtual bool setVibration(float left, float right) = 0;
virtual bool setVibration() = 0;
virtual void getVibration(float &left, float &right) const = 0;
static bool getConstant(const char *in, Hat &out);
static bool getConstant(Hat in, const char *&out);
static bool getConstant(const char *in, GamepadAxis &out);
static bool getConstant(GamepadAxis in, const char *&out);
static bool getConstant(const char *in, GamepadButton &out);
static bool getConstant(GamepadButton in, const char *&out);
static bool getConstant(const char *in, InputType &out);
static bool getConstant(InputType in, const char *&out);
protected:
float clampval(float x) const;
private:
static StringMap<Hat, HAT_MAX_ENUM>::Entry hatEntries[];
static StringMap<Hat, HAT_MAX_ENUM> hats;
static StringMap<GamepadAxis, GAMEPAD_AXIS_MAX_ENUM>::Entry gpAxisEntries[];
static StringMap<GamepadAxis, GAMEPAD_AXIS_MAX_ENUM> gpAxes;
static StringMap<GamepadButton, GAMEPAD_BUTTON_MAX_ENUM>::Entry gpButtonEntries[];
static StringMap<GamepadButton, GAMEPAD_BUTTON_MAX_ENUM> gpButtons;
static StringMap<InputType, INPUT_TYPE_MAX_ENUM>::Entry inputTypeEntries[];
static StringMap<InputType, INPUT_TYPE_MAX_ENUM> inputTypes;
}; // Joystick
} // joystick
} // love
#endif // LOVE_JOYSTICK_JOYSTICK_H
@@ -0,0 +1,93 @@
/**
* Copyright (c) 2006-2013 LOVE Development Team
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
**/
#ifndef LOVE_JOYSTICK_JOYSTICK_MODULE_H
#define LOVE_JOYSTICK_JOYSTICK_MODULE_H
// LOVE
#include "common/Module.h"
#include "Joystick.h"
namespace love
{
namespace joystick
{
class JoystickModule : public Module
{
public:
virtual ~JoystickModule() {}
/**
* Adds a connected Joystick device and opens it for use.
* Returns NULL if the Joystick could not be added.
**/
virtual Joystick *addJoystick(int deviceindex) = 0;
/**
* Removes a disconnected Joystick device.
**/
virtual void removeJoystick(Joystick *joystick) = 0;
/**
* Gets a connected Joystick from its unique Instance ID.
* Returns NULL if the instance ID does not correspond to a connected stick.
**/
virtual Joystick *getJoystickFromID(int instanceid) = 0;
/**
* Gets a connected Joystick.
* Returns NULL if joyindex is not in the range of [0, getJoystickCount()).
**/
virtual Joystick *getJoystick(int joyindex) = 0;
/**
* Gets the index of a connected joystick.
* Returns -1 if the joystick is not connected.
**/
virtual int getIndex(const Joystick *joystick) = 0;
/**
* Gets the number of currently connected Joysticks.
**/
virtual int getJoystickCount() const = 0;
/**
* Sets the virtual Gamepad mapping for a joystick input value for all
* joystick devices with the specified joystick product GUID.
* If any joysticks with the specified GUID are connected, they will be
* added as Gamepads if they aren't already, otherwise their Gamepad mapping
* will be updated.
**/
virtual bool setGamepadMapping(const std::string &pguid, Joystick::GamepadInput gpinput, Joystick::JoystickInput joyinput) = 0;
/**
* Gets the joystick input value the gamepad input value is bound to for the
* specified joystick product GUID.
**/
virtual Joystick::JoystickInput getGamepadMapping(const std::string &pguid, Joystick::GamepadInput gpinput) = 0;
}; // JoystickModule
} // joystick
} // love
#endif // LOVE_JOYSTICK_JOYSTICK_MODULE_H
@@ -0,0 +1,522 @@
/**
* Copyright (c) 2006-2013 LOVE Development Team
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
**/
// LOVE
#include "common/config.h"
#include "Joystick.h"
#include "common/int.h"
// C++
#include <algorithm>
namespace love
{
namespace joystick
{
namespace sdl
{
Joystick::Joystick(int id)
: joyhandle(0)
, controller(0)
, haptic(0)
, instanceid(-1)
, id(id)
, vibration()
{
}
Joystick::Joystick(int id, int joyindex)
: joyhandle(0)
, controller(0)
, haptic(0)
, instanceid(-1)
, id(id)
, vibration()
{
open(joyindex);
}
Joystick::~Joystick()
{
close();
}
bool Joystick::open(int deviceindex)
{
close();
joyhandle = SDL_JoystickOpen(deviceindex);
if (joyhandle)
{
instanceid = SDL_JoystickInstanceID(joyhandle);
// SDL_JoystickGetGUIDString uses 32 bytes plus the null terminator.
char cstr[33];
SDL_JoystickGUID sdlguid = SDL_JoystickGetGUID(joyhandle);
SDL_JoystickGetGUIDString(sdlguid, cstr, (int) sizeof(cstr));
pguid = std::string(cstr);
// See if SDL thinks this is a Game Controller.
openGamepad(deviceindex);
// Prefer the Joystick name for consistency.
const char *joyname = SDL_JoystickName(joyhandle);
if (!joyname && controller)
joyname = SDL_GameControllerName(controller);
if (joyname)
name = joyname;
}
return isConnected();
}
void Joystick::close()
{
if (haptic)
{
SDL_HapticRumbleStop(haptic);
SDL_HapticClose(haptic);
}
if (controller)
SDL_GameControllerClose(controller);
if (joyhandle)
SDL_JoystickClose(joyhandle);
joyhandle = 0;
controller = 0;
haptic = 0;
instanceid = -1;
vibration = Vibration();
}
bool Joystick::isConnected() const
{
return joyhandle != 0 && SDL_JoystickGetAttached(joyhandle);
}
const char *Joystick::getName() const
{
// Use the saved name if this Joystick isn't connected anymore.
if (!isConnected())
return name.c_str();
// Prefer the Joystick name for consistency.
const char *joyname = SDL_JoystickName(joyhandle);
if (!joyname && isGamepad())
joyname = SDL_GameControllerName(controller);
return joyname;
}
int Joystick::getAxisCount() const
{
return isConnected() ? SDL_JoystickNumAxes(joyhandle) : 0;
}
int Joystick::getButtonCount() const
{
return isConnected() ? SDL_JoystickNumButtons(joyhandle) : 0;
}
int Joystick::getHatCount() const
{
return isConnected() ? SDL_JoystickNumHats(joyhandle) : 0;
}
float Joystick::getAxis(int axisindex) const
{
if (!isConnected() || axisindex < 0 || axisindex >= getAxisCount())
return 0;
return clampval(((float) SDL_JoystickGetAxis(joyhandle, axisindex))/32768.0f);
}
std::vector<float> Joystick::getAxes() const
{
std::vector<float> axes;
int count = getAxisCount();
if (!isConnected() || count <= 0)
return axes;
axes.reserve(count);
for (int i = 0; i < count; i++)
axes.push_back(clampval(((float) SDL_JoystickGetAxis(joyhandle, i))/32768.0f));
return axes;
}
Joystick::Hat Joystick::getHat(int hatindex) const
{
Hat h = HAT_INVALID;
if (!isConnected() || hatindex < 0 || hatindex >= getHatCount())
return h;
getConstant(SDL_JoystickGetHat(joyhandle, hatindex), h);
return h;
}
bool Joystick::isDown(const std::vector<int> &buttonlist) const
{
if (!isConnected())
return false;
int num = getButtonCount();
for (size_t i = 0; i < buttonlist.size(); i++)
{
int button = buttonlist[i];
if (button >= 0 && button < num && SDL_JoystickGetButton(joyhandle, button) == 1)
return true;
}
return false;
}
bool Joystick::openGamepad(int deviceindex)
{
if (!SDL_IsGameController(deviceindex))
return false;
if (isGamepad())
{
SDL_GameControllerClose(controller);
controller = 0;
}
controller = SDL_GameControllerOpen(deviceindex);
return isGamepad();
}
bool Joystick::isGamepad() const
{
return controller != 0;
}
float Joystick::getGamepadAxis(love::joystick::Joystick::GamepadAxis axis) const
{
if (!isConnected() || !isGamepad())
return 0.f;
SDL_GameControllerAxis sdlaxis;
if (!getConstant(axis, sdlaxis))
return 0.f;
Sint16 value = SDL_GameControllerGetAxis(controller, sdlaxis);
return clampval((float) value / 32768.0f);
}
bool Joystick::isGamepadDown(const std::vector<GamepadButton> &blist) const
{
if (!isConnected() || !isGamepad())
return false;
SDL_GameControllerButton sdlbutton;
for (size_t i = 0; i < blist.size(); i++)
{
if (!getConstant(blist[i], sdlbutton))
continue;
if (SDL_GameControllerGetButton(controller, sdlbutton) == 1)
return true;
}
return false;
}
void *Joystick::getHandle() const
{
return joyhandle;
}
std::string Joystick::getGUID() const
{
// SDL2's GUIDs identify *classes* of devices, instead of unique devices.
return pguid;
}
int Joystick::getInstanceID() const
{
return instanceid;
}
int Joystick::getID() const
{
return id;
}
bool Joystick::checkCreateHaptic()
{
if (!isConnected())
return false;
if (!SDL_WasInit(SDL_INIT_HAPTIC) && SDL_InitSubSystem(SDL_INIT_HAPTIC) < 0)
return false;
if (haptic && SDL_HapticIndex(haptic) != -1)
return true;
if (haptic)
{
SDL_HapticClose(haptic);
haptic = 0;
}
haptic = SDL_HapticOpenFromJoystick(joyhandle);
vibration = Vibration();
return haptic != 0;
}
bool Joystick::isVibrationSupported()
{
if (!checkCreateHaptic())
return false;
unsigned int features = SDL_HapticQuery(haptic);
if ((features & SDL_HAPTIC_LEFTRIGHT) != 0)
return true;
// Some gamepad drivers only support left/right motors via a custom effect.
if (isGamepad() && (features & SDL_HAPTIC_CUSTOM) != 0)
return true;
// Check SDL's simple rumble as a last resort.
if (SDL_HapticRumbleSupported(haptic) == 1)
return true;
return false;
}
bool Joystick::runVibrationEffect()
{
if (vibration.id != -1)
{
if (SDL_HapticUpdateEffect(haptic, vibration.id, &vibration.effect) == 0)
{
if (SDL_HapticRunEffect(haptic, vibration.id, 1) != -1)
return true;
}
// If the effect fails to update, we should destroy and re-create it.
SDL_HapticDestroyEffect(haptic, vibration.id);
vibration.id = -1;
}
vibration.id = SDL_HapticNewEffect(haptic, &vibration.effect);
if (vibration.id != -1 && SDL_HapticRunEffect(haptic, vibration.id, 1) != -1)
return true;
return false;
}
bool Joystick::setVibration(float left, float right)
{
// TODO: support non-infinite durations? The working Tattiebogle Xbox
// controller driver in OS X seems to ignore durations under 1 second.
left = std::min(std::max(left, 0.0f), 1.0f);
right = std::min(std::max(right, 0.0f), 1.0f);
if (left == 0.0f && right == 0.0f)
return setVibration();
if (!checkCreateHaptic())
return false;
bool success = false;
unsigned int features = SDL_HapticQuery(haptic);
if ((features & SDL_HAPTIC_LEFTRIGHT) != 0)
{
memset(&vibration.effect, 0, sizeof(SDL_HapticEffect));
vibration.effect.type = SDL_HAPTIC_LEFTRIGHT;
// SDL's Xinput code has an int. overflow bug with SDL_HAPTIC_INFINITY.
const Uint32 long_time = 1000 * 60 * 60 * 2;
vibration.effect.leftright.length = long_time;
vibration.effect.leftright.large_magnitude = Uint16(left * LOVE_UINT16_MAX);
vibration.effect.leftright.small_magnitude = Uint16(right * LOVE_UINT16_MAX);
success = runVibrationEffect();
}
// Some gamepad drivers only give support for controlling the motors via
// a custom FF effect.
if (!success && isGamepad() && (features & SDL_HAPTIC_CUSTOM) != 0)
{
// NOTE: this may cause issues with drivers which support custom effects
// but aren't similar to https://github.com/d235j/360Controller .
// Custom effect data is clamped to 0x7FFF in SDL.
vibration.data[0] = vibration.data[2] = Uint16(left * 0x7FFF);
vibration.data[1] = vibration.data[3] = Uint16(right * 0x7FFF);
memset(&vibration.effect, 0, sizeof(SDL_HapticEffect));
vibration.effect.type = SDL_HAPTIC_CUSTOM;
vibration.effect.custom.length = SDL_HAPTIC_INFINITY;
vibration.effect.custom.channels = 2;
vibration.effect.custom.period = 10;
vibration.effect.custom.samples = 2;
vibration.effect.custom.data = vibration.data;
success = runVibrationEffect();
}
// Fall back to a simple rumble if all else fails. SDL's simple rumble API
// only supports a single strength value.
if (!success && SDL_HapticRumbleInit(haptic) == 0)
{
float strength = std::max(left, right);
int played = SDL_HapticRumblePlay(haptic, strength, SDL_HAPTIC_INFINITY);
success = (played == 0);
}
if (success)
{
vibration.left = left;
vibration.right = right;
}
return success;
}
bool Joystick::setVibration()
{
bool success = true;
if (SDL_WasInit(SDL_INIT_HAPTIC) && haptic && SDL_HapticIndex(haptic) != -1)
{
// Stop all playing effects on the haptic device.
// FIXME: We should only stop the vibration effect, in case we use the
// Haptic API for other things in the future.
success = (SDL_HapticStopAll(haptic) == 0);
}
if (success)
vibration.left = vibration.right = 0.0f;
return success;
}
void Joystick::getVibration(float &left, float &right) const
{
left = vibration.left;
right = vibration.right;
}
bool Joystick::getConstant(Uint8 in, Joystick::Hat &out)
{
return hats.find(in, out);
}
bool Joystick::getConstant(Joystick::Hat in, Uint8 &out)
{
return hats.find(in, out);
}
bool Joystick::getConstant(SDL_GameControllerAxis in, Joystick::GamepadAxis &out)
{
return gpAxes.find(in, out);
}
bool Joystick::getConstant(Joystick::GamepadAxis in, SDL_GameControllerAxis &out)
{
return gpAxes.find(in, out);
}
bool Joystick::getConstant(SDL_GameControllerButton in, Joystick::GamepadButton &out)
{
return gpButtons.find(in, out);
}
bool Joystick::getConstant(Joystick::GamepadButton in, SDL_GameControllerButton &out)
{
return gpButtons.find(in, out);
}
EnumMap<Joystick::Hat, Uint8, Joystick::HAT_MAX_ENUM>::Entry Joystick::hatEntries[] =
{
{Joystick::HAT_CENTERED, SDL_HAT_CENTERED},
{Joystick::HAT_UP, SDL_HAT_UP},
{Joystick::HAT_RIGHT, SDL_HAT_RIGHT},
{Joystick::HAT_DOWN, SDL_HAT_DOWN},
{Joystick::HAT_LEFT, SDL_HAT_LEFT},
{Joystick::HAT_RIGHTUP, SDL_HAT_RIGHTUP},
{Joystick::HAT_RIGHTDOWN, SDL_HAT_RIGHTDOWN},
{Joystick::HAT_LEFTUP, SDL_HAT_LEFTUP},
{Joystick::HAT_LEFTDOWN, SDL_HAT_LEFTDOWN},
};
EnumMap<Joystick::Hat, Uint8, Joystick::HAT_MAX_ENUM> Joystick::hats(Joystick::hatEntries, sizeof(Joystick::hatEntries));
EnumMap<Joystick::GamepadAxis, SDL_GameControllerAxis, Joystick::GAMEPAD_AXIS_MAX_ENUM>::Entry Joystick::gpAxisEntries[] =
{
{Joystick::GAMEPAD_AXIS_LEFTX, SDL_CONTROLLER_AXIS_LEFTX},
{Joystick::GAMEPAD_AXIS_LEFTY, SDL_CONTROLLER_AXIS_LEFTY},
{Joystick::GAMEPAD_AXIS_RIGHTX, SDL_CONTROLLER_AXIS_RIGHTX},
{Joystick::GAMEPAD_AXIS_RIGHTY, SDL_CONTROLLER_AXIS_RIGHTY},
{Joystick::GAMEPAD_AXIS_TRIGGERLEFT, SDL_CONTROLLER_AXIS_TRIGGERLEFT},
{Joystick::GAMEPAD_AXIS_TRIGGERRIGHT, SDL_CONTROLLER_AXIS_TRIGGERRIGHT},
};
EnumMap<Joystick::GamepadAxis, SDL_GameControllerAxis, Joystick::GAMEPAD_AXIS_MAX_ENUM> Joystick::gpAxes(Joystick::gpAxisEntries, sizeof(Joystick::gpAxisEntries));
EnumMap<Joystick::GamepadButton, SDL_GameControllerButton, Joystick::GAMEPAD_BUTTON_MAX_ENUM>::Entry Joystick::gpButtonEntries[] =
{
{Joystick::GAMEPAD_BUTTON_A, SDL_CONTROLLER_BUTTON_A},
{Joystick::GAMEPAD_BUTTON_B, SDL_CONTROLLER_BUTTON_B},
{Joystick::GAMEPAD_BUTTON_X, SDL_CONTROLLER_BUTTON_X},
{Joystick::GAMEPAD_BUTTON_Y, SDL_CONTROLLER_BUTTON_Y},
{Joystick::GAMEPAD_BUTTON_BACK, SDL_CONTROLLER_BUTTON_BACK},
{Joystick::GAMEPAD_BUTTON_GUIDE, SDL_CONTROLLER_BUTTON_GUIDE},
{Joystick::GAMEPAD_BUTTON_START, SDL_CONTROLLER_BUTTON_START},
{Joystick::GAMEPAD_BUTTON_LEFTSTICK, SDL_CONTROLLER_BUTTON_LEFTSTICK},
{Joystick::GAMEPAD_BUTTON_RIGHTSTICK, SDL_CONTROLLER_BUTTON_RIGHTSTICK},
{Joystick::GAMEPAD_BUTTON_LEFTSHOULDER, SDL_CONTROLLER_BUTTON_LEFTSHOULDER},
{Joystick::GAMEPAD_BUTTON_RIGHTSHOULDER, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER},
{Joystick::GAMEPAD_BUTTON_DPAD_UP, SDL_CONTROLLER_BUTTON_DPAD_UP},
{Joystick::GAMEPAD_BUTTON_DPAD_DOWN, SDL_CONTROLLER_BUTTON_DPAD_DOWN},
{Joystick::GAMEPAD_BUTTON_DPAD_LEFT, SDL_CONTROLLER_BUTTON_DPAD_LEFT},
{Joystick::GAMEPAD_BUTTON_DPAD_RIGHT, SDL_CONTROLLER_BUTTON_DPAD_RIGHT},
};
EnumMap<Joystick::GamepadButton, SDL_GameControllerButton, Joystick::GAMEPAD_BUTTON_MAX_ENUM> Joystick::gpButtons(Joystick::gpButtonEntries, sizeof(Joystick::gpButtonEntries));
} // sdl
} // joystick
} // love
@@ -0,0 +1,135 @@
/**
* Copyright (c) 2006-2013 LOVE Development Team
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
**/
#ifndef LOVE_JOYSTICK_SDL_JOYSTICK_H
#define LOVE_JOYSTICK_SDL_JOYSTICK_H
// LOVE
#include "joystick/Joystick.h"
#include "common/EnumMap.h"
// SDL
#include <SDL.h>
namespace love
{
namespace joystick
{
namespace sdl
{
class Joystick : public love::joystick::Joystick
{
public:
Joystick(int id);
Joystick(int id, int joyindex);
virtual ~Joystick();
bool open(int deviceindex);
void close();
bool isConnected() const;
const char *getName() const;
int getAxisCount() const;
int getButtonCount() const;
int getHatCount() const;
float getAxis(int axisindex) const;
std::vector<float> getAxes() const;
Hat getHat(int hatindex) const;
bool isDown(const std::vector<int> &buttonlist) const;
bool openGamepad(int deviceindex);
bool isGamepad() const;
float getGamepadAxis(GamepadAxis axis) const;
bool isGamepadDown(const std::vector<GamepadButton> &blist) const;
void *getHandle() const;
std::string getGUID() const;
int getInstanceID() const;
int getID() const;
bool isVibrationSupported();
bool setVibration(float left, float right);
bool setVibration();
void getVibration(float &left, float &right) const;
static bool getConstant(Hat in, Uint8 &out);
static bool getConstant(Uint8 in, Hat &out);
static bool getConstant(SDL_GameControllerAxis in, GamepadAxis &out);
static bool getConstant(GamepadAxis in, SDL_GameControllerAxis &out);
static bool getConstant(SDL_GameControllerButton in, GamepadButton &out);
static bool getConstant(GamepadButton in, SDL_GameControllerButton &out);
private:
Joystick() {}
bool checkCreateHaptic();
bool runVibrationEffect();
SDL_Joystick *joyhandle;
SDL_GameController *controller;
SDL_Haptic *haptic;
SDL_JoystickID instanceid;
std::string pguid;
int id;
std::string name;
struct Vibration
{
float left, right;
SDL_HapticEffect effect;
Uint16 data[4];
int id;
Vibration()
: left(0.0f), right(0.0f), effect(), data(), id(-1)
{}
} vibration;
static EnumMap<Hat, Uint8, Joystick::HAT_MAX_ENUM>::Entry hatEntries[];
static EnumMap<Hat, Uint8, Joystick::HAT_MAX_ENUM> hats;
static EnumMap<GamepadAxis, SDL_GameControllerAxis, GAMEPAD_AXIS_MAX_ENUM>::Entry gpAxisEntries[];
static EnumMap<GamepadAxis, SDL_GameControllerAxis, GAMEPAD_AXIS_MAX_ENUM> gpAxes;
static EnumMap<GamepadButton, SDL_GameControllerButton, GAMEPAD_BUTTON_MAX_ENUM>::Entry gpButtonEntries[];
static EnumMap<GamepadButton, SDL_GameControllerButton, GAMEPAD_BUTTON_MAX_ENUM> gpButtons;
};
} // sdl
} // joystick
} // love
#endif // LOVE_JOYSTICK_SDL_JOYSTICK_H
@@ -0,0 +1,467 @@
/**
* Copyright (c) 2006-2013 LOVE Development Team
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
**/
#include "common/config.h"
#include "JoystickModule.h"
#include "Joystick.h"
// SDL
#include <SDL.h>
// C++
#include <sstream>
#include <algorithm>
// C
#include <cstdlib>
namespace love
{
namespace joystick
{
namespace sdl
{
JoystickModule::JoystickModule()
{
if (SDL_InitSubSystem(SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER) < 0)
throw love::Exception("%s", SDL_GetError());
// Initialize any joysticks which are already connected.
for (int i = 0; i < SDL_NumJoysticks(); i++)
addJoystick(i);
// Start joystick event watching. Joysticks are automatically added and
// removed via love.event.
SDL_JoystickEventState(SDL_ENABLE);
SDL_GameControllerEventState(SDL_ENABLE);
}
JoystickModule::~JoystickModule()
{
// Close any open Joysticks.
for (auto it = joysticks.begin(); it != joysticks.end(); ++it)
{
(*it)->close();
(*it)->release();
}
if (SDL_WasInit(SDL_INIT_HAPTIC) != 0)
SDL_QuitSubSystem(SDL_INIT_HAPTIC);
SDL_QuitSubSystem(SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER);
}
const char *JoystickModule::getName() const
{
return "love.joystick.sdl";
}
love::joystick::Joystick *JoystickModule::getJoystick(int joyindex)
{
if (joyindex < 0 || (size_t) joyindex >= activeSticks.size())
return 0;
return activeSticks[joyindex];
}
int JoystickModule::getIndex(const love::joystick::Joystick *joystick)
{
for (size_t i = 0; i < activeSticks.size(); i++)
{
if (activeSticks[i] == joystick)
return i;
}
// Joystick is not connected.
return -1;
}
int JoystickModule::getJoystickCount() const
{
return (int) activeSticks.size();
}
love::joystick::Joystick *JoystickModule::getJoystickFromID(int instanceid)
{
for (size_t i = 0; i < activeSticks.size(); i++)
{
if (instanceid == activeSticks[i]->getInstanceID())
return activeSticks[i];
}
return 0;
}
love::joystick::Joystick *JoystickModule::addJoystick(int deviceindex)
{
if (deviceindex < 0 || deviceindex >= SDL_NumJoysticks())
return 0;
std::string guidstr = getDeviceGUID(deviceindex);
joystick::Joystick *joystick = 0;
bool reused = false;
for (auto it = joysticks.begin(); it != joysticks.end(); ++it)
{
// Try to re-use a disconnected Joystick with the same GUID.
if (!(*it)->isConnected() && (*it)->getGUID() == guidstr)
{
joystick = *it;
reused = true;
break;
}
}
if (!joystick)
{
joystick = new Joystick(joysticks.size());
joysticks.push_back(joystick);
}
// Make sure the Joystick object isn't in the active list already.
removeJoystick(joystick);
if (!joystick->open(deviceindex))
return 0;
// Make sure multiple instances of the same physical joystick aren't added
// to the active list.
for (auto it = activeSticks.begin(); it != activeSticks.end(); ++it)
{
if (joystick->getHandle() == (*it)->getHandle())
{
joystick->close();
// If we just created the stick, remove it since it's a duplicate.
if (!reused)
{
joysticks.remove(joystick);
joystick->release();
}
return *it;
}
}
activeSticks.push_back(joystick);
return joystick;
}
void JoystickModule::removeJoystick(love::joystick::Joystick *joystick)
{
if (!joystick)
return;
// Close the Joystick and remove it from the active joystick list.
auto it = std::find(activeSticks.begin(), activeSticks.end(), joystick);
if (it != activeSticks.end())
{
(*it)->close();
activeSticks.erase(it);
}
}
bool JoystickModule::setGamepadMapping(const std::string &guid, Joystick::GamepadInput gpinput, Joystick::JoystickInput joyinput)
{
// All SDL joystick GUID strings are 32 characters.
if (guid.length() != 32)
throw love::Exception("Invalid joystick GUID: %s", guid.c_str());
SDL_JoystickGUID sdlguid = SDL_JoystickGetGUIDFromString(guid.c_str());
std::string mapstr;
char *sdlmapstr = SDL_GameControllerMappingForGUID(sdlguid);
if (sdlmapstr)
{
mapstr = sdlmapstr;
SDL_free(sdlmapstr);
}
else
{
// Use a generic name if we have to create a new mapping string.
mapstr = guid + ",Controller,";
}
std::stringstream joyinputstream;
Uint8 sdlhat;
// We can't have negative int values in the bind string.
switch (joyinput.type)
{
case Joystick::INPUT_TYPE_AXIS:
if (joyinput.axis >= 0)
joyinputstream << "a" << joyinput.axis;
break;
case Joystick::INPUT_TYPE_BUTTON:
if (joyinput.button >= 0)
joyinputstream << "b" << joyinput.button;
break;
case Joystick::INPUT_TYPE_HAT:
if (joyinput.hat.value >= 0 && Joystick::getConstant(joyinput.hat.value, sdlhat))
joyinputstream << "h" << joyinput.hat.value << "." << int(sdlhat);
break;
default:
break;
}
std::string joyinputstr = joyinputstream.str();
if (joyinputstr.length() == 0)
throw love::Exception("Invalid joystick input value.");
// SDL's name for the gamepad input value, e.g. "guide".
std::string gpinputname = stringFromGamepadInput(gpinput);
// We should remove any existing joystick bind for this gamepad buttton/axis
// so SDL's parser doesn't get mixed up.
removeBindFromMapString(mapstr, joyinputstr);
// The string we'll be adding to the mapping string, e.g. "guide:b10,"
std::string insertstr = gpinputname + ":" + joyinputstr + ",";
// We should replace any existing gamepad bind.
size_t findpos = mapstr.find(gpinputname + ":");
if (findpos != std::string::npos)
{
// The bind string ends at the next comma, or the end of the string.
size_t endpos = mapstr.find_first_of(',', findpos);
if (endpos == std::string::npos)
endpos = mapstr.length() - 1;
mapstr.replace(findpos, endpos - findpos + 1, insertstr);
}
else
{
// Just append to the end if we don't need to replace anything.
mapstr += insertstr;
}
// 1 == added, 0 == updated, -1 == error.
int status = SDL_GameControllerAddMapping(mapstr.c_str());
// FIXME: massive hack until missing APIs are added to SDL 2:
// https://bugzilla.libsdl.org/show_bug.cgi?id=1975
if (status == 1)
checkGamepads(guid);
return status >= 0;
}
Joystick::JoystickInput JoystickModule::getGamepadMapping(const std::string &guid, Joystick::GamepadInput gpinput)
{
// All SDL joystick GUID strings are 32 characters.
if (guid.length() != 32)
throw love::Exception("Invalid joystick GUID: %s", guid.c_str());
Joystick::JoystickInput jinput;
jinput.type = Joystick::INPUT_TYPE_MAX_ENUM;
SDL_JoystickGUID sdlguid = SDL_JoystickGetGUIDFromString(guid.c_str());
std::string mapstr;
char *sdlmapstr = SDL_GameControllerMappingForGUID(sdlguid);
if (!sdlmapstr)
return jinput;
mapstr = sdlmapstr;
SDL_free(sdlmapstr);
std::string gpbindname = stringFromGamepadInput(gpinput);
size_t findpos = mapstr.find(std::string(",") + gpbindname + ":");
if (findpos == std::string::npos)
return jinput;
size_t endpos = mapstr.find_first_of(',', findpos);
if (endpos == std::string::npos)
{
// Assume end-of-string if we can't find the next comma.
endpos = mapstr.length() - 1;
}
if (endpos >= mapstr.length())
return jinput; // Something went wrong.
// Strip out the trailing comma from our search position, if it exists.
if (mapstr[endpos] == ',')
endpos--;
// New start position: comma + gamepadinputlength + ":".
findpos += 1 + gpbindname.length() + 1;
std::string jbindstr = mapstr.substr(findpos, endpos - findpos + 1);
jinput = JoystickInputFromString(jbindstr);
return jinput;
}
std::string JoystickModule::stringFromGamepadInput(Joystick::GamepadInput gpinput) const
{
SDL_GameControllerAxis sdlaxis;
SDL_GameControllerButton sdlbutton;
const char *gpinputname = 0;
switch (gpinput.type)
{
case Joystick::INPUT_TYPE_AXIS:
if (Joystick::getConstant(gpinput.axis, sdlaxis))
gpinputname = SDL_GameControllerGetStringForAxis(sdlaxis);
break;
case Joystick::INPUT_TYPE_BUTTON:
if (Joystick::getConstant(gpinput.button, sdlbutton))
gpinputname = SDL_GameControllerGetStringForButton(sdlbutton);
break;
default:
break;
}
if (!gpinputname)
throw love::Exception("Invalid gamepad axis/button.");
return std::string(gpinputname);
}
Joystick::JoystickInput JoystickModule::JoystickInputFromString(const std::string &str) const
{
Joystick::JoystickInput jinput;
jinput.type = Joystick::INPUT_TYPE_MAX_ENUM;
// Return an invalid value rather than throwing an exception.
if (str.length() < 2)
return jinput;
// The input type will always be the first character in the string.
char inputtype = str[0];
std::string bindvalues = str.substr(1);
Uint8 sdlhat;
switch (inputtype)
{
case 'a':
jinput.type = Joystick::INPUT_TYPE_AXIS;
jinput.axis = atoi(bindvalues.c_str());
break;
case 'b':
jinput.type = Joystick::INPUT_TYPE_BUTTON;
jinput.button = atoi(bindvalues.c_str());
break;
case 'h':
// Hat string syntax is "index.value".
if (bindvalues.length() < 3)
break;
jinput.type = Joystick::INPUT_TYPE_HAT;
jinput.hat.index = atoi(bindvalues.substr(0, 1).c_str());
sdlhat = (Uint8) atoi(bindvalues.substr(2, 1).c_str());
if (!Joystick::getConstant(sdlhat, jinput.hat.value))
{
// Return an invalid value if we can't find the hat constant.
jinput.type = Joystick::INPUT_TYPE_MAX_ENUM;
return jinput;
}
break;
default:
break;
}
return jinput;
}
void JoystickModule::removeBindFromMapString(std::string &mapstr, const std::string &joybindstr) const
{
// Find the joystick part of the bind in the string.
size_t joybindpos = mapstr.find(joybindstr + ",");
if (joybindpos == std::string::npos)
{
joybindpos = mapstr.rfind(joybindstr);
if (joybindpos != mapstr.length() - joybindstr.length())
return;
}
if (joybindpos == std::string::npos)
return;
// Find the start of the entire bind.
size_t bindstart = mapstr.rfind(',', joybindpos);
if (bindstart != std::string::npos && bindstart < mapstr.length() - 1)
{
size_t bindend = mapstr.find(',', bindstart + 1);
if (bindend == std::string::npos)
bindend = mapstr.length() - 1;
// Replace it with an empty string (remove it.)
mapstr.replace(bindstart, bindend - bindstart + 1, "");
}
}
void JoystickModule::checkGamepads(const std::string &guid) const
{
// FIXME: massive hack until missing APIs are added to SDL 2:
// https://bugzilla.libsdl.org/show_bug.cgi?id=1975
// Make sure all connected joysticks of a certain guid that are
// gamepad-capable are opened as such.
for (int d_index = 0; d_index < SDL_NumJoysticks(); d_index++)
{
if (!SDL_IsGameController(d_index))
continue;
if (guid.compare(getDeviceGUID(d_index)) != 0)
continue;
for (auto it = activeSticks.begin(); it != activeSticks.end(); ++it)
{
if ((*it)->isGamepad() || guid.compare((*it)->getGUID()) != 0)
continue;
// Big hack time: open the index as a game controller and compare
// the underlying joystick handle to the active stick's.
SDL_GameController *ctrl = SDL_GameControllerOpen(d_index);
if (ctrl == NULL)
continue;
SDL_Joystick *stick = SDL_GameControllerGetJoystick(ctrl);
if (stick == (SDL_Joystick *) (*it)->getHandle())
(*it)->openGamepad(d_index);
SDL_GameControllerClose(ctrl);
}
}
}
std::string JoystickModule::getDeviceGUID(int deviceindex) const
{
if (deviceindex < 0 || deviceindex >= SDL_NumJoysticks())
return std::string("");
// SDL_JoystickGetGUIDString uses 32 bytes plus the null terminator.
char guidstr[33] = {'\0'};
// SDL2's GUIDs identify *classes* of devices, instead of unique devices.
SDL_JoystickGUID guid = SDL_JoystickGetDeviceGUID(deviceindex);
SDL_JoystickGetGUIDString(guid, guidstr, sizeof(guidstr));
return std::string(guidstr);
}
} // sdl
} // joystick
} // love
@@ -0,0 +1,83 @@
/**
* Copyright (c) 2006-2013 LOVE Development Team
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
**/
#ifndef LOVE_JOYSTICK_SDL_JOYSTICK_MODULE_H
#define LOVE_JOYSTICK_SDL_JOYSTICK_MODULE_H
// LOVE
#include "joystick/JoystickModule.h"
// C++
#include <string>
#include <vector>
#include <list>
namespace love
{
namespace joystick
{
namespace sdl
{
class JoystickModule : public love::joystick::JoystickModule
{
public:
JoystickModule();
virtual ~JoystickModule();
// Implements Module.
const char *getName() const;
// Implements JoystickModule.
love::joystick::Joystick *addJoystick(int deviceindex);
void removeJoystick(love::joystick::Joystick *joystick);
love::joystick::Joystick *getJoystickFromID(int instanceid);
love::joystick::Joystick *getJoystick(int joyindex);
int getIndex(const love::joystick::Joystick *joystick);
int getJoystickCount() const;
bool setGamepadMapping(const std::string &guid, Joystick::GamepadInput gpinput, Joystick::JoystickInput joyinput);
Joystick::JoystickInput getGamepadMapping(const std::string &guid, Joystick::GamepadInput gpinput);
private:
std::string stringFromGamepadInput(Joystick::GamepadInput gpinput) const;
Joystick::JoystickInput JoystickInputFromString(const std::string &str) const;
void removeBindFromMapString(std::string &mapstr, const std::string &joybindstr) const;
void checkGamepads(const std::string &guid) const;
// SDL2's GUIDs identify *classes* of devices, instead of unique devices.
std::string getDeviceGUID(int deviceindex) const;
// Lists of currently connected Joysticks.
std::vector<Joystick *> activeSticks;
// Persistent list of all Joysticks which have been connected at some point.
std::list<Joystick *> joysticks;
}; // JoystickModule
} // sdl
} // joystick
} // love
#endif // LOVE_JOYSTICK_SDL_JOYSTICK_MODULE_H
@@ -0,0 +1,263 @@
/**
* Copyright (c) 2006-2013 LOVE Development Team
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
**/
// LOVE
#include "wrap_Joystick.h"
#include "wrap_JoystickModule.h"
#include <vector>
namespace love
{
namespace joystick
{
namespace sdl
{
Joystick *luax_checkjoystick(lua_State *L, int idx)
{
return luax_checktype<Joystick>(L, idx, "Joystick", JOYSTICK_JOYSTICK_T);
}
int w_Joystick_isConnected(lua_State *L)
{
Joystick *j = luax_checkjoystick(L, 1);
luax_pushboolean(L, j->isConnected());
return 1;
}
int w_Joystick_getName(lua_State *L)
{
Joystick *j = luax_checkjoystick(L, 1);
lua_pushstring(L, j->getName());
return 1;
}
int w_Joystick_getID(lua_State *L)
{
Joystick *j = luax_checkjoystick(L, 1);
// IDs are 1-based in Lua.
lua_pushinteger(L, j->getID() + 1);
int instanceid = j->getInstanceID();
if (instanceid >= 0)
lua_pushinteger(L, instanceid + 1);
else
lua_pushnil(L);
return 2;
}
int w_Joystick_getGUID(lua_State *L)
{
Joystick *j = luax_checkjoystick(L, 1);
luax_pushstring(L, j->getGUID());
return 1;
}
int w_Joystick_getAxisCount(lua_State *L)
{
Joystick *j = luax_checkjoystick(L, 1);
lua_pushinteger(L, j->getAxisCount());
return 1;
}
int w_Joystick_getButtonCount(lua_State *L)
{
Joystick *j = luax_checkjoystick(L, 1);
lua_pushinteger(L, j->getButtonCount());
return 1;
}
int w_Joystick_getHatCount(lua_State *L)
{
Joystick *j = luax_checkjoystick(L, 1);
lua_pushinteger(L, j->getHatCount());
return 1;
}
int w_Joystick_getAxis(lua_State *L)
{
Joystick *j = luax_checkjoystick(L, 1);
int axisindex = luaL_checkint(L, 2) - 1;
lua_pushnumber(L, j->getAxis(axisindex));
return 1;
}
int w_Joystick_getAxes(lua_State *L)
{
Joystick *j = luax_checkjoystick(L, 1);
std::vector<float> axes = j->getAxes();
for (size_t i = 0; i < axes.size(); i++)
lua_pushnumber(L, axes[i]);
return (int) axes.size();
}
int w_Joystick_getHat(lua_State *L)
{
Joystick *j = luax_checkjoystick(L, 1);
int hatindex = luaL_checkint(L, 2) - 1;
Joystick::Hat h = j->getHat(hatindex);
const char *direction = "";
love::joystick::Joystick::getConstant(h, direction);
lua_pushstring(L, direction);
return 1;
}
int w_Joystick_isDown(lua_State *L)
{
Joystick *j = luax_checkjoystick(L, 1);
luaL_checkinteger(L, 2);
std::vector<int> buttons;
for (int i = 2; i <= lua_gettop(L); i++)
buttons.push_back(luaL_checkint(L, i));
luax_pushboolean(L, j->isDown(buttons));
return 1;
}
int w_Joystick_isGamepad(lua_State *L)
{
Joystick *j = luax_checkjoystick(L, 1);
luax_pushboolean(L, j->isGamepad());
return 1;
}
int w_Joystick_getGamepadAxis(lua_State *L)
{
Joystick *j = luax_checkjoystick(L, 1);
const char *str = luaL_checkstring(L, 2);
Joystick::GamepadAxis axis;
if (!joystick::Joystick::getConstant(str, axis))
return luaL_error(L, "Invalid gamepad axis: %s", str);
lua_pushnumber(L, j->getGamepadAxis(axis));
return 1;
}
int w_Joystick_isGamepadDown(lua_State *L)
{
Joystick *j = luax_checkjoystick(L, 1);
std::vector<Joystick::GamepadButton> buttons;
buttons.reserve(lua_gettop(L) - 1);
luaL_checkstring(L, 2);
for (int i = 2; i <= lua_gettop(L); i++)
{
const char *str = luaL_checkstring(L, i);
Joystick::GamepadButton button;
if (!joystick::Joystick::getConstant(str, button))
return luaL_error(L, "Invalid gamepad button: %s", str);
buttons.push_back(button);
}
luax_pushboolean(L, j->isGamepadDown(buttons));
return 1;
}
int w_Joystick_isVibrationSupported(lua_State *L)
{
Joystick *j = luax_checkjoystick(L, 1);
luax_pushboolean(L, j->isVibrationSupported());
return 1;
}
int w_Joystick_setVibration(lua_State *L)
{
Joystick *j = luax_checkjoystick(L, 1);
bool success = false;
if (lua_isnoneornil(L, 2))
{
// Disable joystick vibration if no argument is given.
success = j->setVibration();
}
else
{
float left = (float) luaL_checknumber(L, 2);
float right = (float) luaL_optnumber(L, 3, left);
success = j->setVibration(left, right);
}
luax_pushboolean(L, success);
return 1;
}
int w_Joystick_getVibration(lua_State *L)
{
Joystick *j = luax_checkjoystick(L, 1);
float left, right;
j->getVibration(left, right);
lua_pushnumber(L, left);
lua_pushnumber(L, right);
return 2;
}
// List of functions to wrap.
static const luaL_Reg functions[] =
{
{ "isConnected", w_Joystick_isConnected },
{ "getName", w_Joystick_getName },
{ "getID", w_Joystick_getID },
{ "getGUID", w_Joystick_getGUID },
{ "getAxisCount", w_Joystick_getAxisCount },
{ "getButtonCount", w_Joystick_getButtonCount },
{ "getHatCount", w_Joystick_getHatCount },
{ "getAxis", w_Joystick_getAxis },
{ "getAxes", w_Joystick_getAxes },
{ "getHat", w_Joystick_getHat },
{ "isDown", w_Joystick_isDown },
{ "isGamepad", w_Joystick_isGamepad },
{ "getGamepadAxis", w_Joystick_getGamepadAxis },
{ "isGamepadDown", w_Joystick_isGamepadDown },
{ "isVibrationSupported", w_Joystick_isVibrationSupported },
{ "setVibration", w_Joystick_setVibration },
{ "getVibration", w_Joystick_getVibration },
// From wrap_JoystickModule.
{ "getConnectedIndex", w_getIndex },
{ "getGamepadMapping", w_getGamepadMapping },
{ 0, 0 },
};
extern "C" int luaopen_joystick(lua_State *L)
{
return luax_register_type(L, "Joystick", functions);
}
} // sdl
} // joystick
} // love
@@ -0,0 +1,60 @@
/**
* Copyright (c) 2006-2013 LOVE Development Team
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
**/
#ifndef LOVE_JOYSTICK_SDL_WRAP_JOYSTICK_H
#define LOVE_JOYSTICK_SDL_WRAP_JOYSTICK_H
// LOVE
#include "common/config.h"
#include "Joystick.h"
#include "common/runtime.h"
namespace love
{
namespace joystick
{
namespace sdl
{
Joystick *luax_checkjoystick(lua_State *L, int idx);
int w_Joystick_isConnected(lua_State *L);
int w_Joystick_getName(lua_State *L);
int w_Joystick_getID(lua_State *L);
int w_Joystick_getGUID(lua_State *L);
int w_Joystick_getAxisCount(lua_State *L);
int w_Joystick_getButtonCount(lua_State *L);
int w_Joystick_getHatCount(lua_State *L);
int w_Joystick_getAxis(lua_State *L);
int w_Joystick_getAxes(lua_State *L);
int w_Joystick_getHat(lua_State *L);
int w_Joystick_isDown(lua_State *L);
int w_Joystick_isGamepad(lua_State *L);
int w_Joystick_getGamepadAxis(lua_State *L);
int w_Joystick_isGamepadDown(lua_State *L);
int w_Joystick_isVibrationSupported(lua_State *L);
int w_Joystick_setVibration(lua_State *L);
int w_Joystick_getVibration(lua_State *L);
extern "C" int luaopen_joystick(lua_State *L);
} // sdl
} // joystick
} // love
#endif // LOVE_JOYSTICK_SDL_WRAP_JOYSTICK_H
@@ -0,0 +1,216 @@
/**
* Copyright (c) 2006-2013 LOVE Development Team
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
**/
#include "wrap_JoystickModule.h"
#include "wrap_Joystick.h"
namespace love
{
namespace joystick
{
namespace sdl
{
static JoystickModule *instance = 0;
int w_getJoysticks(lua_State *L)
{
int stickcount = instance->getJoystickCount();
lua_createtable(L, stickcount, 0);
for (int i = 0; i < stickcount; i++)
{
love::joystick::Joystick *stick = instance->getJoystick(i);
stick->retain();
luax_pushtype(L, "Joystick", JOYSTICK_JOYSTICK_T, stick);
lua_rawseti(L, -2, i + 1);
}
return 1;
}
int w_getIndex(lua_State *L)
{
love::joystick::Joystick *j = luax_checkjoystick(L, 1);
int index = instance->getIndex(j);
if (index >= 0)
lua_pushinteger(L, index + 1);
else
lua_pushnil(L);
return 1;
}
int w_getJoystickCount(lua_State *L)
{
lua_pushinteger(L, instance->getJoystickCount());
return 1;
}
int w_setGamepadMapping(lua_State *L)
{
// Only accept a GUID string. We don't accept a Joystick object because
// the gamepad mapping applies to all joysticks with the same GUID (e.g. all
// Xbox 360 controllers on the system), rather than individual objects.
const char *guid = luaL_checkstring(L, 1);
const char *gpbindstr = luaL_checkstring(L, 2);
Joystick::GamepadInput gpinput;
if (love::joystick::Joystick::getConstant(gpbindstr, gpinput.axis))
gpinput.type = Joystick::INPUT_TYPE_AXIS;
else if (love::joystick::Joystick::getConstant(gpbindstr, gpinput.button))
gpinput.type = Joystick::INPUT_TYPE_BUTTON;
else
return luaL_error(L, "Invalid gamepad axis/button: %s", gpbindstr);
const char *jinputtypestr = luaL_checkstring(L, 3);
Joystick::JoystickInput jinput;
if (!love::joystick::Joystick::getConstant(jinputtypestr, jinput.type))
return luaL_error(L, "Invalid joystick input type: %s", jinputtypestr);
const char *hatstr;
switch (jinput.type)
{
case Joystick::INPUT_TYPE_AXIS:
jinput.axis = luaL_checkint(L, 4) - 1;
break;
case Joystick::INPUT_TYPE_BUTTON:
jinput.button = luaL_checkint(L, 4) - 1;
break;
case Joystick::INPUT_TYPE_HAT:
// Hats need both a hat index and a hat value.
jinput.hat.index = luaL_checkint(L, 4) - 1;
hatstr = luaL_checkstring(L, 5);
if (!love::joystick::Joystick::getConstant(hatstr, jinput.hat.value))
return luaL_error(L, "Invalid joystick hat: %s", hatstr);
break;
default:
return luaL_error(L, "Invalid joystick input type: %s", jinputtypestr);
}
bool success = false;
EXCEPT_GUARD(success = instance->setGamepadMapping(guid, gpinput, jinput);)
luax_pushboolean(L, success);
return 1;
}
int w_getGamepadMapping(lua_State *L)
{
std::string guid;
// Accept either a GUID string or a Joystick object. This way we can re-use
// the function for Joystick:getGamepadMapping.
if (lua_type(L, 1) == LUA_TSTRING)
guid = luax_checkstring(L, 1);
else
{
love::joystick::Joystick *stick = luax_checkjoystick(L, 1);
guid = stick->getGUID();
}
const char *gpbindstr = luaL_checkstring(L, 2);
Joystick::GamepadInput gpinput;
if (love::joystick::Joystick::getConstant(gpbindstr, gpinput.axis))
gpinput.type = Joystick::INPUT_TYPE_AXIS;
else if (love::joystick::Joystick::getConstant(gpbindstr, gpinput.button))
gpinput.type = Joystick::INPUT_TYPE_BUTTON;
else
return luaL_error(L, "Invalid gamepad axis/button: %s", gpbindstr);
Joystick::JoystickInput jinput;
jinput.type = Joystick::INPUT_TYPE_MAX_ENUM;
EXCEPT_GUARD(jinput = instance->getGamepadMapping(guid, gpinput);)
if (jinput.type == Joystick::INPUT_TYPE_MAX_ENUM)
return 0;
const char *inputtypestr;
if (!love::joystick::Joystick::getConstant(jinput.type, inputtypestr))
return luaL_error(L, "Unknown joystick input type.");
lua_pushstring(L, inputtypestr);
const char *hatstr;
switch (jinput.type)
{
case Joystick::INPUT_TYPE_AXIS:
lua_pushinteger(L, jinput.axis + 1);
return 2;
case Joystick::INPUT_TYPE_BUTTON:
lua_pushinteger(L, jinput.button + 1);
return 2;
case Joystick::INPUT_TYPE_HAT:
lua_pushinteger(L, jinput.hat.index + 1);
if (love::joystick::Joystick::getConstant(jinput.hat.value, hatstr))
{
lua_pushstring(L, hatstr);
return 3;
}
else
return luaL_error(L, "Unknown joystick hat.");
default:
break; // ?
}
return 1;
}
// List of functions to wrap.
static const luaL_Reg functions[] =
{
{ "getJoysticks", w_getJoysticks },
{ "getJoystickCount", w_getJoystickCount },
{ "setGamepadMapping", w_setGamepadMapping },
{ "getGamepadMapping", w_getGamepadMapping },
{ 0, 0 }
};
static const lua_CFunction types[] =
{
luaopen_joystick,
0,
};
extern "C" int luaopen_love_joystick(lua_State *L)
{
if (instance == 0)
{
EXCEPT_GUARD(instance = new JoystickModule();)
}
else
instance->retain();
WrappedModule w;
w.module = instance;
w.name = "joystick";
w.flags = MODULE_T;
w.functions = functions;
w.types = types;
return luax_register_module(L, w);
}
} // sdl
} // joystick
} // love
@@ -0,0 +1,46 @@
/**
* Copyright (c) 2006-2013 LOVE Development Team
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
**/
#ifndef LOVE_JOYSTICK_SDL_WRAP_JOYSTICK_MODULE_H
#define LOVE_JOYSTICK_SDL_WRAP_JOYSTICK_MODULE_H
// LOVE
#include "common/config.h"
#include "JoystickModule.h"
namespace love
{
namespace joystick
{
namespace sdl
{
int w_getJoysticks(lua_State *L);
int w_getIndex(lua_State *L);
int w_getJoystickCount(lua_State *L);
int w_setGamepadMapping(lua_State *L);
int w_getGamepadMapping(lua_State *L);
extern "C" LOVE_EXPORT int luaopen_love_joystick(lua_State *L);
} // sdl
} // joystick
} // love
#endif // LOVE_JOYSTICK_SDL_WRAP_JOYSTICK_MODULE_H