Skip to content

Commit 271cbbc

Browse files
committed
JoystickSDL: Show non-gamepad axes and only show gamepad axes if they are valid
Before it was assuming numGapepadAxes == numJoystickAxes, which cannot be assumed. numGamepadAxes can be less than, equal to, or greater than numJoystickAxes. Before it was also assuming a joystickAxisId represents the same axis as a gamepadAxisId, which cannot be assumed ex. A gamepad may map buttons to a gamepad axes, so even if numJoystickAxes == 0 there may still be a gamepad axis ex. With the SDL gamepad interface, a controller can only have 2 joysticks. Some devices that support the SDL gamepad interface have more than 2 joysticks (ex. UXV SRoC or Steam Controller). The SDL joystick interface supports more than 2 joysticks. A joystick axis may not map to be a gamepad axis. note: Most controllers do not have the issues fixed with this commit because they are true gamepads and don't have any axes not mapped/represented in the SDL gamepad interface. I tested with a couple popular controllers (x-box 360 controller and a 8bitDo Ultimate C bluetooth controller) and they had no hidden axes. The QGC joystick configuration page for these controllers will have no visible difference before and after this commit
1 parent e6f178c commit 271cbbc

File tree

2 files changed

+59
-5
lines changed

2 files changed

+59
-5
lines changed

src/Joystick/JoystickSDL.cc

Lines changed: 56 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,10 @@
1818

1919
QGC_LOGGING_CATEGORY(JoystickSDLLog, "qgc.joystick.joysticksdl")
2020

21-
JoystickSDL::JoystickSDL(const QString &name, int axisCount, int buttonCount, int hatCount, int instanceId, bool isGamepad, QObject *parent)
22-
: Joystick(name, axisCount, buttonCount, hatCount, parent)
21+
JoystickSDL::JoystickSDL(const QString &name, QList<int> gamepadAxes, QList<int> nonGamepadAxes, int buttonCount, int hatCount, int instanceId, bool isGamepad, QObject *parent)
22+
: Joystick(name, gamepadAxes.length() + nonGamepadAxes.length(), buttonCount, hatCount, parent)
23+
, _gamepadAxes(gamepadAxes)
24+
, _nonGamepadAxes(nonGamepadAxes)
2325
, _isGamepad(isGamepad)
2426
, _instanceId(instanceId)
2527
{
@@ -75,13 +77,57 @@ QMap<QString, Joystick*> JoystickSDL::discover()
7577
continue;
7678
}
7779

80+
QList<int> gamepadAxes;
81+
QSet<int> joyAxesMappedToGamepad;
82+
83+
if (SDL_IsGamepad(jid)) {
84+
auto tmpGamepad = SDL_OpenGamepad(jid);
85+
if (!tmpGamepad) {
86+
qCWarning(JoystickSDLLog) << "Failed to open gamepad" << jid << SDL_GetError();
87+
continue;
88+
}
89+
90+
// Determine if this gamepad axis is one we should show to the user
91+
for (int i = 0; i < SDL_GAMEPAD_AXIS_COUNT; i++) {
92+
if (SDL_GamepadHasAxis(tmpGamepad, static_cast<SDL_GamepadAxis>(i))) {
93+
gamepadAxes.append(i);
94+
}
95+
}
96+
97+
// If a sdlJoystick axis is mapped to a sdlGamepad axis, then the axis is represented
98+
// by both the sdlJoystick interface and the sdlGamepad interface. If this is the case,
99+
// We'll only show the sdlGamepad interface version of the axis to the user.
100+
int count = 0;
101+
SDL_GamepadBinding **bindings = SDL_GetGamepadBindings(tmpGamepad, &count);
102+
if (bindings) {
103+
for (int i = 0; i < count; ++i) {
104+
SDL_GamepadBinding *binding = bindings[i];
105+
if (binding && binding->input_type == SDL_GAMEPAD_BINDTYPE_AXIS && binding->output_type == SDL_GAMEPAD_BINDTYPE_AXIS) {
106+
joyAxesMappedToGamepad.insert(binding->input.axis.axis);
107+
}
108+
}
109+
SDL_free(bindings);
110+
} else {
111+
qCWarning(JoystickSDLLog) << "Failed to get bindings for" << name << "error:" << SDL_GetError();
112+
}
113+
114+
SDL_CloseGamepad(tmpGamepad);
115+
}
116+
78117
SDL_Joystick *tmpJoy = SDL_OpenJoystick(jid);
79118
if (!tmpJoy) {
80119
qCWarning(JoystickSDLLog) << "Failed to open joystick" << jid << SDL_GetError();
81120
continue;
82121
}
83122

123+
QList<int> nonGamepadAxes;
84124
const int axisCount = SDL_GetNumJoystickAxes(tmpJoy);
125+
for (int i = 0; i < axisCount; i++) {
126+
if (!joyAxesMappedToGamepad.contains(i)) {
127+
nonGamepadAxes.append(i);
128+
}
129+
}
130+
85131
const int buttonCount = SDL_GetNumJoystickButtons(tmpJoy);
86132
const int hatCount = SDL_GetNumJoystickHats(tmpJoy);
87133
SDL_CloseJoystick(tmpJoy);
@@ -95,7 +141,8 @@ QMap<QString, Joystick*> JoystickSDL::discover()
95141
}
96142

97143
current[name] = new JoystickSDL(name,
98-
qMax(0, axisCount),
144+
gamepadAxes,
145+
nonGamepadAxes,
99146
qMax(0, buttonCount),
100147
qMax(0, hatCount),
101148
jid,
@@ -183,7 +230,12 @@ int JoystickSDL::_getAxis(int idx) const
183230
int axis = -1;
184231

185232
if (_isGamepad) {
186-
axis = SDL_GetGamepadAxis(_sdlGamepad, static_cast<SDL_GamepadAxis>(idx));
233+
if (idx < _gamepadAxes.length()) {
234+
axis = SDL_GetGamepadAxis(_sdlGamepad, static_cast<SDL_GamepadAxis>(_gamepadAxes[idx]));
235+
}
236+
else {
237+
axis = SDL_GetJoystickAxis(_sdlJoystick, _nonGamepadAxes[idx - _gamepadAxes.length()]);
238+
}
187239
} else {
188240
axis = SDL_GetJoystickAxis(_sdlJoystick, idx);
189241
}

src/Joystick/JoystickSDL.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ Q_DECLARE_LOGGING_CATEGORY(JoystickSDLLog)
2424
class JoystickSDL : public Joystick
2525
{
2626
public:
27-
explicit JoystickSDL(const QString &name, int axisCount, int buttonCount, int hatCount, int instanceId, bool isGamepad, QObject *parent = nullptr);
27+
explicit JoystickSDL(const QString &name, QList<int> gamepadAxes, QList<int> nonGamepadAxes, int buttonCount, int hatCount, int instanceId, bool isGamepad, QObject *parent = nullptr);
2828
~JoystickSDL() override;
2929

3030
int instanceId() const { return _instanceId; }
@@ -46,6 +46,8 @@ class JoystickSDL : public Joystick
4646

4747
static void _loadGamepadMappings();
4848

49+
QList<int> _gamepadAxes;
50+
QList<int> _nonGamepadAxes;
4951
bool _isGamepad = false;
5052
int _instanceId = -1;
5153

0 commit comments

Comments
 (0)