1 // FGEventInput.cxx -- handle event driven input devices
3 // Written by Torsten Dreyer, started July 2009.
5 // Copyright (C) 2009 Torsten Dreyer, Torsten (at) t3r _dot_ de
7 // This program is free software; you can redistribute it and/or
8 // modify it under the terms of the GNU General Public License as
9 // published by the Free Software Foundation; either version 2 of the
10 // License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful, but
13 // WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 // General Public License for more details.
17 // You should have received a copy of the GNU General Public License
18 // along with this program; if not, write to the Free Software
19 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
28 #include "FGEventInput.hxx"
29 #include <Main/fg_props.hxx>
30 #include <simgear/io/sg_file.hxx>
31 #include <simgear/props/props_io.hxx>
32 #include <simgear/math/SGMath.hxx>
33 #include <Scripting/NasalSys.hxx>
35 using simgear::PropertyList;
40 FGEventSetting::FGEventSetting( SGPropertyNode_ptr base ) :
45 if( (n = base->getNode( "value" )) != NULL ) {
47 value = n->getDoubleValue();
49 n = base->getNode( "property" );
51 SG_LOG( SG_INPUT, SG_WARN, "Neither <value> nor <property> defined for event setting." );
53 valueNode = fgGetNode( n->getStringValue(), true );
57 if( (n = base->getChild("condition")) != NULL )
58 condition = sgReadCondition(base, n);
60 SG_LOG( SG_INPUT, SG_ALERT, "No condition for event setting." );
63 double FGEventSetting::GetValue()
65 return valueNode == NULL ? value : valueNode->getDoubleValue();
68 bool FGEventSetting::Test()
70 return condition == NULL ? true : condition->test();
73 static inline bool StartsWith( string & s, const char * cp )
75 return s.find( cp ) == 0;
78 FGInputEvent * FGInputEvent::NewObject( FGInputDevice * device, SGPropertyNode_ptr node )
80 string name = node->getStringValue( "name", "" );
81 if( StartsWith( name, "button-" ) )
82 return new FGButtonEvent( device, node );
84 if( StartsWith( name, "rel-" ) )
85 return new FGRelAxisEvent( device, node );
87 if( StartsWith( name, "abs-" ) )
88 return new FGAbsAxisEvent( device, node );
90 return new FGInputEvent( device, node );
93 FGInputEvent::FGInputEvent( FGInputDevice * aDevice, SGPropertyNode_ptr node ) :
96 lastSettingValue(std::numeric_limits<float>::quiet_NaN())
98 name = node->getStringValue( "name", "" );
99 desc = node->getStringValue( "desc", "" );
100 intervalSec = node->getDoubleValue("interval-sec",0.0);
102 read_bindings( node, bindings, KEYMOD_NONE, device->GetNasalModule() );
104 PropertyList settingNodes = node->getChildren("setting");
105 for( PropertyList::iterator it = settingNodes.begin(); it != settingNodes.end(); ++it )
106 settings.push_back( new FGEventSetting( *it ) );
109 FGInputEvent::~FGInputEvent()
113 void FGInputEvent::update( double dt )
115 for( setting_list_t::iterator it = settings.begin(); it != settings.end(); ++it ) {
116 if( (*it)->Test() ) {
117 double value = (*it)->GetValue();
118 if( value != lastSettingValue ) {
119 device->Send( GetName(), (*it)->GetValue() );
120 lastSettingValue = value;
126 void FGInputEvent::fire( FGEventData & eventData )
128 lastDt += eventData.dt;
129 if( lastDt >= intervalSec ) {
131 for( binding_list_t::iterator it = bindings[eventData.modifiers].begin(); it != bindings[eventData.modifiers].end(); ++it )
132 fire( *it, eventData );
134 lastDt -= intervalSec;
138 void FGInputEvent::fire( SGBinding * binding, FGEventData & eventData )
145 FGAxisEvent::FGAxisEvent( FGInputDevice * device, SGPropertyNode_ptr node ) :
146 FGInputEvent( device, node )
148 tolerance = node->getDoubleValue("tolerance", 0.002);
149 minRange = node->getDoubleValue("min-range", 0.0 );
150 maxRange = node->getDoubleValue("max-range", 0.0 );
151 center = node->getDoubleValue("center", 0.0);
152 deadband = node->getDoubleValue("dead-band", 0.0);
153 lowThreshold = node->getDoubleValue("low-threshold", -0.9);
154 highThreshold = node->getDoubleValue("high-threshold", 0.9);
158 void FGAxisEvent::fire( FGEventData & eventData )
160 if (fabs( eventData.value - lastValue) < tolerance)
162 lastValue = eventData.value;
164 // We need a copy of the FGEventData struct to set the new value and to avoid side effects
165 FGEventData ed = eventData;
167 if( fabs(ed.value) < deadband )
170 if( minRange != maxRange )
171 ed.value = 2.0*(eventData.value-minRange)/(maxRange-minRange)-1.0;
173 FGInputEvent::fire( ed );
176 void FGAbsAxisEvent::fire( SGBinding * binding, FGEventData & eventData )
178 // sets the "setting" node
179 binding->fire( eventData.value );
182 FGRelAxisEvent::FGRelAxisEvent( FGInputDevice * device, SGPropertyNode_ptr node ) :
183 FGAxisEvent( device, node )
185 // relative axes can't use tolerance
189 void FGRelAxisEvent::fire( SGBinding * binding, FGEventData & eventData )
191 // sets the "offset" node
192 binding->fire( eventData.value, 1.0 );
195 FGButtonEvent::FGButtonEvent( FGInputDevice * device, SGPropertyNode_ptr node ) :
196 FGInputEvent( device, node ),
200 repeatable = node->getBoolValue("repeatable", repeatable);
203 void FGButtonEvent::fire( FGEventData & eventData )
205 bool pressed = eventData.value > 0.0;
207 // The press event may be repeated.
208 if (!lastState || repeatable) {
209 SG_LOG( SG_INPUT, SG_DEBUG, "Button has been pressed" );
210 FGInputEvent::fire( eventData );
213 // The release event is never repeated.
215 SG_LOG( SG_INPUT, SG_DEBUG, "Button has been released" );
216 eventData.modifiers|=KEYMOD_RELEASED;
217 FGInputEvent::fire( eventData );
224 FGInputDevice::~FGInputDevice()
226 FGNasalSys *nas = (FGNasalSys *)globals->get_subsystem("nasal");
227 if (nas && deviceNode ) {
228 SGPropertyNode_ptr nasal = deviceNode->getNode("nasal");
230 SGPropertyNode_ptr nasalClose = nasal->getNode("close");
232 const string s = nasalClose->getStringValue();
233 nas->createModule(nasalModule.c_str(), nasalModule.c_str(), s.c_str(), s.length(), deviceNode );
236 nas->deleteModule(nasalModule.c_str());
240 void FGInputDevice::Configure( SGPropertyNode_ptr aDeviceNode )
242 deviceNode = aDeviceNode;
244 nasalModule = string("__event:") + GetName();
246 PropertyList eventNodes = deviceNode->getChildren( "event" );
247 for( PropertyList::iterator it = eventNodes.begin(); it != eventNodes.end(); ++it )
248 AddHandledEvent( FGInputEvent::NewObject( this, *it ) );
250 debugEvents = deviceNode->getBoolValue("debug-events", debugEvents );
251 grab = deviceNode->getBoolValue("grab", grab );
254 // add nodes for the last event:
255 // last-event/name [string]
256 // last-event/value [double]
258 SGPropertyNode_ptr nasal = deviceNode->getNode("nasal");
260 SGPropertyNode_ptr open = nasal->getNode("open");
262 const string s = open->getStringValue();
263 FGNasalSys *nas = (FGNasalSys *)globals->get_subsystem("nasal");
265 nas->createModule(nasalModule.c_str(), nasalModule.c_str(), s.c_str(), s.length(), deviceNode );
271 void FGInputDevice::update( double dt )
273 for( map<string,FGInputEvent_ptr>::iterator it = handledEvents.begin(); it != handledEvents.end(); it++ )
274 (*it).second->update( dt );
277 void FGInputDevice::HandleEvent( FGEventData & eventData )
279 string eventName = TranslateEventName( eventData );
281 cout << GetName() << " has event " <<
282 eventName << " modifiers=" << eventData.modifiers << " value=" << eventData.value << endl;
284 if( handledEvents.count( eventName ) > 0 ) {
285 handledEvents[ eventName ]->fire( eventData );
289 void FGInputDevice::SetName( string name )
294 const char * FGEventInput::PROPERTY_ROOT = "/input/event";
296 FGEventInput::FGEventInput() :
297 configMap( "Input/Event", fgGetNode(PROPERTY_ROOT, true), "device-named")
301 FGEventInput::~FGEventInput()
303 for( map<int,FGInputDevice*>::iterator it = input_devices.begin(); it != input_devices.end(); ++it )
305 input_devices.clear();
308 void FGEventInput::init( )
310 SG_LOG(SG_INPUT, SG_DEBUG, "Initializing event bindings");
311 // SGPropertyNode * base = fgGetNode("/input/event", true);
315 void FGEventInput::postinit ()
319 void FGEventInput::update( double dt )
321 // call each associated device's update() method
322 for( map<int,FGInputDevice*>::iterator it = input_devices.begin(); it != input_devices.end(); ++it )
323 (*it).second->update( dt );
326 unsigned FGEventInput::AddDevice( FGInputDevice * inputDevice )
328 SGPropertyNode_ptr baseNode = fgGetNode( PROPERTY_ROOT, true );
329 SGPropertyNode_ptr deviceNode = NULL;
331 // look for configuration in the device map
332 if ( configMap.hasConfiguration( inputDevice->GetName() ) ) {
333 // found - copy to /input/event/device[n]
337 for( index = 0; index < MAX_DEVICES; index++ )
338 if( (deviceNode = baseNode->getNode( "device", index, false ) ) == NULL )
341 if( index == MAX_DEVICES ) {
342 SG_LOG(SG_INPUT, SG_WARN, "To many event devices - ignoring " << inputDevice->GetName() );
343 return INVALID_DEVICE_INDEX;
347 deviceNode = baseNode->getNode( "device", index, true );
349 // and copy the properties from the configuration tree
350 copyProperties( configMap.configurationForDeviceName(inputDevice->GetName()), deviceNode );
354 if( deviceNode == NULL ) {
355 SG_LOG(SG_INPUT, SG_DEBUG, "No configuration found for device " << inputDevice->GetName() );
357 return INVALID_DEVICE_INDEX;
360 inputDevice->Configure( deviceNode );
364 input_devices[ deviceNode->getIndex() ] = inputDevice;
368 SG_LOG(SG_INPUT, SG_ALERT, "can't open InputDevice " << inputDevice->GetName() );
369 return INVALID_DEVICE_INDEX;
372 SG_LOG(SG_INPUT, SG_DEBUG, "using InputDevice " << inputDevice->GetName() );
373 return deviceNode->getIndex();
376 void FGEventInput::RemoveDevice( unsigned index )
378 // not fully implemented yet
379 SGPropertyNode_ptr baseNode = fgGetNode( PROPERTY_ROOT, true );
380 SGPropertyNode_ptr deviceNode = NULL;
382 FGInputDevice *inputDevice = input_devices[index];
384 input_devices.erase(index);
388 deviceNode = baseNode->removeChild("device", index, false);