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