Melchior FRANZ wrote:
I found the old code quite horrible, even after the last improvements.
The new method is without any doubt superior. If nobody objects, then
I'll commit that tomorrow. Some things should IMHO get improved:
New version attached. I added some more info about the dead band
detection, as well as a wait for pressing enter before and after this
detection (to prevent the movements getting interpreted as the answer to
the first axis question). Suggestions for a better explanation are very
welcome of course.
I assume that the template.xml shouldn't really contain (odd) <deadband>
values already.
I removed them in the attached template.xml. They were in because I used
my joystick config file as template.xml.
I hope someone who actually knows something about joystick configs will
provide a better template though (which is half of the point of the
exercise).
And then it would be nice if the app would at the beginning
repeat how many axes & buttons are available.
Available in the template, or available on the found joysticks?
The alternating query of
keyboard and joystick buttons is IMHO a usability bug. It's confusing
if joystick buttons are used for pointing to buttons *and* to confirm
program input. Better make joystick input for pointing to js buttons/axes
*only*, and keyboard keys for switching to the next step.
You're right, I hate this, too. Will change it, but first have to find
out how to make it better. There must be a better way than cin to get
keyboard input, but I have no idea about cross platform stuff, so I'd
appreciate some pointers here on how to do that.
Thanks for reviewing,
Nine
Index: src/Input/Makefile.am
===================================================================
RCS file: /var/cvs/FlightGear-0.9/source/src/Input/Makefile.am,v
retrieving revision 1.6
diff -u -3 -p -r1.6 Makefile.am
--- src/Input/Makefile.am 24 Jan 2005 10:17:14 -0000 1.6
+++ src/Input/Makefile.am 4 Jul 2006 21:24:44 -0000
@@ -1,3 +1,5 @@
+AM_CXXFLAGS = -DPKGLIBDIR=\"$(pkgdatadir)\"
+
noinst_LIBRARIES = libInput.a
libInput_a_SOURCES = input.cxx input.hxx
@@ -10,6 +12,7 @@ js_demo_LDADD = -lplibjs $(base_LIBS) $(
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
Index: src/Input/fgjs.cxx
===================================================================
RCS file: /var/cvs/FlightGear-0.9/source/src/Input/fgjs.cxx,v
retrieving revision 1.9
diff -u -3 -p -r1.9 fgjs.cxx
--- src/Input/fgjs.cxx 21 Feb 2006 01:18:51 -0000 1.9
+++ src/Input/fgjs.cxx 4 Jul 2006 21:24:44 -0000
@@ -38,460 +38,329 @@ SG_USING_STD(endl);
SG_USING_STD(ios);
SG_USING_STD(string);
-string axes_humannames[8] = { "Aileron", "Elevator", "Rudder", "Throttle",
- "Mixture", "Pitch", "View Direction",
- "View Elevation"
- };
-
-string axes_propnames[8]={ "/controls/flight/aileron","/controls/flight/elevator",
- "/controls/flight/rudder","/controls/engines/engine[%d]/throttle",
- "/controls/engines/engine[%d]/mixture","/controls/engines/engine[%d]/pitch",
- "/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" };
-
-
-bool half_range[8]={ false,false,false,true,true,true,false,false };
-
-bool repeatable[8]={ false,false,false,false,false,false,true,true };
-
-bool invert[8]= { false,false,false,false,false,false,false,false };
-
-string button_humannames[8]= { "Left Brake", "Right Brake",
- "Flaps Up", "Flaps Down",
- "Elevator Trim Forward", "Elevator Trim Backward",
- "Landing Gear Up", "Landing Gear Down"
- };
-
-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;
+#include <simgear/constants.h>
+#include <simgear/debug/logstream.hxx>
+#include <simgear/misc/sg_path.hxx>
+#include <simgear/misc/sgstream.hxx>
+#include <simgear/structure/exception.hxx>
+#include "fg_io.hxx"
+#include "fg_props.hxx"
+#include "globals.hxx"
+
+bool confirmAnswer() {
+ char answer;
+ do {
+ cout << "Is this correct? (y/n) $ ";
+ cin >> answer;
+ cin.ignore(256, '\n');
+ if (answer == 'y')
+ return true;
+ if (answer == 'n')
+ return false;
+ } while (true);
}
-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;
+int main( int argc, char *argv[] ) {
+
+ for (int i = 1; i < argc; i++) {
+ if (strcmp("--help", argv[i]) == 0) {
+ cout << "Usage:" << endl;
+ cout << " --help\t\t\tShow this help" << endl;
+ exit(0);
+ } else {
+ cout << "Unknown option \"" << argv[i] << "\"" << endl;
+ exit(0);
+ }
+ }
+
+ jsInit();
+
+ jsSuper *jss = new jsSuper();
+ jsInput *jsi = new jsInput(jss);
+ jsi->displayValues(false);
+
+ cout << "Found " << jss->getNumJoysticks() << " joystick(s)" << endl;
+
+ if(jss->getNumJoysticks() <= 0) {
+ cout << "Can't find any joysticks ..." << endl;
+ exit(1);
+ }
+ cout << endl << "Now measuring the dead band of your joystick. The dead band is the area where the joystick is centered and should not generate any input. Move all axis around in this dead zone during the ten seconds this test will take." << endl;
+ cout << "Press enter to continue." << endl;
+ cin.ignore(1024, '\n');
+ jsi->findDeadBand();
+ 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 ();
+ }
+
+ vector<SGPropertyNode_ptr> axes = templatetree->getChildren("axis");
+ for(vector<SGPropertyNode_ptr>::iterator iter = axes.begin(); iter != axes.end(); iter++) {
+ bool next = true;
+ cout << "Move the control you wish to use for " << (*iter)->getStringValue("desc")
+ << " " << (*iter)->getStringValue("direction") << endl;
+ cout << "Pressing a button skips this axis" << endl;
+ fflush( stdout );
+ jsi->getInput();
+ if (jsi->getInputAxis() != -1) {
+ cout << endl << "Assigned axis " << jsi->getInputAxis()
+ << " on joystick " << jsi->getInputJoystick()
+ << " to control " << (*iter)->getStringValue("desc") << endl;
+ if ( confirmAnswer() ) {
+ SGPropertyNode *axis = jstree[ jsi->getInputJoystick() ]->getChild("axis", jsi->getInputAxis(), true);
+ copyProperties(*iter, axis);
+ axis->setDoubleValue("dead-band", jss->getJoystick(jsi->getInputJoystick())->getDeadBand(jsi->getInputAxis()));
+ axis->setDoubleValue("binding/factor", jsi->getInputAxisPositive() ? 1.0 : -1.0);
+ } else {
+ iter--;
+ }
+ } else {
+ cout << "Skipping control" << endl;
+ if ( ! confirmAnswer() )
+ iter--;
+ }
+ cout << endl;
+ }
+
+ vector<SGPropertyNode_ptr> buttons = templatetree->getChildren("button");
+ for(vector<SGPropertyNode_ptr>::iterator iter = buttons.begin(); iter != buttons.end(); iter++) {
+ bool next = true;
+ cout << "Press the button you wish to use for " << (*iter)->getStringValue("desc") << endl;
+ cout << "Moving a joystick axis skips this button" << endl;
+ fflush( stdout );
+ jsi->getInput();
+ if (jsi->getInputButton() != -1) {
+ cout << endl << "Assigned button " << jsi->getInputButton()
+ << " 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 ";
+ 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;
+
+ 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 "";
}
-void writeButtonXML(fstream &fs, int property, int button) {
+// 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 );
- char buttonline[32];
- snprintf(buttonline,32," <button n=\"%d\">",button);
+ int len = option.length();
- 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;
+ 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 "";
}
-void writeButtonProperties(fstream &fs, int property,int joystick, int button) {
+// 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
- char jsDesc[80];
- snprintf(jsDesc,80,"--prop:/input/joysticks/js[%d]/button[%d]",joystick,button);
+ // Next check home directory for .fgfsrc file
+ if ( arg.empty() ) {
+ if ( homedir != NULL ) {
+ SGPath config( homedir );
+ config.append( ".fgfsrc" );
+ arg = fgScanForOption( option, config.str() );
+ }
+ }
- 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;
- }
+ return arg;
}
-int main( int argc, char *argv[] ) {
+// 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;
+ }
+ }
- bool usexml=true;
- float deadband=0;
- char answer[128];
- int btninit=-2;
-
- for (int i=1; i<argc; i++) {
- if (strcmp("--help",argv[i])==0) {
- cout << "Usage:" << endl;
- 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();
-
- jsSuper *jss=new jsSuper();
- jsInput *jsi=new jsInput(jss);
- jsi->displayValues(false);
- int control=0;
-
- cout << "Found " << jss->getNumJoysticks() << " joystick(s)" << endl;
-
- if(jss->getNumJoysticks() <= 0) {
- cout << "Can't find any joysticks ..." << endl;
- 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) {
- char filename[16];
- snprintf(filename,16,"js%i.xml",jss->getCurrentJoystickId());
- xfs[jss->getCurrentJoystickId()].open(filename,ios::out);
- xfs[jss->getCurrentJoystickId()] << "<?xml version=\"1.0\" ?>" << endl
- << endl << "<PropertyList>" << endl << endl << " <name>"
- << jss->getJoystick()->getName() << "</name>" << endl << endl;
- }
- } while( jss->nextJoystick() );
-
- for(control=0;control<=7;control++) {
- cout << "Move the control you wish to use for " << axes_humannames[control]
- << " " << axis_posdir[control] << endl;
- cout << "Pressing a button skips this axis\n";
- fflush( stdout );
- jsi->getInput();
-
- if(jsi->getInputAxis() != -1) {
- cout << endl << "Assigned axis " << jsi->getInputAxis()
- << " on joystick " << jsi->getInputJoystick()
- << " to control " << axes_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 {
- invert[control]=!jsi->getInputAxisPositive();
- if (usexml) {
- writeAxisXML( xfs[jsi->getInputJoystick()], control, jsi->getInputAxis() );
- } else {
- writeAxisProperties( fs, control, jsi->getInputJoystick(), jsi->getInputAxis() );
- }
- }
- } 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 ";
- if (usexml) {
- cout << "js0.xml, js1.xml, etc. depending on how many" << endl << "devices you have." << endl;
- } else {
- cout << "fgfsrc.js" << endl;
- }
- cout << endl << "Check and edit as desired. Once you are happy," << endl;
- if (usexml) {
- cout << "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;
- } else {
- cout << "append its contents to your .fgfsrc or system.fgfsrc" << endl;
- }
+ // 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 1;
+ return root;
}
Index: src/Input/jsinput.cxx
===================================================================
RCS file: /var/cvs/FlightGear-0.9/source/src/Input/jsinput.cxx,v
retrieving revision 1.3
diff -u -3 -p -r1.3 jsinput.cxx
--- src/Input/jsinput.cxx 21 Feb 2006 01:18:51 -0000 1.3
+++ src/Input/jsinput.cxx 4 Jul 2006 21:24:44 -0000
@@ -21,97 +21,141 @@
#include "jsinput.h"
jsInput::jsInput(jsSuper *j) {
- jss=j;
- pretty_display=true;
- joystick=axis=button=-1;
- axis_threshold=0.2;
+ jss=j;
+ pretty_display=true;
+ joystick=axis=button=-1;
+ axis_threshold=0.2;
}
jsInput::~jsInput(void) {}
-int jsInput::getInput(){
-
- bool gotit=false;
-
- float delta;
- int i, current_button = 0, button_bits = 0;
-
- joystick=axis=button=-1;
- axis_positive=false;
-
- if(pretty_display) {
- printf ( "+----------------------------------------------\n" ) ;
- printf ( "| Btns " ) ;
+int jsInput::getInput() {
- for ( i = 0 ; i < jss->getJoystick()->getNumAxes() ; i++ )
- printf ( "Ax:%1d ", i ) ;
+ bool gotit=false;
- for ( ; i < 8 ; i++ )
+ float delta;
+ int i, current_button = 0, button_bits = 0;
+
+ 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 ( "|\n" ) ;
+ printf ( "|\n" ) ;
+
+ printf ( "+----------------------------------------------\n" ) ;
+ }
- printf ( "+----------------------------------------------\n" ) ;
- }
-
- jss->firstJoystick();
- do {
+ jss->firstJoystick();
+ do {
jss->getJoystick()->read ( &button_iv[jss->getCurrentJoystickId()],
- axes_iv[jss->getCurrentJoystickId()] ) ;
- } while( jss->nextJoystick() );
-
-
-
- while(!gotit) {
+ axes_iv[jss->getCurrentJoystickId()] ) ;
+ } while( jss->nextJoystick() );
+
+
+
+ while(!gotit) {
jss->firstJoystick();
do {
- jss->getJoystick()->read ( ¤t_button, axes ) ;
+ jss->getJoystick()->read ( ¤t_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];
- if(pretty_display) printf ( "%+.1f ", delta ) ;
- if(!gotit) {
- if( fabs(delta) > axis_threshold ) {
- gotit=true;
- joystick=jss->getCurrentJoystickId();
- axis=i;
- axis_positive=(delta>0);
- } else if( current_button != 0 ) {
- gotit=true;
- joystick=jss->getCurrentJoystickId();
- button_bits=current_button;
- }
- }
- }
-
- if(pretty_display) {
- for ( ; i < 8 ; i++ )
- printf ( " . " ) ;
- }
+ delta = axes[i] - axes_iv[jss->getCurrentJoystickId()][i];
+ if(pretty_display) printf ( "%+.3f ", delta ) ;
+ if(!gotit) {
+ if( fabs(delta) > axis_threshold ) {
+ gotit=true;
+ joystick=jss->getCurrentJoystickId();
+ axis=i;
+ axis_positive=(delta>0);
+ } else if( current_button != 0 ) {
+ gotit=true;
+ joystick=jss->getCurrentJoystickId();
+ button_bits=current_button;
+ }
+ }
+ }
+
+ if(pretty_display) {
+ for ( ; i < 8 ; i++ )
+ printf ( " . " ) ;
+ }
- } while( jss->nextJoystick() && !gotit);
+ } while( jss->nextJoystick() && !gotit);
if(pretty_display) {
- printf ( "|\r" ) ;
- fflush ( stdout ) ;
+ printf ( "|\r" ) ;
+ fflush ( stdout ) ;
}
ulMilliSecondSleep(1);
- }
- if(button_bits != 0) {
+ }
+ if(button_bits != 0) {
for(int i=0;i<=31;i++) {
- if( ( button_bits & (1 << i) ) > 0 ) {
- button=i;
- break;
- }
- }
- }
+ if( ( button_bits & (1 << i) ) > 0 ) {
+ button=i;
+ break;
+ }
+ }
+ }
+
+ return 0;
+}
+
+void jsInput::findDeadBand() {
- return 0;
+ 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;
+ 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 < 10.0);
+
+ 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() );
}
-
Index: src/Input/jsinput.h
===================================================================
RCS file: /var/cvs/FlightGear-0.9/source/src/Input/jsinput.h,v
retrieving revision 1.3
diff -u -3 -p -r1.3 jsinput.h
--- src/Input/jsinput.h 21 Feb 2006 01:18:51 -0000 1.3
+++ src/Input/jsinput.h 4 Jul 2006 21:24:44 -0000
@@ -32,29 +32,30 @@ class jsInput {
float axes[_JS_MAX_AXES];
float axes_iv[MAX_JOYSTICKS][_JS_MAX_AXES];
int button_iv[MAX_JOYSTICKS];
-
+
int joystick,axis,button;
bool axis_positive;
-
+
float axis_threshold;
-
+
public:
jsInput(jsSuper *jss);
- ~jsInput(void);
-
+ ~jsInput(void);
+
inline void displayValues(bool bb) { pretty_display=bb; }
-
+
int getInput(void);
-
+ void findDeadBand(void);
+
inline int getInputJoystick(void) { return joystick; }
inline int getInputAxis(void) { return axis; }
inline int getInputButton(void) { return button; }
inline bool getInputAxisPositive(void) { return axis_positive; }
-
+
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; }
-};
+};
#endif
<?xml version="1.0" ?>
<PropertyList>
<name>Joystick Configuration Template</name>
<axis n="0">
<desc>Aileron</desc>
<direction>right</direction>
<binding>
<command>property-scale</command>
<property>/controls/flight/aileron</property>
<offset type="double">0.0</offset>
<factor type="double">1.0</factor>
</binding>
</axis>
<axis n="1">
<desc>Elevator</desc>
<direction>down/forward</direction>
<binding>
<command>property-scale</command>
<property>/controls/flight/elevator</property>
<factor type="double">-1.0</factor>
</binding>
</axis>
<axis n="2">
<desc>Rudder</desc>
<direction>right</direction>
<binding>
<command>property-scale</command>
<property>/controls/flight/rudder</property>
<factor type="double">1.0</factor>
</binding>
</axis>
<axis n="3">
<desc>Throttle</desc>
<direction>forward</direction>
<binding>
<command>nasal</command>
<script>controls.throttleAxis()</script>
</binding>
</axis>
<axis n="4">
<desc>View Direction</desc>
<direction>left</direction>
<low>
<repeatable>true</repeatable>
<binding>
<command>property-adjust</command>
<property>/sim/current-view/goal-heading-offset-deg</property>
<step type="double">1.0</step>
</binding>
</low>
<high>
<repeatable>true</repeatable>
<binding>
<command>property-adjust</command>
<property>/sim/current-view/goal-heading-offset-deg</property>
<step type="double">-1.0</step>
</binding>
</high>
</axis>
<axis n="5">
<desc>View Elevation</desc>
<direction>upward</direction>
<low>
<repeatable>true</repeatable>
<binding>
<command>property-adjust</command>
<property>/sim/current-view/goal-pitch-offset-deg</property>
<step type="double">1.0</step>
</binding>
</low>
<high>
<repeatable>true</repeatable>
<binding>
<command>property-adjust</command>
<property>/sim/current-view/goal-pitch-offset-deg</property>
<step type="double">-1.0</step>
</binding>
</high>
</axis>
<button n="0">
<desc>View Cycle</desc>
<repeatable>false</repeatable>
<binding>
<command>view-cycle</command>
<step type="double">1</step>
</binding>
</button>
<button n="1">
<desc>Brakes</desc>
<binding>
<command>nasal</command>
<script>controls.applyBrakes(1)</script>
</binding>
<mod-up>
<binding>
<command>nasal</command>
<script>controls.applyBrakes(0)</script>
</binding>
</mod-up>
</button>
<button n="2">
<desc>Left Brake</desc>
<binding>
<command>nasal</command>
<script>controls.applyBrakes(1, -1)</script>
</binding>
<mod-up>
<binding>
<command>nasal</command>
<script>controls.applyBrakes(0, -1)</script>
</binding>
</mod-up>
</button>
<button n="3">
<desc>Right Brake</desc>
<binding>
<command>nasal</command>
<script>controls.applyBrakes(1, 1)</script>
</binding>
<mod-up>
<binding>
<command>nasal</command>
<script>controls.applyBrakes(0, 1)</script>
</binding>
</mod-up>
</button>
<button n="4">
<desc>Flaps Up</desc>
<repeatable>false</repeatable>
<binding>
<command>nasal</command>
<script>controls.flapsDown(-1)</script>
</binding>
<mod-up>
<binding>
<command>nasal</command>
<script>controls.flapsDown(0)</script>
</binding>
</mod-up>
</button>
<button n="5">
<desc>Flaps Down</desc>
<repeatable>false</repeatable>
<binding>
<command>nasal</command>
<script>controls.flapsDown(1)</script>
</binding>
<mod-up>
<binding>
<command>nasal</command>
<script>controls.flapsDown(0)</script>
</binding>
</mod-up>
</button>
<button n="6">
<desc>Elevator Trim Forward</desc>
<repeatable>true</repeatable>
<binding>
<command>property-adjust</command>
<property>/controls/flight/elevator-trim</property>
<step type="double">0.001</step>
</binding>
</button>
<button n="7">
<desc>Elevator Trim Backward</desc>
<repeatable>true</repeatable>
<binding>
<command>property-adjust</command>
<property>/controls/flight/elevator-trim</property>
<step type="double">-0.001</step>
</binding>
</button>
<button n="8">
<desc>Landing Gear Toggle</desc>
<repeatable>false</repeatable>
<binding>
<command>nasal</command>
<script>controls.gearToggle()</script>
</binding>
</button>
</PropertyList>
<!-- end of joystick.xml -->
Using Tomcat but need to do more? Need to support web services, security?
Get stuff done quickly with pre-integrated technology to make your job easier
Download IBM WebSphere Application Server v.1.0.1 based on Apache Geronimo
http://sel.as-us.falkag.net/sel?cmd=lnk&kid=120709&bid=263057&dat=121642
_______________________________________________
Flightgear-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/flightgear-devel