]> git.mxchange.org Git - flightgear.git/blob - src/Joystick/joystick.cxx
Updates to JSBsim from Jon's CVS.
[flightgear.git] / src / Joystick / joystick.cxx
1 // joystick.cxx -- joystick support
2 //
3 // Original module written by Curtis Olson, started October 1998.
4 // Completely rewritten by David Megginson, July 2000.
5 //
6 // Copyright (C) 1998 - 2000  Curtis L. Olson - curt@flightgear.org
7 //
8 // This program is free software; you can redistribute it and/or
9 // modify it under the terms of the GNU General Public License as
10 // published by the Free Software Foundation; either version 2 of the
11 // License, or (at your option) any later version.
12 //
13 // This program is distributed in the hope that it will be useful, but
14 // WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16 // General Public License for more details.
17 //
18 // You should have received a copy of the GNU General Public License
19 // along with this program; if not, write to the Free Software
20 // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 //
22 // $Id$
23
24
25 #ifdef HAVE_CONFIG_H
26 #  include <config.h>
27 #endif
28
29 #ifdef HAVE_WINDOWS_H
30 #  include <windows.h>                     
31 #endif
32
33 #include <string>
34
35 #include <simgear/misc/props.hxx>
36 #include <simgear/debug/logstream.hxx>
37 #include <plib/js.h>
38 #include "joystick.hxx"
39
40 using std::string;
41
42 static const int MAX_JOYSTICKS = 10;
43 static const int MAX_AXES = 10;
44
45
46 /**
47  * Property names for joysticks and axes.
48  */
49 static const char * jsNames[] = {
50   "js0", "js1", "js2", "js3", "js4",
51   "js5", "js6", "js7", "js8", "js9"
52 };
53 static const char * axisNames[] = {
54   "axis0", "axis1", "axis2", "axis3", "axis4",
55   "axis5", "axis6", "axis7", "axis8", "axis9"
56 };
57
58
59 /**
60  * Settings for a single axis.
61  */
62 struct axis {
63   axis () : value(0), offset(0.0), factor(1.0),
64             last_value(9999999), tolerance(0.002) {}
65   FGValue * value;
66   float offset;
67   float factor;
68   float last_value;
69   float tolerance;
70 };
71
72
73 /**
74  * Settings for a single joystick.
75  */
76 struct joystick {
77   virtual ~joystick () { delete js; delete axes; }
78   jsJoystick * js;
79   axis * axes;
80 };
81
82
83 /**
84  * Array of joystick settings.
85  */
86 static joystick joysticks[MAX_JOYSTICKS];
87
88
89 /**
90  * Set up default values if properties are not specified.
91  */
92 static void
93 setupDefaults ()
94 {
95   FGPropertyList &props = current_properties;
96
97                                 // Default axis 0 to aileron
98   if (!props.getValue("/input/js0/axis0/control")) {
99     props.setStringValue("/input/js0/axis0/control", "/controls/aileron");
100     props.setFloatValue("/input/js0/axis0/dead-band", 0.1);
101   }
102
103                                 // Default axis 1 to elevator
104   if (!props.getValue("/input/js0/axis1/control")) {
105     props.setStringValue("/input/js0/axis1/control", "/controls/elevator");
106     props.setFloatValue("/input/js0/axis1/dead-band", 0.1);
107     props.setFloatValue("/input/js0/axis1/factor", -1.0);
108   }
109
110                                 // Default axis 2 to throttle
111                                 // We need to fiddle with the offset
112                                 // and factor to make it work
113   if (!props.getValue("/input/js0/axis2/control")) {
114     props.setStringValue("/input/js0/axis2/control", "/controls/throttle");
115     props.setFloatValue("/input/js0/axis2/dead-band", 0.0);
116     props.setFloatValue("/input/js0/axis2/offset", -1.0);
117     props.setFloatValue("/input/js0/axis2/factor", -0.5);
118   }
119
120                                 // Default axis 3 to rudder
121   if (!props.getValue("/input/js0/axis3/control")) {
122     props.setStringValue("/input/js0/axis3/control", "/controls/rudder");
123     props.setFloatValue("/input/js0/axis3/dead-band", 0.3);
124   }
125 }
126
127
128 /**
129  * Initialize any joysticks found.
130  */
131 int
132 fgJoystickInit() 
133 {
134   bool seen_joystick = false;
135
136   FG_LOG(FG_INPUT, FG_INFO, "Initializing joysticks");
137
138   setupDefaults();
139
140   for (int i = 0; i < MAX_JOYSTICKS; i++) {
141     jsJoystick * js = new jsJoystick(i);
142     joysticks[i].js = js;
143     if (js->notWorking()) {
144       FG_LOG(FG_INPUT, FG_INFO, "Joystick " << i << " not found");
145       continue;
146     }
147
148     FG_LOG(FG_INPUT, FG_INFO, "Initializing joystick " << i);
149     seen_joystick = true;
150
151                                 // Set up range arrays
152     float minRange[js->getNumAxes()];
153     float maxRange[js->getNumAxes()];
154     float center[js->getNumAxes()];
155
156                                 // Initialize with default values
157     js->getMinRange(minRange);
158     js->getMaxRange(maxRange);
159     js->getCenter(center);
160
161                                 // Allocate axes
162     joysticks[i].axes = new axis[js->getNumAxes()];
163
164     for (int j = 0; j < min(js->getNumAxes(), MAX_AXES); j++) {
165       string base = "/input/";
166       base += jsNames[i];
167       base += '/';
168       base += axisNames[j];
169       FG_LOG(FG_INPUT, FG_INFO, "  Axis " << j << ':');
170
171                                 // Control property
172       string name = base;
173       name += "/control";
174       FGValue * value = current_properties.getValue(name);
175       if (value == 0) {
176         FG_LOG(FG_INPUT, FG_INFO, "    no control defined");
177         continue;
178       }
179       const string &control = value->getStringValue();
180       joysticks[i].axes[j].value = current_properties.getValue(control, true);
181       FG_LOG(FG_INPUT, FG_INFO, "    using control " << control);
182
183                                 // Dead band
184       name = base;
185       name += "/dead-band";
186       value = current_properties.getValue(name);
187       if (value != 0)
188         js->setDeadBand(j, value->getFloatValue());
189       FG_LOG(FG_INPUT, FG_INFO, "    dead-band is " << js->getDeadBand(j));
190
191                                 // Offset
192       name = base;
193       name += "/offset";
194       value = current_properties.getValue(name);
195       if (value != 0)
196         joysticks[i].axes[j].offset = value->getFloatValue();
197       FG_LOG(FG_INPUT, FG_INFO, "    offset is "
198              << joysticks[i].axes[j].offset);
199
200
201                                 // Factor
202       name = base;
203       name += "/factor";
204       value = current_properties.getValue(name);
205       if (value != 0)
206         joysticks[i].axes[j].factor = value->getFloatValue();
207       FG_LOG(FG_INPUT, FG_INFO, "    factor is "
208              << joysticks[i].axes[j].factor);
209
210
211                                 // Tolerance
212       name = base;
213       name += "/tolerance";
214       value = current_properties.getValue(name);
215       if (value != 0)
216         joysticks[i].axes[j].tolerance = value->getFloatValue();
217       FG_LOG(FG_INPUT, FG_INFO, "    tolerance is "
218              << joysticks[i].axes[j].tolerance);
219
220
221                                 // Saturation
222       name = base;
223       name += "/saturation";
224       value = current_properties.getValue(name);
225       if (value != 0)
226         js->setSaturation(j, value->getFloatValue());
227       FG_LOG(FG_INPUT, FG_INFO, "    saturation is " << js->getSaturation(j));
228
229                                 // Minimum range
230       name = base;
231       name += "/min-range";
232       value = current_properties.getValue(name);
233       if (value != 0)
234         minRange[j] = value->getFloatValue();
235       FG_LOG(FG_INPUT, FG_INFO, "    min-range is " << minRange[j]);
236
237                                 // Maximum range
238       name = base;
239       name += "/max-range";
240       value = current_properties.getValue(name);
241       if (value != 0)
242         maxRange[j] = value->getFloatValue();
243       FG_LOG(FG_INPUT, FG_INFO, "    max-range is " << maxRange[j]);
244
245                                 // Center
246       name = base;
247       name += "/center";
248       value = current_properties.getValue(name);
249       if (value != 0)
250         center[j] = value->getFloatValue();
251       FG_LOG(FG_INPUT, FG_INFO, "    center is " << center[j]);
252     }
253
254     js->setMinRange(minRange);
255     js->setMaxRange(maxRange);
256     js->setCenter(center);
257   }
258
259   if (seen_joystick)
260     FG_LOG(FG_INPUT, FG_INFO, "Done initializing joysticks");
261   else
262     FG_LOG(FG_INPUT, FG_ALERT, "No joysticks detected");
263
264   return seen_joystick;
265 }
266
267
268 /**
269  * Update property values based on the joystick state(s).
270  */
271 int
272 fgJoystickRead()
273 {
274   int buttons;
275
276   for (int i = 0; i < MAX_JOYSTICKS; i++) {
277     jsJoystick * js = joysticks[i].js;
278     float axis_values[js->getNumAxes()];
279     if (js->notWorking()) {
280       continue;
281     }
282
283     js->read(&buttons, axis_values);
284
285     for (int j = 0; j < min(MAX_AXES, js->getNumAxes()); j++) {
286
287                                 // If the axis hasn't changed, don't
288                                 // force the value.
289       if (fabs(axis_values[j] - joysticks[i].axes[j].last_value) <=
290           joysticks[i].axes[j].tolerance)
291         continue;
292       else
293         joysticks[i].axes[j].last_value = axis_values[j];
294
295       FGValue * value = joysticks[i].axes[j].value;
296       if (value) {
297         if (!value->setDoubleValue((axis_values[j] +
298                                     joysticks[i].axes[j].offset) *
299                                    joysticks[i].axes[j].factor))
300           FG_LOG(FG_INPUT, FG_ALERT, "Failed to set value for joystick "
301                  << i << ", axis " << j);
302       }
303     }
304   }
305
306   return true;                  // FIXME
307 }
308
309 // end of joystick.cxx
310