]> git.mxchange.org Git - flightgear.git/blobdiff - src/Input/FGEventInput.cxx
Revert joystick patch. One would have to provide a better one
[flightgear.git] / src / Input / FGEventInput.cxx
index bf041367113ce8302a60e2e4f00a8cf83b4e9c2d..8bf9f304e53bb2be03e22c04bbc1182008b3e78b 100644 (file)
 //
 // $Id$
 
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <cstring>
 #include "FGEventInput.hxx"
 #include <Main/fg_props.hxx>
 #include <simgear/io/sg_file.hxx>
-#include <poll.h>
-#include <linux/input.h>
+#include <Scripting/NasalSys.hxx>
+
+using simgear::PropertyList;
+
+FGEventSetting::FGEventSetting( SGPropertyNode_ptr base ) :
+  value(0.0)
+{
+  SGPropertyNode_ptr n;
+
+  if( (n = base->getNode( "value" )) != NULL ) {  
+    valueNode = NULL;
+    value = n->getDoubleValue();
+  } else {
+    n = base->getNode( "property" );
+    if( n == NULL ) {
+      SG_LOG( SG_INPUT, SG_WARN, "Neither <value> nor <property> defined for event setting." );
+    } else {
+      valueNode = fgGetNode( n->getStringValue(), true );
+    }
+  }
+
+  if( (n = base->getChild("condition")) != NULL )
+    condition = sgReadCondition(base, n);
+  else
+    SG_LOG( SG_INPUT, SG_ALERT, "No condition for event setting." );
+}
+
+double FGEventSetting::GetValue()
+{
+  return valueNode == NULL ? value : valueNode->getDoubleValue();
+}
+
+bool FGEventSetting::Test()
+{
+  return condition == NULL ? true : condition->test();
+}
 
 static inline bool StartsWith( string & s, const char * cp )
 {
-  return s.compare( 0, strlen(cp), cp ) == 0;
+  return s.find( cp ) == 0;
 }
 
-FGInputEvent * FGInputEvent::NewObject( SGPropertyNode_ptr node )
+FGInputEvent * FGInputEvent::NewObject( FGInputDevice * device, SGPropertyNode_ptr node )
 {
-  string name = node->getStringValue( "name" );
+  string name = node->getStringValue( "name", "" );
   if( StartsWith( name, "button-" ) )
-    return new FGButtonEvent( node );
+    return new FGButtonEvent( device, node );
 
   if( StartsWith( name, "rel-" ) )
-    return new FGAxisEvent( node );
+    return new FGRelAxisEvent( device, node );
 
   if( StartsWith( name, "abs-" ) )
-    return new FGAxisEvent( node );
+    return new FGAbsAxisEvent( device, node );
 
-  return NULL;
+  return new FGInputEvent( device, node );
 }
 
-FGInputEvent::FGInputEvent( SGPropertyNode_ptr node ) :
-  lastDt(0.0)
+FGInputEvent::FGInputEvent( FGInputDevice * aDevice, SGPropertyNode_ptr node ) :
+  device( aDevice ),
+  lastDt(0.0), 
+  lastSettingValue(std::numeric_limits<float>::quiet_NaN())
 {
-  name = node->getStringValue( "name" );
-  desc = node->getStringValue( "desc" );
+  name = node->getStringValue( "name", "" );
+  desc = node->getStringValue( "desc", "" );
   intervalSec = node->getDoubleValue("interval-sec",0.0);
-  string module = "event";
-  read_bindings( node, bindings, KEYMOD_NONE, module );
+  
+  read_bindings( node, bindings, KEYMOD_NONE, device->GetNasalModule() );
+
+  PropertyList settingNodes = node->getChildren("setting");
+  for( PropertyList::iterator it = settingNodes.begin(); it != settingNodes.end(); it++ )
+    settings.push_back( new FGEventSetting( *it ) );
 }
 
 FGInputEvent::~FGInputEvent()
 {
 }
 
+void FGInputEvent::update( double dt )
+{
+  for( setting_list_t::iterator it = settings.begin(); it != settings.end(); it++ ) {
+    if( (*it)->Test() ) {
+      double value = (*it)->GetValue();
+      if( value != lastSettingValue ) {
+        device->Send( GetName(), (*it)->GetValue() );
+        lastSettingValue = value;
+      }
+    }
+  }
+}
+
 void FGInputEvent::fire( FGEventData & eventData )
 {
   lastDt += eventData.dt;
   if( lastDt >= intervalSec ) {
 
-    for( binding_list_t::iterator it = bindings[KEYMOD_NONE].begin(); it != bindings[KEYMOD_NONE].end(); it++ )
-      (*it)->fire( eventData.value, 1.0 );
+    for( binding_list_t::iterator it = bindings[eventData.modifiers].begin(); it != bindings[eventData.modifiers].end(); it++ )
+      fire( *it, eventData );
 
     lastDt -= intervalSec;
   }
 }
 
