1 // joystick.cxx -- joystick support
3 // Original module written by Curtis Olson, started October 1998.
4 // Completely rewritten by David Megginson, July 2000.
6 // Copyright (C) 1998 - 2000 Curtis L. Olson - curt@flightgear.org
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.
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.
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.
24 #include <simgear/compiler.h>
38 #include <Main/fg_props.hxx>
40 #include <simgear/debug/logstream.hxx>
43 #include "joystick.hxx"
46 #if !defined(SG_HAVE_NATIVE_SGI_COMPILERS)
51 static const int MAX_JOYSTICKS = 2;
53 static const int MAX_JOYSTICKS = 10;
55 static const int MAX_AXES = _JS_MAX_AXES;
56 static const int MAX_BUTTONS = 32;
60 * Property names for joysticks and axes.
62 static const char * jsNames[] = {
63 "js0", "js1", "js2", "js3", "js4",
64 "js5", "js6", "js7", "js8", "js9"
66 static const char * axisNames[] = {
67 "axis0", "axis1", "axis2", "axis3", "axis4",
68 "axis5", "axis6", "axis7", "axis8", "axis9"
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"
93 * Settings for a single axis.
109 trimcapture* capture;
114 * Settings for a single button.
122 button () : value(0), step(0.0), action(ADJUST), isRepeatable(true),
133 * Settings for a single joystick.
136 virtual ~joystick () {
155 * Array of joystick settings.
157 static joystick joysticks[MAX_JOYSTICKS];
163 * Initialize any joysticks found.
168 bool seen_joystick = false;
170 SG_LOG(SG_INPUT, SG_INFO, "Initializing joysticks");
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");
181 joyGetDevCaps( i, &jsCaps, sizeof(jsCaps) );
182 int nbuttons = jsCaps.wNumButtons;
183 if (nbuttons > MAX_BUTTONS) nbuttons = MAX_BUTTONS;
185 int nbuttons = MAX_BUTTONS;
188 int naxes = js->getNumAxes();
189 if (naxes > MAX_AXES) naxes = MAX_AXES;
190 joysticks[i].naxes = naxes;
191 joysticks[i].nbuttons = nbuttons;
193 SG_LOG(SG_INPUT, SG_INFO, "Initializing joystick " << i);
194 seen_joystick = true;
196 // Set up range arrays
197 float *minRange = new float[naxes];
198 float *maxRange = new float[naxes];
199 float *center = new float[naxes];
201 // Initialize with default values
202 js->getMinRange(minRange);
203 js->getMaxRange(maxRange);
204 js->getCenter(center);
206 // Allocate axes and buttons
207 joysticks[i].axes = new axis[naxes];
208 joysticks[i].buttons = new button[nbuttons];
212 // Initialize the axes.
215 for (j = 0; j < naxes; j++) {
216 axis &a = joysticks[i].axes[j];
218 string base = "/input/";
221 base += axisNames[j];
222 SG_LOG(SG_INPUT, SG_INFO, " Axis " << j << ':');
227 SGValue * value = fgGetValue(name);
229 SG_LOG(SG_INPUT, SG_INFO, " no control defined");
232 const string &control = value->getStringValue();
233 a.value = fgGetValue(control, true);
234 SG_LOG(SG_INPUT, SG_INFO, " using control " << control);
238 name += "/dead-band";
239 value = fgGetValue(name);
241 js->setDeadBand(j, value->getDoubleValue());
242 SG_LOG(SG_INPUT, SG_INFO, " dead-band is " << js->getDeadBand(j));
247 value = fgGetValue(name);
249 a.offset = value->getDoubleValue();
250 SG_LOG(SG_INPUT, SG_INFO, " offset is " << a.offset);
256 value = fgGetValue(name);
258 a.factor = value->getDoubleValue();
259 SG_LOG(SG_INPUT, SG_INFO, " factor is " << a.factor);
264 name += "/tolerance";
265 value = fgGetValue(name);
267 a.tolerance = value->getDoubleValue();
268 SG_LOG(SG_INPUT, SG_INFO, " tolerance is " << a.tolerance);
273 name += "/saturation";
274 value = fgGetValue(name);
276 js->setSaturation(j, value->getDoubleValue());
277 SG_LOG(SG_INPUT, SG_INFO, " saturation is " << js->getSaturation(j));
281 name += "/min-range";
282 value = fgGetValue(name);
284 minRange[j] = value->getDoubleValue();
285 SG_LOG(SG_INPUT, SG_INFO, " min-range is " << minRange[j]);
289 name += "/max-range";
290 value = fgGetValue(name);
292 maxRange[j] = value->getDoubleValue();
293 SG_LOG(SG_INPUT, SG_INFO, " max-range is " << maxRange[j]);
298 value = fgGetValue(name);
300 center[j] = value->getDoubleValue();
301 SG_LOG(SG_INPUT, SG_INFO, " center is " << center[j]);
306 value = fgGetValue(name);
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() );
320 SG_LOG(SG_INPUT, SG_INFO, " capture is "
321 << "unsupported by FDM" );
328 // Initialize the buttons.
330 for (j = 0; j < nbuttons; j++) {
331 button &b = joysticks[i].buttons[j];
333 string base = "/input/";
336 base += buttonNames[j];
337 SG_LOG(SG_INPUT, SG_INFO, " Button " << j << ':');
342 cout << "Trying name " << name << endl;
343 SGValue * value = fgGetValue(name);
345 SG_LOG(SG_INPUT, SG_INFO, " no control defined");
348 const string &control = value->getStringValue();
349 b.value = fgGetValue(control, true);
350 SG_LOG(SG_INPUT, SG_INFO, " using control " << control);
355 value = fgGetValue(name);
357 b.step = value->getDoubleValue();
358 SG_LOG(SG_INPUT, SG_INFO, " step is " << b.step);
363 value = fgGetValue(name);
364 string action = "adjust";
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;
377 SG_LOG(SG_INPUT, SG_ALERT, " unknown action " << action);
379 b.action = button::ADJUST;
380 b.isRepeatable = true;
382 SG_LOG(SG_INPUT, SG_INFO, " action is " << action);
386 name += "/repeatable";
387 value = fgGetValue(name);
389 b.isRepeatable = value->getBoolValue();
390 SG_LOG(SG_INPUT, SG_INFO, (b.isRepeatable ?
391 " repeatable" : " not repeatable"));
394 js->setMinRange(minRange);
395 js->setMaxRange(maxRange);
396 js->setCenter(center);
404 trimmed = fgGetValue("/fdm/trim/trimmed");
407 SG_LOG(SG_INPUT, SG_INFO, "Done initializing joysticks");
409 SG_LOG(SG_INPUT, SG_ALERT, "No joysticks detected");
411 return seen_joystick;
416 * Update property values based on the joystick state(s).
423 float *axis_values = new float[MAX_AXES];
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()) {
432 js->read(&buttons, axis_values);
438 for (j = 0; j < joysticks[i].naxes; j++) {
440 axis &a = joysticks[i].axes[j];
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 );
451 // If the axis hasn't changed, don't
453 if (fabs(axis_values[j] - a.last_value) <= a.tolerance)
456 a.last_value = axis_values[j];
459 js_val = ( axis_values[j] + a.offset ) * a.factor;
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
472 flag = a.value->setDoubleValue( js_val );
477 SG_LOG(SG_INPUT, SG_ALERT, "Failed to set value for joystick "
478 << i << ", axis " << j);
484 for (j = 0; j < joysticks[i].nbuttons; j++) {
486 button &b = joysticks[i].buttons[j];
491 if ((buttons & (1 << j)) > 0) {
493 if (b.lastState == 1 && !b.isRepeatable)
499 if (b.value->getDoubleValue() == 0.0)
500 flag = b.value->setDoubleValue(b.step);
502 flag = b.value->setDoubleValue(0.0);
504 if (b.value->getBoolValue())
505 flag = b.value->setBoolValue(false);
507 flag = b.value->setBoolValue(true);
511 flag = b.value->setDoubleValue(b.step);
514 flag = b.value->setDoubleValue(b.value->getDoubleValue() +
526 if (b.lastState == 0 && !b.isRepeatable)
536 flag = b.value->setDoubleValue(0.0);
546 SG_LOG(SG_INPUT, SG_ALERT, "Failed to set value for "
547 << jsNames[i] << ' ' << buttonNames[j]);
557 // end of joystick.cxx