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