mirror of
https://github.com/love2d/love.git
synced 2026-08-20 04:30:09 +02:00
Added an optional duration argument to Joystick:setVibration.
This commit is contained in:
@@ -157,9 +157,9 @@ public:
|
|||||||
virtual int getID() const = 0;
|
virtual int getID() const = 0;
|
||||||
|
|
||||||
virtual bool isVibrationSupported() = 0;
|
virtual bool isVibrationSupported() = 0;
|
||||||
virtual bool setVibration(float left, float right) = 0;
|
virtual bool setVibration(float left, float right, float duration = -1.0f) = 0;
|
||||||
virtual bool setVibration() = 0;
|
virtual bool setVibration() = 0;
|
||||||
virtual void getVibration(float &left, float &right) const = 0;
|
virtual void getVibration(float &left, float &right) = 0;
|
||||||
|
|
||||||
static bool getConstant(const char *in, Hat &out);
|
static bool getConstant(const char *in, Hat &out);
|
||||||
static bool getConstant(Hat in, const char *&out);
|
static bool getConstant(Hat in, const char *&out);
|
||||||
|
|||||||
@@ -25,6 +25,11 @@
|
|||||||
|
|
||||||
// C++
|
// C++
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <limits>
|
||||||
|
|
||||||
|
#ifndef SDL_TICKS_PASSED
|
||||||
|
#define SDL_TICKS_PASSED(A, B) ((Sint32)((B) - (A)) <= 0)
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace love
|
namespace love
|
||||||
{
|
{
|
||||||
@@ -34,9 +39,9 @@ namespace sdl
|
|||||||
{
|
{
|
||||||
|
|
||||||
Joystick::Joystick(int id)
|
Joystick::Joystick(int id)
|
||||||
: joyhandle(0)
|
: joyhandle(nullptr)
|
||||||
, controller(0)
|
, controller(nullptr)
|
||||||
, haptic(0)
|
, haptic(nullptr)
|
||||||
, instanceid(-1)
|
, instanceid(-1)
|
||||||
, id(id)
|
, id(id)
|
||||||
, vibration()
|
, vibration()
|
||||||
@@ -44,9 +49,9 @@ Joystick::Joystick(int id)
|
|||||||
}
|
}
|
||||||
|
|
||||||
Joystick::Joystick(int id, int joyindex)
|
Joystick::Joystick(int id, int joyindex)
|
||||||
: joyhandle(0)
|
: joyhandle(nullptr)
|
||||||
, controller(0)
|
, controller(nullptr)
|
||||||
, haptic(0)
|
, haptic(nullptr)
|
||||||
, instanceid(-1)
|
, instanceid(-1)
|
||||||
, id(id)
|
, id(id)
|
||||||
, vibration()
|
, vibration()
|
||||||
@@ -95,10 +100,7 @@ bool Joystick::open(int deviceindex)
|
|||||||
void Joystick::close()
|
void Joystick::close()
|
||||||
{
|
{
|
||||||
if (haptic)
|
if (haptic)
|
||||||
{
|
|
||||||
SDL_HapticRumbleStop(haptic);
|
|
||||||
SDL_HapticClose(haptic);
|
SDL_HapticClose(haptic);
|
||||||
}
|
|
||||||
|
|
||||||
if (controller)
|
if (controller)
|
||||||
SDL_GameControllerClose(controller);
|
SDL_GameControllerClose(controller);
|
||||||
@@ -106,16 +108,16 @@ void Joystick::close()
|
|||||||
if (joyhandle)
|
if (joyhandle)
|
||||||
SDL_JoystickClose(joyhandle);
|
SDL_JoystickClose(joyhandle);
|
||||||
|
|
||||||
joyhandle = 0;
|
joyhandle = nullptr;
|
||||||
controller = 0;
|
controller = nullptr;
|
||||||
haptic = 0;
|
haptic = nullptr;
|
||||||
instanceid = -1;
|
instanceid = -1;
|
||||||
vibration = Vibration();
|
vibration = Vibration();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Joystick::isConnected() const
|
bool Joystick::isConnected() const
|
||||||
{
|
{
|
||||||
return joyhandle != 0 && SDL_JoystickGetAttached(joyhandle);
|
return joyhandle != nullptr && SDL_JoystickGetAttached(joyhandle);
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *Joystick::getName() const
|
const char *Joystick::getName() const
|
||||||
@@ -209,7 +211,7 @@ bool Joystick::openGamepad(int deviceindex)
|
|||||||
if (isGamepad())
|
if (isGamepad())
|
||||||
{
|
{
|
||||||
SDL_GameControllerClose(controller);
|
SDL_GameControllerClose(controller);
|
||||||
controller = 0;
|
controller = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
controller = SDL_GameControllerOpen(deviceindex);
|
controller = SDL_GameControllerOpen(deviceindex);
|
||||||
@@ -218,7 +220,7 @@ bool Joystick::openGamepad(int deviceindex)
|
|||||||
|
|
||||||
bool Joystick::isGamepad() const
|
bool Joystick::isGamepad() const
|
||||||
{
|
{
|
||||||
return controller != 0;
|
return controller != nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
float Joystick::getGamepadAxis(love::joystick::Joystick::GamepadAxis axis) const
|
float Joystick::getGamepadAxis(love::joystick::Joystick::GamepadAxis axis) const
|
||||||
@@ -289,13 +291,13 @@ bool Joystick::checkCreateHaptic()
|
|||||||
if (haptic)
|
if (haptic)
|
||||||
{
|
{
|
||||||
SDL_HapticClose(haptic);
|
SDL_HapticClose(haptic);
|
||||||
haptic = 0;
|
haptic = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
haptic = SDL_HapticOpenFromJoystick(joyhandle);
|
haptic = SDL_HapticOpenFromJoystick(joyhandle);
|
||||||
vibration = Vibration();
|
vibration = Vibration();
|
||||||
|
|
||||||
return haptic != 0;
|
return haptic != nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Joystick::isVibrationSupported()
|
bool Joystick::isVibrationSupported()
|
||||||
@@ -312,8 +314,8 @@ bool Joystick::isVibrationSupported()
|
|||||||
if (isGamepad() && (features & SDL_HAPTIC_CUSTOM) != 0)
|
if (isGamepad() && (features & SDL_HAPTIC_CUSTOM) != 0)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// Check SDL's simple rumble as a last resort.
|
// Test for simple sine wave support as a last resort.
|
||||||
if (SDL_HapticRumbleSupported(haptic) == 1)
|
if ((features & SDL_HAPTIC_SINE) != 0)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@@ -325,7 +327,7 @@ bool Joystick::runVibrationEffect()
|
|||||||
{
|
{
|
||||||
if (SDL_HapticUpdateEffect(haptic, vibration.id, &vibration.effect) == 0)
|
if (SDL_HapticUpdateEffect(haptic, vibration.id, &vibration.effect) == 0)
|
||||||
{
|
{
|
||||||
if (SDL_HapticRunEffect(haptic, vibration.id, 1) != -1)
|
if (SDL_HapticRunEffect(haptic, vibration.id, 1) == 0)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -336,17 +338,14 @@ bool Joystick::runVibrationEffect()
|
|||||||
|
|
||||||
vibration.id = SDL_HapticNewEffect(haptic, &vibration.effect);
|
vibration.id = SDL_HapticNewEffect(haptic, &vibration.effect);
|
||||||
|
|
||||||
if (vibration.id != -1 && SDL_HapticRunEffect(haptic, vibration.id, 1) != -1)
|
if (vibration.id != -1 && SDL_HapticRunEffect(haptic, vibration.id, 1) == 0)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Joystick::setVibration(float left, float right)
|
bool Joystick::setVibration(float left, float right, float duration)
|
||||||
{
|
{
|
||||||
// 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);
|
left = std::min(std::max(left, 0.0f), 1.0f);
|
||||||
right = std::min(std::max(right, 0.0f), 1.0f);
|
right = std::min(std::max(right, 0.0f), 1.0f);
|
||||||
|
|
||||||
@@ -356,24 +355,32 @@ bool Joystick::setVibration(float left, float right)
|
|||||||
if (!checkCreateHaptic())
|
if (!checkCreateHaptic())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
Uint32 length = SDL_HAPTIC_INFINITY;
|
||||||
|
if (duration >= 0.0f)
|
||||||
|
{
|
||||||
|
float maxduration = std::numeric_limits<Uint32>::max() / 1000.0f;
|
||||||
|
length = Uint32(std::min(duration, maxduration) * 1000);
|
||||||
|
}
|
||||||
|
|
||||||
bool success = false;
|
bool success = false;
|
||||||
unsigned int features = SDL_HapticQuery(haptic);
|
unsigned int features = SDL_HapticQuery(haptic);
|
||||||
|
int axes = SDL_HapticNumAxes(haptic);
|
||||||
|
|
||||||
if ((features & SDL_HAPTIC_LEFTRIGHT) != 0)
|
if ((features & SDL_HAPTIC_LEFTRIGHT) != 0)
|
||||||
{
|
{
|
||||||
memset(&vibration.effect, 0, sizeof(SDL_HapticEffect));
|
memset(&vibration.effect, 0, sizeof(SDL_HapticEffect));
|
||||||
vibration.effect.type = SDL_HAPTIC_LEFTRIGHT;
|
vibration.effect.type = SDL_HAPTIC_LEFTRIGHT;
|
||||||
|
|
||||||
vibration.effect.leftright.length = SDL_HAPTIC_INFINITY;
|
vibration.effect.leftright.length = length;
|
||||||
vibration.effect.leftright.large_magnitude = Uint16(left * LOVE_UINT16_MAX);
|
vibration.effect.leftright.large_magnitude = Uint16(left * LOVE_UINT16_MAX);
|
||||||
vibration.effect.leftright.small_magnitude = Uint16(right * LOVE_UINT16_MAX);
|
vibration.effect.leftright.small_magnitude = Uint16(right * LOVE_UINT16_MAX);
|
||||||
|
|
||||||
success = runVibrationEffect();
|
success = runVibrationEffect();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Some gamepad drivers only give support for controlling the motors via
|
// Some gamepad drivers only give support for controlling individual motors
|
||||||
// a custom FF effect.
|
// through a custom FF effect.
|
||||||
if (!success && isGamepad() && (features & SDL_HAPTIC_CUSTOM) != 0)
|
if (!success && isGamepad() && (features & SDL_HAPTIC_CUSTOM) && axes == 2)
|
||||||
{
|
{
|
||||||
// NOTE: this may cause issues with drivers which support custom effects
|
// NOTE: this may cause issues with drivers which support custom effects
|
||||||
// but aren't similar to https://github.com/d235j/360Controller .
|
// but aren't similar to https://github.com/d235j/360Controller .
|
||||||
@@ -385,7 +392,7 @@ bool Joystick::setVibration(float left, float right)
|
|||||||
memset(&vibration.effect, 0, sizeof(SDL_HapticEffect));
|
memset(&vibration.effect, 0, sizeof(SDL_HapticEffect));
|
||||||
vibration.effect.type = SDL_HAPTIC_CUSTOM;
|
vibration.effect.type = SDL_HAPTIC_CUSTOM;
|
||||||
|
|
||||||
vibration.effect.custom.length = SDL_HAPTIC_INFINITY;
|
vibration.effect.custom.length = length;
|
||||||
vibration.effect.custom.channels = 2;
|
vibration.effect.custom.channels = 2;
|
||||||
vibration.effect.custom.period = 10;
|
vibration.effect.custom.period = 10;
|
||||||
vibration.effect.custom.samples = 2;
|
vibration.effect.custom.samples = 2;
|
||||||
@@ -394,19 +401,36 @@ bool Joystick::setVibration(float left, float right)
|
|||||||
success = runVibrationEffect();
|
success = runVibrationEffect();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fall back to a simple rumble if all else fails. SDL's simple rumble API
|
// Fall back to a simple sine wave if all else fails. This only supports a
|
||||||
// only supports a single strength value.
|
// single strength value.
|
||||||
if (!success && SDL_HapticRumbleInit(haptic) == 0)
|
if (!success && (features & SDL_HAPTIC_SINE) != 0)
|
||||||
{
|
{
|
||||||
|
memset(&vibration.effect, 0, sizeof(SDL_HapticEffect));
|
||||||
|
vibration.effect.type = SDL_HAPTIC_SINE;
|
||||||
|
|
||||||
|
vibration.effect.periodic.length = length;
|
||||||
|
vibration.effect.periodic.period = 10;
|
||||||
|
|
||||||
float strength = std::max(left, right);
|
float strength = std::max(left, right);
|
||||||
int played = SDL_HapticRumblePlay(haptic, strength, SDL_HAPTIC_INFINITY);
|
vibration.effect.periodic.magnitude = Sint16(strength * 0x7FFF);
|
||||||
success = (played == 0);
|
|
||||||
|
success = runVibrationEffect();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (success)
|
if (success)
|
||||||
{
|
{
|
||||||
vibration.left = left;
|
vibration.left = left;
|
||||||
vibration.right = right;
|
vibration.right = right;
|
||||||
|
|
||||||
|
if (length == SDL_HAPTIC_INFINITY)
|
||||||
|
vibration.endtime = SDL_HAPTIC_INFINITY;
|
||||||
|
else
|
||||||
|
vibration.endtime = SDL_GetTicks() + length;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
vibration.left = vibration.right = 0.0f;
|
||||||
|
vibration.endtime = SDL_HAPTIC_INFINITY;
|
||||||
}
|
}
|
||||||
|
|
||||||
return success;
|
return success;
|
||||||
@@ -417,12 +441,7 @@ bool Joystick::setVibration()
|
|||||||
bool success = true;
|
bool success = true;
|
||||||
|
|
||||||
if (SDL_WasInit(SDL_INIT_HAPTIC) && haptic && SDL_HapticIndex(haptic) != -1)
|
if (SDL_WasInit(SDL_INIT_HAPTIC) && haptic && SDL_HapticIndex(haptic) != -1)
|
||||||
{
|
success = (SDL_HapticStopEffect(haptic, vibration.id) == 0);
|
||||||
// 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)
|
if (success)
|
||||||
vibration.left = vibration.right = 0.0f;
|
vibration.left = vibration.right = 0.0f;
|
||||||
@@ -430,8 +449,25 @@ bool Joystick::setVibration()
|
|||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Joystick::getVibration(float &left, float &right) const
|
void Joystick::getVibration(float &left, float &right)
|
||||||
{
|
{
|
||||||
|
if (vibration.endtime != SDL_HAPTIC_INFINITY)
|
||||||
|
{
|
||||||
|
// With some drivers, the effect physically stops at the right time, but
|
||||||
|
// SDL_HapticGetEffectStatus still thinks it's playing. So we explicitly
|
||||||
|
// stop it once it's done, just to be sure.
|
||||||
|
if (SDL_TICKS_PASSED(SDL_GetTicks(), vibration.endtime))
|
||||||
|
{
|
||||||
|
setVibration();
|
||||||
|
vibration.endtime = SDL_HAPTIC_INFINITY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the haptic effect has stopped playing.
|
||||||
|
int id = vibration.id;
|
||||||
|
if (!haptic || id == -1 || SDL_HapticGetEffectStatus(haptic, id) != 1)
|
||||||
|
vibration.left = vibration.right = 0.0f;
|
||||||
|
|
||||||
left = vibration.left;
|
left = vibration.left;
|
||||||
right = vibration.right;
|
right = vibration.right;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -74,9 +74,9 @@ public:
|
|||||||
int getID() const;
|
int getID() const;
|
||||||
|
|
||||||
bool isVibrationSupported();
|
bool isVibrationSupported();
|
||||||
bool setVibration(float left, float right);
|
bool setVibration(float left, float right, float duration = -1.0f);
|
||||||
bool setVibration();
|
bool setVibration();
|
||||||
void getVibration(float &left, float &right) const;
|
void getVibration(float &left, float &right);
|
||||||
|
|
||||||
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);
|
||||||
@@ -111,8 +111,12 @@ private:
|
|||||||
Uint16 data[4];
|
Uint16 data[4];
|
||||||
int id;
|
int id;
|
||||||
|
|
||||||
|
Uint32 endtime;
|
||||||
|
|
||||||
Vibration()
|
Vibration()
|
||||||
: left(0.0f), right(0.0f), effect(), data(), id(-1)
|
: left(0.0f), right(0.0f)
|
||||||
|
, effect(), data(), id(-1)
|
||||||
|
, endtime(SDL_HAPTIC_INFINITY)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
} vibration;
|
} vibration;
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ const char *JoystickModule::getName() const
|
|||||||
love::joystick::Joystick *JoystickModule::getJoystick(int joyindex)
|
love::joystick::Joystick *JoystickModule::getJoystick(int joyindex)
|
||||||
{
|
{
|
||||||
if (joyindex < 0 || (size_t) joyindex >= activeSticks.size())
|
if (joyindex < 0 || (size_t) joyindex >= activeSticks.size())
|
||||||
return 0;
|
return nullptr;
|
||||||
|
|
||||||
return activeSticks[joyindex];
|
return activeSticks[joyindex];
|
||||||
}
|
}
|
||||||
@@ -107,13 +107,13 @@ love::joystick::Joystick *JoystickModule::getJoystickFromID(int instanceid)
|
|||||||
return activeSticks[i];
|
return activeSticks[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
love::joystick::Joystick *JoystickModule::addJoystick(int deviceindex)
|
love::joystick::Joystick *JoystickModule::addJoystick(int deviceindex)
|
||||||
{
|
{
|
||||||
if (deviceindex < 0 || deviceindex >= SDL_NumJoysticks())
|
if (deviceindex < 0 || deviceindex >= SDL_NumJoysticks())
|
||||||
return 0;
|
return nullptr;
|
||||||
|
|
||||||
std::string guidstr = getDeviceGUID(deviceindex);
|
std::string guidstr = getDeviceGUID(deviceindex);
|
||||||
joystick::Joystick *joystick = 0;
|
joystick::Joystick *joystick = 0;
|
||||||
@@ -140,7 +140,7 @@ love::joystick::Joystick *JoystickModule::addJoystick(int deviceindex)
|
|||||||
removeJoystick(joystick);
|
removeJoystick(joystick);
|
||||||
|
|
||||||
if (!joystick->open(deviceindex))
|
if (!joystick->open(deviceindex))
|
||||||
return 0;
|
return nullptr;
|
||||||
|
|
||||||
// Make sure multiple instances of the same physical joystick aren't added
|
// Make sure multiple instances of the same physical joystick aren't added
|
||||||
// to the active list.
|
// to the active list.
|
||||||
@@ -262,7 +262,7 @@ bool JoystickModule::setGamepadMapping(const std::string &guid, Joystick::Gamepa
|
|||||||
if (status == 1)
|
if (status == 1)
|
||||||
checkGamepads(guid);
|
checkGamepads(guid);
|
||||||
|
|
||||||
return status >= 0;
|
return status >= 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
Joystick::JoystickInput JoystickModule::getGamepadMapping(const std::string &guid, Joystick::GamepadInput gpinput)
|
Joystick::JoystickInput JoystickModule::getGamepadMapping(const std::string &guid, Joystick::GamepadInput gpinput)
|
||||||
@@ -318,7 +318,7 @@ std::string JoystickModule::stringFromGamepadInput(Joystick::GamepadInput gpinpu
|
|||||||
SDL_GameControllerAxis sdlaxis;
|
SDL_GameControllerAxis sdlaxis;
|
||||||
SDL_GameControllerButton sdlbutton;
|
SDL_GameControllerButton sdlbutton;
|
||||||
|
|
||||||
const char *gpinputname = 0;
|
const char *gpinputname = nullptr;
|
||||||
|
|
||||||
switch (gpinput.type)
|
switch (gpinput.type)
|
||||||
{
|
{
|
||||||
@@ -435,7 +435,7 @@ void JoystickModule::checkGamepads(const std::string &guid) const
|
|||||||
// Big hack time: open the index as a game controller and compare
|
// Big hack time: open the index as a game controller and compare
|
||||||
// the underlying joystick handle to the active stick's.
|
// the underlying joystick handle to the active stick's.
|
||||||
SDL_GameController *ctrl = SDL_GameControllerOpen(d_index);
|
SDL_GameController *ctrl = SDL_GameControllerOpen(d_index);
|
||||||
if (ctrl == NULL)
|
if (ctrl == nullptr)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
SDL_Joystick *stick = SDL_GameControllerGetJoystick(ctrl);
|
SDL_Joystick *stick = SDL_GameControllerGetJoystick(ctrl);
|
||||||
|
|||||||
@@ -207,7 +207,8 @@ int w_Joystick_setVibration(lua_State *L)
|
|||||||
{
|
{
|
||||||
float left = (float) luaL_checknumber(L, 2);
|
float left = (float) luaL_checknumber(L, 2);
|
||||||
float right = (float) luaL_optnumber(L, 3, left);
|
float right = (float) luaL_optnumber(L, 3, left);
|
||||||
success = j->setVibration(left, right);
|
float duration = (float) luaL_optnumber(L, 4, -1.0); // -1 is infinite.
|
||||||
|
success = j->setVibration(left, right, duration);
|
||||||
}
|
}
|
||||||
|
|
||||||
luax_pushboolean(L, success);
|
luax_pushboolean(L, success);
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ namespace joystick
|
|||||||
namespace sdl
|
namespace sdl
|
||||||
{
|
{
|
||||||
|
|
||||||
static JoystickModule *instance = 0;
|
static JoystickModule *instance = nullptr;
|
||||||
|
|
||||||
int w_getJoysticks(lua_State *L)
|
int w_getJoysticks(lua_State *L)
|
||||||
{
|
{
|
||||||
@@ -194,7 +194,7 @@ static const lua_CFunction types[] =
|
|||||||
|
|
||||||
extern "C" int luaopen_love_joystick(lua_State *L)
|
extern "C" int luaopen_love_joystick(lua_State *L)
|
||||||
{
|
{
|
||||||
if (instance == 0)
|
if (instance == nullptr)
|
||||||
{
|
{
|
||||||
EXCEPT_GUARD(instance = new JoystickModule();)
|
EXCEPT_GUARD(instance = new JoystickModule();)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user