-FGAxisEvent::FGAxisEvent( SGPropertyNode_ptr node ) :
-  FGInputEvent( node )
+void FGInputEvent::fire( SGBinding * binding, FGEventData & eventData )
+{
+  binding->fire();
+}
+
+
+
+FGAxisEvent::FGAxisEvent( FGInputDevice * device, SGPropertyNode_ptr node ) :
+  FGInputEvent( device, node )
 {
   tolerance = node->getDoubleValue("tolerance", 0.002);
-  minRange = node->getDoubleValue("min-range", -1024.0);
-  maxRange = node->getDoubleValue("max-range", 1024.0);
+  minRange = node->getDoubleValue("min-range", 0.0 );
+  maxRange = node->getDoubleValue("max-range", 0.0 );
   center = node->getDoubleValue("center", 0.0);
   deadband = node->getDoubleValue("dead-band", 0.0);
   lowThreshold = node->getDoubleValue("low-threshold", -0.9);
@@ -90,27 +155,127 @@ void FGAxisEvent::fire( FGEventData & eventData )
   if (fabs( eventData.value - lastValue) < tolerance)
     return;
   lastValue = eventData.value;
-  FGInputEvent::fire( eventData );
+
+  // We need a copy of the  FGEventData struct to set the new value and to avoid side effects
+  FGEventData ed = eventData;
+
+  if( fabs(ed.value) < deadband )
+    ed.value = 0.0;
+
+  if( minRange != maxRange )
+    ed.value = 2.0*(eventData.value-minRange)/(maxRange-minRange)-1.0;
+
+  FGInputEvent::fire( ed );
 }
 
-FGButtonEvent::FGButtonEvent( SGPropertyNode_ptr node ) :
-  FGInputEvent( node )
+void FGAbsAxisEvent::fire( SGBinding * binding, FGEventData & eventData )
 {
+  // sets the "setting" node
+  binding->fire( eventData.value );
+}
+
+FGRelAxisEvent::FGRelAxisEvent( FGInputDevice * device, SGPropertyNode_ptr node ) : 
+  FGAxisEvent( device, node ) 
+{
+  // relative axes can't use tolerance
+  tolerance = 0.0;
+}
+
+void FGRelAxisEvent::fire( SGBinding * binding, FGEventData & eventData )
+{
+  // sets the "offset" node
+  binding->fire( eventData.value, 1.0 );
+}
+
+FGButtonEvent::FGButtonEvent( FGInputDevice * device, SGPropertyNode_ptr node ) :
+  FGInputEvent( device, node ),
+  repeatable(false),
+  lastState(false)
+{
+  repeatable = node->getBoolValue("repeatable", repeatable);
 }
 
 void FGButtonEvent::fire( FGEventData & eventData )
 {
-  FGInputEvent::fire( eventData );
+  bool pressed = eventData.value > 0.0;
+  if (pressed) {
+    // The press event may be repeated.
+    if (!lastState || repeatable) {
+      SG_LOG( SG_INPUT, SG_DEBUG, "Button has been pressed" );
+      FGInputEvent::fire( eventData );
+    }
+  } else {
+    // The release event is never repeated.
+    if (lastState) {
+      SG_LOG( SG_INPUT, SG_DEBUG, "Button has been released" );
+      eventData.modifiers|=KEYMOD_RELEASED;
+      FGInputEvent::fire( eventData );
+    }
+  }
+          
+  lastState = pressed;
 }
 
 FGInputDevice::~FGInputDevice()
 {
+  FGNasalSys *nas = (FGNasalSys *)globals->get_subsystem("nasal");
+  if (nas && deviceNode ) {
+    SGPropertyNode_ptr nasal = deviceNode->getNode("nasal");
+    if( nasal ) {
+      SGPropertyNode_ptr nasalClose = nasal->getNode("close");
+      if (nasalClose) {
+        const string s = nasalClose->getStringValue();
+        nas->createModule(nasalModule.c_str(), nasalModule.c_str(), s.c_str(), s.length(), deviceNode );
+      }
+    }
+    nas->deleteModule(nasalModule.c_str());
+  }
 } 
 
