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