FlightGear next
FGEventInput.hxx
Go to the documentation of this file.
1// FGEventInput.hxx -- 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#ifndef __FGEVENTINPUT_HXX
24#define __FGEVENTINPUT_HXX
25
26#include "FGCommonInput.hxx"
27
28#include <vector>
29#include <memory>
30
31#include "FGButton.hxx"
33#include <simgear/structure/subsystem_mgr.hxx>
34
35// forward decls
36class SGInterpTable;
37
38/*
39 * A base structure for event data.
40 * To be extended for O/S specific implementation data
41 */
43 FGEventData( double aValue, double aDt, int aModifiers ) : modifiers(aModifiers), value(aValue), dt(aDt) {}
44 int modifiers {0};
45 double value {0.0};
46 double dt {0.0};
47};
48
49/*
50 FGEventSetting
51 stores one value or property node together with an optional condition
52 Multiple FGEventSetting can be assigned to one FGInputEvent
53*/
54class FGEventSetting : public SGReferenced
55{
56public:
57 FGEventSetting( SGPropertyNode_ptr base );
58 // return evaluted condition or true if condition is nullptr
59 bool Test();
60 // return either value of valueNode or value if valueNode is nullptr
61 double GetValue();
62
63protected:
64 double value {0.0};
65 SGPropertyNode_ptr valueNode;
66 SGSharedPtr<const SGCondition> condition;
67};
68
69typedef SGSharedPtr<FGEventSetting> FGEventSetting_ptr;
70typedef std::vector<FGEventSetting_ptr> setting_list_t;
71
72class FGReportSetting : public SGReferenced,
73 public SGPropertyChangeListener
74{
75public:
76 FGReportSetting( SGPropertyNode_ptr base );
77 unsigned int getReportId() const { return reportId; }
78 std::string getNasalFunctionName() const { return nasalFunction; }
79 bool Test();
80 std::string reportBytes(const std::string& moduleName) const;
81 virtual void valueChanged(SGPropertyNode * node);
82
83protected:
84 unsigned int reportId;
85 std::string nasalFunction;
86 bool dirty;
87};
88
89typedef SGSharedPtr<FGReportSetting> FGReportSetting_ptr;
90typedef std::vector<FGReportSetting_ptr> report_setting_list_t;
91
92/*
93 * A wrapper class for a configured event.
94 *
95 * <event>
96 * <desc>Change the view pitch</desc>
97 * <name>rel-x-rotate</name>
98 * <binding>
99 * <command>property-adjust</command>
100 * <property>sim/current-view/pitch-offset-deg</property>
101 * <factor type="double">0.01</factor>
102 * <min type="double">-90.0</min>
103 * <max type="double">90.0</max>
104 * <wrap type="bool">false</wrap>
105 * </binding>
106 * <mod-xyz>
107 * <binding>
108 * ...
109 * </binding>
110 * </mod-xyz>
111 * </event>
112 */
113class FGInputDevice;
114class FGInputEvent : public SGReferenced,
116{
117public:
118 FGInputEvent( FGInputDevice * device, SGPropertyNode_ptr eventNode );
119 virtual ~FGInputEvent();
120
121 // dispatch the event value through all bindings
122 virtual void fire( FGEventData & eventData );
123
124 std::string GetName() const { return name; }
125 std::string GetDescription() const { return desc; }
126
127 virtual void update( double dt );
128 static FGInputEvent * NewObject( FGInputDevice * device, SGPropertyNode_ptr node );
129
130protected:
131 virtual void fire(SGAbstractBinding* binding, FGEventData& eventData);
132 /* A more or less meaningfull description of the event */
133 std::string desc;
134
135 /* One of the predefined names of the event */
136 std::string name;
137
138 /* A list of SGBinding objects */
140
141 /* A list of FGEventSetting objects */
143
144 /* A pointer to the associated device */
146
147 double lastDt;
150};
151
153{
154public:
155 FGButtonEvent( FGInputDevice * device, SGPropertyNode_ptr node );
156 virtual void fire( FGEventData & eventData );
157
158 void update( double dt ) override;
159protected:
162};
163
165{
166public:
167 FGAxisEvent( FGInputDevice * device, SGPropertyNode_ptr eventNode );
168 ~FGAxisEvent();
169
170 void SetMaxRange( double value ) { maxRange = value; }
171 void SetMinRange( double value ) { minRange = value; }
172 void SetRange( double min, double max ) { minRange = min; maxRange = max; }
173
174protected:
175 virtual void fire( FGEventData & eventData );
176 double tolerance;
177 double minRange;
178 double maxRange;
179 double center;
180 double deadband;
183 double lastValue;
184 std::unique_ptr<SGInterpTable> interpolater;
185 bool mirrorInterpolater = false;
186};
187
189{
190public:
191 FGRelAxisEvent( FGInputDevice * device, SGPropertyNode_ptr eventNode );
192
193protected:
194 void fire(SGAbstractBinding* binding, FGEventData& eventData) override;
195};
196
198{
199public:
200 FGAbsAxisEvent( FGInputDevice * device, SGPropertyNode_ptr eventNode ) : FGAxisEvent( device, eventNode ) {}
201
202protected:
203 void fire(SGAbstractBinding* binding, FGEventData& eventData) override;
204};
205
206typedef class SGSharedPtr<FGInputEvent> FGInputEvent_ptr;
207
208/*
209 * A abstract class implementing basic functionality of input devices for
210 * all operating systems. This is the base class for the O/S-specific
211 * implementation of input device handlers
212 */
213class FGInputDevice : public SGReferenced
214{
215public:
217 FGInputDevice( std::string aName, std::string aSerial = {} ) :
218 name(aName), serialNumber(aSerial) {}
219
220 virtual ~FGInputDevice();
221
222 virtual bool Open() = 0;
223 virtual void Close() = 0;
224
225 virtual void Send( const char * eventName, double value ) = 0;
226
227 inline void Send( const std::string & eventName, double value ) {
228 Send( eventName.c_str(), value );
229 }
230
231 virtual void SendFeatureReport(unsigned int reportId, const std::string& data);
232
233 virtual const char * TranslateEventName( FGEventData & eventData ) = 0;
234
235
236 void SetName( std::string name );
237 std::string & GetName() { return name; }
238
239 void SetUniqueName(const std::string& name);
240 const std::string GetUniqueName() const { return _uniqueName; }
241
242 void SetSerialNumber( std::string serial );
243 std::string& GetSerialNumber() { return serialNumber; }
244
245 void HandleEvent( FGEventData & eventData );
246
247 virtual void AddHandledEvent( FGInputEvent_ptr handledEvent );
248
249 virtual void Configure( SGPropertyNode_ptr deviceNode );
250
251 virtual void update( double dt );
252
253 bool GetDebugEvents () const { return debugEvents; }
254
255 bool GetGrab() const { return grab; }
256
257 const std::string & GetNasalModule() const { return nasalModule; }
258 std::string class_id = "FGInputDevice";
259protected:
260 // A map of events, this device handles
261 std::map<std::string,FGInputEvent_ptr> handledEvents;
262
263 // the device has a name to be recognized
264 std::string name;
265
266 // serial number string to disambiguate multiple instances
267 // of the same device
268 std::string serialNumber;
269
270 // print out events comming in from the device
271 // if true
272 bool debugEvents = false;
273
274 // grab the device exclusively, if O/S supports this
275 // so events are not sent to other applications
276 bool grab = false;
277
278 //configuration in property tree
279 SGPropertyNode_ptr deviceNode;
280 SGPropertyNode_ptr lastEventName;
281 SGPropertyNode_ptr lastEventValue;
282
283 std::string nasalModule;
284
286
290 std::string _uniqueName;
291};
292
293typedef SGSharedPtr<FGInputDevice> FGInputDevice_ptr;
294
295
296/*
297 * The Subsystem for the event input device
298 */
299class FGEventInput : public SGSubsystem,
301{
302public:
303 FGEventInput();
304 FGEventInput(const char* filePath, const char* propertyRoot);
305 virtual ~FGEventInput();
306
307 // Subsystem API.
308 void init() override;
309 void postinit() override;
310 void shutdown() override;
311 void update(double dt) override;
312
313 const static unsigned MAX_DEVICES = 1000;
314 const static unsigned INVALID_DEVICE_INDEX = MAX_DEVICES + 1;
315
316protected:
317 // where to search for configs and where to put them in the property tree
318 const char* filePath;
319 const char* propertyRoot;
320
321 unsigned AddDevice(FGInputDevice* inputDevice);
322 void RemoveDevice( unsigned index );
323
324 std::map<int,FGInputDevice*> inputDevices;
326
327 SGPropertyNode_ptr nasalClose;
328
329private:
330 std::string computeDeviceIndexName(FGInputDevice *dev) const;
331};
332
333#endif
std::vector< FGEventSetting_ptr > setting_list_t
class SGSharedPtr< FGInputEvent > FGInputEvent_ptr
SGSharedPtr< FGEventSetting > FGEventSetting_ptr
std::vector< FGReportSetting_ptr > report_setting_list_t
SGSharedPtr< FGReportSetting > FGReportSetting_ptr
SGSharedPtr< FGInputDevice > FGInputDevice_ptr
#define min(X, Y)
FGAbsAxisEvent(FGInputDevice *device, SGPropertyNode_ptr eventNode)
void fire(SGAbstractBinding *binding, FGEventData &eventData) override
void SetMinRange(double value)
bool mirrorInterpolater
double highThreshold
void SetMaxRange(double value)
virtual void fire(FGEventData &eventData)
FGAxisEvent(FGInputDevice *device, SGPropertyNode_ptr eventNode)
std::unique_ptr< SGInterpTable > interpolater
double lowThreshold
void SetRange(double min, double max)
void update(double dt) override
virtual void fire(FGEventData &eventData)
FGButtonEvent(FGInputDevice *device, SGPropertyNode_ptr node)
SGBindingList binding_list_t
void update(double dt) override
std::map< int, FGInputDevice * > inputDevices
FGDeviceConfigurationMap configMap
const char * filePath
void RemoveDevice(unsigned index)
const char * propertyRoot
void postinit() override
SGPropertyNode_ptr nasalClose
static const unsigned MAX_DEVICES
void shutdown() override
unsigned AddDevice(FGInputDevice *inputDevice)
virtual ~FGEventInput()
static const unsigned INVALID_DEVICE_INDEX
void init() override
SGSharedPtr< const SGCondition > condition
FGEventSetting(SGPropertyNode_ptr base)
SGPropertyNode_ptr valueNode
std::string class_id
virtual bool Open()=0
void SetName(std::string name)
void SetUniqueName(const std::string &name)
virtual void Configure(SGPropertyNode_ptr deviceNode)
SGPropertyNode_ptr deviceNode
std::string & GetSerialNumber()
std::string name
virtual void AddHandledEvent(FGInputEvent_ptr handledEvent)
FGInputDevice(std::string aName, std::string aSerial={})
SGPropertyNode_ptr lastEventValue
const std::string & GetNasalModule() const
SGPropertyNode_ptr lastEventName
void HandleEvent(FGEventData &eventData)
report_setting_list_t reportSettings
virtual void SendFeatureReport(unsigned int reportId, const std::string &data)
const std::string GetUniqueName() const
bool GetDebugEvents() const
bool GetGrab() const
std::map< std::string, FGInputEvent_ptr > handledEvents
virtual void update(double dt)
std::string serialNumber
void Send(const std::string &eventName, double value)
std::string _uniqueName
name, but with suffix / serial appended.
virtual ~FGInputDevice()
virtual void Send(const char *eventName, double value)=0
std::string nasalModule
std::string & GetName()
virtual const char * TranslateEventName(FGEventData &eventData)=0
void SetSerialNumber(std::string serial)
virtual void Close()=0
std::string GetName() const
double lastSettingValue
virtual ~FGInputEvent()
binding_list_t bindings[KEYMOD_MAX]
FGInputDevice * device
std::string GetDescription() const
std::string desc
FGInputEvent(FGInputDevice *device, SGPropertyNode_ptr eventNode)
virtual void update(double dt)
std::string name
static FGInputEvent * NewObject(FGInputDevice *device, SGPropertyNode_ptr node)
setting_list_t settings
virtual void fire(FGEventData &eventData)
void fire(SGAbstractBinding *binding, FGEventData &eventData) override
FGRelAxisEvent(FGInputDevice *device, SGPropertyNode_ptr eventNode)
std::string getNasalFunctionName() const
FGReportSetting(SGPropertyNode_ptr base)
std::string reportBytes(const std::string &moduleName) const
virtual void valueChanged(SGPropertyNode *node)
unsigned int getReportId() const
std::string nasalFunction
unsigned int reportId
const char * name
@ KEYMOD_MAX
Definition fg_os.hxx:32
FGEventData(double aValue, double aDt, int aModifiers)