]> git.mxchange.org Git - flightgear.git/blob - src/Joystick/joystick.cxx
Reduce spurious output from joystick.cxx
[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 #else
162         int nbuttons = MAX_BUTTONS;
163 #endif
164         
165         int naxes = js->getNumAxes();
166         joysticks[i].naxes = naxes;
167         joysticks[i].nbuttons = nbuttons;
168
169         FG_LOG(FG_INPUT, FG_INFO, "Initializing joystick " << i);
170         seen_joystick = true;
171
172         // Set up range arrays
173         float *minRange = new float[naxes];
174         float *maxRange = new float[naxes];
175         float *center = new float[naxes];
176
177         // Initialize with default values
178         js->getMinRange(minRange);
179         js->getMaxRange(maxRange);
180         js->getCenter(center);
181
182         // Allocate axes and buttons
183         joysticks[i].axes = new axis[naxes];
184         joysticks[i].buttons = new button[nbuttons];
185
186
187         //
188         // Initialize the axes.
189         //
190         int j;
191         for (j = 0; j < naxes; j++) {
192             axis &a = joysticks[i].axes[j];
193
194             string base = "/input/";
195             base += jsNames[i];
196             base += '/';
197             base += axisNames[j];
198             FG_LOG(FG_INPUT, FG_INFO, "  Axis " << j << ':');
199
200             // Control property
201             string name = base;
202             name += "/control";
203             SGValue * value = fgGetValue(name);
204             if (value == 0) {
205                 FG_LOG(FG_INPUT, FG_INFO, "    no control defined");
206                 continue;
207             }
208             const string &control = value->getStringValue();
209             a.value = fgGetValue(control, true);
210             FG_LOG(FG_INPUT, FG_INFO, "    using control " << control);
211
212             // Dead band
213             name = base;
214             name += "/dead-band";
215             value = fgGetValue(name);
216             if (value != 0)
217                 js->setDeadBand(j, value->getDoubleValue());
218             FG_LOG(FG_INPUT, FG_INFO, "    dead-band is " << js->getDeadBand(j));
219
220             // Offset
221             name = base;
222             name += "/offset";
223             value = fgGetValue(name);
224             if (value != 0)
225                 a.offset = value->getDoubleValue();
226             FG_LOG(FG_INPUT, FG_INFO, "    offset is " << a.offset);
227
228
229             // Factor
230             name = base;
231             name += "/factor";
232             value = fgGetValue(name);
233             if (value != 0)
234                 a.factor = value->getDoubleValue();
235             FG_LOG(FG_INPUT, FG_INFO, "    factor is " << a.factor);
236
237
238             // Tolerance
239             name = base;
240             name += "/tolerance";
241             value = fgGetValue(name);
242             if (value != 0)
243                 a.tolerance = value->getDoubleValue();
244             FG_LOG(FG_INPUT, FG_INFO, "    tolerance is " << a.tolerance);
245
246
247             // Saturation
248             name = base;
249             name += "/saturation";
250             value = fgGetValue(name);
251             if (value != 0)
252                 js->setSaturation(j, value->getDoubleValue());
253             FG_LOG(FG_INPUT, FG_INFO, "    saturation is " << js->getSaturation(j));
254
255             // Minimum range
256             name = base;
257             name += "/min-range";
258             value = fgGetValue(name);
259             if (value != 0)
260                 minRange[j] = value->getDoubleValue();
261             FG_LOG(FG_INPUT, FG_INFO, "    min-range is " << minRange[j]);
262
263             // Maximum range
264             name = base;
265             name += "/max-range";
266             value = fgGetValue(name);
267             if (value != 0)
268                 maxRange[j] = value->getDoubleValue();
269             FG_LOG(FG_INPUT, FG_INFO, "    max-range is " << maxRange[j]);
270
271             // Center
272             name = base;
273             name += "/center";
274             value = fgGetValue(name);
275             if (value != 0)
276                 center[j] = value->getDoubleValue();
277             FG_LOG(FG_INPUT, FG_INFO, "    center is " << center[j]);
278         }
279
280
281         //
282         // Initialize the buttons.
283         //
284         for (j = 0; j < nbuttons; j++) {
285             button &b = joysticks[i].buttons[j];
286       
287             string base = "/input/";
288             base += jsNames[i];
289             base += '/';
290             base += buttonNames[j];
291             FG_LOG(FG_INPUT, FG_INFO, "  Button " << j << ':');
292
293             // Control property
294             string name = base;
295             name += "/control";
296             cout << "Trying name " << name << endl;
297             SGValue * value = fgGetValue(name);
298             if (value == 0) {
299                 FG_LOG(FG_INPUT, FG_INFO, "    no control defined");
300                 continue;
301             }
302             const string &control = value->getStringValue();
303             b.value = fgGetValue(control, true);
304             FG_LOG(FG_INPUT, FG_INFO, "    using control " << control);
305
306             // Step
307             name = base;
308             name += "/step";
309             value = fgGetValue(name);
310             if (value != 0)
311                 b.step = value->getDoubleValue();
312             FG_LOG(FG_INPUT, FG_INFO, "    step is " << b.step);
313
314             // Type
315             name = base;
316             name += "/action";
317             value = fgGetValue(name);
318             string action = "adjust";
319             if (value != 0)
320                 action = value->getStringValue();
321             if (action == "toggle") {
322                 b.action = button::TOGGLE;
323                 b.isRepeatable = false;
324             } else if (action == "switch") {
325                 b.action = button::SWITCH;
326                 b.isRepeatable = false;
327             } else if (action == "adjust") {
328                 b.action = button::ADJUST;
329                 b.isRepeatable = true;
330             } else {
331                 FG_LOG(FG_INPUT, FG_ALERT, "    unknown action " << action);
332                 action = "adjust";
333                 b.action = button::ADJUST;
334                 b.isRepeatable = true;
335             }
336             FG_LOG(FG_INPUT, FG_INFO, "    action is " << action);
337
338             // Repeatability.
339             name = base;
340             name += "/repeatable";
341             value = fgGetValue(name);
342             if (value != 0)
343                 b.isRepeatable = value->getBoolValue();
344             FG_LOG(FG_INPUT, FG_INFO, (b.isRepeatable ?
345                                        "    repeatable" : "    not repeatable"));
346         }
347
348         js->setMinRange(minRange);
349         js->setMaxRange(maxRange);
350         js->setCenter(center);
351
352         //-dw- clean up
353         delete minRange;
354         delete maxRange;
355         delete center;
356     }
357
358     if (seen_joystick)
359         FG_LOG(FG_INPUT, FG_INFO, "Done initializing joysticks");
360     else
361         FG_LOG(FG_INPUT, FG_ALERT, "No joysticks detected");
362
363     return seen_joystick;
364 }
365
366
367 /**
368  * Update property values based on the joystick state(s).
369  */
370 int
371 fgJoystickRead()
372 {
373     int buttons;
374     float *axis_values = new float[MAX_AXES];
375
376     for (int i = 0; i < MAX_JOYSTICKS; i++) {
377         jsJoystick * js = joysticks[i].js;
378         // float *axis_values = new float[joysticks[i].naxes];
379         if (js->notWorking()) {
380             continue;
381         }
382
383         js->read(&buttons, axis_values);
384
385         //
386         // Axes
387         //
388         int j;
389         for (j = 0; j < joysticks[i].naxes; j++) {
390             bool flag = true;
391             axis &a = joysticks[i].axes[j];
392
393             // If the axis hasn't changed, don't
394             // force the value.
395             if (fabs(axis_values[j] - a.last_value) <= a.tolerance)
396                 continue;
397             else
398                 a.last_value = axis_values[j];
399
400             if (a.value)
401                 flag = a.value->setDoubleValue((axis_values[j] + a.offset) *
402                                                a.factor);
403             if (!flag)
404                 FG_LOG(FG_INPUT, FG_ALERT, "Failed to set value for joystick "
405                        << i << ", axis " << j);
406         }
407
408         //
409         // Buttons
410         //
411         for (j = 0; j < joysticks[i].nbuttons; j++) {
412             bool flag = false;
413             button &b = joysticks[i].buttons[j];
414             if (b.value == 0)
415                 continue;
416
417             // Button is on.
418             if ((buttons & (1 << j)) > 0) {
419                 // Repeating?
420                 if (b.lastState == 1 && !b.isRepeatable)
421                     continue;
422
423                 switch (b.action) {
424                 case button::TOGGLE:
425                     if (b.step != 0.0) {
426                         if (b.value->getDoubleValue() == 0.0)
427                             flag = b.value->setDoubleValue(b.step);
428                         else
429                             flag = b.value->setDoubleValue(0.0);
430                     } else {
431                         if (b.value->getBoolValue())
432                             flag = b.value->setBoolValue(false);
433                         else
434                             flag = b.value->setBoolValue(true);
435                     }
436                     break;
437                 case button::SWITCH:
438                     flag = b.value->setDoubleValue(b.step);
439                     break;
440                 case button::ADJUST:
441                     flag = b.value->setDoubleValue(b.value->getDoubleValue() +
442                                                    b.step);
443                     break;
444                 default:
445                     flag = false;
446                     break;
447                 }
448                 b.lastState = 1;
449
450                 // Button is off
451             } else {
452                 // Repeating?
453                 if (b.lastState == 0 && !b.isRepeatable)
454                     continue;
455
456                 switch (b.action) {
457                 case button::ADJUST:
458                 case button::TOGGLE:
459                     // no op
460                     flag = true;
461                     break;
462                 case button::SWITCH:
463                     flag = b.value->setDoubleValue(0.0);
464                     break;
465                 default:
466                     flag = false;
467                     break;
468                 }
469
470                 b.lastState = 0;
471             }
472             if (!flag)
473                 FG_LOG(FG_INPUT, FG_ALERT, "Failed to set value for "
474                        << jsNames[i] << ' ' << buttonNames[j]);
475         }
476     }
477
478     // -dw- cleanup 
479     delete axis_values;
480
481     return true;
482 }
483
484 // end of joystick.cxx