Added love.joystick.loadGamepadMappings (resolves issue #842), and Joystick:saveGamepadMapping.

The latter returns a mapping string, and the former loads a newline-separated list of mapping strings.
This commit is contained in:
Alex Szpakowski
2014-06-04 15:50:06 -03:00
parent dfa319e01a
commit 79b453653a
14 changed files with 166 additions and 35 deletions
+2 -2
View File
@@ -148,7 +148,7 @@ int w_newFile(lua_State *L)
return 1;
}
FileData *luax_getFileData(lua_State *L, int idx)
FileData *luax_getfiledata(lua_State *L, int idx)
{
FileData *data = nullptr;
File *file = nullptr;
@@ -191,7 +191,7 @@ int w_newFileData(lua_State *L)
// Single argument: treat as filepath or File.
if (lua_gettop(L) == 1)
{
// We don't use luax_getFileData because we want to use an ioError.
// We don't use luax_getfiledata because we want to use an ioError.
if (lua_isstring(L, 1))
luax_convobj(L, 1, "filesystem", "newFile");
+1 -1
View File
@@ -37,7 +37,7 @@ namespace filesystem
* so a matching release() is required!
* May trigger a Lua error.
**/
FileData *luax_getFileData(lua_State *L, int idx);
FileData *luax_getfiledata(lua_State *L, int idx);
bool hack_setupWriteDirectory();
int w_init(lua_State *L);
+1 -1
View File
@@ -51,7 +51,7 @@ int w_newRasterizer(lua_State *L)
}
else if (lua_isstring(L, 1) || luax_istype(L, 1, FILESYSTEM_FILE_T) || luax_istype(L, 1, FILESYSTEM_FILE_DATA_T))
{
love::filesystem::FileData *d = love::filesystem::luax_getFileData(L, 1);
love::filesystem::FileData *d = love::filesystem::luax_getfiledata(L, 1);
int size = luaL_checkint(L, 2);
luax_catchexcept(L,
[&]() { t = instance->newRasterizer(d, size); },
@@ -172,7 +172,7 @@ int w_newImage(lua_State *L)
if (image == nullptr)
return luaL_error(L, "Cannot load images without the love.image module.");
love::filesystem::FileData *fdata = love::filesystem::luax_getFileData(L, 1);
love::filesystem::FileData *fdata = love::filesystem::luax_getfiledata(L, 1);
if (image->isCompressed(fdata))
{
+3 -3
View File
@@ -52,7 +52,7 @@ int w_newImageData(lua_State *L)
}
// Case 2: File(Data).
love::filesystem::FileData *data = love::filesystem::luax_getFileData(L, 1);
love::filesystem::FileData *data = love::filesystem::luax_getfiledata(L, 1);
ImageData *t = nullptr;
luax_catchexcept(L,
@@ -66,7 +66,7 @@ int w_newImageData(lua_State *L)
int w_newCompressedData(lua_State *L)
{
love::filesystem::FileData *data = love::filesystem::luax_getFileData(L, 1);
love::filesystem::FileData *data = love::filesystem::luax_getfiledata(L, 1);
CompressedData *t = nullptr;
luax_catchexcept(L,
@@ -80,7 +80,7 @@ int w_newCompressedData(lua_State *L)
int w_isCompressed(lua_State *L)
{
love::filesystem::FileData *data = love::filesystem::luax_getFileData(L, 1);
love::filesystem::FileData *data = love::filesystem::luax_getfiledata(L, 1);
bool compressed = instance->isCompressed(data);
data->release();
+10
View File
@@ -85,6 +85,16 @@ public:
**/
virtual Joystick::JoystickInput getGamepadMapping(const std::string &pguid, Joystick::GamepadInput gpinput) = 0;
/**
*
**/
virtual void loadGamepadMappings(const std::string &mappings) = 0;
/**
*
**/
virtual std::string saveGamepadMapping(const std::string &pguid) = 0;
}; // JoystickModule
} // joystick
+8 -6
View File
@@ -191,12 +191,14 @@ bool Joystick::isDown(const std::vector<int> &buttonlist) const
if (!isConnected())
return false;
int num = getButtonCount();
int numbuttons = getButtonCount();
for (size_t i = 0; i < buttonlist.size(); i++)
for (int button : buttonlist)
{
int button = buttonlist[i];
if (button >= 0 && button < num && SDL_JoystickGetButton(joyhandle, button) == 1)
if (button < 0 || button >= numbuttons)
continue;
if (SDL_JoystickGetButton(joyhandle, button) == 1)
return true;
}
@@ -244,9 +246,9 @@ bool Joystick::isGamepadDown(const std::vector<GamepadButton> &blist) const
SDL_GameControllerButton sdlbutton;
for (size_t i = 0; i < blist.size(); i++)
for (GamepadButton button : blist)
{
if (!getConstant(blist[i], sdlbutton))
if (!getConstant(button, sdlbutton))
continue;
if (SDL_GameControllerGetButton(controller, sdlbutton) == 1)
+82 -20
View File
@@ -57,10 +57,10 @@ JoystickModule::JoystickModule()
JoystickModule::~JoystickModule()
{
// Close any open Joysticks.
for (auto it = joysticks.begin(); it != joysticks.end(); ++it)
for (auto stick : joysticks)
{
(*it)->close();
(*it)->release();
stick->close();
stick->release();
}
if (SDL_WasInit(SDL_INIT_HAPTIC) != 0)
@@ -101,10 +101,10 @@ int JoystickModule::getJoystickCount() const
love::joystick::Joystick *JoystickModule::getJoystickFromID(int instanceid)
{
for (size_t i = 0; i < activeSticks.size(); i++)
for (auto stick : activeSticks)
{
if (instanceid == activeSticks[i]->getInstanceID())
return activeSticks[i];
if (stick->getInstanceID() == instanceid)
return stick;
}
return nullptr;
@@ -119,12 +119,12 @@ love::joystick::Joystick *JoystickModule::addJoystick(int deviceindex)
joystick::Joystick *joystick = 0;
bool reused = false;
for (auto it = joysticks.begin(); it != joysticks.end(); ++it)
for (auto stick : joysticks)
{
// Try to re-use a disconnected Joystick with the same GUID.
if (!(*it)->isConnected() && (*it)->getGUID() == guidstr)
if (!stick->isConnected() && stick->getGUID() == guidstr)
{
joystick = *it;
joystick = stick;
reused = true;
break;
}
@@ -144,9 +144,9 @@ love::joystick::Joystick *JoystickModule::addJoystick(int deviceindex)
// 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)
for (auto activestick : activeSticks)
{
if (joystick->getHandle() == (*it)->getHandle())
if (joystick->getHandle() == activestick->getHandle())
{
joystick->close();
@@ -157,7 +157,7 @@ love::joystick::Joystick *JoystickModule::addJoystick(int deviceindex)
joystick->release();
}
return *it;
return activestick;
}
}
@@ -427,22 +427,23 @@ void JoystickModule::checkGamepads(const std::string &guid) const
if (guid.compare(getDeviceGUID(d_index)) != 0)
continue;
for (auto it = activeSticks.begin(); it != activeSticks.end(); ++it)
for (auto stick : activeSticks)
{
if ((*it)->isGamepad() || guid.compare((*it)->getGUID()) != 0)
if (stick->isGamepad() || guid.compare(stick->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 == nullptr)
SDL_GameController *controller = SDL_GameControllerOpen(d_index);
if (controller == nullptr)
continue;
SDL_Joystick *stick = SDL_GameControllerGetJoystick(ctrl);
if (stick == (SDL_Joystick *) (*it)->getHandle())
(*it)->openGamepad(d_index);
SDL_Joystick *sdlstick = SDL_GameControllerGetJoystick(controller);
if (sdlstick == (SDL_Joystick *) stick->getHandle())
stick->openGamepad(d_index);
SDL_GameControllerClose(ctrl);
// GameController objects are reference-counted in SDL.
SDL_GameControllerClose(controller);
}
}
}
@@ -462,6 +463,67 @@ std::string JoystickModule::getDeviceGUID(int deviceindex) const
return std::string(guidstr);
}
void JoystickModule::loadGamepadMappings(const std::string &mappings)
{
// TODO: We should use SDL_GameControllerAddMappingsFromRW. We're
// duplicating its functionality for now because it was added after
// SDL 2.0.0's release, and we want runtime compat with 2.0.0 on Linux...
std::stringstream ss(mappings);
std::string mapping;
bool success = false;
// The mappings string contains newline-separated mappings.
while (std::getline(ss, mapping))
{
if (mapping.empty())
continue;
// Strip out and compare any "platform:XYZ," in the mapping.
size_t pstartpos = mapping.find("platform:");
if (pstartpos != std::string::npos)
{
pstartpos += strlen("platform:");
size_t pendpos = mapping.find_first_of(',', pstartpos);
std::string platform = mapping.substr(pstartpos, pendpos - pstartpos);
if (platform.compare(SDL_GetPlatform()) != 0)
continue;
pstartpos -= strlen("platform:");
mapping.erase(pstartpos, pendpos - pstartpos + 1);
}
success = success || (SDL_GameControllerAddMapping(mapping.c_str()) != -1);
}
if (!success)
throw love::Exception("Invalid gamepad mappings.");
}
std::string JoystickModule::saveGamepadMapping(const std::string &pguid)
{
SDL_JoystickGUID sdlguid = SDL_JoystickGetGUIDFromString(pguid.c_str());
std::string mapping;
char *sdlmapping = SDL_GameControllerMappingForGUID(sdlguid);
if (sdlmapping == nullptr)
throw love::Exception("The specified Joystick GUID string has no gamepad mapping.");
mapping = sdlmapping;
SDL_free(sdlmapping);
if (mapping.find_last_of(',') != mapping.size() - 1)
mapping += ",";
// Matches SDL_GameControllerAddMappingsFromRW.
mapping += "platform:" + std::string(SDL_GetPlatform()) + ",";
return mapping;
}
} // sdl
} // joystick
} // love
@@ -56,6 +56,8 @@ public:
bool setGamepadMapping(const std::string &guid, Joystick::GamepadInput gpinput, Joystick::JoystickInput joyinput);
Joystick::JoystickInput getGamepadMapping(const std::string &guid, Joystick::GamepadInput gpinput);
void loadGamepadMappings(const std::string &mappings);
std::string saveGamepadMapping(const std::string &pguid);
private:
@@ -251,6 +251,8 @@ static const luaL_Reg functions[] =
// From wrap_JoystickModule.
{ "getConnectedIndex", w_getIndex },
{ "getGamepadMapping", w_getGamepadMapping },
{ "saveGamepadMapping", w_saveGamepadMapping },
{ 0, 0 },
};
@@ -21,6 +21,8 @@
#include "wrap_JoystickModule.h"
#include "wrap_Joystick.h"
#include "filesystem/wrap_Filesystem.h"
namespace love
{
namespace joystick
@@ -176,6 +178,49 @@ int w_getGamepadMapping(lua_State *L)
return 1;
}
int w_loadGamepadMappings(lua_State *L)
{
lua_pushvalue(L, 1);
luax_convobj(L, -1, "filesystem", "isFile");
bool isfile = luax_toboolean(L, -1);
lua_pop(L, 1);
std::string mappings;
if (isfile)
{
love::filesystem::FileData *fd = love::filesystem::luax_getfiledata(L, 1);
mappings = std::string((const char *) fd->getData(), fd->getSize());
fd->release();
}
else
mappings = luax_checkstring(L, 1);
luax_catchexcept(L, [&](){ instance->loadGamepadMappings(mappings); });
return 0;
}
int w_saveGamepadMapping(lua_State *L)
{
std::string guid, mapping;
// 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();
}
luax_catchexcept(L, [&](){ mapping = instance->saveGamepadMapping(guid); });
luax_pushstring(L, mapping);
return 1;
}
// List of functions to wrap.
static const luaL_Reg functions[] =
{
@@ -183,6 +228,8 @@ static const luaL_Reg functions[] =
{ "getJoystickCount", w_getJoystickCount },
{ "setGamepadMapping", w_setGamepadMapping },
{ "getGamepadMapping", w_getGamepadMapping },
{ "loadGamepadMappings", w_loadGamepadMappings },
{ "saveGamepadMapping", w_saveGamepadMapping },
{ 0, 0 }
};
@@ -38,6 +38,8 @@ int w_getIndex(lua_State *L);
int w_getJoystickCount(lua_State *L);
int w_setGamepadMapping(lua_State *L);
int w_getGamepadMapping(lua_State *L);
int w_loadGamepadMappings(lua_State *L);
int w_saveGamepadMapping(lua_State *L);
extern "C" LOVE_EXPORT int luaopen_love_joystick(lua_State *L);
} // sdl
+1 -1
View File
@@ -64,7 +64,7 @@ int w_newSoundData(lua_State *L)
int w_newDecoder(lua_State *L)
{
love::filesystem::FileData *data = love::filesystem::luax_getFileData(L, 1);
love::filesystem::FileData *data = love::filesystem::luax_getfiledata(L, 1);
int bufferSize = luaL_optint(L, 2, Decoder::DEFAULT_BUFFER_SIZE);
Decoder *t = nullptr;