+void FGInputDevice::Configure( SGPropertyNode_ptr aDeviceNode )
+{
+  deviceNode = aDeviceNode;
+
+  nasalModule = string("__event:") + GetName();
+
+  PropertyList eventNodes = deviceNode->getChildren( "event" );
+  for( PropertyList::iterator it = eventNodes.begin(); it != eventNodes.end(); it++ )
+    AddHandledEvent( FGInputEvent::NewObject( this, *it ) );
+
+  debugEvents = deviceNode->getBoolValue("debug-events", debugEvents );
+  grab = deviceNode->getBoolValue("grab", grab );
+
+  // TODO:
+  // add nodes for the last event:
+  // last-event/name [string]
+  // last-event/value [double]
+
+  SGPropertyNode_ptr nasal = deviceNode->getNode("nasal");
+  if (nasal) {
+    SGPropertyNode_ptr open = nasal->getNode("open");
+    if (open) {
+      const string s = open->getStringValue();
+      FGNasalSys *nas = (FGNasalSys *)globals->get_subsystem("nasal");
+      if (nas)
+        nas->createModule(nasalModule.c_str(), nasalModule.c_str(), s.c_str(), s.length(), deviceNode );
+    }
+  }
+
+}
+
+void FGInputDevice::update( double dt )
+{
+  for( map<string,FGInputEvent_ptr>::iterator it = handledEvents.begin(); it != handledEvents.end(); it++ )
+    (*it).second->update( dt );
+}
+
 void FGInputDevice::HandleEvent( FGEventData & eventData )
 {
   string eventName = TranslateEventName( eventData );  
-  cout << GetName() << " has event " << eventName << endl;
+  if( debugEvents )
+    cout << GetName() << " has event " << 
+    eventName << " modifiers=" << eventData.modifiers << " value=" << eventData.value << endl;
+
   if( handledEvents.count( eventName ) > 0 ) {
     handledEvents[ eventName ]->fire( eventData );
   }
@@ -138,7 +303,7 @@ FGEventInput::~FGEventInput()
 void FGEventInput::init( )
 {
   SG_LOG(SG_INPUT, SG_DEBUG, "Initializing event bindings");
-  SGPropertyNode * base = fgGetNode("/input/event", true);
+//  SGPropertyNode * base = fgGetNode("/input/event", true);
 
 }
 
@@ -146,7 +311,14 @@ void FGEventInput::postinit ()
 {
 }
 
-void FGEventInput::AddDevice( FGInputDevice * inputDevice )
+void FGEventInput::update( double dt )
+{
+  // call each associated device's update() method
+  for( map<int,FGInputDevice*>::iterator it =  input_devices.begin(); it != input_devices.end(); it++ )
+    (*it).second->update( dt );
+}
+
+unsigned FGEventInput::AddDevice( FGInputDevice * inputDevice )
 {
   SGPropertyNode_ptr baseNode = fgGetNode( PROPERTY_ROOT, true );
   SGPropertyNode_ptr deviceNode = NULL;
@@ -157,13 +329,13 @@ void FGEventInput::AddDevice( FGInputDevice * inputDevice )
 
     // find a free index
     unsigned index;
-    for( index = 0; index < 1000; index++ )
+    for( index = 0; index < MAX_DEVICES; index++ )
       if( (deviceNode = baseNode->getNode( "device", index, false ) ) == NULL )
         break;
 
-    if( index == 1000 ) {
+    if( index == MAX_DEVICES ) {
       SG_LOG(SG_INPUT, SG_WARN, "To many event devices - ignoring " << inputDevice->GetName() );
-      return;
+      return INVALID_DEVICE_INDEX;
     }
 
     // create this node 
@@ -171,33 +343,43 @@ void FGEventInput::AddDevice( FGInputDevice * inputDevice )
 
     // and copy the properties from the configuration tree
     copyProperties( configMap[ inputDevice->GetName() ], deviceNode );
+
   }
 
   if( deviceNode == NULL ) {
-    SG_LOG(SG_INPUT, SG_WARN, "No configuration found for device " << inputDevice->GetName() );
-    return;
+    SG_LOG(SG_INPUT, SG_DEBUG, "No configuration found for device " << inputDevice->GetName() );
+    delete  inputDevice;
+    return INVALID_DEVICE_INDEX;
   }
 
-  vector<SGPropertyNode_ptr> eventNodes = deviceNode->getChildren( "event" );
-  for( vector<SGPropertyNode_ptr>::iterator it = eventNodes.begin(); it != eventNodes.end(); it++ ) {
-    FGInputEvent * p = FGInputEvent::NewObject( *it );
-    if( p == NULL ) {
-      SG_LOG(SG_INPUT, SG_WARN, "Unhandled event/name in " << inputDevice->GetName()  );
-      continue;
-    }
-    inputDevice->AddHandledEvent( p );
-  }
+  inputDevice->Configure( deviceNode );
 
-  // TODO:
-  // add nodes for the last event:
-  // last-event/name [string]
-  // last-event/value [double]
-  
   try {        
     inputDevice->Open();
     input_devices[ deviceNode->getIndex() ] = inputDevice;
   }
   catch( ... ) {
-    SG_LOG(SG_INPUT, SG_WARN, "can't open InputDevice " << inputDevice->GetName()  );
+    delete  inputDevice;
+    SG_LOG(SG_INPUT, SG_ALERT, "can't open InputDevice " << inputDevice->GetName()  );
+    return INVALID_DEVICE_INDEX;
+  }
+
+  SG_LOG(SG_INPUT, SG_DEBUG, "using InputDevice " << inputDevice->GetName()  );
+  return deviceNode->getIndex();
+}
+
+void FGEventInput::RemoveDevice( unsigned index )
+{
+  // not fully implemented yet
+  SGPropertyNode_ptr baseNode = fgGetNode( PROPERTY_ROOT, true );
+  SGPropertyNode_ptr deviceNode = NULL;
+
+  FGInputDevice *inputDevice = input_devices[index];
+  if (inputDevice) {
+    input_devices.erase(index);
+    delete inputDevice;
+    
   }
+  deviceNode = baseNode->removeChild("device", index, false);
 }
+