static const int MAX_JOYSTICKS = 10;
static const int MAX_AXES = 10;
+static const int MAX_BUTTONS = 10;
/**
"axis0", "axis1", "axis2", "axis3", "axis4",
"axis5", "axis6", "axis7", "axis8", "axis9"
};
+static const char * buttonNames[] = {
+ "button0", "button1", "button2", "button3", "button4",
+ "button5", "button6", "button7", "button8", "button9"
+};
/**
};
+/**
+ * Settings for a single button.
+ */
+struct button {
+ enum Action {
+ TOGGLE,
+ SWITCH,
+ ADJUST
+ };
+ button () : value(0), step(0.0), action(ADJUST), isRepeatable(true),
+ lastState(-1) {}
+ FGValue * value;
+ float step;
+ Action action;
+ bool isRepeatable;
+ int lastState;
+};
+
+
/**
* Settings for a single joystick.
*/
virtual ~joystick () { delete js; delete axes; }
jsJoystick * js;
axis * axes;
+ button * buttons;
};
if (!props.getValue("/input/js0/axis3/control")) {
props.setStringValue("/input/js0/axis3/control", "/controls/rudder");
props.setFloatValue("/input/js0/axis3/dead-band", 0.3);
+ }
+
+ // Default button 0 to all brakes
+ if (!props.getValue("/input/js0/button0/control")) {
+ props.setStringValue("/input/js0/button0/action", "switch");
+ props.setStringValue("/input/js0/button0/control", "/controls/brake");
+ props.setFloatValue("/input/js0/button0/step", 1.0);
+ props.setFloatValue("/input/js0/button0/repeatable", false);
+ }
+
+ // Default button 1 to left brake.
+ if (!props.getValue("/input/js0/button1/control")) {
+ props.setStringValue("/input/js0/button1/action", "switch");
+ props.setStringValue("/input/js0/button1/control", "/controls/left-brake");
+ props.setFloatValue("/input/js0/button1/step", 1.0);
+ props.setFloatValue("/input/js0/button1/repeatable", false);
+ }
+
+ // Default button 2 to right brake.
+ if (!props.getValue("/input/js0/button2/control")) {
+ props.setStringValue("/input/js0/button2/action", "switch");
+ props.setStringValue("/input/js0/button2/control",
+ "/controls/right-brake");
+ props.setFloatValue("/input/js0/button2/step", 1.0);
+ props.setFloatValue("/input/js0/button2/repeatable", false);
+ }
+
+ // Default buttons 3 and 4 to elevator trim
+ if (!props.getValue("/input/js0/button3/control")) {
+ props.setStringValue("/input/js0/button3/action", "adjust");
+ props.setStringValue("/input/js0/button3/control",
+ "/controls/elevator-trim");
+ props.setFloatValue("/input/js0/button3/step", 0.001);
+ props.setBoolValue("/input/js0/button3/repeatable", true);
+ }
+ if (!props.getValue("/input/js0/button4/control")) {
+ props.setStringValue("/input/js0/button4/action", "adjust");
+ props.setStringValue("/input/js0/button4/control",
+ "/controls/elevator-trim");
+ props.setFloatValue("/input/js0/button4/step", -0.001);
+ props.setBoolValue("/input/js0/button4/repeatable", true);
+ }
+
+ // Default buttons 5 and 6 to flaps
+ if (!props.getValue("/input/js0/button5/control")) {
+ props.setStringValue("/input/js0/button5/action", "adjust");
+ props.setStringValue("/input/js0/button5/control", "/controls/flaps");
+ props.setFloatValue("/input/js0/button5/step", -0.34);
+ props.setBoolValue("/input/js0/button5/repeatable", false);
+ }
+ if (!props.getValue("/input/js0/button6/control")) {
+ props.setStringValue("/input/js0/button6/action", "adjust");
+ props.setStringValue("/input/js0/button6/control", "/controls/flaps");
+ props.setFloatValue("/input/js0/button6/step", 0.34);
+ props.setBoolValue("/input/js0/button6/repeatable", false);
}
}
js->getMaxRange(maxRange);
js->getCenter(center);
- // Allocate axes
+ // Allocate axes and buttons
joysticks[i].axes = new axis[js->getNumAxes()];
+ joysticks[i].buttons = new button[MAX_BUTTONS];
+
+ //
+ // Initialize the axes.
+ //
for (int j = 0; j < min(js->getNumAxes(), MAX_AXES); j++) {
+ axis &a = joysticks[i].axes[j];
+
string base = "/input/";
base += jsNames[i];
base += '/';
continue;
}
const string &control = value->getStringValue();
- joysticks[i].axes[j].value = current_properties.getValue(control, true);
+ a.value = current_properties.getValue(control, true);
FG_LOG(FG_INPUT, FG_INFO, " using control " << control);
// Dead band
name += "/offset";
value = current_properties.getValue(name);
if (value != 0)
- joysticks[i].axes[j].offset = value->getFloatValue();
- FG_LOG(FG_INPUT, FG_INFO, " offset is "
- << joysticks[i].axes[j].offset);
+ a.offset = value->getFloatValue();
+ FG_LOG(FG_INPUT, FG_INFO, " offset is " << a.offset);
// Factor
name += "/factor";
value = current_properties.getValue(name);
if (value != 0)
- joysticks[i].axes[j].factor = value->getFloatValue();
- FG_LOG(FG_INPUT, FG_INFO, " factor is "
- << joysticks[i].axes[j].factor);
+ a.factor = value->getFloatValue();
+ FG_LOG(FG_INPUT, FG_INFO, " factor is " << a.factor);
// Tolerance
name += "/tolerance";
value = current_properties.getValue(name);
if (value != 0)
- joysticks[i].axes[j].tolerance = value->getFloatValue();
- FG_LOG(FG_INPUT, FG_INFO, " tolerance is "
- << joysticks[i].axes[j].tolerance);
+ a.tolerance = value->getFloatValue();
+ FG_LOG(FG_INPUT, FG_INFO, " tolerance is " << a.tolerance);
// Saturation
FG_LOG(FG_INPUT, FG_INFO, " center is " << center[j]);
}
+
+ //
+ // Initialize the buttons.
+ //
+ for (int j = 0; j < MAX_BUTTONS; j++) {
+ button &b = joysticks[i].buttons[j];
+
+ string base = "/input/";
+ base += jsNames[i];
+ base += '/';
+ base += buttonNames[j];
+ FG_LOG(FG_INPUT, FG_INFO, " Button " << j << ':');
+
+ // Control property
+ string name = base;
+ name += "/control";
+ cout << "Trying name " << name << endl;
+ FGValue * value = current_properties.getValue(name);
+ if (value == 0) {
+ FG_LOG(FG_INPUT, FG_INFO, " no control defined");
+ continue;
+ }
+ const string &control = value->getStringValue();
+ b.value = current_properties.getValue(control, true);
+ FG_LOG(FG_INPUT, FG_INFO, " using control " << control);
+
+ // Step
+ name = base;
+ name += "/step";
+ value = current_properties.getValue(name);
+ if (value != 0)
+ b.step = value->getFloatValue();
+ FG_LOG(FG_INPUT, FG_INFO, " step is " << b.step);
+
+ // Type
+ name = base;
+ name += "/action";
+ value = current_properties.getValue(name);
+ string action = "adjust";
+ if (value != 0)
+ action = value->getStringValue();
+ if (action == "toggle") {
+ b.action = button::TOGGLE;
+ b.isRepeatable = false;
+ } else if (action == "switch") {
+ b.action = button::SWITCH;
+ b.isRepeatable = false;
+ } else if (action == "adjust") {
+ b.action = button::ADJUST;
+ b.isRepeatable = true;
+ } else {
+ FG_LOG(FG_INPUT, FG_ALERT, " unknown action " << action);
+ action = "adjust";
+ b.action = button::ADJUST;
+ b.isRepeatable = true;
+ }
+ FG_LOG(FG_INPUT, FG_INFO, " action is " << action);
+
+ // Repeatability.
+ name = base;
+ name += "/repeatable";
+ value = current_properties.getValue(name);
+ if (value != 0)
+ b.isRepeatable = value->getBoolValue();
+ FG_LOG(FG_INPUT, FG_INFO, (b.isRepeatable ?
+ " repeatable" : " not repeatable"));
+ }
+
js->setMinRange(minRange);
js->setMaxRange(maxRange);
js->setCenter(center);
js->read(&buttons, axis_values);
+ //
+ // Axes
+ //
for (int j = 0; j < min(MAX_AXES, js->getNumAxes()); j++) {
+ bool flag = true;
+ axis &a = joysticks[i].axes[j];
// If the axis hasn't changed, don't
// force the value.
- if (fabs(axis_values[j] - joysticks[i].axes[j].last_value) <=
- joysticks[i].axes[j].tolerance)
+ if (fabs(axis_values[j] - a.last_value) <= a.tolerance)
continue;
else
- joysticks[i].axes[j].last_value = axis_values[j];
-
- FGValue * value = joysticks[i].axes[j].value;
- if (value) {
- if (!value->setDoubleValue((axis_values[j] +
- joysticks[i].axes[j].offset) *
- joysticks[i].axes[j].factor))
- FG_LOG(FG_INPUT, FG_ALERT, "Failed to set value for joystick "
- << i << ", axis " << j);
+ a.last_value = axis_values[j];
+
+ if (a.value)
+ flag = a.value->setDoubleValue((axis_values[j] + a.offset) *
+ a.factor);
+ if (!flag)
+ FG_LOG(FG_INPUT, FG_ALERT, "Failed to set value for joystick "
+ << i << ", axis " << j);
+ }
+
+ //
+ // Buttons
+ //
+ for (int j = 0; j < MAX_BUTTONS; j++) {
+ bool flag;
+ button &b = joysticks[i].buttons[j];
+ if (b.value == 0)
+ continue;
+
+ // Button is on.
+ if ((buttons & (1 << j)) > 0) {
+ // Repeating?
+ if (b.lastState == 1 && !b.isRepeatable)
+ continue;
+
+ switch (b.action) {
+ case button::TOGGLE:
+ if (b.step != 0.0) {
+ if (b.value->getDoubleValue() == 0.0)
+ flag = b.value->setDoubleValue(b.step);
+ else
+ flag = b.value->setDoubleValue(0.0);
+ } else {
+ if (b.value->getBoolValue())
+ flag = b.value->setBoolValue(false);
+ else
+ flag = b.value->setBoolValue(true);
+ }
+ break;
+ case button::SWITCH:
+ flag = b.value->setDoubleValue(b.step);
+ break;
+ case button::ADJUST:
+ if (!b.value->setDoubleValue(b.value->getDoubleValue() + b.step))
+ FG_LOG(FG_INPUT, FG_ALERT, "Failed to set value for joystick "
+ << i << ", axis " << j);
+ break;
+ default:
+ flag = false;
+ break;
+ }
+ b.lastState = 1;
+
+ // Button is off
+ } else {
+ // Repeating?
+ if (b.lastState == 0 && !b.isRepeatable)
+ continue;
+
+ switch (b.action) {
+ case button::TOGGLE:
+ // no op
+ break;
+ case button::SWITCH:
+ flag = b.value->setDoubleValue(0.0);
+ break;
+ case button::ADJUST:
+ // no op
+ break;
+ default:
+ flag = false;
+ break;
+ }
+
+ b.lastState = 0;
}
+ if (!flag)
+ FG_LOG(FG_INPUT, FG_ALERT, "Failed to set value for "
+ << jsNames[i] << ' ' << buttonNames[j]);
}
}
- return true; // FIXME
+ return true;
}
// end of joystick.cxx