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