1
0
Fork 0

Stefan Seifert:

- read bindings from template
- automatic deadband detection

mf:
- write js name into output file
- poor man's progress bar during deadband detection
- fix header inclusion, fix mixed indentation
This commit is contained in:
mfranz 2006-07-04 23:29:05 +00:00
parent 1d0b6290c4
commit 2c7e01133f
4 changed files with 456 additions and 516 deletions

View file

@ -1,3 +1,5 @@
AM_CXXFLAGS = -DPKGLIBDIR=\"$(pkgdatadir)\"
noinst_LIBRARIES = libInput.a noinst_LIBRARIES = libInput.a
libInput_a_SOURCES = input.cxx input.hxx libInput_a_SOURCES = input.cxx input.hxx
@ -10,6 +12,7 @@ js_demo_LDADD = -lplibjs $(base_LIBS) $(joystick_LIBS) -lplibul
fgjs_SOURCES = fgjs.cxx jsinput.cxx jsinput.h jssuper.cxx jssuper.h fgjs_SOURCES = fgjs.cxx jsinput.cxx jsinput.h jssuper.cxx jssuper.h
fgjs_LDADD = -lplibjs $(base_LIBS) $(joystick_LIBS) -lplibul fgjs_LDADD = -lplibjs $(base_LIBS) $(joystick_LIBS) -lplibul \
-lsgprops -lsgmisc -lsgio -lsgdebug -lsgstructure -lsgxml -lz
INCLUDES = -I$(top_srcdir) -I$(top_srcdir)/src INCLUDES = -I$(top_srcdir) -I$(top_srcdir)/src -I$(top_srcdir)/src/Main

View file

