1 #if defined(QMC2_ARCADE_ENABLE_JOYSTICK)
2
3 #include <QRegExp>
4
5 #include "joystick.h"
6 #include "arcadesettings.h"
7 #include "tweakedqmlappviewer.h"
8 #include "macros.h"
9
10 extern ArcadeSettings *globalConfig;
11
Joystick(QObject * parent,int joystickEventTimeout,bool doAutoRepeat,int repeatDelay)12 Joystick::Joystick(QObject *parent, int joystickEventTimeout, bool doAutoRepeat, int repeatDelay)
13 : QObject(parent)
14 {
15 if ( SDL_Init(SDL_INIT_JOYSTICK) == 0 ) {
16 QRegExp rx("(\\b.*\\b)\\1");
17 for (int i = 0; i < SDL_NumJoysticks(); i++) {
18 #if SDL_MAJOR_VERSION == 1
19 QString jsName(SDL_JoystickName(i));
20 #elif SDL_MAJOR_VERSION == 2
21 SDL_Joystick *js = SDL_JoystickOpen(i);
22 QString jsName(SDL_JoystickName(js));
23 SDL_JoystickClose(js);
24 #endif
25 jsName.replace(rx, "\\1"); // remove consecutive duplicate words in the joystick name (i. e. "Logitech Logitech Extreme 3D" becomes "Logitech Extreme 3D")
26 joystickNames.append(jsName);
27 }
28 connect(&joystickTimer, SIGNAL(timeout()), this, SLOT(processEvents()));
29 } else
30 QMC2_ARCADE_LOG_STR(tr("ERROR: couldn't initialize SDL joystick support"));
31 joystick = 0;
32 jsIndex = -1;
33 numAxes = numButtons = numHats = numTrackballs = 0;
34 autoRepeat = doAutoRepeat;
35 autoRepeatDelay = repeatDelay;
36 eventTimeout = joystickEventTimeout;
37 }
38
~Joystick()39 Joystick::~Joystick()
40 {
41 if ( isOpen() )
42 close();
43 SDL_Quit();
44 }
45
open(int stick)46 bool Joystick::open(int stick)
47 {
48 if ( isOpen() )
49 close();
50 joystick = SDL_JoystickOpen(stick);
51 if ( joystick ) {
52 numAxes = SDL_JoystickNumAxes(joystick);
53 numButtons = SDL_JoystickNumButtons(joystick);
54 numHats = SDL_JoystickNumHats(joystick);
55 numTrackballs = SDL_JoystickNumBalls(joystick);
56 QMC2_ARCADE_LOG_STR(tr("SDL joystick #%1 opened: name = %2, axes = %3, buttons = %4, hats = %5, trackballs = %6").arg(stick).arg(joystickNames[stick]).arg(numAxes).arg(numButtons).arg(numHats).arg(numTrackballs));
57 joystickTimer.start(eventTimeout);
58 jsIndex = stick;
59 deadzones.clear();
60 sensitivities.clear();
61 for (int axis = 0; axis < numAxes; axis++) {
62 deadzones[axis] = globalConfig->joystickDeadzone(jsIndex, axis);
63 sensitivities[axis] = globalConfig->joystickSensitivity(jsIndex, axis);
64 }
65 return true;
66 } else {
67 jsIndex = -1;
68 return false;
69 }
70 }
71
close()72 void Joystick::close()
73 {
74 joystickTimer.stop();
75 if ( joystick ) {
76 SDL_JoystickClose(joystick);
77 QMC2_ARCADE_LOG_STR(tr("SDL joystick #%1 closed").arg(jsIndex));
78 }
79 joystick = 0;
80 jsIndex = -1;
81 numAxes = numButtons = numHats = numTrackballs = 0;
82 }
83
processEvents()84 void Joystick::processEvents()
85 {
86 if ( !isOpen() )
87 return;
88 SDL_JoystickUpdate();
89 for (int i = 0; i < numAxes; i++) {
90 Sint16 moved = normalizeAxisValue(SDL_JoystickGetAxis(joystick, i), i);
91 if ( abs(moved) >= deadzones[i] ) {
92 if ( (moved != axes[i]) ) {
93 int deltaMoved = abs(axes[i] - moved);
94 if ( deltaMoved >= sensitivities[i] )
95 emit axisValueChanged(i, moved);
96 axes[i] = moved;
97 axisRepeatTimers[i].restart();
98 } else if (autoRepeat && moved != 0) {
99 if ( axisRepeatTimers[i].elapsed() >= autoRepeatDelay ) {
100 emit axisValueChanged(i, moved);
101 axes[i] = moved;
102 }
103 } else
104 axisRepeatTimers[i].restart();
105 } else
106 emit axisValueChanged(i, 0);
107 }
108 for (int i = 0; i < numButtons; i++) {
109 Uint8 changed = SDL_JoystickGetButton(joystick, i);
110 if ( (changed != buttons[i]) ) {
111 emit buttonValueChanged(i, (bool) changed);
112 buttons[i] = changed;
113 buttonRepeatTimers[i].restart();
114 } else if (autoRepeat && changed != 0) {
115 if ( buttonRepeatTimers[i].elapsed() >= autoRepeatDelay ) {
116 emit buttonValueChanged(i, (bool) changed);
117 buttons[i] = changed;
118 }
119 } else
120 buttonRepeatTimers[i].restart();
121 }
122 for (int i = 0; i < numHats; i++) {
123 Uint8 changed = SDL_JoystickGetHat(joystick, i);
124 if ( (changed != hats[i]) ) {
125 emit hatValueChanged(i, changed);
126 hats[i] = changed;
127 hatRepeatTimers[i].restart();
128 } else if (autoRepeat && changed != 0) {
129 if ( hatRepeatTimers[i].elapsed() >= autoRepeatDelay ) {
130 emit hatValueChanged(i, changed);
131 hats[i] = changed;
132 }
133 } else
134 hatRepeatTimers[i].restart();
135 }
136 for (int i = 0; i < numTrackballs; i++) {
137 int dx, dy;
138 SDL_JoystickGetBall(joystick, i, &dx, &dy);
139 if ( dx != 0 || dy != 0 )
140 emit trackballValueChanged(i, dx, dy);
141 }
142 }
143
getAxisValue(int axis)144 int Joystick::getAxisValue(int axis)
145 {
146 if ( isOpen() ) {
147 SDL_JoystickUpdate();
148 return normalizeAxisValue(SDL_JoystickGetAxis(joystick, axis), axis);
149 } else
150 return 0;
151 }
152
normalizeAxisValue(Sint16 rawValue,int axis)153 Sint16 Joystick::normalizeAxisValue(Sint16 rawValue, int axis)
154 {
155 int max = globalConfig->joystickAxisMaximum(jsIndex, axis);
156 int min = globalConfig->joystickAxisMinimum(jsIndex, axis);
157 if ( max > min ) {
158 rawValue -= (max + min) / 2;
159 return 65535.0 * (double)rawValue / (double)(max - min);
160 } else
161 return 0;
162 }
163
164 #endif
165