mirror of
https://github.com/love2d/love-android.git
synced 2026-08-19 12:14:49 +02:00
imported Löve GLES branch (changeset 1ba9037e558b)
This commit is contained in:
@@ -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
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user