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"
49 static const int MAX_JOYSTICKS = 2;
51 static const int MAX_JOYSTICKS = 10;
53 static const int MAX_AXES = _JS_MAX_AXES;
54 static const int MAX_BUTTONS = 32;
58 * Property names for joysticks and axes.
60 static const char * jsNames[] = {
61 "js0", "js1", "js2", "js3", "js4",
62 "js5", "js6", "js7", "js8", "js9"
64 static const char * axisNames[] = {
65 "axis0", "axis1", "axis2", "axis3", "axis4",
66 "axis5", "axis6", "axis7", "axis8", "axis9"
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"
91 * Settings for a single axis.
107 trimcapture* capture;
112 * Settings for a single button.
120 button () : value(0), step(0.0), action(ADJUST), isRepeatable(true),
131 * Settings for a single joystick.
134 virtual ~joystick () {
153 * Array of joystick settings.
155 static joystick joysticks[MAX_JOYSTICKS];
161 * Initialize any joysticks found.
166 bool seen_joystick = false;
168 FG_LOG(FG_INPUT, FG_INFO, "Initializing joysticks");
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");
179 joyGetDevCaps( i, &jsCaps, sizeof(jsCaps) );
180 int nbuttons = jsCaps.wNumButtons;
181 if (nbuttons > MAX_BUTTONS) nbuttons = MAX_BUTTONS;
183 int nbuttons = MAX_BUTTONS;
186 int naxes = js->getNumAxes();
187 if (naxes > MAX_AXES) naxes = MAX_AXES;
188 joysticks[i].naxes = naxes;
189 joysticks[i].nbuttons = nbuttons;
191 FG_LOG(FG_INPUT, FG_INFO, "Initializing joystick " << i);
192 seen_joystick = true;
194 // Set up range arrays
195 float *minRange = new float[naxes];
196 float *maxRange = new float[naxes];
197 float *center = new float[naxes];
199 // Initialize with default values
200 js->getMinRange(minRange);
201 js->getMaxRange(maxRange);
202 js->getCenter(center);
204 // Allocate axes and buttons
205 joysticks[i].axes = new axis[naxes];
206 joysticks[i].buttons = new button[nbuttons];
210 // Initialize the axes.
213 for (j = 0; j < naxes; j++) {
214 axis &a = joysticks[i].axes[j];
216 string base = "/input/";
219 base += axisNames[j];
220 FG_LOG(FG_INPUT, FG_INFO, " Axis " << j << ':');
225 SGValue * value = fgGetValue(name);
227 FG_LOG(FG_INPUT, FG_INFO, " no control defined");
230 const string &control = value->getStringValue();
231 a.value = fgGetValue(control, true);
232 FG_LOG(FG_INPUT, FG_INFO, " using control " << control);
236 name += "/dead-band";
237 value = fgGetValue(name);
239 js->setDeadBand(j, value->getDoubleValue());
240 FG_LOG(FG_INPUT, FG_INFO, " dead-band is " << js->getDeadBand(j));
245 value = fgGetValue(name);
247 a.offset = value->getDoubleValue();
248 FG_LOG(FG_INPUT, FG_INFO, " offset is " << a.offset);
254 value = fgGetValue(name);
256 a.factor = value->getDoubleValue();
257 FG_LOG(FG_INPUT, FG_INFO, " factor is " << a.factor);
262 name += "/tolerance";
263 value = fgGetValue(name);
265 a.tolerance = value->getDoubleValue();
266 FG_LOG(FG_INPUT, FG_INFO, " tolerance is " << a.tolerance);
271 name += "/saturation";
272 value = fgGetValue(name);
274 js->setSaturation(j, value->getDoubleValue());
275 FG_LOG(FG_INPUT, FG_INFO, " saturation is " << js->getSaturation(j));
279 name += "/min-range";
280 value = fgGetValue(name);
282 minRange[j] = value->getDoubleValue();
283 FG_LOG(FG_INPUT, FG_INFO, " min-range is " << minRange[j]);
287 name += "/max-range";
288 value = fgGetValue(name);
290 maxRange[j] = value->getDoubleValue();
291 FG_LOG(FG_INPUT, FG_INFO, " max-range is " << maxRange[j]);
296 value = fgGetValue(name);
298 center[j] = value->getDoubleValue();
299 FG_LOG(FG_INPUT, FG_INFO, " center is " << center[j]);
304 value = fgGetValue(name);
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() );
318 FG_LOG(FG_INPUT, FG_INFO, " capture is "
319 << "unsupported by FDM" );
326 // Initialize the buttons.
328 for (j = 0; j < nbuttons; j++) {
329 button &b = joysticks[i].buttons[j];
331 string base = "/input/";
334 base += buttonNames[j];
335 FG_LOG(FG_INPUT, FG_INFO, " Button " << j << ':');
340 cout << "Trying name " << name << endl;
341 SGValue * value = fgGetValue(name);
343 FG_LOG(FG_INPUT, FG_INFO, " no control defined");
346 const string &control = value->getStringValue();
347 b.value = fgGetValue(control, true);
348 FG_LOG(FG_INPUT, FG_INFO, " using control " << control);
353 value = fgGetValue(name);
355 b.step = value->getDoubleValue();
356 FG_LOG(FG_INPUT, FG_INFO, " step is " << b.step);
361 value = fgGetValue(name);
362 string action = "adjust";
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;
375 FG_LOG(FG_INPUT, FG_ALERT, " unknown action " << action);
377 b.action = button::ADJUST;
378 b.isRepeatable = true;
380 FG_LOG(FG_INPUT, FG_INFO, " action is " << action);
384 name += "/repeatable";
385 value = fgGetValue(name);
387 b.isRepeatable = value->getBoolValue();
388 FG_LOG(FG_INPUT, FG_INFO, (b.isRepeatable ?
389 " repeatable" : " not repeatable"));
392 js->setMinRange(minRange);
393 js->setMaxRange(maxRange);
394 js->setCenter(center);
402 trimmed = fgGetValue("/fdm/trim/trimmed");
405 FG_LOG(FG_INPUT, FG_INFO, "Done initializing joysticks");
407 FG_LOG(FG_INPUT, FG_ALERT, "No joysticks detected");
409 return seen_joystick;
414 * Update property values based on the joystick state(s).
421 float *axis_values = new float[MAX_AXES];
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()) {
430 js->read(&buttons, axis_values);
436 for (j = 0; j < joysticks[i].naxes; j++) {
438 axis &a = joysticks[i].axes[j];
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 );
449 // If the axis hasn't changed, don't
451 if (fabs(axis_values[j] - a.last_value) <= a.tolerance)
454 a.last_value = axis_values[j];
457 js_val = ( axis_values[j] + a.offset ) * a.factor;
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
470 flag = a.value->setDoubleValue( js_val );
475 FG_LOG(FG_INPUT, FG_ALERT, "Failed to set value for joystick "
476 << i << ", axis " << j);
482 for (j = 0; j < joysticks[i].nbuttons; j++) {
484 button &b = joysticks[i].buttons[j];
489 if ((buttons & (1 << j)) > 0) {
491 if (b.lastState == 1 && !b.isRepeatable)
497 if (b.value->getDoubleValue() == 0.0)
498 flag = b.value->setDoubleValue(b.step);
500 flag = b.value->setDoubleValue(0.0);
502 if (b.value->getBoolValue())
503 flag = b.value->setBoolValue(false);
505 flag = b.value->setBoolValue(true);
509 flag = b.value->setDoubleValue(b.step);
512 flag = b.value->setDoubleValue(b.value->getDoubleValue() +
524 if (b.lastState == 0 && !b.isRepeatable)
534 flag = b.value->setDoubleValue(0.0);
544 FG_LOG(FG_INPUT, FG_ALERT, "Failed to set value for "
545 << jsNames[i] << ' ' << buttonNames[j]);
555 // end of joystick.cxx