]> git.mxchange.org Git - flightgear.git/blob - src/Joystick/joystick.cxx
Fixes to vor/ils/adf range pickup.
[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  * trim capture
81  */
82 struct trimcapture {
83     float tolerance;
84     bool captured;
85     string name;
86     SGValue* value;
87 };   
88
89
90 /**
91  * Settings for a single axis.
92  */
93 struct axis {
94     axis () :
95         value(0),
96         offset(0.0),
97         factor(1.0),
98         last_value(9999999),
99         tolerance(0.002),
100         capture(NULL)
101     { }
102     SGValue * value;
103     float offset;
104     float factor;
105     float last_value;
106     float tolerance;
107     trimcapture* capture;
108 };
109
110
111 /**
112  * Settings for a single button.
113  */
114 struct button {
115     enum Action {
116         TOGGLE,
117         SWITCH,
118         ADJUST
119     };
120     button () : value(0), step(0.0), action(ADJUST), isRepeatable(true),
121         lastState(-1) {}
122     SGValue * value;
123     float step;
124     Action action;
125     bool isRepeatable;
126     int lastState;
127 };
128
129
130 /**
131  * Settings for a single joystick.
132  */
133 struct joystick {
134     virtual ~joystick () {
135         delete js;
136 #ifndef macintosh
137         delete axes;
138         delete buttons;
139 #else
140         delete[] axes;
141         delete[] buttons;
142 #endif
143     }
144     int naxes;
145     int nbuttons;
146     jsJoystick * js;
147     axis * axes;
148     button * buttons;
149 };
150
151
152 /**
153  * Array of joystick settings.
154  */
155 static joystick joysticks[MAX_JOYSTICKS];
156
157 SGValue *trimmed;
158
159
160 /**
161  * Initialize any joysticks found.
162  */
163 int
164 fgJoystickInit() 
165 {
166     bool seen_joystick = false;
167
168     FG_LOG(FG_INPUT, FG_INFO, "Initializing joysticks");
169
170     for (int i = 0; i < MAX_JOYSTICKS; i++) {
171         jsJoystick * js = new jsJoystick(i);
172         joysticks[i].js = js;
173         if (js->notWorking()) {
174             FG_LOG(FG_INPUT, FG_INFO, "Joystick " << i << " not found");
175             continue;
176         }
177 #ifdef WIN32
178         JOYCAPS jsCaps ;
179         joyGetDevCaps( i, &jsCaps, sizeof(jsCaps) );
180         int nbuttons = jsCaps.wNumButtons;
181         if (nbuttons > MAX_BUTTONS) nbuttons = MAX_BUTTONS;
182 #else
183         int nbuttons = MAX_BUTTONS;
184 #endif
185         
186         int naxes = js->getNumAxes();
187         if (naxes > MAX_AXES) naxes = MAX_AXES;
188         joysticks[i].naxes = naxes;
189         joysticks[i].nbuttons = nbuttons;
190
191         FG_LOG(FG_INPUT, FG_INFO, "Initializing joystick " << i);
192         seen_joystick = true;
193
194         // Set up range arrays
195         float *minRange = new float[naxes];
196         float *maxRange = new float[naxes];
197         float *center = new float[naxes];
198
199         // Initialize with default values
200         js->getMinRange(minRange);
201         js->getMaxRange(maxRange);
202         js->getCenter(center);
203
204         // Allocate axes and buttons
205         joysticks[i].axes = new axis[naxes];
206         joysticks[i].buttons = new button[nbuttons];
207
208
209         //
210         // Initialize the axes.
211         //
212         int j;
213         for (j = 0; j < naxes; j++) {
214             axis &a = joysticks[i].axes[j];
215
216             string base = "/input/";
217             base += jsNames[i];
218             base += '/';
219             base += axisNames[j];
220             FG_LOG(FG_INPUT, FG_INFO, "  Axis " << j << ':');
221
222             // Control property
223             string name = base;
224             name += "/control";
225             SGValue * value = fgGetValue(name);
226             if (value == 0) {
227                 FG_LOG(FG_INPUT, FG_INFO, "    no control defined");
228                 continue;
229             }
230             const string &control = value->getStringValue();
231             a.value = fgGetValue(control, true);
232             FG_LOG(FG_INPUT, FG_INFO, "    using control " << control);
233
234             // Dead band
235             name = base;
236             name += "/dead-band";
237             value = fgGetValue(name);
238             if (value != 0)
239                 js->setDeadBand(j, value->getDoubleValue());
240             FG_LOG(FG_INPUT, FG_INFO, "    dead-band is " << js->getDeadBand(j));
241
242             // Offset
243             name = base;
244             name += "/offset";
245             value = fgGetValue(name);
246             if (value != 0)
247                 a.offset = value->getDoubleValue();
248             FG_LOG(FG_INPUT, FG_INFO, "    offset is " << a.offset);
249
250
251             // Factor
252             name = base;
253             name += "/factor";
254             value = fgGetValue(name);
255             if (value != 0)
256                 a.factor = value->getDoubleValue();
257             FG_LOG(FG_INPUT, FG_INFO, "    factor is " << a.factor);
258
259
260             // Tolerance
261             name = base;
262             name += "/tolerance";
263             value = fgGetValue(name);
264             if (value != 0)
265                 a.tolerance = value->getDoubleValue();
266             FG_LOG(FG_INPUT, FG_INFO, "    tolerance is " << a.tolerance);
267
268
269             // Saturation
270             name = base;
271             name += "/saturation";
272             value = fgGetValue(name);
273             if (value != 0)
274                 js->setSaturation(j, value->getDoubleValue());
275             FG_LOG(FG_INPUT, FG_INFO, "    saturation is " << js->getSaturation(j));
276
277             // Minimum range
278             name = base;
279             name += "/min-range";
280             value = fgGetValue(name);
281             if (value != 0)
282                 minRange[j] = value->getDoubleValue();
283             FG_LOG(FG_INPUT, FG_INFO, "    min-range is " << minRange[j]);
284
285             // Maximum range
286             name = base;
287             name += "/max-range";
288             value = fgGetValue(name);
289             if (value != 0)
290                 maxRange[j] = value->getDoubleValue();
291             FG_LOG(FG_INPUT, FG_INFO, "    max-range is " << maxRange[j]);
292
293             // Center
294             name = base;
295             name += "/center";
296             value = fgGetValue(name);
297             if (value != 0)
298                 center[j] = value->getDoubleValue();
299             FG_LOG(FG_INPUT, FG_INFO, "    center is " << center[j]);
300       
301             // Capture
302             name = base;
303             name += "/capture";
304             value = fgGetValue(name);
305             if ( value != 0 ) {
306                 string trimname = "/fdm/trim"
307                     + control.substr(control.rfind("/"),control.length());
308                 if ( fgHasValue(trimname) ) {   
309                     a.capture = new trimcapture;
310                     a.capture->tolerance = value->getDoubleValue();
311                     a.capture->captured = false;
312                     a.capture->name = control;
313                     a.capture->value = fgGetValue(trimname);
314                     FG_LOG(FG_INPUT, FG_INFO, "    capture is " 
315                            << value->getDoubleValue() );
316                 } else {
317                     a.capture = NULL;
318                     FG_LOG(FG_INPUT, FG_INFO, "    capture is "         
319                            << "unsupported by FDM" );
320                 }                               
321            }                            
322         }
323
324
325         //
326         // Initialize the buttons.
327         //
328         for (j = 0; j < nbuttons; j++) {
329             button &b = joysticks[i].buttons[j];
330       
331             string base = "/input/";
332             base += jsNames[i];
333             base += '/';
334             base += buttonNames[j];
335             FG_LOG(FG_INPUT, FG_INFO, "  Button " << j << ':');
336
337             // Control property
338             string name = base;
339             name += "/control";
340             cout << "Trying name " << name << endl;
341             SGValue * value = fgGetValue(name);
342             if (value == 0) {
343                 FG_LOG(FG_INPUT, FG_INFO, "    no control defined");
344                 continue;
345             }
346             const string &control = value->getStringValue();
347             b.value = fgGetValue(control, true);
348             FG_LOG(FG_INPUT, FG_INFO, "    using control " << control);
349
350             // Step
351             name = base;
352             name += "/step";
353             value = fgGetValue(name);
354             if (value != 0)
355                 b.step = value->getDoubleValue();
356             FG_LOG(FG_INPUT, FG_INFO, "    step is " << b.step);
357
358             // Type
359             name = base;
360             name += "/action";
361             value = fgGetValue(name);
362             string action = "adjust";
363             if (value != 0)
364                 action = value->getStringValue();
365             if (action == "toggle") {
366                 b.action = button::TOGGLE;
367                 b.isRepeatable = false;
368             } else if (action == "switch") {
369                 b.action = button::SWITCH;
370                 b.isRepeatable = false;
371             } else if (action == "adjust") {
372                 b.action = button::ADJUST;
373                 b.isRepeatable = true;
374             } else {
375                 FG_LOG(FG_INPUT, FG_ALERT, "    unknown action " << action);
376                 action = "adjust";
377                 b.action = button::ADJUST;
378                 b.isRepeatable = true;
379             }
380             FG_LOG(FG_INPUT, FG_INFO, "    action is " << action);
381
382             // Repeatability.
383             name = base;
384             name += "/repeatable";
385             value = fgGetValue(name);
386             if (value != 0)
387                 b.isRepeatable = value->getBoolValue();
388             FG_LOG(FG_INPUT, FG_INFO, (b.isRepeatable ?
389                                        "    repeatable" : "    not repeatable"));
390         }
391
392         js->setMinRange(minRange);
393         js->setMaxRange(maxRange);
394         js->setCenter(center);
395
396         //-dw- clean up
397         delete minRange;
398         delete maxRange;
399         delete center;
400     }
401
402     trimmed = fgGetValue("/fdm/trim/trimmed");
403     
404     if (seen_joystick)
405         FG_LOG(FG_INPUT, FG_INFO, "Done initializing joysticks");
406     else
407         FG_LOG(FG_INPUT, FG_ALERT, "No joysticks detected");
408
409     return seen_joystick;
410 }
411
412
413 /**
414  * Update property values based on the joystick state(s).
415  */
416 int
417 fgJoystickRead()
418 {
419     int buttons;
420     float js_val, diff;
421     float *axis_values = new float[MAX_AXES];
422
423     for (int i = 0; i < MAX_JOYSTICKS; i++) {
424         jsJoystick * js = joysticks[i].js;
425         // float *axis_values = new float[joysticks[i].naxes];
426         if (js->notWorking()) {
427             continue;
428         }
429
430         js->read(&buttons, axis_values);
431
432         //
433         // Axes
434         //
435         int j;
436         for (j = 0; j < joysticks[i].naxes; j++) {
437             bool flag = true;
438             axis &a = joysticks[i].axes[j];
439
440             if ( a.capture && trimmed->getBoolValue() ) {
441                 // if the model has been trimmed then capture the
442                 // joystick. When a trim succeeds, the above
443                 // is true for one frame only.
444                 a.capture->captured = false;
445                 FG_LOG( FG_GENERAL, FG_INFO, "Successful trim, capture is " <<
446                         "enabled on " << a.capture->name );
447             } 
448
449             // If the axis hasn't changed, don't
450             // force the value.
451             if (fabs(axis_values[j] - a.last_value) <= a.tolerance)
452                 continue;
453             else
454                 a.last_value = axis_values[j];
455             
456             if ( a.value ) {
457                 js_val = ( axis_values[j] + a.offset ) * a.factor; 
458                 
459                 if ( a.capture && !a.capture->captured ) {
460                     diff = js_val - a.capture->value->getDoubleValue();
461                     FG_LOG( FG_GENERAL, FG_INFO, a.capture->name
462                             << " capture: " << diff );
463                     if ( fabs( diff ) < a.capture->tolerance ) {
464                         flag = a.value->setDoubleValue( js_val );
465                         a.capture->captured = true;
466                         FG_LOG(FG_GENERAL,FG_INFO, a.capture->name 
467                                << " captured." );
468                     }
469                 } else {
470                     flag = a.value->setDoubleValue( js_val );
471                 }
472             }
473                 
474             if (!flag)
475                 FG_LOG(FG_INPUT, FG_ALERT, "Failed to set value for joystick "
476                        << i << ", axis " << j);
477         }
478
479         //
480         // Buttons
481         //
482         for (j = 0; j < joysticks[i].nbuttons; j++) {
483             bool flag = false;
484             button &b = joysticks[i].buttons[j];
485             if (b.value == 0)
486                 continue;
487
488             // Button is on.
489             if ((buttons & (1 << j)) > 0) {
490                 // Repeating?
491                 if (b.lastState == 1 && !b.isRepeatable)
492                     continue;
493
494                 switch (b.action) {
495                 case button::TOGGLE:
496                     if (b.step != 0.0) {
497                         if (b.value->getDoubleValue() == 0.0)
498                             flag = b.value->setDoubleValue(b.step);
499                         else
500                             flag = b.value->setDoubleValue(0.0);
501                     } else {
502                         if (b.value->getBoolValue())
503                             flag = b.value->setBoolValue(false);
504                         else
505                             flag = b.value->setBoolValue(true);
506                     }
507                     break;
508                 case button::SWITCH:
509                     flag = b.value->setDoubleValue(b.step);
510                     break;
511                 case button::ADJUST:
512                     flag = b.value->setDoubleValue(b.value->getDoubleValue() +
513                                                    b.step);
514                     break;
515                 default:
516                     flag = false;
517                     break;
518                 }
519                 b.lastState = 1;
520
521                 // Button is off
522             } else {
523                 // Repeating?
524                 if (b.lastState == 0 && !b.isRepeatable)
525                     continue;
526
527                 switch (b.action) {
528                 case button::ADJUST:
529                 case button::TOGGLE:
530                     // no op
531                     flag = true;
532                     break;
533                 case button::SWITCH:
534                     flag = b.value->setDoubleValue(0.0);
535                     break;
536                 default:
537                     flag = false;
538                     break;
539                 }
540
541                 b.lastState = 0;
542             }
543             if (!flag)
544                 FG_LOG(FG_INPUT, FG_ALERT, "Failed to set value for "
545                        << jsNames[i] << ' ' << buttonNames[j]);
546         }
547     }
548
549     // -dw- cleanup 
550     delete axis_values;
551
552     return true;
553 }
554
555 // end of joystick.cxx