]> git.mxchange.org Git - flightgear.git/blob - src/Input/FGEventInput.cxx
Merge branch 'jmt/gps' into next
[flightgear.git] / src / Input / FGEventInput.cxx
1 // FGEventInput.cxx -- handle event driven input devices
2 //
3 // Written by Torsten Dreyer, started July 2009.
4 //
5 // Copyright (C) 2009 Torsten Dreyer, Torsten (at) t3r _dot_ de
6 //
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.
11 //
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.
16 //
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.
20 //
21 // $Id$
22
23 #ifdef HAVE_CONFIG_H
24 #  include <config.h>
25 #endif
26
27 #include "FGEventInput.hxx"
28 #include <Main/fg_props.hxx>
29 #include <simgear/io/sg_file.hxx>
30 #include <Scripting/NasalSys.hxx>
31
32 using simgear::PropertyList;
33
34 FGEventSetting::FGEventSetting( SGPropertyNode_ptr base ) :
35   value(0.0)
36 {
37   SGPropertyNode_ptr n;
38
39   if( (n = base->getNode( "value" )) != NULL ) {  
40     valueNode = NULL;
41     value = n->getDoubleValue();
42   } else {
43     n = base->getNode( "property" );
44     if( n == NULL ) {
45       SG_LOG( SG_INPUT, SG_WARN, "Neither <value> nor <property> defined for event setting." );
46     } else {
47       valueNode = fgGetNode( n->getStringValue(), true );
48     }
49   }
50
51   if( (n = base->getChild("condition")) != NULL )
52     condition = sgReadCondition(base, n);
53   else
54     SG_LOG( SG_INPUT, SG_ALERT, "No condition for event setting." );
55 }
56
57 double FGEventSetting::GetValue()
58 {
59   return valueNode == NULL ? value : valueNode->getDoubleValue();
60 }
61
62 bool FGEventSetting::Test()
63 {
64   return condition == NULL ? true : condition->test();
65 }
66
67 static inline bool StartsWith( string & s, const char * cp )
68 {
69   return s.compare( 0, strlen(cp), cp ) == 0;
70 }
71
72 FGInputEvent * FGInputEvent::NewObject( FGInputDevice * device, SGPropertyNode_ptr node )
73 {
74   string name = node->getStringValue( "name", "" );
75   if( StartsWith( name, "button-" ) )
76     return new FGButtonEvent( device, node );
77
78   if( StartsWith( name, "rel-" ) )
79     return new FGRelAxisEvent( device, node );
80
81   if( StartsWith( name, "abs-" ) )
82     return new FGAbsAxisEvent( device, node );
83
84   return new FGInputEvent( device, node );
85 }
86
87 FGInputEvent::FGInputEvent( FGInputDevice * aDevice, SGPropertyNode_ptr node ) :
88   device( aDevice ),
89   lastDt(0.0), 
90   lastSettingValue(std::numeric_limits<float>::quiet_NaN())
91 {
92   name = node->getStringValue( "name", "" );
93   desc = node->getStringValue( "desc", "" );
94   intervalSec = node->getDoubleValue("interval-sec",0.0);
95   
96   read_bindings( node, bindings, KEYMOD_NONE, device->GetNasalModule() );
97
98   PropertyList settingNodes = node->getChildren("setting");
99   for( PropertyList::iterator it = settingNodes.begin(); it != settingNodes.end(); it++ )
100     settings.push_back( new FGEventSetting( *it ) );
101 }
102
103 FGInputEvent::~FGInputEvent()
104 {
105 }
106
107 void FGInputEvent::update( double dt )
108 {
109   for( setting_list_t::iterator it = settings.begin(); it != settings.end(); it++ ) {
110     if( (*it)->Test() ) {
111       double value = (*it)->GetValue();
112       if( value != lastSettingValue ) {
113         device->Send( GetName(), (*it)->GetValue() );
114         lastSettingValue = value;
115       }
116     }
117   }
118 }
119
120 void FGInputEvent::fire( FGEventData & eventData )
121 {
122   lastDt += eventData.dt;
123   if( lastDt >= intervalSec ) {
124
125     for( binding_list_t::iterator it = bindings[eventData.modifiers].begin(); it != bindings[eventData.modifiers].end(); it++ )
126       fire( *it, eventData );
127
128     lastDt -= intervalSec;
129   }
130 }
131
132 void FGInputEvent::fire( SGBinding * binding, FGEventData & eventData )
133 {
134   binding->fire();
135 }
136
137
138
139 FGAxisEvent::FGAxisEvent( FGInputDevice * device, SGPropertyNode_ptr node ) :
140   FGInputEvent( device, node )
141 {
142   tolerance = node->getDoubleValue("tolerance", 0.002);
143   minRange = node->getDoubleValue("min-range", 0.0 );
144   maxRange = node->getDoubleValue("max-range", 0.0 );
145   center = node->getDoubleValue("center", 0.0);
146   deadband = node->getDoubleValue("dead-band", 0.0);
147   lowThreshold = node->getDoubleValue("low-threshold", -0.9);
148   highThreshold = node->getDoubleValue("high-threshold", 0.9);
149   lastValue = 9999999;
150 }
151
152 void FGAxisEvent::fire( FGEventData & eventData )
153 {
154   if (fabs( eventData.value - lastValue) < tolerance)
155     return;
156   lastValue = eventData.value;
157
158   // We need a copy of the  FGEventData struct to set the new value and to avoid side effects
159   FGEventData ed = eventData;
160
161   if( fabs(ed.value) < deadband )
162     ed.value = 0.0;
163
164   if( minRange != maxRange )
165     ed.value = 2.0*(eventData.value-minRange)/(maxRange-minRange)-1.0;
166
167   FGInputEvent::fire( ed );
168 }
169
170 void FGAbsAxisEvent::fire( SGBinding * binding, FGEventData & eventData )
171 {
172   // sets the "setting" node
173   binding->fire( eventData.value );
174 }
175
176 FGRelAxisEvent::FGRelAxisEvent( FGInputDevice * device, SGPropertyNode_ptr node ) : 
177   FGAxisEvent( device, node ) 
178 {
179   // relative axes can't use tolerance
180   tolerance = 0.0;
181 }
182
183 void FGRelAxisEvent::fire( SGBinding * binding, FGEventData & eventData )
184 {
185   // sets the "offset" node
186   binding->fire( eventData.value, 1.0 );
187 }
188
189 FGButtonEvent::FGButtonEvent( FGInputDevice * device, SGPropertyNode_ptr node ) :
190   FGInputEvent( device, node ),
191   repeatable(false),
192   lastState(false)
193 {
194   repeatable = node->getBoolValue("repeatable", repeatable);
195 }
196
197 void FGButtonEvent::fire( FGEventData & eventData )
198 {
199   bool pressed = eventData.value > 0.0;
200   if (pressed) {
201     // The press event may be repeated.
202     if (!lastState || repeatable) {
203       SG_LOG( SG_INPUT, SG_DEBUG, "Button has been pressed" );
204       FGInputEvent::fire( eventData );
205     }
206   } else {
207     // The release event is never repeated.
208     if (lastState) {
209       SG_LOG( SG_INPUT, SG_DEBUG, "Button has been released" );
210       eventData.modifiers|=KEYMOD_RELEASED;
211       FGInputEvent::fire( eventData );
212     }
213   }
214           
215   lastState = pressed;
216 }
217
218 FGInputDevice::~FGInputDevice()
219 {
220   FGNasalSys *nas = (FGNasalSys *)globals->get_subsystem("nasal");
221   if (nas && deviceNode ) {
222     SGPropertyNode_ptr nasal = deviceNode->getNode("nasal");
223     if( nasal ) {
224       SGPropertyNode_ptr nasalClose = nasal->getNode("close");
225       if (nasalClose) {
226         const char *s = nasalClose->getStringValue();
227         nas->createModule(nasalModule.c_str(), nasalModule.c_str(), s, strlen(s), deviceNode );
228       }
229     }
230     nas->deleteModule(nasalModule.c_str());
231   }
232
233
234 void FGInputDevice::Configure( SGPropertyNode_ptr aDeviceNode )
235 {
236   deviceNode = aDeviceNode;
237
238   nasalModule = string("__event:") + GetName();
239
240   PropertyList eventNodes = deviceNode->getChildren( "event" );
241   for( PropertyList::iterator it = eventNodes.begin(); it != eventNodes.end(); it++ )
242     AddHandledEvent( FGInputEvent::NewObject( this, *it ) );
243
244   debugEvents = deviceNode->getBoolValue("debug-events", debugEvents );
245   grab = deviceNode->getBoolValue("grab", grab );
246
247   // TODO:
248   // add nodes for the last event:
249   // last-event/name [string]
250   // last-event/value [double]
251
252   SGPropertyNode_ptr nasal = deviceNode->getNode("nasal");
253   if (nasal) {
254     SGPropertyNode_ptr open = nasal->getNode("open");
255     if (open) {
256       const char *s = open->getStringValue();
257       FGNasalSys *nas = (FGNasalSys *)globals->get_subsystem("nasal");
258       if (nas)
259         nas->createModule(nasalModule.c_str(), nasalModule.c_str(), s, strlen(s), deviceNode );
260     }
261   }
262
263 }
264
265 void FGInputDevice::update( double dt )
266 {
267   for( map<string,FGInputEvent_ptr>::iterator it = handledEvents.begin(); it != handledEvents.end(); it++ )
268     (*it).second->update( dt );
269 }
270
271 void FGInputDevice::HandleEvent( FGEventData & eventData )
272 {
273   string eventName = TranslateEventName( eventData );  
274   if( debugEvents )
275     cout << GetName() << " has event " << 
276     eventName << " modifiers=" << eventData.modifiers << " value=" << eventData.value << endl;
277
278   if( handledEvents.count( eventName ) > 0 ) {
279     handledEvents[ eventName ]->fire( eventData );
280   }
281 }
282
283 void FGInputDevice::SetName( string name )
284 {
285   this->name = name; 
286 }
287
288 const char * FGEventInput::PROPERTY_ROOT = "/input/event";
289
290 FGEventInput::FGEventInput() : 
291   configMap( "Input/Event", fgGetNode( PROPERTY_ROOT, true ), "device-named" )
292 {
293 }
294
295 FGEventInput::~FGEventInput()
296 {
297   for( map<int,FGInputDevice*>::iterator it = input_devices.begin(); it != input_devices.end(); it++ )
298     delete (*it).second;
299   input_devices.clear();
300 }
301
302 void FGEventInput::init( )
303 {
304   SG_LOG(SG_INPUT, SG_DEBUG, "Initializing event bindings");
305 //  SGPropertyNode * base = fgGetNode("/input/event", true);
306
307 }
308
309 void FGEventInput::postinit ()
310 {
311 }
312
313 void FGEventInput::update( double dt )
314 {
315   // call each associated device's update() method
316   for( map<int,FGInputDevice*>::iterator it =  input_devices.begin(); it != input_devices.end(); it++ )
317     (*it).second->update( dt );
318 }
319
320 unsigned FGEventInput::AddDevice( FGInputDevice * inputDevice )
321 {
322   SGPropertyNode_ptr baseNode = fgGetNode( PROPERTY_ROOT, true );
323   SGPropertyNode_ptr deviceNode = NULL;
324
325   // look for configuration in the device map
326   if( configMap.count( inputDevice->GetName() ) > 0 ) {
327     // found - copy to /input/event/device[n]
328
329     // find a free index
330     unsigned index;
331     for( index = 0; index < MAX_DEVICES; index++ )
332       if( (deviceNode = baseNode->getNode( "device", index, false ) ) == NULL )
333         break;
334
335     if( index == MAX_DEVICES ) {
336       SG_LOG(SG_INPUT, SG_WARN, "To many event devices - ignoring " << inputDevice->GetName() );
337       return INVALID_DEVICE_INDEX;
338     }
339
340     // create this node 
341     deviceNode = baseNode->getNode( "device", index, true );
342
343     // and copy the properties from the configuration tree
344     copyProperties( configMap[ inputDevice->GetName() ], deviceNode );
345
346   }
347
348   if( deviceNode == NULL ) {
349     SG_LOG(SG_INPUT, SG_DEBUG, "No configuration found for device " << inputDevice->GetName() );
350     delete  inputDevice;
351     return INVALID_DEVICE_INDEX;
352   }
353
354   inputDevice->Configure( deviceNode );
355
356   try { 
357     inputDevice->Open();
358     input_devices[ deviceNode->getIndex() ] = inputDevice;
359   }
360   catch( ... ) {
361     delete  inputDevice;
362     SG_LOG(SG_INPUT, SG_ALERT, "can't open InputDevice " << inputDevice->GetName()  );
363     return INVALID_DEVICE_INDEX;
364   }
365
366   SG_LOG(SG_INPUT, SG_DEBUG, "using InputDevice " << inputDevice->GetName()  );
367   return deviceNode->getIndex();
368 }
369
370 void FGEventInput::RemoveDevice( unsigned index )
371 {
372   // not fully implemented yet
373   SGPropertyNode_ptr baseNode = fgGetNode( PROPERTY_ROOT, true );
374   SGPropertyNode_ptr deviceNode = NULL;
375
376   FGInputDevice *inputDevice = input_devices[index];
377   if (inputDevice) {
378     input_devices.erase(index);
379     delete inputDevice;
380     
381   }
382   deviceNode = baseNode->removeChild("device", index, false);
383 }
384