Commit 7af1f46c authored by Gregory Dymarek's avatar Gregory Dymarek

Restructuring + Initial Android handler

parent 877cef55
......@@ -312,6 +312,11 @@ HEADERS += \
src/AutoPilotPlugins/APM/APMRemoteParamsDownloader.h \
src/QtLocationPlugin/QMLControl/QGCMapEngineManager.h \
AndroidBuild {
HEADERS += \
src/Joystick/JoystickAndroid.h \
}
DebugBuild {
HEADERS += \
src/comm/MockLink.h \
......@@ -344,6 +349,7 @@ HEADERS += \
src/comm/QGCHilLink.h \
src/comm/QGCJSBSimLink.h \
src/comm/QGCXPlaneLink.h \
src/Joystick/JoystickSDL.h \
src/QGCFileDialog.h \
src/QGCMessageBox.h \
src/uas/FileManager.h \
......@@ -400,8 +406,10 @@ iOSBuild {
src/audio/QGCAudioWorker_iOS.mm \
src/MobileScreenMgr.mm \
}
AndroidBuild {
SOURCES += src/MobileScreenMgr.cc \
src/Joystick/JoystickAndroid.cc \
}
......@@ -497,6 +505,7 @@ SOURCES += \
src/comm/QGCFlightGearLink.cc \
src/comm/QGCJSBSimLink.cc \
src/comm/QGCXPlaneLink.cc \
src/Joystick/JoystickSDL.cc \
src/ui/HILDockWidget.cc \
src/ui/linechart/ChartPlot.cc \
src/ui/linechart/IncrementalPlot.cc \
......
This diff is collapsed.
......@@ -39,9 +39,9 @@ class Joystick : public QThread
Q_OBJECT
public:
Joystick(const QString& name, int axisCount, int buttonCount, int sdlIndex, MultiVehicleManager* multiVehicleManager);
Joystick(const QString& name, int axisCount, int buttonCount, MultiVehicleManager* multiVehicleManager);
~Joystick();
typedef struct {
int min;
int max;
......@@ -136,7 +136,7 @@ signals:
void buttonActionTriggered(int action);
private:
protected:
void _saveSettings(void);
void _loadSettings(void);
float _adjustRange(int value, Calibration_t calibration);
......@@ -144,11 +144,18 @@ private:
bool _validAxis(int axis);
bool _validButton(int button);
private:
virtual bool open() = 0;
virtual void close() = 0;
virtual bool update() = 0;
virtual bool getButton(int i) = 0;
virtual int getAxis(int i) = 0;
// Override from QThread
virtual void run(void);
private:
int _sdlIndex; ///< Index for SDL_JoystickOpen
protected:
bool _exitThread; ///< true: signal thread to exit
......
#include "JoystickAndroid.h"
#include "QGCApplication.h"
#include <QQmlEngine>
int JoystickAndroid::_androidBtnListCount;
int *JoystickAndroid::_androidBtnList;
QMutex JoystickAndroid::m_mutex;
JoystickAndroid::JoystickAndroid(const QString& name, int id, MultiVehicleManager* multiVehicleManager)
: Joystick(name,0,0,multiVehicleManager) //buttonCount and axisCount is computed below
, deviceId(id)
{
int i;
QAndroidJniEnvironment env;
QAndroidJniObject inputDevice = QAndroidJniObject::callStaticObjectMethod("android/view/InputDevice", "getDevice", "(I)Landroid/view/InputDevice;", id);
//get number of buttons
jintArray a = env->NewIntArray(_androidBtnListCount);
env->SetIntArrayRegion(a,0,_androidBtnListCount,_androidBtnList);
QAndroidJniObject btns = inputDevice.callObjectMethod("hasKeys", "([I)[Z", a);
jbooleanArray jSupportedButtons = btns.object<jbooleanArray>();
int btn_sz = env->GetArrayLength(jSupportedButtons);
jboolean* supportedButtons = env->GetBooleanArrayElements(jSupportedButtons, nullptr);
_buttonCount=0;
for (i=0;i<btn_sz;i++)
if (supportedButtons[i]) _buttonCount++;
//create a mapping table (btnCode) that maps button number with button code
btnValue = new bool[_buttonCount];
btnCode = new int[_buttonCount];
int c = 0;
for (i=0;i<btn_sz;i++)
if (supportedButtons[i]) {
btnValue[c] = false;
btnCode[c] = _androidBtnList[i];
c++;
}
env->ReleaseBooleanArrayElements(jSupportedButtons, supportedButtons, 0);
//get number of axis
QAndroidJniObject rangeListNative = inputDevice.callObjectMethod("getMotionRanges", "()Ljava/util/List;");
_axisCount = rangeListNative.callMethod<jint>("size");
axisValue = new int[_axisCount];
axisCode = new int[_axisCount];
for (i=0;i<_axisCount;i++) {
QAndroidJniObject range = rangeListNative.callObjectMethod("get", "()Landroid/view/InputDevice/MotionRange;");
if (range.isValid())
axisCode[i] = range.callMethod<jint>("getAxis");
axisValue[i] = 0;
}
qDebug() << "joystick constructor:" << _name;
QtAndroidPrivate::registerGenericMotionEventListener(this);
QtAndroidPrivate::registerKeyEventListener(this);
}
JoystickAndroid::~JoystickAndroid() {
qDebug() << "joystick destructor" << _name;
delete btnCode;
delete axisCode;
delete btnValue;
delete axisValue;
QtAndroidPrivate::unregisterGenericMotionEventListener(this);
QtAndroidPrivate::unregisterKeyEventListener(this);
}
bool JoystickAndroid::handleKeyEvent(jobject event) {
QJNIObjectPrivate ev(event);
QMutexLocker lock(&m_mutex);
const int _deviceId = ev.callMethod<jint>("getDeviceId", "()I");
if (_deviceId!=deviceId) return false;
qDebug() << "handleKeyEvent!" << deviceId;
return true;
}
bool JoystickAndroid::handleGenericMotionEvent(jobject event) {
QJNIObjectPrivate ev(event);
QMutexLocker lock(&m_mutex);
const int _deviceId = ev.callMethod<jint>("getDeviceId", "()I");
if (_deviceId!=deviceId) return false;
qDebug() << "handleMotionEvent!" << deviceId;
return true;
}
QMap<QString, Joystick*> JoystickAndroid::discover(MultiVehicleManager* _multiVehicleManager) {
bool joystickFound = false;
static QMap<QString, Joystick*> ret;
_buttonList(); //it's enough to run it once, should be in a static constructor
QMutexLocker lock(&m_mutex);
QAndroidJniEnvironment env;
QAndroidJniObject o = QAndroidJniObject::callStaticObjectMethod<jintArray>("android/view/InputDevice", "getDeviceIds");
jintArray jarr = o.object<jintArray>();
size_t sz = env->GetArrayLength(jarr);
jint *buff = env->GetIntArrayElements(jarr, nullptr);
int SOURCE_GAMEPAD = QAndroidJniObject::getStaticField<jint>("android/view/InputDevice", "SOURCE_GAMEPAD");
int SOURCE_JOYSTICK = QAndroidJniObject::getStaticField<jint>("android/view/InputDevice", "SOURCE_JOYSTICK");
for (size_t i = 0; i < sz; ++i) {
QAndroidJniObject inputDevice = QAndroidJniObject::callStaticObjectMethod("android/view/InputDevice", "getDevice", "(I)Landroid/view/InputDevice;", buff[i]);
int sources = inputDevice.callMethod<jint>("getSources", "()I");
if (((sources & SOURCE_GAMEPAD) != SOURCE_GAMEPAD) //check if the input device is interesting to us
&& ((sources & SOURCE_JOYSTICK) != SOURCE_JOYSTICK)) continue;
//get id and name
QString id = inputDevice.callObjectMethod("getDescriptor", "()Ljava/lang/String;").toString();
QString name = inputDevice.callObjectMethod("getName", "()Ljava/lang/String;").toString();
if (joystickFound) { //skipping {
qWarning() << "Skipping joystick:" << name;
continue;
}
qDebug() << "\t" << name << "id:" << buff[i];
ret[name] = new JoystickAndroid(name, buff[i], _multiVehicleManager);
joystickFound = true;
}
env->ReleaseIntArrayElements(jarr, buff, 0);
return ret;
}
bool JoystickAndroid::open(void) {
return true;
}
void JoystickAndroid::close(void) {
}
bool JoystickAndroid::update(void)
{
return true;
}
bool JoystickAndroid::getButton(int i) {
return btnValue[ btnCode[i] ];
}
int JoystickAndroid::getAxis(int i) {
return axisValue[ axisCode[i] ];
}
//helper method
void JoystickAndroid::_buttonList() {
//this gets list of all possible buttons - this is needed to check how many buttons our gamepad supports
//instead of the whole logic below we could have just a simple array of hardcoded int values as these 'should' not change
//int JoystickAndroid::_androidBtnListCount;
_androidBtnListCount = 31;
static int ret[31]; //there are 31 buttons in total accordingy to the API
int i;
//int *JoystickAndroid::
_androidBtnList = ret;
for (i=1;i<=16;i++) {
QString name = "KEYCODE_BUTTON_"+QString::number(i);
ret[i-1] = QAndroidJniObject::getStaticField<jint>("android/view/KeyEvent", name.toStdString().c_str());
}
i--;
ret[i++] = QAndroidJniObject::getStaticField<jint>("android/view/KeyEvent", "KEYCODE_BUTTON_A");
ret[i++] = QAndroidJniObject::getStaticField<jint>("android/view/KeyEvent", "KEYCODE_BUTTON_B");
ret[i++] = QAndroidJniObject::getStaticField<jint>("android/view/KeyEvent", "KEYCODE_BUTTON_C");
ret[i++] = QAndroidJniObject::getStaticField<jint>("android/view/KeyEvent", "KEYCODE_BUTTON_L1");
ret[i++] = QAndroidJniObject::getStaticField<jint>("android/view/KeyEvent", "KEYCODE_BUTTON_L2");
ret[i++] = QAndroidJniObject::getStaticField<jint>("android/view/KeyEvent", "KEYCODE_BUTTON_R1");
ret[i++] = QAndroidJniObject::getStaticField<jint>("android/view/KeyEvent", "KEYCODE_BUTTON_R2");
ret[i++] = QAndroidJniObject::getStaticField<jint>("android/view/KeyEvent", "KEYCODE_BUTTON_MODE");
ret[i++] = QAndroidJniObject::getStaticField<jint>("android/view/KeyEvent", "KEYCODE_BUTTON_SELECT");
ret[i++] = QAndroidJniObject::getStaticField<jint>("android/view/KeyEvent", "KEYCODE_BUTTON_START");
ret[i++] = QAndroidJniObject::getStaticField<jint>("android/view/KeyEvent", "KEYCODE_BUTTON_THUMBL");
ret[i++] = QAndroidJniObject::getStaticField<jint>("android/view/KeyEvent", "KEYCODE_BUTTON_THUMBR");
ret[i++] = QAndroidJniObject::getStaticField<jint>("android/view/KeyEvent", "KEYCODE_BUTTON_X");
ret[i++] = QAndroidJniObject::getStaticField<jint>("android/view/KeyEvent", "KEYCODE_BUTTON_Y");
ret[i++] = QAndroidJniObject::getStaticField<jint>("android/view/KeyEvent", "KEYCODE_BUTTON_Z");
for (int j=0;j<_androidBtnListCount;j++)
qDebug() << "\tpossible button: "+QString::number(_androidBtnList[j]);
}
#ifndef JOYSTICKANDROID_H
#define JOYSTICKANDROID_H
#include "Joystick.h"
#include "Vehicle.h"
#include "MultiVehicleManager.h"
#include <jni.h>
#include <QtCore/private/qjni_p.h>
#include <QtCore/private/qjnihelpers_p.h>
#include <QtAndroidExtras/QtAndroidExtras>
#include <QtAndroidExtras/QAndroidJniObject>
class JoystickAndroid : public Joystick, public QtAndroidPrivate::GenericMotionEventListener, public QtAndroidPrivate::KeyEventListener
{
public:
JoystickAndroid(const QString& name, int id, MultiVehicleManager* multiVehicleManager);
~JoystickAndroid();
static QMap<QString, Joystick*> discover(MultiVehicleManager* _multiVehicleManager);
private:
bool handleKeyEvent(jobject event);
bool handleGenericMotionEvent(jobject event);
virtual bool open();
virtual void close();
virtual bool update();
virtual bool getButton(int i);
virtual int getAxis(int i);
int *btnCode;
int *axisCode;
bool *btnValue;
int *axisValue;
static void _buttonList();
static int * _androidBtnList; //list of all possible android buttons
static int _androidBtnListCount;
static QMutex m_mutex;
int deviceId;
};
#endif // JOYSTICKANDROID_H
......@@ -27,12 +27,12 @@
#include <QQmlEngine>
#ifndef __mobile__
#include "JoystickSDL.h"
#define __sdljoystick__
#ifdef Q_OS_MAC
#include <SDL.h>
#else
#include <SDL/SDL.h>
#endif
#endif
#ifdef __android__
#include "JoystickAndroid.h"
#endif
QGC_LOGGING_CATEGORY(JoystickManagerLog, "JoystickManagerLog")
......@@ -45,7 +45,15 @@ JoystickManager::JoystickManager(QGCApplication* app)
, _activeJoystick(NULL)
, _multiVehicleManager(NULL)
{
}
JoystickManager::~JoystickManager() {
QMap<QString, Joystick*>::iterator i;
for (i = _name2JoystickMap.begin(); i != _name2JoystickMap.end(); ++i) {
qDebug() << "Releasing joystick:" << i.key();
delete i.value();
}
qDebug() << "Done";
}
void JoystickManager::setToolbox(QGCToolbox *toolbox)
......@@ -57,82 +65,9 @@ void JoystickManager::setToolbox(QGCToolbox *toolbox)
QQmlEngine::setObjectOwnership(this, QQmlEngine::CppOwnership);
#ifdef __sdljoystick__
if (SDL_InitSubSystem(SDL_INIT_JOYSTICK | SDL_INIT_NOPARACHUTE) < 0) {
qWarning() << "Couldn't initialize SimpleDirectMediaLayer:" << SDL_GetError();
return;
}
// Load available joysticks
qCDebug(JoystickManagerLog) << "Available joysticks";
for (int i=0; i<SDL_NumJoysticks(); i++) {
QString name = SDL_JoystickName(i);
if (!_name2JoystickMap.contains(name)) {
int axisCount, buttonCount;
SDL_Joystick* sdlJoystick = SDL_JoystickOpen(i);
axisCount = SDL_JoystickNumAxes(sdlJoystick);
buttonCount = SDL_JoystickNumButtons(sdlJoystick);
SDL_JoystickClose(sdlJoystick);
qCDebug(JoystickManagerLog) << "\t" << name << "axes:" << axisCount << "buttons:" << buttonCount;
_name2JoystickMap[name] = new Joystick(name, axisCount, buttonCount, i, _multiVehicleManager);
} else {
qCDebug(JoystickManagerLog) << "\tSkipping duplicate" << name;
}
}
_name2JoystickMap = JoystickSDL::discover(_multiVehicleManager);
#elif defined(__android__)
QMutexLocker lock(&m_mutex);
computePossibleButtons(); //this is just needed to get number of supported buttons
QAndroidJniEnvironment env;
QAndroidJniObject o = QAndroidJniObject::callStaticObjectMethod<jintArray>("android/view/InputDevice", "getDeviceIds");
jintArray jarr = o.object<jintArray>();
size_t sz = env->GetArrayLength(jarr);
jint *buff = env->GetIntArrayElements(jarr, nullptr);
int SOURCE_GAMEPAD = QAndroidJniObject::getStaticField<jint>("android/view/InputDevice", "SOURCE_GAMEPAD");
int SOURCE_JOYSTICK = QAndroidJniObject::getStaticField<jint>("android/view/InputDevice", "SOURCE_JOYSTICK");
for (size_t i = 0; i < sz; ++i) {
int axisCount, buttonCount;
QAndroidJniObject inputDevice = QAndroidJniObject::callStaticObjectMethod("android/view/InputDevice", "getDevice", "(I)Landroid/view/InputDevice;", buff[i]);
int sources = inputDevice.callMethod<jint>("getSources", "()I");
if (((sources & SOURCE_GAMEPAD) != SOURCE_GAMEPAD) //check if the input device is interesting to us
&& ((sources & SOURCE_JOYSTICK) != SOURCE_JOYSTICK)) continue;
//get id and name
QString id = inputDevice.callObjectMethod("getDescriptor", "()Ljava/lang/String;").toString();
QString name = inputDevice.callObjectMethod("getName", "()Ljava/lang/String;").toString();
//get number of buttons
jintArray a = env->NewIntArray(31);
env->SetIntArrayRegion(a,0,31,_possibleButtons);
//QAndroidJniObject keyMap = inputDevice.callObjectMethod("getKeyCharacterMap", "()Landroid/view/KeyCharacterMap;");
//QAndroidJniObject btns = keyMap.callStaticObjectMethod("android/view/KeyCharacterMap","deviceHasKeys", "([I)[Z", a);
QAndroidJniObject btns = inputDevice.callObjectMethod("hasKeys", "([I)[Z", a);
jbooleanArray jSupportedButtons = btns.object<jbooleanArray>();
size_t btn_sz = env->GetArrayLength(jSupportedButtons);
jboolean* supportedButtons = env->GetBooleanArrayElements(jSupportedButtons, nullptr);
buttonCount=0;
for (size_t j=0;j<btn_sz;j++)
if (supportedButtons[j]) buttonCount++;
env->ReleaseBooleanArrayElements(jSupportedButtons, supportedButtons, 0);
//get number of axis
QAndroidJniObject rangeListNative = inputDevice.callObjectMethod("getMotionRanges", "()Ljava/util/List;");
axisCount = rangeListNative.callMethod<jint>("size");
qCDebug(JoystickManagerLog) << "\t" << name << "axes:" << axisCount << "buttons:" << buttonCount;
_name2JoystickMap[name] = new Joystick(name, axisCount, buttonCount, buff[i], _multiVehicleManager);
}
env->ReleaseIntArrayElements(jarr, buff, 0);
_name2JoystickMap = JoystickAndroid::discover(_multiVehicleManager);
#endif
if (!_name2JoystickMap.count()) {
......@@ -143,38 +78,6 @@ void JoystickManager::setToolbox(QGCToolbox *toolbox)
_setActiveJoystickFromSettings();
}
void JoystickManager::computePossibleButtons() {
static int ret[31];
int i;
for (i=1;i<=16;i++) {
QString name = "KEYCODE_BUTTON_"+QString::number(i);
ret[i-1] = QAndroidJniObject::getStaticField<jint>("android/view/KeyEvent", name.toStdString().c_str());
}
i--;
ret[i++] = QAndroidJniObject::getStaticField<jint>("android/view/KeyEvent", "KEYCODE_BUTTON_A");
ret[i++] = QAndroidJniObject::getStaticField<jint>("android/view/KeyEvent", "KEYCODE_BUTTON_B");
ret[i++] = QAndroidJniObject::getStaticField<jint>("android/view/KeyEvent", "KEYCODE_BUTTON_C");
ret[i++] = QAndroidJniObject::getStaticField<jint>("android/view/KeyEvent", "KEYCODE_BUTTON_L1");
ret[i++] = QAndroidJniObject::getStaticField<jint>("android/view/KeyEvent", "KEYCODE_BUTTON_L2");
ret[i++] = QAndroidJniObject::getStaticField<jint>("android/view/KeyEvent", "KEYCODE_BUTTON_R1");
ret[i++] = QAndroidJniObject::getStaticField<jint>("android/view/KeyEvent", "KEYCODE_BUTTON_R2");
ret[i++] = QAndroidJniObject::getStaticField<jint>("android/view/KeyEvent", "KEYCODE_BUTTON_MODE");
ret[i++] = QAndroidJniObject::getStaticField<jint>("android/view/KeyEvent", "KEYCODE_BUTTON_SELECT");
ret[i++] = QAndroidJniObject::getStaticField<jint>("android/view/KeyEvent", "KEYCODE_BUTTON_START");
ret[i++] = QAndroidJniObject::getStaticField<jint>("android/view/KeyEvent", "KEYCODE_BUTTON_THUMBL");
ret[i++] = QAndroidJniObject::getStaticField<jint>("android/view/KeyEvent", "KEYCODE_BUTTON_THUMBR");
ret[i++] = QAndroidJniObject::getStaticField<jint>("android/view/KeyEvent", "KEYCODE_BUTTON_X");
ret[i++] = QAndroidJniObject::getStaticField<jint>("android/view/KeyEvent", "KEYCODE_BUTTON_Y");
ret[i++] = QAndroidJniObject::getStaticField<jint>("android/view/KeyEvent", "KEYCODE_BUTTON_Z");
for (int j=0;j<i;j++)
qCDebug(JoystickManagerLog) << "\tpossible button: "+ret[j];
_possibleButtons = ret;
}
void JoystickManager::_setActiveJoystickFromSettings(void)
{
QSettings settings;
......
......@@ -31,14 +31,6 @@
#include <QVariantList>
#ifdef __android__
#include <jni.h>
#include <QtCore/private/qjni_p.h>
#include <QtCore/private/qjnihelpers_p.h>
#include <QtAndroidExtras/QtAndroidExtras>
#include <QtAndroidExtras/QAndroidJniObject>
#endif
Q_DECLARE_LOGGING_CATEGORY(JoystickManagerLog)
class QGCApplicaiton;
......@@ -49,6 +41,7 @@ class JoystickManager : public QGCTool
public:
JoystickManager(QGCApplication* app);
~JoystickManager();
/// List of available joysticks
Q_PROPERTY(QVariantList joysticks READ joysticks CONSTANT)
......@@ -86,12 +79,6 @@ private:
static const char * _settingsGroup;
static const char * _settingsKeyActiveJoystick;
#ifdef __android__
void computePossibleButtons();
int * _possibleButtons;
QMutex m_mutex;
#endif
};
#endif
#include "JoystickSDL.h"
#include "QGCApplication.h"
#include <QQmlEngine>
JoystickSDL::JoystickSDL(const QString& name, int axisCount, int buttonCount, int index, MultiVehicleManager* multiVehicleManager)
: Joystick(name,axisCount,buttonCount,multiVehicleManager)
, _index(index)
{
}
QMap<QString, Joystick*> JoystickSDL::discover(MultiVehicleManager* _multiVehicleManager) {
static QMap<QString, Joystick*> ret;
if (SDL_InitSubSystem(SDL_INIT_JOYSTICK | SDL_INIT_NOPARACHUTE) < 0) {
qWarning() << "Couldn't initialize SimpleDirectMediaLayer:" << SDL_GetError();
return ret;
}
// Load available joysticks
qCDebug(JoystickLog) << "Available joysticks";
for (int i=0; i<SDL_NumJoysticks(); i++) {
QString name = SDL_JoystickName(i);
if (!ret.contains(name)) {
int axisCount, buttonCount;
SDL_Joystick* sdlJoystick = SDL_JoystickOpen(i);
axisCount = SDL_JoystickNumAxes(sdlJoystick);
buttonCount = SDL_JoystickNumButtons(sdlJoystick);
SDL_JoystickClose(sdlJoystick);
qCDebug(JoystickLog) << "\t" << name << "axes:" << axisCount << "buttons:" << buttonCount;
ret[name] = new JoystickSDL(name, axisCount, buttonCount, i, _multiVehicleManager);
} else {
qCDebug(JoystickLog) << "\tSkipping duplicate" << name;
}
}
return ret;
}
bool JoystickSDL::open(void) {
sdlJoystick = SDL_JoystickOpen(_index);
if (!sdlJoystick) {
qCWarning(JoystickLog) << "SDL_JoystickOpen failed:" << SDL_GetError();
return false;
}
return true;
}
void JoystickSDL::close(void) {
SDL_JoystickClose(sdlJoystick);
}
bool JoystickSDL::update(void)
{
SDL_JoystickUpdate();
return true;
}
bool JoystickSDL::getButton(int i) {
return !!SDL_JoystickGetButton(sdlJoystick, i);
}
int JoystickSDL::getAxis(int i) {
return SDL_JoystickGetAxis(sdlJoystick, i);
}
#ifndef JOYSTICKSDL_H
#define JOYSTICKSDL_H
#include "Joystick.h"
#include "Vehicle.h"
#include "MultiVehicleManager.h"
#ifdef Q_OS_MAC
#include <SDL.h>
#else
#include <SDL/SDL.h>
#endif
class JoystickSDL : public Joystick
{
public:
JoystickSDL(const QString& name, int axisCount, int buttonCount, int index, MultiVehicleManager* multiVehicleManager);
static QMap<QString, Joystick*> discover(MultiVehicleManager* _multiVehicleManager);
private:
virtual bool open();
virtual void close();
virtual bool update();
virtual bool getButton(int i);
virtual int getAxis(int i);
SDL_Joystick *sdlJoystick;
int _index; ///< Index for SDL_JoystickOpen
};
#endif // JOYSTICKSDL_H
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment