]> git.mxchange.org Git - flightgear.git/blobdiff - src/Input/fgjs.cxx
MSVC9 fix
[flightgear.git] / src / Input / fgjs.cxx
index a5dcffa6cf195c9b41f93df01e1acc4da02a9559..9391c022afd879447c73db2e4790c698f4664a86 100644 (file)
@@ -1,8 +1,12 @@
 // fgjs.cxx -- assign joystick axes to flightgear properties
 //
+// Updated to allow xml output & added a few bits & pieces
+// Laurie Bradshaw, Jun 2005
+//
 // Written by Tony Peden, started May 2001
 //
 // Copyright (C) 2001  Tony Peden (apeden@earthlink.net)
+// Copyright (C) 2006  Stefan Seifert
 //
 // This program is free software; you can redistribute it and/or
 // modify it under the terms of the GNU General Public License as
 //
 // You should have received a copy of the GNU General Public License
 // along with this program; if not, write to the Free Software
-// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
 
 #include <simgear/compiler.h>
 
+#ifdef _WIN32
+#  include <winsock2.h>
+#endif
+
 #include <math.h>
 
-#include STL_IOSTREAM
-#include STL_FSTREAM
-#include STL_STRING
-
-#include <jsinput.h>
-
-SG_USING_STD(fstream);
-SG_USING_STD(cout);
-SG_USING_STD(endl);
-SG_USING_STD(ios);
-SG_USING_STD(string);
-
-string axes_humannames[8] = { "elevator", "ailerons", "rudder", "throttle", 
-                              "mixture","propller pitch", "lateral view", 
-                              "longitudinal view" 
-                            };
-
-string axes_propnames[8]={ "/controls/elevator","/controls/aileron",
-                           "/controls/rudder","/controls/throttle",
-                           "/controls/mixture","/controls/pitch", 
-                           "/sim/views/axes/lat","/sim/views/axes/long" 
-                         };
-                      
-bool half_range[8]={ false,false,false,true,true,true,false,false };
-
-
-string button_humannames[7]= { "apply all brakes", "apply left brake", 
-                               "apply right brake", "step flaps up", 
-                               "step flaps down","apply nose-up trim",
-                               "apply nose-down trim"
-                             }; 
-
-string button_propnames[7]={ "/controls/brakes/all", "/controls/brakes[0]",
-                             "/controls/brakes[1]", "/controls/flaps",
-                             "/controls/flaps","/controls/elevator-trim",
-                             "/controls/elevator-trim" 
-                           };                                                   
-
-float button_step[7]={ 1.0, 1.0, 1.0, 0.34, -0.34, 0.001, -0.001 };
-
-string button_repeat[7]={ "false", "false", "false", "false", "false", 
-                          "true", "true" };
-
-
-void waitForButton(jsSuper *jss, int wait_ms) {
-      int b,lastb;
-      float axes[_JS_MAX_AXES];
-      b=0;
-      ulMilliSecondSleep(wait_ms);
-      do {
-        lastb=b;
-        do {
-          jss->getJoystick()->read ( &b, axes ) ;
-        } while( jss->nextJoystick()); 
-        
-        ulMilliSecondSleep(1); 
-      }while( lastb == b ); 
-      ulMilliSecondSleep(wait_ms);
+#include <iostream>
+#include <fstream>
+#include <string>
+
+using std::fstream;
+using std::cout;
+using std::cin;
+using std::endl;
+using std::ios;
+using std::string;
+
+#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 <simgear/props/props_io.hxx>
+
+#include <Main/fg_io.hxx>
+#include <Main/fg_props.hxx>
+#include <Main/globals.hxx>
+
+#include "jsinput.h"
+
+
+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) {
-     
-     char jsDesc[80];
-     snprintf(jsDesc,80,"--prop:/input/joysticks/js[%d]/axis[%d]/binding",joystick,axis);
-     fs << jsDesc  << "/command=property-scale" << endl; 
-     fs << jsDesc  << "/property=" << axes_propnames[control] << endl; 
-     
-     fs << jsDesc << "/dead-band=0.02"  << endl; 
-     
-     if( half_range[control] == true) {
-       fs << jsDesc << "/offset=-1.0" << endl; 
-       fs << jsDesc << "/factor=-0.5" << endl;
-     } else {
-       fs << jsDesc << "/offset=0.0" << endl; 
-       fs << jsDesc << "/factor=1.0" << endl;
-     }
-     fs << endl;
-} 
-
-void writeButtonProperties(fstream &fs, int property,int joystick, int button) {
-     
-     char jsDesc[80];
-     snprintf(jsDesc,80,"--prop:/input/joysticks/js[%d]/button[%d]/binding",joystick,button);
-     
-     fs << jsDesc << "/repeatable=" << button_repeat[property] << endl;
-     fs << jsDesc << "/command=property-adjust" << endl; 
-     fs << jsDesc << "/property=" << button_propnames[property] << endl;
-     fs << jsDesc << "/step=" << button_step[property] << endl; 
-     fs << endl; 
-}    
-
-        
-
-      
-int main(void) {
-  jsSuper *jss=new jsSuper();
-  jsInput *jsi=new jsInput(jss);
-  jsi->displayValues(false);
-  // int i;
-  int control=0;
-  
-  
-  cout << "Found " << jss->getNumJoysticks() << " joystick(s)" << endl;
-  
-  if(jss->getNumJoysticks() <= 0) { 
-    cout << "Can't find any joysticks ..." << endl;
-    exit(1);
-  }  
-  
-  jss->firstJoystick();
-  do {
-    cout << "Joystick " << jss->getCurrentJoystickId() << " has "
-         << jss->getJoystick()->getNumAxes() << " axes" << endl;
-  } while( jss->nextJoystick() ); 
-  
-  fstream fs("fgfsrc.js",ios::out);
-
-  
-  for(control=0;control<=7;control++) {
-      cout << "Move the control you wish to use for " << axes_humannames[control]
-           << endl;
-      fflush( stdout );
-      jsi->getInput();
-      
-      if(jsi->getInputAxis() != -1) {
-         cout << endl << "Assigned axis " << jsi->getInputAxis() 
-              << " on joystick " << jsi->getInputJoystick() 
-              << " to control " << axes_humannames[control]
-              << endl;
-      
-          writeAxisProperties( fs, control, jsi->getInputJoystick(), 
-                               jsi->getInputAxis() ); 
-      } else {
-          cout << "Skipping Axis" << endl;
-      }           
-      
-      cout << "Press any button for next control" << endl;
-      
-      waitForButton(jss,500);
-      cout << endl;
-  }
-  
-  for(control=0;control<=6;control++) {
-      cout << "Press the button you wish to use to " 
-           << button_humannames[control]
-           << endl;
-      fflush( stdout );
-      jsi->getInput();
-      if(jsi->getInputButton() != -1) {
-         
-         cout << endl << "Assigned button " << jsi->getInputButton() 
-              << " on joystick " << jsi->getInputJoystick() 
-              << " to control " << button_humannames[control]
-              << endl;
-      
-          writeButtonProperties( fs, control, jsi->getInputJoystick(), 
-                               jsi->getInputButton() ); 
-      } else {
-          cout << "Skipping..." << endl;
-      }           
-      
-      cout << "Press any button for next axis" << endl;
-      
-      waitForButton(jss,500);
-      cout << endl;
-  }
-
-  delete jsi;
-  delete jss;
-      
-  cout << "Your joystick settings are in the file fgfsrc.js" << endl;
-  cout << "Check and edit as desired (especially important if you are"
-         << " using a hat switch" << endl;
-  cout << "as this program will, most likely, not get those right).  ";        
-  
-  cout << "Once you are happy, " << endl 
-       << "append its contents to your .fgfsrc or system.fgfsrc" << endl;     
-     
-  return 1;
-}      
+string getFGRoot( int argc, char *argv[] );
+
+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 if (strncmp("--fg-root=", argv[i], 10) == 0) {
+           // used later
+        } 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 " << endl
+                 << "where the joystick is centered and should not generate any input. Move all " << endl
+                 << "axes 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++) {
+        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++) {
+        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 ";
+
+            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;
+
+    delete jsi;
+    delete[] xfs;
+    delete jss;
+    delete[] jstree;
+
+    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;
+    while ( ! in.eof() ) {
+        string line;
+        getline( in, line, '\n' );
+
+        // 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 = "../data";
+#elif defined( _WIN32 )
+        root = "..\\data";
+#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;
+}