Browse Source

Work around SDL issues in Joystick:getGamepadMapping with XInput controllers (issue #1239).

This doesn’t fix the underlying issues in SDL so there may be other aspects of love.joystick which are still affected.

--HG--
branch : minor
Alex Szpakowski 8 years ago
parent
commit
b620f32200

+ 2 - 0
src/modules/joystick/Joystick.h

@@ -152,6 +152,8 @@ public:
 	virtual float getGamepadAxis(GamepadAxis axis) const = 0;
 	virtual float getGamepadAxis(GamepadAxis axis) const = 0;
 	virtual bool isGamepadDown(const std::vector<GamepadButton> &blist) const = 0;
 	virtual bool isGamepadDown(const std::vector<GamepadButton> &blist) const = 0;
 
 
+	virtual JoystickInput getGamepadMapping(const GamepadInput &input) const = 0;
+
 	virtual void *getHandle() const = 0;
 	virtual void *getHandle() const = 0;
 
 
 	virtual std::string getGUID() const = 0;
 	virtual std::string getGUID() const = 0;

+ 0 - 6
src/modules/joystick/JoystickModule.h

@@ -82,12 +82,6 @@ public:
 	 **/
 	 **/
 	virtual bool setGamepadMapping(const std::string &pguid, Joystick::GamepadInput gpinput, Joystick::JoystickInput joyinput) = 0;
 	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;
-
 	/**
 	/**
 	 * Loads a newline-separated list of virtual Gamepad mapping strings for
 	 * Loads a newline-separated list of virtual Gamepad mapping strings for
 	 * multiple joysticks at a time. The mapping strings must have been
 	 * multiple joysticks at a time. The mapping strings must have been

+ 53 - 0
src/modules/joystick/sdl/Joystick.cpp

@@ -248,6 +248,59 @@ bool Joystick::isGamepadDown(const std::vector<GamepadButton> &blist) const
 	return false;
 	return false;
 }
 }
 
 
+Joystick::JoystickInput Joystick::getGamepadMapping(const GamepadInput &input) const
+{
+	Joystick::JoystickInput jinput;
+	jinput.type = INPUT_TYPE_MAX_ENUM;
+
+	if (!isGamepad())
+		return jinput;
+
+	SDL_GameControllerButtonBind sdlbind = {};
+	sdlbind.bindType = SDL_CONTROLLER_BINDTYPE_NONE;
+
+	SDL_GameControllerButton sdlbutton;
+	SDL_GameControllerAxis sdlaxis;
+
+	switch (input.type)
+	{
+	case INPUT_TYPE_BUTTON:
+		if (getConstant(input.button, sdlbutton))
+			sdlbind = SDL_GameControllerGetBindForButton(controller, sdlbutton);
+		break;
+	case INPUT_TYPE_AXIS:
+		if (getConstant(input.axis, sdlaxis))
+			sdlbind = SDL_GameControllerGetBindForAxis(controller, sdlaxis);
+		break;
+	default:
+		break;
+	}
+
+	switch (sdlbind.bindType)
+	{
+	case SDL_CONTROLLER_BINDTYPE_BUTTON:
+		jinput.type = INPUT_TYPE_BUTTON;
+		jinput.button = sdlbind.value.button;
+		break;
+	case SDL_CONTROLLER_BINDTYPE_AXIS:
+		jinput.type = INPUT_TYPE_AXIS;
+		jinput.axis = sdlbind.value.axis;
+		break;
+	case SDL_CONTROLLER_BINDTYPE_HAT:
+		if (getConstant(sdlbind.value.hat.hat_mask, jinput.hat.value))
+		{
+			jinput.type = INPUT_TYPE_HAT;
+			jinput.hat.index = sdlbind.value.hat.hat;
+		}
+		break;
+	case SDL_CONTROLLER_BINDTYPE_NONE:
+	default:
+		break;
+	}
+
+	return jinput;
+}
+
 void *Joystick::getHandle() const
 void *Joystick::getHandle() const
 {
 {
 	return joyhandle;
 	return joyhandle;

+ 25 - 23
src/modules/joystick/sdl/Joystick.h

@@ -44,39 +44,41 @@ public:
 
 
 	virtual ~Joystick();
 	virtual ~Joystick();
 
 
-	bool open(int deviceindex);
-	void close();
+	bool open(int deviceindex) override;
+	void close() override;
 
 
-	bool isConnected() const;
+	bool isConnected() const override;
 
 
-	const char *getName() const;
+	const char *getName() const override;
 
 
-	int getAxisCount() const;
-	int getButtonCount() const;
-	int getHatCount() const;
+	int getAxisCount() const override;
+	int getButtonCount() const override;
+	int getHatCount() const override;
 
 
-	float getAxis(int axisindex) const;
-	std::vector<float> getAxes() const;
-	Hat getHat(int hatindex) const;
+	float getAxis(int axisindex) const override;
+	std::vector<float> getAxes() const override;
+	Hat getHat(int hatindex) const override;
 
 
-	bool isDown(const std::vector<int> &buttonlist) const;
+	bool isDown(const std::vector<int> &buttonlist) const override;
 
 
-	bool openGamepad(int deviceindex);
-	bool isGamepad() const;
+	bool openGamepad(int deviceindex) override;
+	bool isGamepad() const override;
 
 
-	float getGamepadAxis(GamepadAxis axis) const;
-	bool isGamepadDown(const std::vector<GamepadButton> &blist) const;
+	float getGamepadAxis(GamepadAxis axis) const override;
+	bool isGamepadDown(const std::vector<GamepadButton> &blist) const override;
 
 
-	void *getHandle() const;
+	JoystickInput getGamepadMapping(const GamepadInput &input) const override;
 
 
-	std::string getGUID() const;
-	int getInstanceID() const;
-	int getID() const;
+	void *getHandle() const override;
 
 
-	bool isVibrationSupported();
-	bool setVibration(float left, float right, float duration = -1.0f);
-	bool setVibration();
-	void getVibration(float &left, float &right);
+	std::string getGUID() const override;
+	int getInstanceID() const override;
+	int getID() const override;
+
+	bool isVibrationSupported() override;
+	bool setVibration(float left, float right, float duration = -1.0f) override;
+	bool setVibration() override;
+	void getVibration(float &left, float &right) override;
 
 
 	static bool getConstant(Hat in, Uint8 &out);
 	static bool getConstant(Hat in, Uint8 &out);
 	static bool getConstant(Uint8 in, Hat &out);
 	static bool getConstant(Uint8 in, Hat &out);

+ 0 - 93
src/modules/joystick/sdl/JoystickModule.cpp

@@ -271,54 +271,6 @@ bool JoystickModule::setGamepadMapping(const std::string &guid, Joystick::Gamepa
 	return status >= 0;
 	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 + 1);
-	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
 std::string JoystickModule::stringFromGamepadInput(Joystick::GamepadInput gpinput) const
 {
 {
 	SDL_GameControllerAxis sdlaxis;
 	SDL_GameControllerAxis sdlaxis;
@@ -346,51 +298,6 @@ std::string JoystickModule::stringFromGamepadInput(Joystick::GamepadInput gpinpu
 	return std::string(gpinputname);
 	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 = (int) strtol(bindvalues.c_str(), nullptr, 10);
-		break;
-	case 'b':
-		jinput.type = Joystick::INPUT_TYPE_BUTTON;
-		jinput.button = (int) strtol(bindvalues.c_str(), nullptr, 10);
-		break;
-	case 'h':
-		// Hat string syntax is "index.value".
-		if (bindvalues.length() < 3)
-			break;
-		jinput.type = Joystick::INPUT_TYPE_HAT;
-		jinput.hat.index = (int) strtol(bindvalues.substr(0, 1).c_str(), nullptr, 10);
-		sdlhat = (Uint8) strtol(bindvalues.substr(2).c_str(), nullptr, 10);
-		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
 void JoystickModule::removeBindFromMapString(std::string &mapstr, const std::string &joybindstr) const
 {
 {
 	// Find the joystick part of the bind in the string.
 	// Find the joystick part of the bind in the string.

+ 0 - 2
src/modules/joystick/sdl/JoystickModule.h

@@ -56,14 +56,12 @@ public:
 	int getJoystickCount() const;
 	int getJoystickCount() const;
 
 
 	bool setGamepadMapping(const std::string &guid, Joystick::GamepadInput gpinput, Joystick::JoystickInput joyinput);
 	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);
 	void loadGamepadMappings(const std::string &mappings);
 	std::string saveGamepadMappings();
 	std::string saveGamepadMappings();
 
 
 private:
 private:
 
 
 	std::string stringFromGamepadInput(Joystick::GamepadInput gpinput) const;
 	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 removeBindFromMapString(std::string &mapstr, const std::string &joybindstr) const;
 
 
 	void checkGamepads(const std::string &guid) const;
 	void checkGamepads(const std::string &guid) const;

+ 54 - 1
src/modules/joystick/wrap_Joystick.cpp

@@ -225,6 +225,59 @@ int w_Joystick_isGamepadDown(lua_State *L)
 	return 1;
 	return 1;
 }
 }
 
 
+int w_Joystick_getGamepadMapping(lua_State *L)
+{
+	Joystick *j = luax_checkjoystick(L, 1);
+
+	const char *gpbindstr = luaL_checkstring(L, 2);
+	Joystick::GamepadInput gpinput;
+
+	if (Joystick::getConstant(gpbindstr, gpinput.axis))
+		gpinput.type = Joystick::INPUT_TYPE_AXIS;
+	else if (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;
+
+	luax_catchexcept(L, [&](){ jinput = j->getGamepadMapping(gpinput); });
+
+	if (jinput.type == Joystick::INPUT_TYPE_MAX_ENUM)
+		return 0;
+
+	const char *inputtypestr;
+	if (!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 (Joystick::getConstant(jinput.hat.value, hatstr))
+		{
+			lua_pushstring(L, hatstr);
+			return 3;
+		}
+		else
+			return luaL_error(L, "Unknown joystick hat.");
+	default:
+		return luaL_error(L, "Unknown joystick input type.");
+	}
+	
+	return 1;
+}
+
 int w_Joystick_isVibrationSupported(lua_State *L)
 int w_Joystick_isVibrationSupported(lua_State *L)
 {
 {
 	Joystick *j = luax_checkjoystick(L, 1);
 	Joystick *j = luax_checkjoystick(L, 1);
@@ -282,6 +335,7 @@ static const luaL_Reg w_Joystick_functions[] =
 	{ "isGamepad", w_Joystick_isGamepad },
 	{ "isGamepad", w_Joystick_isGamepad },
 	{ "getGamepadAxis", w_Joystick_getGamepadAxis },
 	{ "getGamepadAxis", w_Joystick_getGamepadAxis },
 	{ "isGamepadDown", w_Joystick_isGamepadDown },
 	{ "isGamepadDown", w_Joystick_isGamepadDown },
+	{ "getGamepadMapping", w_Joystick_getGamepadMapping },
 
 
 	{ "isVibrationSupported", w_Joystick_isVibrationSupported },
 	{ "isVibrationSupported", w_Joystick_isVibrationSupported },
 	{ "setVibration", w_Joystick_setVibration },
 	{ "setVibration", w_Joystick_setVibration },
@@ -289,7 +343,6 @@ static const luaL_Reg w_Joystick_functions[] =
 
 
 	// From wrap_JoystickModule.
 	// From wrap_JoystickModule.
 	{ "getConnectedIndex", w_getIndex },
 	{ "getConnectedIndex", w_getIndex },
-	{ "getGamepadMapping", w_getGamepadMapping },
 
 
 	{ 0, 0 },
 	{ 0, 0 },
 };
 };

+ 0 - 64
src/modules/joystick/wrap_JoystickModule.cpp

@@ -114,69 +114,6 @@ int w_setGamepadMapping(lua_State *L)
 	return 1;
 	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
-	{
-		Joystick *stick = luax_checkjoystick(L, 1);
-		guid = stick->getGUID();
-	}
-
-	const char *gpbindstr = luaL_checkstring(L, 2);
-	Joystick::GamepadInput gpinput;
-
-	if (Joystick::getConstant(gpbindstr, gpinput.axis))
-		gpinput.type = Joystick::INPUT_TYPE_AXIS;
-	else if (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;
-
-	luax_catchexcept(L, [&](){ jinput = instance()->getGamepadMapping(guid, gpinput); });
-
-	if (jinput.type == Joystick::INPUT_TYPE_MAX_ENUM)
-		return 0;
-
-	const char *inputtypestr;
-	if (!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 (Joystick::getConstant(jinput.hat.value, hatstr))
-		{
-			lua_pushstring(L, hatstr);
-			return 3;
-		}
-		else
-			return luaL_error(L, "Unknown joystick hat.");
-	default:
-		break; // ?
-	}
-
-	return 1;
-}
-
 int w_loadGamepadMappings(lua_State *L)
 int w_loadGamepadMappings(lua_State *L)
 {
 {
 	bool isfile = true;
 	bool isfile = true;
@@ -229,7 +166,6 @@ static const luaL_Reg functions[] =
 	{ "getJoysticks", w_getJoysticks },
 	{ "getJoysticks", w_getJoysticks },
 	{ "getJoystickCount", w_getJoystickCount },
 	{ "getJoystickCount", w_getJoystickCount },
 	{ "setGamepadMapping", w_setGamepadMapping },
 	{ "setGamepadMapping", w_setGamepadMapping },
-	{ "getGamepadMapping", w_getGamepadMapping },
 	{ "loadGamepadMappings", w_loadGamepadMappings },
 	{ "loadGamepadMappings", w_loadGamepadMappings },
 	{ "saveGamepadMappings", w_saveGamepadMappings },
 	{ "saveGamepadMappings", w_saveGamepadMappings },
 	{ 0, 0 }
 	{ 0, 0 }

+ 0 - 1
src/modules/joystick/wrap_JoystickModule.h

@@ -32,7 +32,6 @@ namespace joystick
 {
 {
 
 
 int w_getIndex(lua_State *L);
 int w_getIndex(lua_State *L);
-int w_getGamepadMapping(lua_State *L);
 extern "C" LOVE_EXPORT int luaopen_love_joystick(lua_State *L);
 extern "C" LOVE_EXPORT int luaopen_love_joystick(lua_State *L);
 
 
 } // joystick
 } // joystick