Joystick updates from David Megginson to add the beginnings of button support.
This commit is contained in:
parent
4f19d10485
commit
4dcd4cda79
3 changed files with 299 additions and 26 deletions
|
@ -41,6 +41,7 @@ using std::string;
|
|||
|
||||
static const int MAX_JOYSTICKS = 10;
|
||||
static const int MAX_AXES = 10;
|
||||
static const int MAX_BUTTONS = 10;
|
||||
|
||||
|
||||
/**
|
||||
|
@ -54,6 +55,10 @@ static const char * axisNames[] = {
|
|||
"axis0", "axis1", "axis2", "axis3", "axis4",
|
||||
"axis5", "axis6", "axis7", "axis8", "axis9"
|
||||
};
|
||||
static const char * buttonNames[] = {
|
||||
"button0", "button1", "button2", "button3", "button4",
|
||||
"button5", "button6", "button7", "button8", "button9"
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
|
@ -70,6 +75,25 @@ struct axis {
|
|||
};
|
||||
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
|
@ -77,6 +101,7 @@ struct joystick {
|
|||
virtual ~joystick () { delete js; delete axes; }
|
||||
jsJoystick * js;
|
||||
axis * axes;
|
||||
button * buttons;
|
||||
};
|
||||
|
||||
|
||||
|
@ -121,6 +146,61 @@ setupDefaults ()
|
|||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -158,10 +238,17 @@ fgJoystickInit()
|
|||
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 += '/';
|
||||
|
@ -177,7 +264,7 @@ fgJoystickInit()
|
|||
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
|
||||
|
@ -193,9 +280,8 @@ fgJoystickInit()
|
|||
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
|
||||
|
@ -203,9 +289,8 @@ fgJoystickInit()
|
|||
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
|
||||
|
@ -213,9 +298,8 @@ fgJoystickInit()
|
|||
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
|
||||
|
@ -251,6 +335,74 @@ fgJoystickInit()
|
|||
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);
|
||||
|
@ -282,28 +434,101 @@ fgJoystickRead()
|
|||
|
||||
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];
|
||||
a.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);
|
||||
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
|
||||
|
|
|
@ -149,6 +149,10 @@ FGBFI::init ()
|
|||
getElevatorTrim, setElevatorTrim);
|
||||
current_properties.tieDouble("/controls/brake",
|
||||
getBrake, setBrake);
|
||||
current_properties.tieDouble("/controls/left-brake",
|
||||
getLeftBrake, setLeftBrake);
|
||||
current_properties.tieDouble("/controls/right-brake",
|
||||
getRightBrake, setRightBrake);
|
||||
|
||||
// Autopilot
|
||||
current_properties.tieBool("/autopilot/locks/altitude",
|
||||
|
@ -509,7 +513,7 @@ double
|
|||
FGBFI::getAGL ()
|
||||
{
|
||||
return current_aircraft.fdm_state->get_Altitude()
|
||||
- scenery.cur_elev * METER_TO_FEET;
|
||||
- (scenery.cur_elev * METER_TO_FEET);
|
||||
}
|
||||
|
||||
|
||||
|
@ -866,7 +870,7 @@ double
|
|||
FGBFI::getBrake ()
|
||||
{
|
||||
// FIXME: add brake selector
|
||||
return controls.get_brake(0);
|
||||
return controls.get_brake(2);
|
||||
}
|
||||
|
||||
|
||||
|
@ -876,12 +880,52 @@ FGBFI::getBrake ()
|
|||
void
|
||||
FGBFI::setBrake (double brake)
|
||||
{
|
||||
// FIXME: clamp?
|
||||
// FIXME: allow brake selection
|
||||
controls.set_brake(FGControls::ALL_WHEELS, brake);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the left brake, from 0.0 (none) to 1.0 (full).
|
||||
*/
|
||||
double
|
||||
FGBFI::getLeftBrake ()
|
||||
{
|
||||
return controls.get_brake(0);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the left brake, from 0.0 (none) to 1.0 (full).
|
||||
*/
|
||||
void
|
||||
FGBFI::setLeftBrake (double brake)
|
||||
{
|
||||
controls.set_brake(0, brake);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the right brake, from 0.0 (none) to 1.0 (full).
|
||||
*/
|
||||
double
|
||||
FGBFI::getRightBrake ()
|
||||
{
|
||||
return controls.get_brake(1);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the right brake, from 0.0 (none) to 1.0 (full).
|
||||
*/
|
||||
void
|
||||
FGBFI::setRightBrake (double brake)
|
||||
{
|
||||
controls.set_brake(1, brake);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Autopilot
|
||||
|
|
|
@ -111,6 +111,8 @@ public:
|
|||
static double getElevator ();
|
||||
static double getElevatorTrim ();
|
||||
static double getBrake ();
|
||||
static double getLeftBrake ();
|
||||
static double getRightBrake ();
|
||||
|
||||
static void setThrottle (double throttle);
|
||||
static void setFlaps (double flaps);
|
||||
|
@ -119,6 +121,8 @@ public:
|
|||
static void setElevator (double elevator);
|
||||
static void setElevatorTrim (double trim);
|
||||
static void setBrake (double brake);
|
||||
static void setLeftBrake (double brake);
|
||||
static void setRightBrake (double brake);
|
||||
|
||||
|
||||
// Autopilot
|
||||
|
|
Loading…
Add table
Reference in a new issue