mirror of
https://github.com/love2d/love.git
synced 2026-08-18 11:44:15 +02:00
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
This commit is contained in:
@@ -248,6 +248,59 @@ bool Joystick::isGamepadDown(const std::vector<GamepadButton> &blist) const
|
||||
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
|
||||
{
|
||||
return joyhandle;
|
||||
|
||||
@@ -44,39 +44,41 @@ public:
|
||||
|
||||
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(Uint8 in, Hat &out);
|
||||
|
||||
@@ -271,54 +271,6 @@ bool JoystickModule::setGamepadMapping(const std::string &guid, Joystick::Gamepa
|
||||
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
|
||||
{
|
||||
SDL_GameControllerAxis sdlaxis;
|
||||
@@ -346,51 +298,6 @@ std::string JoystickModule::stringFromGamepadInput(Joystick::GamepadInput gpinpu
|
||||
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
|
||||
{
|
||||
// Find the joystick part of the bind in the string.
|
||||
|
||||
@@ -56,14 +56,12 @@ public:
|
||||
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);
|
||||
void loadGamepadMappings(const std::string &mappings);
|
||||
std::string saveGamepadMappings();
|
||||
|
||||
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;
|
||||
|
||||
Reference in New Issue
Block a user