* Reduce RAM usage for advanced joystick system on radio: - Don't allocate memory blocks unless joystick mode is being used. Support multiple radio joystick configurations in Companion: - Save configured joystick settings by joystick name in Companion settings. - Save last joystick name used in each profile. - Reload joystick settings by name when profile is changed. * Only show configuration for used axes and buttons in Companion. Send actual number of configured joystick buttons from radio in USB packet. * Fix issue where USB joystick not recognised if no buttons configured. * Fix compiler warnings. * Remove debugging. * Fix crash in Companion. * Change channel 8 to type 'dial', workaround for Linux mapping issue. --------- Co-authored-by: Phil Mitchell <phil.a.mitchell@gmail.com>
180 lines
4.4 KiB
C++
180 lines
4.4 KiB
C++
/*
|
|
* Copyright (C) OpenTX
|
|
*
|
|
* Based on code named
|
|
* th9x - http://code.google.com/p/th9x
|
|
* er9x - http://code.google.com/p/er9x
|
|
* gruvin9x - http://code.google.com/p/gruvin9x
|
|
*
|
|
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License version 2 as
|
|
* published by the Free Software Foundation.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*/
|
|
|
|
#include "joystick.h"
|
|
|
|
Joystick::Joystick(QObject *parent, int joystickEventTimeout, bool doAutoRepeat, int repeatDelay)
|
|
: QObject(parent)
|
|
{
|
|
if ( SDL_WasInit(SDL_INIT_JOYSTICK) ) {
|
|
int i;
|
|
for (i = 0; i < SDL_NumJoysticks(); i++)
|
|
{
|
|
SDL_Joystick* joy = SDL_JoystickOpen(i);
|
|
if(joy == nullptr)
|
|
continue;
|
|
joystickNames.append(SDL_JoystickName(joy));
|
|
SDL_JoystickClose(joy);
|
|
}
|
|
connect(&joystickTimer, SIGNAL(timeout()), this, SLOT(processEvents()));
|
|
} else {
|
|
fprintf(stderr, "ERROR: couldn't initialize SDL joystick support\n");
|
|
}
|
|
|
|
joystick = NULL;
|
|
numAxes = numButtons = numHats = numTrackballs = 0;
|
|
autoRepeat = doAutoRepeat;
|
|
autoRepeatDelay = repeatDelay;
|
|
eventTimeout = joystickEventTimeout;
|
|
}
|
|
|
|
Joystick::~Joystick()
|
|
{
|
|
if ( isOpen() )
|
|
close();
|
|
}
|
|
|
|
bool Joystick::open(int stick)
|
|
{
|
|
if (isOpen())
|
|
close();
|
|
|
|
joystick = SDL_JoystickOpen(stick);
|
|
if (joystick) {
|
|
numAxes = SDL_JoystickNumAxes(joystick);
|
|
numButtons = SDL_JoystickNumButtons(joystick);
|
|
numHats = SDL_JoystickNumHats(joystick);
|
|
numTrackballs = SDL_JoystickNumBalls(joystick);
|
|
joystickTimer.start(eventTimeout);
|
|
for (int i = 0; i < numButtons; i += 1) {
|
|
buttons[i] = -1;
|
|
}
|
|
return true;
|
|
}
|
|
else {
|
|
fprintf(stderr, "ERROR: couldn't open SDL joystick #%d", stick);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
void Joystick::close()
|
|
{
|
|
joystickTimer.stop();
|
|
if (joystick) {
|
|
SDL_JoystickClose(joystick);
|
|
joystick = NULL;
|
|
}
|
|
numAxes = numButtons = numHats = numTrackballs = 0;
|
|
}
|
|
|
|
void Joystick::processEvents()
|
|
{
|
|
if ( !isOpen() )
|
|
return;
|
|
|
|
SDL_JoystickUpdate();
|
|
|
|
int i;
|
|
for (i = 0; i < numAxes; i++) {
|
|
Sint16 moved = SDL_JoystickGetAxis(joystick, i);
|
|
if ( abs(moved) >= deadzones[i] ) {
|
|
if ( (moved != axes[i]) ) {
|
|
int deltaMoved = abs(axes[i] - moved);
|
|
if ( deltaMoved >= sensitivities[i] )
|
|
emit axisValueChanged(i, moved);
|
|
axes[i] = moved;
|
|
axisRepeatTimers[i].restart();
|
|
}
|
|
else if (autoRepeat && moved != 0) {
|
|
if ( axisRepeatTimers[i].elapsed() >= autoRepeatDelay ) {
|
|
emit axisValueChanged(i, moved);
|
|
axes[i] = moved;
|
|
}
|
|
}
|
|
else {
|
|
axisRepeatTimers[i].restart();
|
|
}
|
|
}
|
|
// else {
|
|
// emit axisValueChanged(i, 0);
|
|
// }
|
|
}
|
|
for (i = 0; i < numButtons; i++) {
|
|
Uint8 changed = SDL_JoystickGetButton(joystick, i);
|
|
if (changed != buttons[i]) {
|
|
emit buttonValueChanged(i, (bool) changed);
|
|
buttons[i] = changed;
|
|
buttonRepeatTimers[i].restart();
|
|
}
|
|
else if (autoRepeat && changed != 0) {
|
|
if (buttonRepeatTimers[i].elapsed() >= autoRepeatDelay) {
|
|
emit buttonValueChanged(i, (bool) changed);
|
|
buttons[i] = changed;
|
|
}
|
|
}
|
|
else {
|
|
buttonRepeatTimers[i].restart();
|
|
}
|
|
}
|
|
for (i = 0; i < numHats; i++) {
|
|
Uint8 changed = SDL_JoystickGetHat(joystick, i);
|
|
if (changed != hats[i]) {
|
|
emit hatValueChanged(i, changed);
|
|
hats[i] = changed;
|
|
hatRepeatTimers[i].restart();
|
|
}
|
|
else if (autoRepeat && changed != 0) {
|
|
if (hatRepeatTimers[i].elapsed() >= autoRepeatDelay) {
|
|
emit hatValueChanged(i, changed);
|
|
hats[i] = changed;
|
|
}
|
|
}
|
|
else {
|
|
hatRepeatTimers[i].restart();
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < numTrackballs; i++) {
|
|
int dx, dy;
|
|
SDL_JoystickGetBall(joystick, i, &dx, &dy);
|
|
if (dx != 0 || dy != 0)
|
|
emit trackballValueChanged(i, dx, dy);
|
|
}
|
|
}
|
|
|
|
int Joystick::getAxisValue(int axis)
|
|
{
|
|
if ( isOpen() ) {
|
|
SDL_JoystickUpdate();
|
|
return SDL_JoystickGetAxis(joystick, axis);
|
|
} else
|
|
return 0;
|
|
}
|
|
|
|
int Joystick::findCurrent(QString jsName)
|
|
{
|
|
for (int i = 0; i < joystickNames.size(); i += 1) {
|
|
if (joystickNames[i] == jsName) {
|
|
return i;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|