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