]> git.mxchange.org Git - flightgear.git/blob - src/Joystick/joystick.cxx
Added some sanity checking on max number of bottons and axes.
[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 #include <simgear/compiler.h>
25
26 #ifdef HAVE_CONFIG_H
27 #  include <config.h>
28 #endif
29
30 #ifdef HAVE_WINDOWS_H
31 #  include <windows.h>                     
32 #endif
33
34 #include <math.h>
35
36 #include <string>
37
38 #include <Main/fg_props.hxx>
39
40 #include <simgear/debug/logstream.hxx>
41 #include <plib/js.h>
42
43 #include "joystick.hxx"
44
45 FG_USING_STD(string);
46 FG_USING_STD(cout);
47
48 #ifdef WIN32
49 static const int MAX_JOYSTICKS = 2;
50 #else
51 static const int MAX_JOYSTICKS = 10;
52 #endif
53 static const int MAX_AXES = _JS_MAX_AXES;
54 static const int MAX_BUTTONS = 32;
55
56
57 /**
58  * Property names for joysticks and axes.
59  */
60 static const char * jsNames[] = {
61     "js0", "js1", "js2", "js3", "js4",
62     "js5", "js6", "js7", "js8", "js9"
63 };
64 static const char * axisNames[] = {
65     "axis0", "axis1", "axis2", "axis3", "axis4",
66     "axis5", "axis6", "axis7", "axis8", "axis9"
67 };
68 static const char * buttonNames[] = {
69     "button0", "button1", "button2", "button3", "button4",
70     "button5", "button6", "button7", "button8", "button9",
71     "button10", "button11", "button12", "button13", "button14",
72     "button15", "button16", "button17", "button18", "button19",
73     "button20", "button21", "button22", "button23", "button24",
74     "button25", "button26", "button27", "button28", "button29",
75     "button30", "button31"
76 };
77
78
79 /**
80  * Settings for a single axis.
81  */
82 struct axis {
83     axis () : value(0), offset(0.0), factor(1.0),
84         last_value(9999999), tolerance(0.002) {}
85     SGValue * value;
86     float offset;
87     float factor;
88     float last_value;
89     float tolerance;
90 };
91
92
93 /**
94  * Settings for a single button.
95  */
96 struct button {
97     enum Action {
98         TOGGLE,
99         SWITCH,
100         ADJUST
101     };
102     button () : value(0), step(0.0), action(ADJUST), isRepeatable(true),
103         lastState(-1) {}
104     SGValue * value;
105     float step;
106     Action action;
107     bool isRepeatable;
108     int lastState;
109 };
110
111
112 /**
113  * Settings for a single joystick.
114  */
115 struct joystick {
116     virtual ~joystick () {
117         delete js;
118 #ifndef macintosh
119         delete axes;
120         delete buttons;
121 #else
122         delete[] axes;
123         delete[] buttons;
124 #endif
125     }
126     int naxes;
127     int nbuttons;
128     jsJoystick * js;
129     axis * axes;
130     button * buttons;
131 };
132
133
134 /**
135  * Array of joystick settings.
136  */
137 static joystick joysticks[MAX_JOYSTICKS];
138
139
140 /**
141  * Initialize any joysticks found.
142  */
143 int
144 fgJoystickInit() 
145 {
146     bool seen_joystick = false;
147
148     FG_LOG(FG_INPUT, FG_INFO, "Initializing joysticks");
149
150     for (int i = 0; i < MAX_JOYSTICKS; i++) {
151         jsJoystick * js = new jsJoystick(i);
152         joysticks[i].js = js;
153         if (js->notWorking()) {
154             FG_LOG(FG_INPUT, FG_INFO, "Joystick " << i << " not found");
155             continue;
156         }
157 #ifdef WIN32
158         JOYCAPS jsCaps ;
159         joyGetDevCaps( i, &jsCaps, sizeof(jsCaps) );
160         int nbuttons = jsCaps.wNumButtons;
161         if (nbuttons > MAX_BUTTONS) nbuttons = MAX_BUTTONS;
162 #else
163         int nbuttons = MAX_BUTTONS;
164 #endif
165         
166         int naxes = js->getNumAxes();
167         if (naxes > MAX_AXES) naxes = MAX_AXES;
168         joysticks[i].naxes = naxes;
169         joysticks[i].nbuttons = nbuttons;
170
171         FG_LOG(FG_INPUT, FG_INFO, "Initializing joystick " << i);
172         seen_joystick = true;
173
174         // Set up range arrays
175         float *minRange = new float[naxes];
176         float *maxRange = new float[naxes];
177         float *center = new float[naxes];
178
179         // Initialize with default values
180         js->getMinRange(minRange);
181         js->getMaxRange(maxRange);
182         js->getCenter(center);
183
184         // Allocate axes and buttons
185         joysticks[i].axes = new axis[naxes];
186         joysticks[i].buttons = new button[nbuttons];
187
188
189         //
190         // Initialize the axes.
191         //
192         int j;
193         for (j = 0; j < naxes; j++) {
194             axis &a = joysticks[i].axes[j];
195
196             string base = "/input/";
197             base += jsNames[i];
198             base += '/';
199             base += axisNames[j];
200             FG_LOG(FG_INPUT, FG_INFO, "  Axis " << j << ':');
201
202             // Control property
203             string name = base;
204             name += "/control";
205             SGValue * value = fgGetValue(name);
206             if (value == 0) {
207                 FG_LOG(FG_INPUT, FG_INFO, "    no control defined");
208                 continue;
209             }
210             const string &control = value->getStringValue();
211             a.value = fgGetValue(control, true);
212             FG_LOG(FG_INPUT, FG_INFO, "    using control " << control);
213
214             // Dead band
215             name = base;
216             name += "/dead-band";
217             value = fgGetValue(name);
218             if (value != 0)
219                 js->setDeadBand(j, value->getDoubleValue());
220             FG_LOG(FG_INPUT, FG_INFO, "    dead-band is " << js->getDeadBand(j));
221
222             // Offset
223             name = base;
224             name += "/offset";
225             value = fgGetValue(name);
226             if (value != 0)
227                 a.offset = value->getDoubleValue();
228             FG_LOG(FG_INPUT, FG_INFO, "    offset is " << a.offset);
229
230
231             // Factor
232             name = base;
233             name += "/factor";
234             value = fgGetValue(name);
235             if (value != 0)
236                 a.factor = value->getDoubleValue();
237             FG_LOG(FG_INPUT, FG_INFO, "    factor is " << a.factor);
238
239
240             // Tolerance
241             name = base;
242             name += "/tolerance";
243             value = fgGetValue(name);
244             if (value != 0)
245                 a.tolerance = value->getDoubleValue();
246             FG_LOG(FG_INPUT, FG_INFO, "    tolerance is " << a.tolerance);
247
248
249             // Saturation
250             name = base;
251             name += "/saturation";
252             value = fgGetValue(name);
253             if (value != 0)
254                 js->setSaturation(j, value->getDoubleValue());
255             FG_LOG(FG_INPUT, FG_INFO, "    saturation is " << js->getSaturation(j));
256
257             // Minimum range
258             name = base;
259             name += "/min-range";
260             value = fgGetValue(name);
261             if (value != 0)
262                 minRange[j] = value->getDoubleValue();
263             FG_LOG(FG_INPUT, FG_INFO, "    min-range is " << minRange[j]);
264
265             // Maximum range
266             name = base;
267             name += "/max-range";
268             value = fgGetValue(name);
269             if (value != 0)
270                 maxRange[j] = value->getDoubleValue();
271             FG_LOG(FG_INPUT, FG_INFO, "    max-range is " << maxRange[j]);
272
273             // Center
274             name = base;
275             name += "/center";
276             value = fgGetValue(name);
277             if (value != 0)
278                 center[j] = value->getDoubleValue();
279             FG_LOG(FG_INPUT, FG_INFO, "    center is " << center[j]);
280         }
281
282
283         //
284         // Initialize the buttons.
285         //
286         for (j = 0; j < nbuttons; j++) {
287             button &b = joysticks[i].buttons[j];
288       
289             string base = "/input/";
290             base += jsNames[i];
291             base += '/';
292             base += buttonNames[j];
293             FG_LOG(FG_INPUT, FG_INFO, "  Button " << j << ':');
294
295             // Control property
296             string name = base;
297             name += "/control";
298             cout << "Trying name " << name << endl;
299             SGValue * value = fgGetValue(name);
300             if (value == 0) {
301                 FG_LOG(FG_INPUT, FG_INFO, "    no control defined");
302                 continue;
303             }
304             const string &control = value->getStringValue();
305             b.value = fgGetValue(control, true);
306             FG_LOG(FG_INPUT, FG_INFO, "    using control " << control);
307
308             // Step
309             name = base;
310             name += "/step";
311             value = fgGetValue(name);
312             if (value != 0)
313                 b.step = value->getDoubleValue();
314             FG_LOG(FG_INPUT, FG_INFO, "    step is " << b.step);
315
316             // Type
317             name = base;
318             name += "/action";
319             value = fgGetValue(name);
320             string action = "adjust";
321             if (value != 0)
322                 action = value->getStringValue();
323             if (action == "toggle") {
324                 b.action = button::TOGGLE;
325                 b.isRepeatable = false;
326             } else if (action == "switch") {
327                 b.action = button::SWITCH;
328                 b.isRepeatable = false;
329             } else if (action == "adjust") {
330                 b.action = button::ADJUST;
331                 b.isRepeatable = true;
332             } else {
333                 FG_LOG(FG_INPUT, FG_ALERT, "    unknown action " << action);
334                 action = "adjust";
335                 b.action = button::ADJUST;
336                 b.isRepeatable = true;
337             }
338             FG_LOG(FG_INPUT, FG_INFO, "    action is " << action);
339
340             // Repeatability.
341             name = base;
342             name += "/repeatable";
343             value = fgGetValue(name);
344             if (value != 0)
345                 b.isRepeatable = value->getBoolValue();
346             FG_LOG(FG_INPUT, FG_INFO, (b.isRepeatable ?
347                                        "    repeatable" : "    not repeatable"));
348         }
349
350         js->setMinRange(minRange);
351         js->setMaxRange(maxRange);
352         js->setCenter(center);
353
354         //-dw- clean up
355         delete minRange;
356         delete maxRange;
357         delete center;
358     }
359
360     if (seen_joystick)
361         FG_LOG(FG_INPUT, FG_INFO, "Done initializing joysticks");
362     else
363         FG_LOG(FG_INPUT, FG_ALERT, "No joysticks detected");
364
365     return seen_joystick;
366 }
367
368
369 /**
370  * Update property values based on the joystick state(s).
371  */
372 int
373 fgJoystickRead()
374 {
375     int buttons;
376     float *axis_values = new float[MAX_AXES];
377
378     for (int i = 0; i < MAX_JOYSTICKS; i++) {
379         jsJoystick * js = joysticks[i].js;
380         // float *axis_values = new float[joysticks[i].naxes];
381         if (js->notWorking()) {
382             continue;
383         }
384
385         js->read(&buttons, axis_values);
386
387         //
388         // Axes
389         //
390         int j;
391         for (j = 0; j < joysticks[i].naxes; j++) {
392             bool flag = true;
393             axis &a = joysticks[i].axes[j];
394
395             // If the axis hasn't changed, don't
396             // force the value.
397             if (fabs(axis_values[j] - a.last_value) <= a.tolerance)
398                 continue;
399             else
400                 a.last_value = axis_values[j];
401
402             if (a.value)
403                 flag = a.value->setDoubleValue((axis_values[j] + a.offset) *
404                                                a.factor);
405             if (!flag)
406                 FG_LOG(FG_INPUT, FG_ALERT, "Failed to set value for joystick "
407                        << i << ", axis " << j);
408         }
409
410         //
411         // Buttons
412         //
413         for (j = 0; j < joysticks[i].nbuttons; j++) {
414             bool flag = false;
415             button &b = joysticks[i].buttons[j];
416             if (b.value == 0)
417                 continue;
418
419             // Button is on.
420             if ((buttons & (1 << j)) > 0) {
421                 // Repeating?
422                 if (b.lastState == 1 && !b.isRepeatable)
423                     continue;
424
425                 switch (b.action) {
426                 case button::TOGGLE:
427                     if (b.step != 0.0) {
428                         if (b.value->getDoubleValue() == 0.0)
429                             flag = b.value->setDoubleValue(b.step);
430                         else
431                             flag = b.value->setDoubleValue(0.0);
432                     } else {
433                         if (b.value->getBoolValue())
434                             flag = b.value->setBoolValue(false);
435                         else
436                             flag = b.value->setBoolValue(true);
437                     }
438                     break;
439                 case button::SWITCH:
440                     flag = b.value->setDoubleValue(b.step);
441                     break;
442                 case button::ADJUST:
443                     flag = b.value->setDoubleValue(b.value->getDoubleValue() +
444                                                    b.step);
445                     break;
446                 default:
447                     flag = false;
448                     break;
449                 }
450                 b.lastState = 1;
451
452                 // Button is off
453             } else {
454                 // Repeating?
455                 if (b.lastState == 0 && !b.isRepeatable)
456                     continue;
457
458                 switch (b.action) {
459                 case button::ADJUST:
460                 case button::TOGGLE:
461                     // no op
462                     flag = true;
463                     break;
464                 case button::SWITCH:
465                     flag = b.value->setDoubleValue(0.0);
466                     break;
467                 default:
468                     flag = false;
469                     break;
470                 }
471
472                 b.lastState = 0;
473             }
474             if (!flag)
475                 FG_LOG(FG_INPUT, FG_ALERT, "Failed to set value for "
476                        << jsNames[i] << ' ' << buttonNames[j]);
477         }
478     }
479
480     // -dw- cleanup 
481     delete axis_values;
482
483     return true;
484 }
485
486 // end of joystick.cxx