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.
35 #include <simgear/misc/props.hxx>
36 #include <simgear/debug/logstream.hxx>
38 #include "joystick.hxx"
42 static const int MAX_JOYSTICKS = 10;
43 static const int MAX_AXES = 10;
47 * Property names for joysticks and axes.
49 static const char * jsNames[] = {
50 "js0", "js1", "js2", "js3", "js4",
51 "js5", "js6", "js7", "js8", "js9"
53 static const char * axisNames[] = {
54 "axis0", "axis1", "axis2", "axis3", "axis4",
55 "axis5", "axis6", "axis7", "axis8", "axis9"
60 * Settings for a single axis.
63 axis () : value(0), offset(0.0), factor(1.0),
64 last_value(9999999), tolerance(0.002) {}
74 * Settings for a single joystick.
77 virtual ~joystick () { delete js; delete axes; }
84 * Array of joystick settings.
86 static joystick joysticks[MAX_JOYSTICKS];
90 * Set up default values if properties are not specified.
95 FGPropertyList &props = current_properties;
97 // Default axis 0 to aileron
98 if (!props.getValue("/input/js0/axis0/control")) {
99 props.setStringValue("/input/js0/axis0/control", "/controls/aileron");
100 props.setFloatValue("/input/js0/axis0/dead-band", 0.1);
103 // Default axis 1 to elevator
104 if (!props.getValue("/input/js0/axis1/control")) {
105 props.setStringValue("/input/js0/axis1/control", "/controls/elevator");
106 props.setFloatValue("/input/js0/axis1/dead-band", 0.1);
107 props.setFloatValue("/input/js0/axis1/factor", -1.0);
110 // Default axis 2 to throttle
111 // We need to fiddle with the offset
112 // and factor to make it work
113 if (!props.getValue("/input/js0/axis2/control")) {
114 props.setStringValue("/input/js0/axis2/control", "/controls/throttle");
115 props.setFloatValue("/input/js0/axis2/dead-band", 0.0);
116 props.setFloatValue("/input/js0/axis2/offset", -1.0);
117 props.setFloatValue("/input/js0/axis2/factor", -0.5);
120 // Default axis 3 to rudder
121 if (!props.getValue("/input/js0/axis3/control")) {
122 props.setStringValue("/input/js0/axis3/control", "/controls/rudder");
123 props.setFloatValue("/input/js0/axis3/dead-band", 0.3);
129 * Initialize any joysticks found.
134 bool seen_joystick = false;
136 FG_LOG(FG_INPUT, FG_INFO, "Initializing joysticks");
140 for (int i = 0; i < MAX_JOYSTICKS; i++) {
141 jsJoystick * js = new jsJoystick(i);
142 joysticks[i].js = js;
143 if (js->notWorking()) {
144 FG_LOG(FG_INPUT, FG_INFO, "Joystick " << i << " not found");
148 FG_LOG(FG_INPUT, FG_INFO, "Initializing joystick " << i);
149 seen_joystick = true;
151 // Set up range arrays
152 float minRange[js->getNumAxes()];
153 float maxRange[js->getNumAxes()];
154 float center[js->getNumAxes()];
156 // Initialize with default values
157 js->getMinRange(minRange);
158 js->getMaxRange(maxRange);
159 js->getCenter(center);
162 joysticks[i].axes = new axis[js->getNumAxes()];
164 for (int j = 0; j < min(js->getNumAxes(), MAX_AXES); j++) {
165 string base = "/input/";
168 base += axisNames[j];
169 FG_LOG(FG_INPUT, FG_INFO, " Axis " << j << ':');
174 FGValue * value = current_properties.getValue(name);
176 FG_LOG(FG_INPUT, FG_INFO, " no control defined");
179 const string &control = value->getStringValue();
180 joysticks[i].axes[j].value = current_properties.getValue(control, true);
181 FG_LOG(FG_INPUT, FG_INFO, " using control " << control);
185 name += "/dead-band";
186 value = current_properties.getValue(name);
188 js->setDeadBand(j, value->getFloatValue());
189 FG_LOG(FG_INPUT, FG_INFO, " dead-band is " << js->getDeadBand(j));
194 value = current_properties.getValue(name);
196 joysticks[i].axes[j].offset = value->getFloatValue();
197 FG_LOG(FG_INPUT, FG_INFO, " offset is "
198 << joysticks[i].axes[j].offset);
204 value = current_properties.getValue(name);
206 joysticks[i].axes[j].factor = value->getFloatValue();
207 FG_LOG(FG_INPUT, FG_INFO, " factor is "
208 << joysticks[i].axes[j].factor);
213 name += "/tolerance";
214 value = current_properties.getValue(name);
216 joysticks[i].axes[j].tolerance = value->getFloatValue();
217 FG_LOG(FG_INPUT, FG_INFO, " tolerance is "
218 << joysticks[i].axes[j].tolerance);
223 name += "/saturation";
224 value = current_properties.getValue(name);
226 js->setSaturation(j, value->getFloatValue());
227 FG_LOG(FG_INPUT, FG_INFO, " saturation is " << js->getSaturation(j));
231 name += "/min-range";
232 value = current_properties.getValue(name);
234 minRange[j] = value->getFloatValue();
235 FG_LOG(FG_INPUT, FG_INFO, " min-range is " << minRange[j]);
239 name += "/max-range";
240 value = current_properties.getValue(name);
242 maxRange[j] = value->getFloatValue();
243 FG_LOG(FG_INPUT, FG_INFO, " max-range is " << maxRange[j]);
248 value = current_properties.getValue(name);
250 center[j] = value->getFloatValue();
251 FG_LOG(FG_INPUT, FG_INFO, " center is " << center[j]);
254 js->setMinRange(minRange);
255 js->setMaxRange(maxRange);
256 js->setCenter(center);
260 FG_LOG(FG_INPUT, FG_INFO, "Done initializing joysticks");
262 FG_LOG(FG_INPUT, FG_ALERT, "No joysticks detected");
264 return seen_joystick;
269 * Update property values based on the joystick state(s).
276 for (int i = 0; i < MAX_JOYSTICKS; i++) {
277 jsJoystick * js = joysticks[i].js;
278 float axis_values[js->getNumAxes()];
279 if (js->notWorking()) {
283 js->read(&buttons, axis_values);
285 for (int j = 0; j < min(MAX_AXES, js->getNumAxes()); j++) {
287 // If the axis hasn't changed, don't
289 if (fabs(axis_values[j] - joysticks[i].axes[j].last_value) <=
290 joysticks[i].axes[j].tolerance)
293 joysticks[i].axes[j].last_value = axis_values[j];
295 FGValue * value = joysticks[i].axes[j].value;
297 if (!value->setDoubleValue((axis_values[j] +
298 joysticks[i].axes[j].offset) *
299 joysticks[i].axes[j].factor))
300 FG_LOG(FG_INPUT, FG_ALERT, "Failed to set value for joystick "
301 << i << ", axis " << j);
306 return true; // FIXME
309 // end of joystick.cxx