30#include <simgear/io/sg_file.hxx>
31#include <simgear/props/props_io.hxx>
32#include <simgear/math/SGMath.hxx>
33#include <simgear/math/interpolater.hxx>
36using simgear::PropertyList;
47 if( (n = base->getNode(
"value" )) != NULL ) {
49 value = n->getDoubleValue();
51 n = base->getNode(
"property" );
53 SG_LOG( SG_INPUT, SG_WARN,
"Neither <value> nor <property> defined for event setting." );
55 valueNode = fgGetNode( n->getStringValue(), true );
59 if( (n = base->getChild(
"condition")) != NULL )
60 condition = sgReadCondition(base, n);
62 SG_LOG( SG_INPUT, SG_ALERT,
"No condition for event setting." );
75static inline bool StartsWith(
string & s,
const char * cp )
77 return s.find( cp ) == 0;
82 string name = eventNode->getStringValue(
"name",
"" );
100 name = eventNode->getStringValue(
"name",
"" );
101 desc = eventNode->getStringValue(
"desc",
"" );
102 intervalSec = eventNode->getDoubleValue(
"interval-sec",0.0);
106 for (
auto child : eventNode->getChildren(
"setting"))
118 if( setting->Test() ) {
119 const double value = setting->GetValue();
134 fire( *it, eventData );
150 tolerance = eventNode->getDoubleValue(
"tolerance", 0.002);
151 minRange = eventNode->getDoubleValue(
"min-range", 0.0 );
152 maxRange = eventNode->getDoubleValue(
"max-range", 0.0 );
153 center = eventNode->getDoubleValue(
"center", 0.0);
154 deadband = eventNode->getDoubleValue(
"dead-band", 0.0);
155 lowThreshold = eventNode->getDoubleValue(
"low-threshold", -0.9);
156 highThreshold = eventNode->getDoubleValue(
"high-threshold", 0.9);
160 if (eventNode->hasChild(
"interpolater")) {
161 interpolater.reset(new SGInterpTable{eventNode->getChild(
"interpolater")});
200 binding->fire( eventData.
value );
213 binding->fire( eventData.
value, 1.0 );
226 bool pressed = eventData.
value > 0.0;
230 SG_LOG( SG_INPUT, SG_DEBUG,
"Button '" << this->
name <<
"' has been pressed" );
236 SG_LOG( SG_INPUT, SG_DEBUG,
"Button '" << this->
name <<
"' has been released" );
260 SGPropertyNode_ptr nasalClose =
nasal->getNode(
"close");
262 const string s = nasalClose->getStringValue();
277 SG_LOG(SG_INPUT, SG_DEBUG,
"FGInputDevice::Configure");
282 for (
auto ev :
deviceNode->getChildren(
"event" )) {
290 for( PropertyList::iterator it = reportNodes.begin(); it != reportNodes.end(); ++it ) {
303 SGPropertyNode_ptr open =
nasal->getNode(
"open");
305 const string s = open->getStringValue();
317 handledEvents.insert(it, std::make_pair(event->GetName(), event));
324 (*it).second->update( dt );
326 report_setting_list_t::const_iterator it;
329 std::string reportData = (*it)->reportBytes(
nasalModule);
340 eventName <<
" modifiers=" << eventData.
modifiers <<
" value=" << eventData.
value);
366 SG_LOG(SG_INPUT, SG_WARN,
"SendFeatureReport not implemented");
387 SG_LOG(SG_INPUT, SG_DEBUG,
"FGEventInput::shutdown()");
389 for (
auto it : tmp) {
407 it.second->update(dt);
411std::string FGEventInput::computeDeviceIndexName(
FGInputDevice* dev)
const
414 const auto devName = dev->
GetName();
416 if (it.second->GetName() == devName) {
421 std::ostringstream os;
422 os << devName <<
"_" << count;
429 SGPropertyNode_ptr deviceNode =
nullptr;
431 const string deviceName = inputDevice->
GetName();
432 SGPropertyNode_ptr configNode =
nullptr;
436 const string nameWithSerial = deviceName +
"::" + inputDevice->
GetSerialNumber();
437 if (
configMap.hasConfiguration(nameWithSerial)) {
438 configNode =
configMap.configurationForDeviceName(nameWithSerial);
439 SG_LOG(SG_INPUT, SG_INFO,
"using instance-specific configuration for device "
440 << nameWithSerial <<
" : " << configNode->getStringValue(
"source"));
444 if (configNode ==
nullptr) {
445 const auto nameWithIndex = computeDeviceIndexName(inputDevice);
447 if (
configMap.hasConfiguration(nameWithIndex)) {
448 configNode =
configMap.configurationForDeviceName(nameWithIndex);
449 SG_LOG(SG_INPUT, SG_INFO,
"using instance-specific configuration for device "
450 << nameWithIndex <<
" : " << configNode->getStringValue(
"source"));
453 else if (
configMap.hasConfiguration(deviceName)) {
454 configNode =
configMap.configurationForDeviceName(deviceName);
457 SG_LOG(SG_INPUT, SG_INFO,
"No configuration found for device " << deviceName);
468 if ((deviceNode = baseNode->getNode(
"device", index,
false)) ==
nullptr)
473 SG_LOG(SG_INPUT, SG_WARN,
"To many event devices - ignoring " << inputDevice->
GetUniqueName() );
479 deviceNode = baseNode->getNode(
"device", index,
true );
482 copyProperties(configNode, deviceNode );
486 bool ok = inputDevice->
Open();
489 SG_LOG(SG_INPUT, SG_ALERT,
"can't open InputDevice " << inputDevice->
GetUniqueName());
497 return deviceNode->getIndex();
504 SGPropertyNode_ptr deviceNode = NULL;
506 SG_LOG(SG_INPUT, SG_DEBUG,
"FGEventInput::RemoveDevice(" << index <<
") ");
509 SG_LOG(SG_INPUT, SG_DEBUG,
"\tremoving (" << index <<
") " << inputDevice->
GetUniqueName());
510 inputDevice->
Close();
514 deviceNode = baseNode->removeChild(
"device", index);
519 reportId = base->getIntValue(
"report-id");
523 for (PropertyList::iterator it = watchNodes.begin(); it != watchNodes.end(); ++it ) {
524 std::string path = (*it)->getStringValue();
525 SGPropertyNode_ptr n =
globals->get_props()->getNode(path,
true);
526 n->addChangeListener(
this);
546 naRef module = nas->
getModule(moduleName.c_str());
547 if (naIsNil(module)) {
548 SG_LOG(SG_IO, SG_WARN,
"No such Nasal module:" << moduleName);
553 if (!naIsFunc(
func)) {
554 return std::string();
557 naRef result = nas->call(
func, 0, 0, naNil());
558 if (naIsString(result)) {
559 size_t len = naStr_len(result);
560 char* bytes = naStr_data(result);
561 return std::string(bytes, len);
564 if (naIsVector(result)) {
565 int len = naVec_size(result);
567 for (
int b=0; b < len; ++b) {
568 int num = naNumValue(naVec_get(result, b)).num;
569 s.push_back(
static_cast<char>(num));
574 std::ostringstream byteString;
575 static const char*
hexTable =
"0123456789ABCDEF";
577 for (
int i=0;
i<s.size(); ++
i) {
578 uint8_t uc =
static_cast<uint8_t
>(s[
i]);
579 byteString << hexTable[uc >> 4];
583 SG_LOG(SG_INPUT, SG_INFO,
"report bytes: (" << s.size() <<
") " << byteString.str());
589 SG_LOG(SG_INPUT, SG_DEV_WARN,
"bad return data from report setting");
void fire(SGAbstractBinding *binding, FGEventData &eventData) override
virtual void fire(FGEventData &eventData)
FGAxisEvent(FGInputDevice *device, SGPropertyNode_ptr eventNode)
std::unique_ptr< SGInterpTable > interpolater
SGSharedPtr< const SGCondition > condition
FGEventSetting(SGPropertyNode_ptr base)
SGPropertyNode_ptr valueNode
bool createModule(const char *moduleName, const char *fileName, const char *src, int len, const SGPropertyNode *cmdarg=0, int argc=0, naRef *args=0)
naRef getModule(const std::string &moduleName) const
void fire(SGAbstractBinding *binding, FGEventData &eventData) override
FGRelAxisEvent(FGInputDevice *device, SGPropertyNode_ptr eventNode)
FGReportSetting(SGPropertyNode_ptr base)
std::string reportBytes(const std::string &moduleName) const
virtual void valueChanged(SGPropertyNode *node)
std::string nasalFunction
SGPropertyNode * fgGetNode(const char *path, bool create)
Get a property node.