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 <simgear/misc/props.hxx>
39 #include <simgear/debug/logstream.hxx>
41 #include "joystick.hxx"
47 static const int MAX_JOYSTICKS = 2;
49 static const int MAX_JOYSTICKS = 10;
51 static const int MAX_AXES = _JS_MAX_AXES;
52 static const int MAX_BUTTONS = 32;
56 * Property names for joysticks and axes.
58 static const char * jsNames[] = {
59 "js0", "js1", "js2", "js3", "js4",
60 "js5", "js6", "js7", "js8", "js9"
62 static const char * axisNames[] = {
63 "axis0", "axis1", "axis2", "axis3", "axis4",
64 "axis5", "axis6", "axis7", "axis8", "axis9"
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"
78 * Settings for a single axis.
81 axis () : value(0), offset(0.0), factor(1.0),
82 last_value(9999999), tolerance(0.002) {}
92 * Settings for a single button.
100 button () : value(0), step(0.0), action(ADJUST), isRepeatable(true),
111 * Settings for a single joystick.
114 virtual ~joystick () {
128 * Array of joystick settings.
130 static joystick joysticks[MAX_JOYSTICKS];
134 * Initialize any joysticks found.
139 bool seen_joystick = false;
141 FG_LOG(FG_INPUT, FG_INFO, "Initializing joysticks");
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");
152 joyGetDevCaps( i, &jsCaps, sizeof(jsCaps) );
153 int nbuttons = jsCaps.wNumButtons;
155 int nbuttons = MAX_BUTTONS;
158 int naxes = js->getNumAxes();
159 joysticks[i].naxes = naxes;
160 joysticks[i].nbuttons = nbuttons;
162 FG_LOG(FG_INPUT, FG_INFO, "Initializing joystick " << i);
163 seen_joystick = true;
165 // Set up range arrays
166 float *minRange = new float[naxes];
167 float *maxRange = new float[naxes];
168 float *center = new float[naxes];
170 // Initialize with default values
171 js->getMinRange(minRange);
172 js->getMaxRange(maxRange);
173 js->getCenter(center);
175 // Allocate axes and buttons
176 joysticks[i].axes = new axis[naxes];
177 joysticks[i].buttons = new button[nbuttons];
181 // Initialize the axes.
184 for (j = 0; j < naxes; j++) {
185 axis &a = joysticks[i].axes[j];
187 string base = "/input/";
190 base += axisNames[j];
191 FG_LOG(FG_INPUT, FG_INFO, " Axis " << j << ':');
196 SGValue * value = current_properties.getValue(name);
198 FG_LOG(FG_INPUT, FG_INFO, " no control defined");
201 const string &control = value->getStringValue();
202 a.value = current_properties.getValue(control, true);
203 FG_LOG(FG_INPUT, FG_INFO, " using control " << control);
207 name += "/dead-band";
208 value = current_properties.getValue(name);
210 js->setDeadBand(j, value->getDoubleValue());
211 FG_LOG(FG_INPUT, FG_INFO, " dead-band is " << js->getDeadBand(j));
216 value = current_properties.getValue(name);
218 a.offset = value->getDoubleValue();
219 FG_LOG(FG_INPUT, FG_INFO, " offset is " << a.offset);
225 value = current_properties.getValue(name);
227 a.factor = value->getDoubleValue();
228 FG_LOG(FG_INPUT, FG_INFO, " factor is " << a.factor);
233 name += "/tolerance";
234 value = current_properties.getValue(name);
236 a.tolerance = value->getDoubleValue();
237 FG_LOG(FG_INPUT, FG_INFO, " tolerance is " << a.tolerance);
242 name += "/saturation";
243 value = current_properties.getValue(name);
245 js->setSaturation(j, value->getDoubleValue());
246 FG_LOG(FG_INPUT, FG_INFO, " saturation is " << js->getSaturation(j));
250 name += "/min-range";
251 value = current_properties.getValue(name);
253 minRange[j] = value->getDoubleValue();
254 FG_LOG(FG_INPUT, FG_INFO, " min-range is " << minRange[j]);
258 name += "/max-range";
259 value = current_properties.getValue(name);
261 maxRange[j] = value->getDoubleValue();
262 FG_LOG(FG_INPUT, FG_INFO, " max-range is " << maxRange[j]);
267 value = current_properties.getValue(name);
269 center[j] = value->getDoubleValue();
270 FG_LOG(FG_INPUT, FG_INFO, " center is " << center[j]);
275 // Initialize the buttons.
277 for (j = 0; j < nbuttons; j++) {
278 button &b = joysticks[i].buttons[j];
280 string base = "/input/";
283 base += buttonNames[j];
284 FG_LOG(FG_INPUT, FG_INFO, " Button " << j << ':');
289 cout << "Trying name " << name << endl;
290 SGValue * value = current_properties.getValue(name);
292 FG_LOG(FG_INPUT, FG_INFO, " no control defined");
295 const string &control = value->getStringValue();
296 b.value = current_properties.getValue(control, true);
297 FG_LOG(FG_INPUT, FG_INFO, " using control " << control);
302 value = current_properties.getValue(name);
304 b.step = value->getDoubleValue();
305 FG_LOG(FG_INPUT, FG_INFO, " step is " << b.step);
310 value = current_properties.getValue(name);
311 string action = "adjust";
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;
324 FG_LOG(FG_INPUT, FG_ALERT, " unknown action " << action);
326 b.action = button::ADJUST;
327 b.isRepeatable = true;
329 FG_LOG(FG_INPUT, FG_INFO, " action is " << action);
333 name += "/repeatable";
334 value = current_properties.getValue(name);
336 b.isRepeatable = value->getBoolValue();
337 FG_LOG(FG_INPUT, FG_INFO, (b.isRepeatable ?
338 " repeatable" : " not repeatable"));
341 js->setMinRange(minRange);
342 js->setMaxRange(maxRange);
343 js->setCenter(center);
352 FG_LOG(FG_INPUT, FG_INFO, "Done initializing joysticks");
354 FG_LOG(FG_INPUT, FG_ALERT, "No joysticks detected");
356 return seen_joystick;
361 * Update property values based on the joystick state(s).
367 float *axis_values = new float[MAX_AXES];
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()) {
376 js->read(&buttons, axis_values);
382 for (j = 0; j < joysticks[i].naxes; j++) {
384 axis &a = joysticks[i].axes[j];
386 // If the axis hasn't changed, don't
388 if (fabs(axis_values[j] - a.last_value) <= a.tolerance)
391 a.last_value = axis_values[j];
394 flag = a.value->setDoubleValue((axis_values[j] + a.offset) *
397 FG_LOG(FG_INPUT, FG_ALERT, "Failed to set value for joystick "
398 << i << ", axis " << j);
404 for (j = 0; j < joysticks[i].nbuttons; j++) {
406 button &b = joysticks[i].buttons[j];
411 if ((buttons & (1 << j)) > 0) {
413 if (b.lastState == 1 && !b.isRepeatable)
419 if (b.value->getDoubleValue() == 0.0)
420 flag = b.value->setDoubleValue(b.step);
422 flag = b.value->setDoubleValue(0.0);
424 if (b.value->getBoolValue())
425 flag = b.value->setBoolValue(false);
427 flag = b.value->setBoolValue(true);
431 flag = b.value->setDoubleValue(b.step);
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);
447 if (b.lastState == 0 && !b.isRepeatable)
457 flag = b.value->setDoubleValue(0.0);
467 FG_LOG(FG_INPUT, FG_ALERT, "Failed to set value for "
468 << jsNames[i] << ' ' << buttonNames[j]);
478 // end of joystick.cxx