@ -6,6 +6,7 @@
// Written by Tony Peden, started May 2001 // Written by Tony Peden, started May 2001
// //
// Copyright (C) 2001 Tony Peden (apeden@earthlink.net) // Copyright (C) 2001 Tony Peden (apeden@earthlink.net)
// Copyright (C) 2006 Stefan Seifert
// //
// This program is free software; you can redistribute it and/or // This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as // modify it under the terms of the GNU General Public License as
@ -29,8 +30,6 @@
#include STL_FSTREAM #include STL_FSTREAM
#include STL_STRING #include STL_STRING
#include <jsinput.h>
SG_USING_STD(fstream); SG_USING_STD(fstream);
SG_USING_STD(cout); SG_USING_STD(cout);
SG_USING_STD(cin); SG_USING_STD(cin);
@ -38,460 +37,336 @@ SG_USING_STD(endl);
SG_USING_STD(ios); SG_USING_STD(ios);
SG_USING_STD(string); SG_USING_STD(string);
string axes_humannames[8] = { "Aileron", "Elevator", "Rudder", "Throttle", #include <simgear/constants.h>
"Mixture", "Pitch", "View Direction", #include <simgear/debug/logstream.hxx>
"View Elevation" #include <simgear/misc/sg_path.hxx>
}; #include <simgear/misc/sgstream.hxx>
#include <simgear/structure/exception.hxx>
string axes_propnames[8]={ "/controls/flight/aileron","/controls/flight/elevator", #include <Main/fg_io.hxx>
"/controls/flight/rudder","/controls/engines/engine[%d]/throttle", #include <Main/fg_props.hxx>
"/controls/engines/engine[%d]/mixture","/controls/engines/engine[%d]/pitch", #include <Main/globals.hxx>
"/sim/current-view/goal-heading-offset-deg",
"/sim/current-view/goal-pitch-offset-deg"
};
string axis_posdir[8]= { "right", "down/forward", "right", "forward", "forward", "forward", "left", "upward" }; #include "jsinput.h"
bool half_range[8]={ false,false,false,true,true,true,false,false }; bool confirmAnswer() {
char answer;
bool repeatable[8]={ false,false,false,false,false,false,true,true }; do {
cout << "Is this correct? (y/n) $ ";
bool invert[8]= { false,false,false,false,false,false,false,false }; cin >> answer;
cin.ignore(256, '\n');
string button_humannames[8]= { "Left Brake", "Right Brake", if (answer == 'y')
"Flaps Up", "Flaps Down", return true;
"Elevator Trim Forward", "Elevator Trim Backward", if (answer == 'n')
"Landing Gear Up", "Landing Gear Down" return false;
}; } while (true);
string button_propnames[8]={ "/controls/gear/brake-left",
"/controls/gear/brake-right",
"/controls/flight/flaps",
"/controls/flight/flaps",
"/controls/flight/elevator-trim",
"/controls/flight/elevator-trim",
"/controls/gear/gear-down",
"/controls/gear/gear-down"
};
bool button_modup[8]={ true,true,false,false,false,false,false,false };
bool button_boolean[8]={ false,false,false,false,false,false,true,true };
float button_step[8]={ 1.0, 1.0, -0.34, 0.34, 0.001, -0.001, 0.0, 1.0 };
string button_repeat[8]={ "false", "false", "false", "false", "true", "true", "false", "false" };
void writeAxisXML(fstream &fs, int control, int axis) {
char axisline[16];
snprintf(axisline,16," <axis n=\"%d\">",axis);
fs << axisline << endl;
fs << " <desc>" << axes_humannames[control] << "</desc>" << endl;
if (half_range[control]) {
for (int i=0; i<=7; i++) {
fs << " <binding>" << endl;
fs << " <command>property-scale</command>" << endl;
char propertyline[256];
snprintf(propertyline,256,axes_propnames[control].c_str(),i);
fs << " <property>" << propertyline << "</property>" << endl;
fs << " <offset type=\"double\">-1.0</offset>" << endl;
fs << " <factor type=\"double\">-0.5</factor>" << endl;
fs << " </binding>" << endl;
}
} else if (repeatable[control]) {
fs << " <low>" << endl;
fs << " <repeatable>true</repeatable>" << endl;
fs << " <binding>" << endl;
fs << " <command>property-adjust</command>" << endl;
fs << " <property>" << axes_propnames[control] << "</property>" << endl;
if (invert[control]) {
fs << " <step type=\"double\">1.0</step>" << endl;
} else {
fs << " <step type=\"double\">-1.0</step>" << endl;
}
fs << " </binding>" << endl;
fs << " </low>" << endl;
fs << " <high>" << endl;
fs << " <repeatable>true</repeatable>" << endl;
fs << " <binding>" << endl;
fs << " <command>property-adjust</command>" << endl;
fs << " <property>" << axes_propnames[control] << "</property>" << endl;
if (invert[control]) {
fs << " <step type=\"double\">-1.0</step>" << endl;
} else {
fs << " <step type=\"double\">1.0</step>" << endl;
}
fs << " </binding>" << endl;
fs << " </high>" << endl;
} else {
fs << " <binding>" << endl;
fs << " <command>property-scale</command>" << endl;
fs << " <property>" << axes_propnames[control] << "</property>" << endl;
fs << " <dead-band type=\"double\">0.02</dead-band>" << endl;
fs << " <offset type=\"double\">0.0</offset>" << endl;
if (invert[control]) {
fs << " <factor type=\"double\">-1.0</factor>" << endl;
} else {
fs << " <factor type=\"double\">1.0</factor>" << endl;
}
fs << " </binding>" << endl;
}
fs << " </axis>" << endl << endl;
} }
void writeAxisProperties(fstream &fs, int control,int joystick, int axis) { string getFGRoot( int argc, char *argv[] );
char jsDesc[80];
snprintf(jsDesc,80,"--prop:/input/joysticks/js[%d]/axis[%d]",joystick,axis);
if( half_range[control] == true) {
for (int i=0; i<=7; i++) {
char bindno[64];
snprintf(bindno,64,"/binding[%d]",i);
char propertyline[256];
snprintf(propertyline,256,axes_propnames[control].c_str(),i);
fs << jsDesc << bindno << "/command=property-scale" << endl;
fs << jsDesc << bindno << "/property=" << propertyline << endl;
fs << jsDesc << bindno << "/offset=-1.0" << endl;
fs << jsDesc << bindno << "/factor=-0.5" << endl;
}
} else if (repeatable[control]) {
fs << jsDesc << "/low/repeatable=true" << endl;
fs << jsDesc << "/low/binding/command=property-adjust" << endl;
fs << jsDesc << "/low/binding/property=" << axes_propnames[control] << endl;
if (invert[control]) {
fs << jsDesc << "/low/binding/step=1.0" << endl;
} else {
fs << jsDesc << "/low/binding/step=-1.0" << endl;
}
fs << jsDesc << "/high/repeatable=true" << endl;
fs << jsDesc << "/high/binding/command=property-adjust" << endl;
fs << jsDesc << "/high/binding/property=" << axes_propnames[control] << endl;
if (invert[control]) {
fs << jsDesc << "/high/binding/step=-1.0" << endl;
} else {
fs << jsDesc << "/high/binding/step=1.0" << endl;
}
} else {
fs << jsDesc << "/binding/command=property-scale" << endl;
fs << jsDesc << "/binding/property=" << axes_propnames[control] << endl;
fs << jsDesc << "/binding/dead-band=0.02" << endl;
fs << jsDesc << "/binding/offset=0.0" << endl;
if (invert[control]) {
fs << jsDesc << "/binding/factor=-1.0" << endl;
} else {
fs << jsDesc << "/binding/factor=1.0" << endl;
}
}
fs << endl;
}
void writeButtonXML(fstream &fs, int property, int button) {
char buttonline[32];
snprintf(buttonline,32," <button n=\"%d\">",button);
fs << buttonline << endl;
if (property==-2) {
fs << " <desc>View Cycle</desc>" << endl;
fs << " <repeatable>false</repeatable>" << endl;
fs << " <binding>" << endl;
fs << " <command>view-cycle</command>" << endl;
fs << " <step type=\"double\">1</step>" << endl;
fs << " </binding>" << endl;
} else if (property==-1) {
fs << " <desc>Brakes</desc>" << endl;
fs << " <binding>" << endl;
fs << " <command>property-assign</command>" << endl;
fs << " <property>" << button_propnames[0] << "</property>" << endl;
fs << " <value type=\"double\">" << button_step[0] << "</value>" << endl;
fs << " </binding>" << endl;
fs << " <binding>" << endl;
fs << " <command>property-assign</command>" << endl;
fs << " <property>" << button_propnames[1] << "</property>" << endl;
fs << " <value type=\"double\">" << button_step[1] << "</value>" << endl;
fs << " </binding>" << endl;
fs << " <mod-up>" << endl;
fs << " <binding>" << endl;
fs << " <command>property-assign</command>" << endl;
fs << " <property>" << button_propnames[0] << "</property>" << endl;
fs << " <value type=\"double\">0</value>" << endl;
fs << " </binding>" << endl;
fs << " <binding>" << endl;
fs << " <command>property-assign</command>" << endl;
fs << " <property>" << button_propnames[1] << "</property>" << endl;
fs << " <value type=\"double\">0</value>" << endl;
fs << " </binding>" << endl;
fs << " </mod-up>" << endl;
} else {
fs << " <desc>" << button_humannames[property] << "</desc>" << endl;
if (button_modup[property]) {
fs << " <binding>" << endl;
fs << " <command>property-assign</command>" << endl;
fs << " <property>" << button_propnames[property] << "</property>" << endl;
fs << " <value type=\"double\">" << button_step[property] << "</value>" << endl;
fs << " </binding>" << endl;
fs << " <mod-up>" << endl;
fs << " <binding>" << endl;
fs << " <command>property-assign</command>" << endl;
fs << " <property>" << button_propnames[property] << "</property>" << endl;
fs << " <value type=\"double\">0</value>" << endl;
fs << " </binding>" << endl;
fs << " </mod-up>" << endl;
} else if (button_boolean[property]) {
fs << " <repeatable>" << button_repeat[property] << "</repeatable>" << endl;
fs << " <binding>" << endl;
fs << " <command>property-assign</command>" << endl;
fs << " <property>" << button_propnames[property] << "</property>" << endl;
fs << " <value type=\"bool\">";
if (button_step[property]==1) {
fs << "true";
} else {
fs << "false";
}
fs << "</value>" << endl;
fs << " </binding>" << endl;
} else {
fs << " <repeatable>" << button_repeat[property] << "</repeatable>" << endl;
fs << " <binding>" << endl;
fs << " <command>property-adjust</command>" << endl;
fs << " <property>" << button_propnames[property] << "</property>" << endl;
fs << " <step type=\"double\">" << button_step[property] << "</step>" << endl;
fs << " </binding>" << endl;
}
}
fs << " </button>" << endl << endl;
}
void writeButtonProperties(fstream &fs, int property,int joystick, int button) {
char jsDesc[80];
snprintf(jsDesc,80,"--prop:/input/joysticks/js[%d]/button[%d]",joystick,button);
if (property==-1) {
fs << jsDesc << "/binding[0]/command=property-assign" << endl;
fs << jsDesc << "/binding[0]/property=" << button_propnames[0] << endl;
fs << jsDesc << "/binding[0]/value=" << button_step[0] << endl;
fs << jsDesc << "/binding[1]/command=property-assign" << endl;
fs << jsDesc << "/binding[1]/property=" << button_propnames[1] << endl;
fs << jsDesc << "/binding[1]/value=" << button_step[1] << endl;
fs << jsDesc << "/mod-up/binding[0]/command=property-assign" << endl;
fs << jsDesc << "/mod-up/binding[0]/property=" << button_propnames[0] << endl;
fs << jsDesc << "/mod-up/binding[0]/value=0" << endl;
fs << jsDesc << "/mod-up/binding[1]/command=property-assign" << endl;
fs << jsDesc << "/mod-up/binding[1]/property=" << button_propnames[1] << endl;
fs << jsDesc << "/mod-up/binding[1]/value=0" << endl;
fs << endl;
} else if (button_modup[property]) {
fs << jsDesc << "/binding/command=property-assign" << endl;
fs << jsDesc << "/binding/property=" << button_propnames[property] << endl;
fs << jsDesc << "/binding/value=" << button_step[property] << endl;
fs << jsDesc << "/mod-up/binding/command=property-assign" << endl;
fs << jsDesc << "/mod-up/binding/property=" << button_propnames[property] << endl;
fs << jsDesc << "/mod-up/binding/value=0" << endl;
fs << endl;
} else if (button_boolean[property]) {
fs << jsDesc << "/repeatable=" << button_repeat[property] << endl;
fs << jsDesc << "/binding/command=property-assign" << endl;
fs << jsDesc << "/binding/property=" << button_propnames[property] << endl;
fs << jsDesc << "/binding/value=";
if (button_step[property]==1) {
fs << "true";
} else {
fs << "false";
}
fs << endl << endl;
} else {
fs << jsDesc << "/repeatable=" << button_repeat[property] << endl;
fs << jsDesc << "/binding/command=property-adjust" << endl;
fs << jsDesc << "/binding/property=" << button_propnames[property] << endl;
fs << jsDesc << "/binding/step=" << button_step[property] << endl;
fs << endl;
}
}
int main( int argc, char *argv[] ) { int main( int argc, char *argv[] ) {
bool usexml=true; for (int i = 1; i < argc; i++) {
float deadband=0; if (strcmp("--help", argv[i]) == 0) {
char answer[128]; cout << "Usage:" << endl;
int btninit=-2; cout << " --help\t\t\tShow this help" << endl;
exit(0);
for (int i=1; i<argc; i++) { } else {
if (strcmp("--help",argv[i])==0) { cout << "Unknown option \"" << argv[i] << "\"" << endl;
cout << "Usage:" << endl; exit(0);
cout << " --help\t\t\tShow this help" << endl; }
cout << " --prop\t\t\tOutput property list" << endl;
cout << " --xml\t\t\t\tOutput xml (default)" << endl;
cout << " --deadband <float>\t\tSet deadband (for this program only, useful" << endl;
cout << "\t\t\t\tfor 'twitchy' joysticks)" << endl;
exit(0);
} else if (strcmp("--prop",argv[i])==0) {
usexml=false;
btninit=-1;
} else if (strcmp("--deadband",argv[i])==0) {
i++;
deadband=atoi(argv[i]);
cout << "Deadband set to " << argv[i] << endl;
} else if (strcmp("--xml",argv[i])!=0) {
cout << "Unknown option \"" << argv[i] << "\"" << endl;
exit(0);
} }
}
jsInit(); jsInit();
jsSuper *jss=new jsSuper(); jsSuper *jss = new jsSuper();
jsInput *jsi=new jsInput(jss); jsInput *jsi = new jsInput(jss);
jsi->displayValues(false); jsi->displayValues(false);
int control=0;
cout << "Found " << jss->getNumJoysticks() << " joystick(s)" << endl; cout << "Found " << jss->getNumJoysticks() << " joystick(s)" << endl;
if(jss->getNumJoysticks() <= 0) { if(jss->getNumJoysticks() <= 0) {
cout << "Can't find any joysticks ..." << endl; cout << "Can't find any joysticks ..." << endl;
exit(1); exit(1);
}
fstream fs;
fstream *xfs = new fstream[jss->getNumJoysticks()];
if (!usexml) {
fs.open("fgfsrc.js",ios::out);
}
jss->firstJoystick();
do {
cout << "Joystick #" << jss->getCurrentJoystickId()
<< " \"" << jss->getJoystick()->getName() << "\" has "
<< jss->getJoystick()->getNumAxes() << " axes" << endl;
for (int i=0; i<jss->getJoystick()->getNumAxes(); i++) {
jss->getJoystick()->setDeadBand(i,deadband);
} }
if (usexml) { cout << endl << "Now measuring the dead band of your joystick. The dead band is the area " << endl
char filename[16]; << "where the joystick is centered and should not generate any input. Move all " << endl
snprintf(filename,16,"js%i.xml",jss->getCurrentJoystickId()); << "axes around in this dead zone during the ten seconds this test will take." << endl;
xfs[jss->getCurrentJoystickId()].open(filename,ios::out); cout << "Press enter to continue." << endl;
xfs[jss->getCurrentJoystickId()] << "<?xml version=\"1.0\" ?>" << endl cin.ignore(1024, '\n');
<< endl << "<PropertyList>" << endl << endl << " <name>" jsi->findDeadBand();
<< jss->getJoystick()->getName() << "</name>" << endl << endl; cout << endl << "Dead band calibration finished. Press enter to start control assignment." << endl;
cin.ignore(1024, '\n');
jss->firstJoystick();
fstream *xfs = new fstream[ jss->getNumJoysticks() ];
SGPropertyNode_ptr *jstree = new SGPropertyNode_ptr[ jss->getNumJoysticks() ];
do {
cout << "Joystick #" << jss->getCurrentJoystickId()
<< " \"" << jss->getJoystick()->getName() << "\" has "
<< jss->getJoystick()->getNumAxes() << " axes" << endl;
char filename[16];
snprintf(filename, 16, "js%i.xml", jss->getCurrentJoystickId());
xfs[ jss->getCurrentJoystickId() ].open(filename, ios::out);
jstree[ jss->getCurrentJoystickId() ] = new SGPropertyNode();
} while ( jss->nextJoystick() );
SGPath templatefile( getFGRoot(argc, argv) );
templatefile.append("Input");
templatefile.append("Joysticks");
templatefile.append("template.xml");
SGPropertyNode *templatetree = new SGPropertyNode();
try {
readProperties(templatefile.str().c_str(), templatetree);
} catch (sg_io_exception e) {
cout << e.getFormattedMessage ();
} }
} while( jss->nextJoystick() );
for(control=0;control<=7;control++) { vector<SGPropertyNode_ptr> axes = templatetree->getChildren("axis");
cout << "Move the control you wish to use for " << axes_humannames[control] for(vector<SGPropertyNode_ptr>::iterator iter = axes.begin(); iter != axes.end(); iter++) {
<< " " << axis_posdir[control] << endl; cout << "Move the control you wish to use for " << (*iter)->getStringValue("desc")
cout << "Pressing a button skips this axis\n"; << " " << (*iter)->getStringValue("direction") << endl;
fflush( stdout ); cout << "Pressing a button skips this axis" << endl;
jsi->getInput(); fflush( stdout );
jsi->getInput();
if(jsi->getInputAxis() != -1) { if (jsi->getInputAxis() != -1) {
cout << endl << "Assigned axis " << jsi->getInputAxis() cout << endl << "Assigned axis " << jsi->getInputAxis()
<< " on joystick " << jsi->getInputJoystick() << " on joystick " << jsi->getInputJoystick()
<< " to control " << axes_humannames[control] << " to control " << (*iter)->getStringValue("desc") << endl;
<< endl; if ( confirmAnswer() ) {
bool badanswer=true; SGPropertyNode *axis = jstree[ jsi->getInputJoystick() ]->getChild("axis", jsi->getInputAxis(), true);
do { copyProperties(*iter, axis);
cout << "Is this correct? (y/n) $ "; axis->setDoubleValue("dead-band", jss->getJoystick(jsi->getInputJoystick())
cin >> answer; ->getDeadBand(jsi->getInputAxis()));
if ((strcmp(answer,"y")==0) || (strcmp(answer,"n")==0)) { badanswer=false; } axis->setDoubleValue("binding/factor", jsi->getInputAxisPositive() ? 1.0 : -1.0);
} while (badanswer); } else {
if (strcmp(answer,"n")==0) { iter--;
control--; }
} else { } else {
invert[control]=!jsi->getInputAxisPositive(); cout << "Skipping control" << endl;
if (usexml) { if ( ! confirmAnswer() )
writeAxisXML( xfs[jsi->getInputJoystick()], control, jsi->getInputAxis() ); iter--;
} else { }
writeAxisProperties( fs, control, jsi->getInputJoystick(), jsi->getInputAxis() ); cout << endl;
}
}
} else {
cout << "Skipping control" << endl;
bool badanswer=true;
do {
cout << "Is this correct? (y/n) $ ";
cin >> answer;
if ((strcmp(answer,"y")==0) || (strcmp(answer,"n")==0)) { badanswer=false; }
} while (badanswer);
if (strcmp(answer,"n")==0) { control--; }
}
cout << endl;
}
for(control=btninit;control<=7;control++) {
if ( control == -2 ) {
cout << "Press the button you wish to use for View Cycle" << endl;
} else if ( control == -1 ) {
cout << "Press the button you wish to use for Brakes" << endl;
} else {
cout << "Press the button you wish to use for " << button_humannames[control] << endl;
}
cout << "Moving a joystick axis skips this button\n";
fflush( stdout );
jsi->getInput();
if(jsi->getInputButton() != -1) {
cout << endl << "Assigned button " << jsi->getInputButton()
<< " on joystick " << jsi->getInputJoystick()
<< " to control ";
if ( control == -2 ) { cout << "View Cycle" << endl; }
else if ( control == -1 ) { cout << "Brakes" << endl; }
else { cout << button_humannames[control] << endl; }
bool badanswer=true;
do {
cout << "Is this correct? (y/n) $ ";
cin >> answer;
if ((strcmp(answer,"y")==0) || (strcmp(answer,"n")==0)) { badanswer=false; }
} while (badanswer);
if (strcmp(answer,"n")==0) {
control--;
} else {
if (usexml) {
writeButtonXML( xfs[jsi->getInputJoystick()], control, jsi->getInputButton() );
} else {
writeButtonProperties( fs, control, jsi->getInputJoystick(), jsi->getInputButton() );
}
}
} else {
cout << "Skipping control" << endl;
bool badanswer=true;
do {
cout << "Is this correct? (y/n) $ ";
cin >> answer;
if ((strcmp(answer,"y")==0) || (strcmp(answer,"n")==0)) { badanswer=false; }
} while (badanswer);
if (strcmp(answer,"n")==0) { control--; }
}
cout << endl;
}
if (usexml) {
for (int i=0; i<jss->getNumJoysticks(); i++) {
xfs[i] << "</PropertyList>" << endl << endl << "<!-- end of joystick.xml -->" << endl;
xfs[i].close();
} }
} else {
fs.close();
}
delete jsi;
delete[] xfs;
delete jss;
cout << "Your joystick settings are in "; vector<SGPropertyNode_ptr> buttons = templatetree->getChildren("button");
if (usexml) { for(vector<SGPropertyNode_ptr>::iterator iter = buttons.begin(); iter != buttons.end(); iter++) {
cout << "js0.xml, js1.xml, etc. depending on how many" << endl << "devices you have." << endl; cout << "Press the button you wish to use for " << (*iter)->getStringValue("desc") << endl;
} else { cout << "Moving a joystick axis skips this button" << endl;
cout << "fgfsrc.js" << endl; fflush( stdout );
} jsi->getInput();
cout << endl << "Check and edit as desired. Once you are happy," << endl; if (jsi->getInputButton() != -1) {
if (usexml) { cout << endl << "Assigned button " << jsi->getInputButton()
cout << "move relevant js<n>.xml files to $FG_ROOT/Input/Joysticks/ (if you didn't use" << endl << " on joystick " << jsi->getInputJoystick()
<< " to control " << (*iter)->getStringValue("desc") << endl;
if ( confirmAnswer() ) {
SGPropertyNode *button = jstree[ jsi->getInputJoystick() ]->getChild("button", jsi->getInputButton(), true);
copyProperties(*iter, button);
} else {
iter--;
}
} else {
cout << "Skipping control" << endl;
if (! confirmAnswer())
iter--;
}
cout << endl;
}
cout << "Your joystick settings are in ";
for (int i = 0; i < jss->getNumJoysticks(); i++) {
try {
cout << "js" << i << ".xml";
if (i + 2 < jss->getNumJoysticks())
cout << ", ";
else if (i + 1 < jss->getNumJoysticks())
cout << " and ";
jstree[i]->setStringValue("name", jss->getJoystick(i)->getName());
writeProperties(xfs[i], jstree[i], true);
} catch (sg_io_exception e) {
cout << e.getFormattedMessage ();
}
xfs[i].close();
}
cout << "." << endl << "Check and edit as desired. Once you are happy," << endl
<< "move relevant js<n>.xml files to $FG_ROOT/Input/Joysticks/ (if you didn't use" << endl
<< "an attached controller, you don't need to move the corresponding file)" << endl; << "an attached controller, you don't need to move the corresponding file)" << endl;
} else {
cout << "append its contents to your .fgfsrc or system.fgfsrc" << endl;
}
return 1; delete jsi;
delete[] xfs;
delete jss;
return 1;
}
char *homedir = ::getenv( "HOME" );
char *hostname = ::getenv( "HOSTNAME" );
bool free_hostname = false;
// Scan the command line options for the specified option and return
// the value.
static string fgScanForOption( const string& option, int argc, char **argv ) {
int i = 1;
if (hostname == NULL)
{
char _hostname[256];
gethostname(_hostname, 256);
hostname = strdup(_hostname);
free_hostname = true;
}
SG_LOG(SG_GENERAL, SG_INFO, "Scanning command line for: " << option );
int len = option.length();
while ( i < argc ) {
SG_LOG( SG_GENERAL, SG_DEBUG, "argv[" << i << "] = " << argv[i] );
string arg = argv[i];
if ( arg.find( option ) == 0 ) {
return arg.substr( len );
}
i++;
}
return "";
}
// Scan the user config files for the specified option and return
// the value.
static string fgScanForOption( const string& option, const string& path ) {
sg_gzifstream in( path );
if ( !in.is_open() ) {
return "";
}
SG_LOG( SG_GENERAL, SG_INFO, "Scanning " << path << " for: " << option );
int len = option.length();
in >> skipcomment;
#ifndef __MWERKS__
while ( ! in.eof() ) {
#else
char c = '\0';
while ( in.get(c) && c != '\0' ) {
in.putback(c);
#endif
string line;
#if defined( macintosh )
getline( in, line, '\r' );
#else
getline( in, line, '\n' );
#endif
// catch extraneous (DOS) line ending character
if ( line[line.length() - 1] < 32 ) {
line = line.substr( 0, line.length()-1 );
}
if ( line.find( option ) == 0 ) {
return line.substr( len );
}
in >> skipcomment;
}
return "";
}
// Scan the user config files for the specified option and return
// the value.
static string fgScanForOption( const string& option ) {
string arg("");
#if defined( unix ) || defined( __CYGWIN__ )
// Next check home directory for .fgfsrc.hostname file
if ( arg.empty() ) {
if ( homedir != NULL ) {
SGPath config( homedir );
config.append( ".fgfsrc" );
config.concat( "." );
config.concat( hostname );
arg = fgScanForOption( option, config.str() );
}
}
#endif
// Next check home directory for .fgfsrc file
if ( arg.empty() ) {
if ( homedir != NULL ) {
SGPath config( homedir );
config.append( ".fgfsrc" );
arg = fgScanForOption( option, config.str() );
}
}
return arg;
}
// Read in configuration (files and command line options) but only set
// fg_root
string getFGRoot ( int argc, char **argv ) {
string root;
// First parse command line options looking for --fg-root=, this
// will override anything specified in a config file
root = fgScanForOption( "--fg-root=", argc, argv);
// Check in one of the user configuration files.
if (root.empty() )
root = fgScanForOption( "--fg-root=" );
// Next check if fg-root is set as an env variable
if ( root.empty() ) {
char *envp = ::getenv( "FG_ROOT" );
if ( envp != NULL ) {
root = envp;
}
}
// Otherwise, default to a random compiled-in location if we can't
// find fg-root any other way.
if ( root.empty() ) {
#if defined( __CYGWIN__ )
root = "/FlightGear";
#elif defined( WIN32 )
root = "\\FlightGear";
#elif defined(OSX_BUNDLE)
/* the following code looks for the base package directly inside
the application bundle. This can be changed fairly easily by
fiddling with the code below. And yes, I know it's ugly and verbose.
*/
CFBundleRef appBundle = CFBundleGetMainBundle();
CFURLRef appUrl = CFBundleCopyBundleURL(appBundle);
CFRelease(appBundle);
// look for a 'data' subdir directly inside the bundle : is there
// a better place? maybe in Resources? I don't know ...
CFURLRef dataDir = CFURLCreateCopyAppendingPathComponent(NULL, appUrl, CFSTR("data"), true);
// now convert down to a path, and the a c-string
CFStringRef path = CFURLCopyFileSystemPath(dataDir, kCFURLPOSIXPathStyle);
root = CFStringGetCStringPtr(path, CFStringGetSystemEncoding());
// tidy up.
CFRelease(appBundle);
CFRelease(dataDir);
CFRelease(path);
#else
root = PKGLIBDIR;
#endif
}
SG_LOG(SG_INPUT, SG_INFO, "fg_root = " << root );
return root;
} }

View file

@ -18,100 +18,161 @@
// along with this program; if not, write to the Free Software // along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include <simgear/compiler.h>
#include STL_IOSTREAM
SG_USING_STD(cout);
SG_USING_STD(cin);
SG_USING_STD(endl);
#include "jsinput.h" #include "jsinput.h"
jsInput::jsInput(jsSuper *j) { jsInput::jsInput(jsSuper *j) {
jss=j; jss=j;
pretty_display=true; pretty_display=true;
joystick=axis=button=-1; joystick=axis=button=-1;
axis_threshold=0.2; axis_threshold=0.2;
} }
jsInput::~jsInput(void) {} jsInput::~jsInput(void) {}
int jsInput::getInput(){ int jsInput::getInput() {
bool gotit=false;
float delta;
int i, current_button = 0, button_bits = 0;
joystick=axis=button=-1; bool gotit=false;
axis_positive=false;
if(pretty_display) {
printf ( "+----------------------------------------------\n" ) ;
printf ( "| Btns " ) ;
for ( i = 0 ; i < jss->getJoystick()->getNumAxes() ; i++ ) float delta;
printf ( "Ax:%1d ", i ) ; int i, current_button = 0, button_bits = 0;
for ( ; i < 8 ; i++ ) joystick=axis=button=-1;
axis_positive=false;
if(pretty_display) {
printf ( "+----------------------------------------------\n" ) ;
printf ( "| Btns " ) ;
for ( i = 0 ; i < jss->getJoystick()->getNumAxes() ; i++ )
printf ( "Ax:%3d ", i ) ;
for ( ; i < 8 ; i++ )
printf ( " " ) ; printf ( " " ) ;
printf ( "|\n" ) ; printf ( "|\n" ) ;
printf ( "+----------------------------------------------\n" ) ; printf ( "+----------------------------------------------\n" ) ;
} }
jss->firstJoystick();
do { jss->firstJoystick();
do {
jss->getJoystick()->read ( &button_iv[jss->getCurrentJoystickId()], jss->getJoystick()->read ( &button_iv[jss->getCurrentJoystickId()],
axes_iv[jss->getCurrentJoystickId()] ) ; axes_iv[jss->getCurrentJoystickId()] ) ;
} while( jss->nextJoystick() ); } while( jss->nextJoystick() );
while(!gotit) { while(!gotit) {
jss->firstJoystick(); jss->firstJoystick();
do { do {
jss->getJoystick()->read ( &current_button, axes ) ; jss->getJoystick()->read ( &current_button, axes ) ;
if(pretty_display) printf ( "| %04x ", current_button ) ; if(pretty_display) printf ( "| %04x ", current_button ) ;
for ( i = 0 ; i < jss->getJoystick()->getNumAxes(); i++ ) { for ( i = 0 ; i < jss->getJoystick()->getNumAxes(); i++ ) {
delta = axes[i] - axes_iv[jss->getCurrentJoystickId()][i]; delta = axes[i] - axes_iv[jss->getCurrentJoystickId()][i];
if(pretty_display) printf ( "%+.1f ", delta ) ; if(pretty_display) printf ( "%+.3f ", delta ) ;
if(!gotit) { if(!gotit) {
if( fabs(delta) > axis_threshold ) { if( fabs(delta) > axis_threshold ) {
gotit=true; gotit=true;
joystick=jss->getCurrentJoystickId(); joystick=jss->getCurrentJoystickId();
axis=i; axis=i;
axis_positive=(delta>0); axis_positive=(delta>0);
} else if( current_button != 0 ) { } else if( current_button != 0 ) {
gotit=true; gotit=true;
joystick=jss->getCurrentJoystickId(); joystick=jss->getCurrentJoystickId();
button_bits=current_button; button_bits=current_button;
} }
} }
} }
if(pretty_display) { if(pretty_display) {
for ( ; i < 8 ; i++ ) for ( ; i < 8 ; i++ )
printf ( " . " ) ; printf ( " . " ) ;
} }
} while( jss->nextJoystick() && !gotit); } while( jss->nextJoystick() && !gotit);
if(pretty_display) { if(pretty_display) {
printf ( "|\r" ) ; printf ( "|\r" ) ;
fflush ( stdout ) ; fflush ( stdout ) ;
} }
ulMilliSecondSleep(1); ulMilliSecondSleep(1);
} }
if(button_bits != 0) { if(button_bits != 0) {
for(int i=0;i<=31;i++) { for(int i=0;i<=31;i++) {
if( ( button_bits & (1 << i) ) > 0 ) { if( ( button_bits & (1 << i) ) > 0 ) {
button=i; button=i;
break; break;
} }
} }
} }
return 0; return 0;
}
void jsInput::findDeadBand() {
float delta;
int i;
float dead_band[MAX_JOYSTICKS][_JS_MAX_AXES];
jss->firstJoystick();
do {
jss->getJoystick()->read ( NULL,
axes_iv[jss->getCurrentJoystickId()] ) ;
for ( i = 0; i < jss->getJoystick()->getNumAxes(); i++ ) {
dead_band[jss->getCurrentJoystickId()][i] = 0;
}
} while( jss->nextJoystick() );
ulClock clock;
cout << 10;
cout.flush();
for (int j = 9; j >= 0; j--) {
double start_time = clock.getAbsTime();
do {
jss->firstJoystick();
do {
jss->getJoystick()->read ( NULL, axes ) ;
for ( i = 0 ; i < jss->getJoystick()->getNumAxes(); i++ ) {
delta = axes[i] - axes_iv[jss->getCurrentJoystickId()][i];
if (fabs(delta) > dead_band[jss->getCurrentJoystickId()][i])
dead_band[jss->getCurrentJoystickId()][i] = delta;
}
} while( jss->nextJoystick());
ulMilliSecondSleep(1);
clock.update();
} while (clock.getAbsTime() - start_time < 1.0);
cout << " - " << j;
cout.flush();
}
cout << endl << endl;
jss->firstJoystick();
do {
for ( i = 0; i < jss->getJoystick()->getNumAxes(); i++ ) {
jss->getJoystick()->setDeadBand(i, dead_band[jss->getCurrentJoystickId()][i]);
printf("Joystick %i, axis %i: %f\n", jss->getCurrentJoystickId(), i, dead_band[jss->getCurrentJoystickId()][i]);
}
} while( jss->nextJoystick() );
} }

View file

@ -32,29 +32,30 @@ class jsInput {
float axes[_JS_MAX_AXES]; float axes[_JS_MAX_AXES];
float axes_iv[MAX_JOYSTICKS][_JS_MAX_AXES]; float axes_iv[MAX_JOYSTICKS][_JS_MAX_AXES];
int button_iv[MAX_JOYSTICKS]; int button_iv[MAX_JOYSTICKS];
int joystick,axis,button; int joystick,axis,button;
bool axis_positive; bool axis_positive;
float axis_threshold; float axis_threshold;
public: public:
jsInput(jsSuper *jss); jsInput(jsSuper *jss);
~jsInput(void); ~jsInput(void);
inline void displayValues(bool bb) { pretty_display=bb; } inline void displayValues(bool bb) { pretty_display=bb; }
int getInput(void); int getInput(void);
void findDeadBand(void);
inline int getInputJoystick(void) { return joystick; } inline int getInputJoystick(void) { return joystick; }
inline int getInputAxis(void) { return axis; } inline int getInputAxis(void) { return axis; }
inline int getInputButton(void) { return button; } inline int getInputButton(void) { return button; }
inline bool getInputAxisPositive(void) { return axis_positive; } inline bool getInputAxisPositive(void) { return axis_positive; }
inline float getReturnThreshold(void) { return axis_threshold; } inline float getReturnThreshold(void) { return axis_threshold; }
inline void setReturnThreshold(float ff) inline void setReturnThreshold(float ff)
{ if(fabs(ff) <= 1.0) axis_threshold=ff; } { if(fabs(ff) <= 1.0) axis_threshold=ff; }
}; };
#endif #endif