Merged SDL2 changes from bartbes/love-experiments/SDL2 into default.

- Added love.system module, including clipboard functions.

- Added custom hardware cursors (love.mouse.newCursor, love.mouse.setCursor.)

- Revamped love.joystick:
-- added Joystick objects and moved love.joystick functions which operated on individual joysticks to methods on the Joystick objects.
-- Added love.joystick.getJoystick and love.joystick.getJoystickCount.
-- Added events for when joysticks are connected and disconnected.
-- Added 'Gamepad' methods to Joystick objects: Joystick:isGamepad, Joystick:getGamepadAxis, and Joystick:isGamepadDown. They're a common abstraction for xbox controller-like joystick across operating systems.

- Added monitor choosing support and "fullscreen desktop" mode to love.window.

- Moved unicode text input events to their own callback function (love.textinput), removed the key repeat functions from love.keyboard and made the second argument of love.keypressed a boolean saying whether the keypress was a repeat.

- liblove now works with love.window and love.graphics in OS X
This commit is contained in:
Alex Szpakowski
2013-08-25 16:51:42 -03:00
parent 035130533b
commit 113ed1cfe7
67 changed files with 4691 additions and 1665 deletions
+85 -2
View File
@@ -18,15 +18,26 @@
* 3. This notice may not be removed or altered from any source distribution.
**/
// LOVE
#include "Joystick.h"
// STL
#include <cmath>
namespace love
{
namespace joystick
{
Joystick::~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)
@@ -34,11 +45,41 @@ bool Joystick::getConstant(const char *in, Joystick::Hat &out)
return hats.find(in, out);
}
bool Joystick::getConstant(Joystick::Hat in, const char *&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},
@@ -54,5 +95,47 @@ StringMap<Joystick::Hat, Joystick::HAT_MAX_ENUM>::Entry Joystick::hatEntries[] =
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
+133 -5
View File
@@ -22,18 +22,23 @@
#define LOVE_JOYSTICK_JOYSTICK_H
// LOVE
#include "common/Module.h"
#include "common/Object.h"
#include "common/StringMap.h"
// stdlib
#include <vector>
#include <string>
namespace love
{
namespace joystick
{
class Joystick : public Module
class Joystick : public Object
{
public:
// Joystick hat values.
enum Hat
{
HAT_INVALID,
@@ -49,19 +54,142 @@ public:
HAT_MAX_ENUM = 16
};
virtual ~Joystick();
// 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;
static bool getConstant(const char *in, Hat &out);
static bool getConstant(Hat in, const char *&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
#endif // LOVE_JOYSTICK_JOYSTICK_H
+99
View File
@@ -0,0 +1,99 @@
/**
* 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;
/**
* Determines whether the Joystick at the specified index is a recognized
* Gamepad.
**/
virtual bool isGamepad(int joyindex) const = 0;
/**
* Sets the virtual Gamepad mapping for a joystick input value for all
* joystick devices with the specified joystick 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 &guid, Joystick::GamepadInput gpinput, Joystick::JoystickInput joyinput) = 0;
/**
* Gets the joystick input value the gamepad input value is bound to for the
* specified joystick GUID.
**/
virtual Joystick::JoystickInput getGamepadMapping(const std::string &guid, Joystick::GamepadInput gpinput) = 0;
}; // JoystickModule
} // joystick
} // love
#endif // LOVE_JOYSTICK_JOYSTICK_MODULE_H
+225 -141
View File
@@ -20,9 +20,6 @@
#include "Joystick.h"
// STD
#include <cmath>
namespace love
{
namespace joystick
@@ -30,206 +27,260 @@ namespace joystick
namespace sdl
{
Joystick::Joystick()
: joysticks(0)
Joystick::Joystick(int id)
: joyhandle(0)
, controller(0)
, instanceid(-1)
, id(id)
{
// Init the SDL joystick system.
if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) < 0)
throw love::Exception("%s", SDL_GetError());
}
// Start joystick event watching.
SDL_JoystickEventState(SDL_ENABLE);
// Open all connected joysticks.
int numjoysticks = getJoystickCount();
if (numjoysticks > 0)
this->joysticks = (SDL_Joystick **)calloc(numjoysticks, sizeof(SDL_Joystick *));
for (int i = 0; i<numjoysticks; i++)
this->open(i);
Joystick::Joystick(int id, int joyindex)
: joyhandle(0)
, controller(0)
, instanceid(-1)
, id(id)
{
open(joyindex);
}
Joystick::~Joystick()
{
// Closes any open joysticks.
for (int i = 0; i != getJoystickCount(); i++)
{
if (isOpen(i))
close(i);
}
free(joysticks);
SDL_QuitSubSystem(SDL_INIT_JOYSTICK);
close();
}
void Joystick::reload()
bool Joystick::open(int deviceindex)
{
// Closes any open joysticks.
for (int i = 0; i != getJoystickCount(); i++)
close();
joyhandle = SDL_JoystickOpen(deviceindex);
if (joyhandle)
{
if (isOpen(i))
close(i);
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));
guid = std::string(cstr);
// See if SDL thinks this is a Game Controller.
openGamepad(deviceindex);
// Prefer the GameController name.
if (controller)
name = SDL_GameControllerName(controller);
else
name = SDL_JoystickName(joyhandle);
}
free(joysticks);
return isConnected();
}
SDL_QuitSubSystem(SDL_INIT_JOYSTICK);
void Joystick::close()
{
if (controller)
SDL_GameControllerClose(controller);
if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) < 0)
throw love::Exception("%s", SDL_GetError());
if (joyhandle)
SDL_JoystickClose(joyhandle);
int numjoysticks = this->getJoystickCount();
if (numjoysticks > 0)
this->joysticks = (SDL_Joystick **)calloc(numjoysticks, sizeof(SDL_Joystick *));
joyhandle = 0;
controller = 0;
instanceid = -1;
}
for (int i = 0; i<numjoysticks; i++)
this->open(i);
bool Joystick::isConnected() const
{
return joyhandle != 0 && SDL_JoystickGetAttached(joyhandle);
}
const char *Joystick::getName() const
{
return "love.joystick.sdl";
// Use the saved name if this Joystick isn't connected anymore.
if (!isConnected())
return name.c_str();
// Prefer SDL's GameController name, if possible.
if (isGamepad())
return SDL_GameControllerName(controller);
return SDL_JoystickName(joyhandle);
}
bool Joystick::checkIndex(int index)
int Joystick::getAxisCount() const
{
return index >= 0 && index < getJoystickCount();
return isConnected() ? SDL_JoystickNumAxes(joyhandle) : 0;
}
int Joystick::getJoystickCount()
int Joystick::getButtonCount() const
{
int num = SDL_NumJoysticks();
return num < 0 ? 0 : num;
return isConnected() ? SDL_JoystickNumButtons(joyhandle) : 0;
}
const char *Joystick::getName(int index)
int Joystick::getHatCount() const
{
return SDL_JoystickName(index);
return isConnected() ? SDL_JoystickNumHats(joyhandle) : 0;
}
bool Joystick::open(int index)
float Joystick::getAxis(int axisindex) const
{
if (isOpen(index))
return true;
if (!checkIndex(index))
return false;
if (!(joysticks[index] = SDL_JoystickOpen(index)))
return false;
return true;
}
bool Joystick::isOpen(int index)
{
if (!checkIndex(index))
return false;
return joysticks[index] != 0 ? true : false;
}
bool Joystick::verifyJoystick(int index)
{
if (!checkIndex(index))
return false;
if (!isOpen(index))
return false;
return true;
}
int Joystick::getAxisCount(int index)
{
return verifyJoystick(index) ? SDL_JoystickNumAxes(joysticks[index]) : 0;
}
int Joystick::getButtonCount(int index)
{
return verifyJoystick(index) ? SDL_JoystickNumButtons(joysticks[index]) : 0;
}
int Joystick::getHatCount(int index)
{
return verifyJoystick(index) ? SDL_JoystickNumHats(joysticks[index]) : 0;
}
float Joystick::clampval(float x)
{
if (fabs((double)x) < 0.01) return 0.0f;
if (x < -0.99f) return -1.0f;
if (x > 0.99f) return 1.0f;
return x;
}
float Joystick::getAxis(int index, int axis)
{
if (!verifyJoystick(index))
if (!isConnected() || axisindex < 0 || axisindex >= getAxisCount())
return 0;
if (axis >= getAxisCount(index))
return 0;
return clampval(((float)SDL_JoystickGetAxis(joysticks[index], axis))/32768.0f);
return clampval(((float) SDL_JoystickGetAxis(joyhandle, axisindex))/32768.0f);
}
int Joystick::getAxes(lua_State *L)
std::vector<float> Joystick::getAxes() const
{
int index = luaL_checkint(L, 1) - 1;
std::vector<float> axes;
int count = getAxisCount();
if (!verifyJoystick(index))
return 0;
if (!isConnected() || count <= 0)
return axes;
int num = getAxisCount(index);
axes.reserve(count);
for (int i = 0; i<num; i++)
lua_pushnumber(L, clampval(((float)SDL_JoystickGetAxis(joysticks[index], i))/32768.0f));
return num;
for (int i = 0; i < count; i++)
axes.push_back(clampval(((float) SDL_JoystickGetAxis(joyhandle, i))/32768.0f));
return axes;
}
bool Joystick::isDown(int index, int *buttonlist)
Joystick::Hat Joystick::getHat(int hatindex) const
{
if (!verifyJoystick(index))
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(index);
int num = getButtonCount();
for (int button = *buttonlist; button != -1; button = *(++buttonlist))
for (size_t i = 0; i < buttonlist.size(); i++)
{
if (button >= 0 && button < num && SDL_JoystickGetButton(joysticks[index], button) == 1)
int button = buttonlist[i];
if (button >= 0 && button < num && SDL_JoystickGetButton(joyhandle, button) == 1)
return true;
}
return false;
}
Joystick::Hat Joystick::getHat(int index, int hat)
bool Joystick::openGamepad(int deviceindex)
{
Hat h = HAT_INVALID;
if (!SDL_IsGameController(deviceindex))
return false;
if (!verifyJoystick(index))
return h;
if (isGamepad())
{
SDL_GameControllerClose(controller);
controller = 0;
}
if (hat >= getHatCount(index))
return h;
hats.find(SDL_JoystickGetHat(joysticks[index], hat), h);
return h;
controller = SDL_GameControllerOpen(deviceindex);
return isGamepad();
}
void Joystick::close(int index)
bool Joystick::isGamepad() const
{
if (!checkIndex(index))
return;
return controller != 0;
}
if (joysticks[index]!=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++)
{
SDL_JoystickClose(joysticks[index]);
joysticks[index] = 0;
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 guid;
}
int Joystick::getInstanceID() const
{
return instanceid;
}
int Joystick::getID() const
{
return id;
}
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[] =
@@ -247,6 +298,39 @@ EnumMap<Joystick::Hat, Uint8, Joystick::HAT_MAX_ENUM>::Entry Joystick::hatEntrie
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
+59 -22
View File
@@ -26,7 +26,8 @@
#include "common/EnumMap.h"
// SDL
#include <SDL.h>
#include <SDL_joystick.h>
#include <SDL_gamecontroller.h>
namespace love
{
@@ -37,38 +38,74 @@ namespace sdl
class Joystick : public love::joystick::Joystick
{
private:
SDL_Joystick **joysticks;
public:
Joystick();
Joystick(int id);
Joystick(int id, int joyindex);
virtual ~Joystick();
// Implements Module.
bool open(int deviceindex);
void close();
bool isConnected() const;
const char *getName() const;
void reload();
bool checkIndex(int index);
int getJoystickCount();
const char *getName(int index);
bool open(int index);
bool isOpen(int index);
bool verifyJoystick(int index);
int getAxisCount(int index);
int getButtonCount(int index);
int getHatCount(int index);
float clampval(float x);
float getAxis(int index, int axis);
int getAxes(lua_State *L);
bool isDown(int index, int *buttonlist);
Hat getHat(int index, int hat);
void close(int index);
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;
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() {}
SDL_Joystick *joyhandle;
SDL_GameController *controller;
SDL_JoystickID instanceid;
std::string guid;
int id;
std::string name;
static EnumMap<Hat, Uint8, Joystick::HAT_MAX_ENUM>::Entry hatEntries[];
static EnumMap<Hat, Uint8, Joystick::HAT_MAX_ENUM> hats;
}; // Joystick
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
+450
View File
@@ -0,0 +1,450 @@
/**
* 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()
{
// Init the SDL Joystick and Game Controller systems.
if (SDL_InitSubSystem(SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER) < 0)
throw love::Exception("%s", SDL_GetError());
// 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 (size_t i = 0; i < joysticks.size(); i++)
{
joysticks[i]->close();
joysticks[i]->release();
}
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();
}
bool JoystickModule::isGamepad(int joyindex) const
{
if (joyindex < 0 || (size_t) joyindex >= activeSticks.size())
return false;
return activeSticks[joyindex]->isGamepad();
}
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;
for (size_t i = 0; i < joysticks.size(); i++)
{
// Try to re-use a disconnected Joystick with the same GUID.
if (!joysticks[i]->isConnected() && joysticks[i]->getGUID() == guidstr)
{
joystick = joysticks[i];
joystick->open(deviceindex);
break;
}
}
if (!joystick)
{
// Make a new Joystick and add it to the persistent list, if we can't
// re-use one.
joystick = new Joystick(joysticks.size(), deviceindex);
joysticks.push_back(joystick);
}
// Add the Joystick to the connected list, if it's not there already.
if (std::find(activeSticks.begin(), activeSticks.end(), joystick) == activeSticks.end())
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.
std::vector<joystick::Joystick *>::iterator 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;
std::vector<love::joystick::Joystick *>::const_iterator it;
for (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
+81
View File
@@ -0,0 +1,81 @@
/**
* 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"
// STL
#include <string>
#include <map>
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 isGamepad(int joyindex) 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::vector<Joystick *> joysticks;
}; // JoystickModule
} // sdl
} // joystick
} // love
#endif // LOVE_JOYSTICK_SDL_JOYSTICK_MODULE_H
+132 -90
View File
@@ -18,7 +18,11 @@
* 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
{
@@ -27,141 +31,179 @@ namespace joystick
namespace sdl
{
static Joystick *instance = 0;
int w_reload(lua_State *L)
Joystick *luax_checkjoystick(lua_State *L, int idx)
{
try
{
instance->reload();
}
catch(love::Exception &e)
{
return luaL_error(L, "%s", e.what());
}
return 0;
return luax_checktype<Joystick>(L, idx, "Joystick", JOYSTICK_JOYSTICK_T);
}
int w_getJoystickCount(lua_State *L)
int w_Joystick_isConnected(lua_State *L)
{
lua_pushinteger(L, instance->getJoystickCount());
Joystick *j = luax_checkjoystick(L, 1);
luax_pushboolean(L, j->isConnected());
return 1;
}
int w_getName(lua_State *L)
int w_Joystick_getName(lua_State *L)
{
int index = luaL_checkint(L, 1) - 1;
lua_pushstring(L, instance->getName(index));
Joystick *j = luax_checkjoystick(L, 1);
lua_pushstring(L, j->getName());
return 1;
}
int w_getAxisCount(lua_State *L)
int w_Joystick_getID(lua_State *L)
{
int index = luaL_checkint(L, 1) - 1;
lua_pushinteger(L, instance->getAxisCount(index));
Joystick *j = luax_checkjoystick(L, 1);
lua_pushinteger(L, j->getID());
return 1;
}
int w_getButtonCount(lua_State *L)
int w_Joystick_getGUID(lua_State *L)
{
int index = luaL_checkint(L, 1) - 1;
lua_pushinteger(L, instance->getButtonCount(index));
Joystick *j = luax_checkjoystick(L, 1);
luax_pushstring(L, j->getGUID());
return 1;
}
int w_getHatCount(lua_State *L)
int w_Joystick_getAxisCount(lua_State *L)
{
int index = luaL_checkint(L, 1) - 1;
lua_pushinteger(L, instance->getHatCount(index));
Joystick *j = luax_checkjoystick(L, 1);
lua_pushinteger(L, j->getAxisCount());
return 1;
}
int w_getAxis(lua_State *L)
int w_Joystick_getButtonCount(lua_State *L)
{
int index = luaL_checkint(L, 1) - 1;
int axis = luaL_checkint(L, 2) - 1;
lua_pushnumber(L, instance->getAxis(index, axis));
Joystick *j = luax_checkjoystick(L, 1);
lua_pushinteger(L, j->getButtonCount());
return 1;
}
int w_getAxes(lua_State *L)
int w_Joystick_getHatCount(lua_State *L)
{
return instance->getAxes(L);
}
int w_isDown(lua_State *L)
{
int index = luaL_checkint(L, 1) - 1;
int num = lua_gettop(L);
int *buttonlist = new int[num];
int counter = 0;
for (int i = 1; i < num; i++)
buttonlist[counter++] = luaL_checkint(L, i + 1) - 1;
buttonlist[counter] = -1;
luax_pushboolean(L, instance->isDown(index, buttonlist));
delete[] buttonlist;
Joystick *j = luax_checkjoystick(L, 1);
lua_pushinteger(L, j->getHatCount());
return 1;
}
int w_getHat(lua_State *L)
int w_Joystick_getAxis(lua_State *L)
{
int index = luaL_checkint(L, 1)-1;
int hat = luaL_checkint(L, 2)-1;
Joystick *j = luax_checkjoystick(L, 1);
int axisindex = luaL_checkint(L, 2) - 1;
lua_pushnumber(L, j->getAxis(axisindex));
return 1;
}
Joystick::Hat h = instance->getHat(index, hat);
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 = "";
Joystick::getConstant(h, direction);
lua_pushstring(L, 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;
}
// List of functions to wrap.
static const luaL_Reg functions[] =
{
{ "reload", w_reload },
{ "getJoystickCount", w_getJoystickCount },
{ "getName", w_getName },
{ "getAxisCount", w_getAxisCount },
{ "getButtonCount", w_getButtonCount },
{ "getHatCount", w_getHatCount },
{ "getAxis", w_getAxis },
{ "getAxes", w_getAxes },
{ "isDown", w_isDown },
{ "getHat", w_getHat },
{ 0, 0 }
{ "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 },
// From wrap_JoystickModule.
{ "getIndex", w_getIndex },
{ "getGamepadMapping", w_getGamepadMapping },
{ 0, 0 },
};
extern "C" int luaopen_love_joystick(lua_State *L)
extern "C" int luaopen_joystick(lua_State *L)
{
if (instance == 0)
{
try
{
instance = new Joystick();
}
catch(Exception &e)
{
return luaL_error(L, e.what());
}
}
else
instance->retain();
WrappedModule w;
w.module = instance;
w.name = "joystick";
w.flags = MODULE_T;
w.functions = functions;
w.types = 0;
return luax_register_module(L, w);
return luax_register_type(L, "Joystick", functions);
}
} // sdl
+17 -11
View File
@@ -24,6 +24,7 @@
// LOVE
#include "common/config.h"
#include "Joystick.h"
#include "common/runtime.h"
namespace love
{
@@ -32,17 +33,22 @@ namespace joystick
namespace sdl
{
int w_reload(lua_State *L);
int w_getJoystickCount(lua_State *L);
int w_getName(lua_State *L);
int w_getAxisCount(lua_State *L);
int w_getButtonCount(lua_State *L);
int w_getHatCount(lua_State *L);
int w_getAxis(lua_State *L);
int w_getAxes(lua_State *L);
int w_isDown(lua_State *L);
int w_getHat(lua_State *L);
extern "C" LOVE_EXPORT int luaopen_love_joystick(lua_State *L);
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);
extern "C" int luaopen_joystick(lua_State *L);
} // sdl
} // joystick
@@ -0,0 +1,244 @@
/**
* 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_getJoystick(lua_State *L)
{
int index = luaL_checkint(L, 1) - 1;
love::joystick::Joystick *stick = instance->getJoystick(index);
if (!stick)
return luaL_error(L, "Invalid joystick index");
stick->retain();
luax_newtype(L, "Joystick", JOYSTICK_JOYSTICK_T, (void *) stick);
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_pushinteger(L, -1);
return 1;
}
int w_getJoystickCount(lua_State *L)
{
lua_pushinteger(L, instance->getJoystickCount());
return 1;
}
int w_isGamepad(lua_State *L)
{
int index = luaL_checkint(L, 1) - 1;
luax_pushboolean(L, instance->isGamepad(index));
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.
std::string guid = luax_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;
try
{
success = instance->setGamepadMapping(guid, gpinput, jinput);
}
catch (love::Exception &e)
{
return luaL_error(L, "%s", e.what());
}
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;
try
{
jinput = instance->getGamepadMapping(guid, gpinput);
}
catch (love::Exception &e)
{
return luaL_error(L, "%s", e.what());
}
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[] =
{
{ "getJoystick", w_getJoystick },
{ "getIndex", w_getIndex },
{ "getJoystickCount", w_getJoystickCount },
{ "isGamepad", w_isGamepad },
{ "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)
{
try
{
instance = new JoystickModule();
}
catch (Exception &e)
{
return luaL_error(L, e.what());
}
}
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,47 @@
/**
* 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_getJoystick(lua_State *L);
int w_getIndex(lua_State *L);
int w_getJoystickCount(lua_State *L);
int w_isGamepad(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