From 26859ad4b96aaa8ec901c5c8f9de57105247fde5 Mon Sep 17 00:00:00 2001 From: torsten Date: Thu, 1 Oct 2009 11:49:10 +0000 Subject: [PATCH] Non platform specific: - normalize axes events - handle relative and absolute axes separately in own classes - ignore tolerance for relative axes, they can fire the same event multiple times which must not be ignored. --- src/Input/FGEventInput.cxx | 48 ++++++++++++++++++++++++++++----- src/Input/FGEventInput.hxx | 19 +++++++++++++ src/Input/FGLinuxEventInput.cxx | 40 +++++++++++++++++++++++++-- src/Input/FGLinuxEventInput.hxx | 4 +++ 4 files changed, 103 insertions(+), 8 deletions(-) diff --git a/src/Input/FGEventInput.cxx b/src/Input/FGEventInput.cxx index 6ac1dd4af..928c20c24 100644 --- a/src/Input/FGEventInput.cxx +++ b/src/Input/FGEventInput.cxx @@ -74,10 +74,10 @@ FGInputEvent * FGInputEvent::NewObject( FGInputDevice * device, SGPropertyNode_p return new FGButtonEvent( device, node ); if( StartsWith( name, "rel-" ) ) - return new FGAxisEvent( device, node ); + return new FGRelAxisEvent( device, node ); if( StartsWith( name, "abs-" ) ) - return new FGAxisEvent( device, node ); + return new FGAbsAxisEvent( device, node ); return new FGInputEvent( device, node ); } @@ -121,18 +121,25 @@ void FGInputEvent::fire( FGEventData & eventData ) if( lastDt >= intervalSec ) { for( binding_list_t::iterator it = bindings[eventData.modifiers].begin(); it != bindings[eventData.modifiers].end(); it++ ) - (*it)->fire( eventData.value, 1.0 ); + fire( *it, eventData ); lastDt -= intervalSec; } } +void FGInputEvent::fire( SGBinding * binding, FGEventData & eventData ) +{ + binding->fire(); +} + + + FGAxisEvent::FGAxisEvent( FGInputDevice * device, SGPropertyNode_ptr node ) : FGInputEvent( device, node ) { tolerance = node->getDoubleValue("tolerance", 0.002); - minRange = node->getDoubleValue("min-range", -1024.0); - maxRange = node->getDoubleValue("max-range", 1024.0); + minRange = node->getDoubleValue("min-range", 0.0 ); + maxRange = node->getDoubleValue("max-range", 0.0 ); center = node->getDoubleValue("center", 0.0); deadband = node->getDoubleValue("dead-band", 0.0); lowThreshold = node->getDoubleValue("low-threshold", -0.9); @@ -145,7 +152,36 @@ void FGAxisEvent::fire( FGEventData & eventData ) if (fabs( eventData.value - lastValue) < tolerance) return; lastValue = eventData.value; - FGInputEvent::fire( eventData ); + + // We need a copy of the FGEventData struct to set the new value and to avoid side effects + FGEventData ed = eventData; + + if( fabs(ed.value) < deadband ) + ed.value = 0.0; + + if( minRange != maxRange ) + ed.value = 2.0*(eventData.value-minRange)/(maxRange-minRange)-1.0; + + FGInputEvent::fire( ed ); +} + +void FGAbsAxisEvent::fire( SGBinding * binding, FGEventData & eventData ) +{ + // sets the "setting" node + binding->fire( eventData.value ); +} + +FGRelAxisEvent::FGRelAxisEvent( FGInputDevice * device, SGPropertyNode_ptr node ) : + FGAxisEvent( device, node ) +{ + // relative axes can't use tolerance + tolerance = 0.0; +} + +void FGRelAxisEvent::fire( SGBinding * binding, FGEventData & eventData ) +{ + // sets the "offset" node + binding->fire( eventData.value, 1.0 ); } FGButtonEvent::FGButtonEvent( FGInputDevice * device, SGPropertyNode_ptr node ) : diff --git a/src/Input/FGEventInput.hxx b/src/Input/FGEventInput.hxx index 973821bd0..7188c8381 100644 --- a/src/Input/FGEventInput.hxx +++ b/src/Input/FGEventInput.hxx @@ -83,6 +83,7 @@ typedef vector setting_list_t; class FGInputDevice; class FGInputEvent : public SGReferenced,FGCommonInput { public: + /* * Constructor for the class. The arg node shall point * to the property corresponding to the node @@ -110,6 +111,7 @@ public: static FGInputEvent * NewObject( FGInputDevice * device, SGPropertyNode_ptr node ); protected: + virtual void fire( SGBinding * binding, FGEventData & eventData ); /* A more or less meaningfull description of the event */ string desc; @@ -143,6 +145,9 @@ protected: class FGAxisEvent : public FGInputEvent { public: FGAxisEvent( FGInputDevice * device, SGPropertyNode_ptr node ); + void SetMaxRange( double value ) { maxRange = value; } + void SetMinRange( double value ) { minRange = value; } + void SetRange( double min, double max ) { minRange = min; maxRange = max; } protected: virtual void fire( FGEventData & eventData ); double tolerance; @@ -155,6 +160,20 @@ protected: double lastValue; }; +class FGRelAxisEvent : public FGAxisEvent { +public: + FGRelAxisEvent( FGInputDevice * device, SGPropertyNode_ptr node ); +protected: + virtual void fire( SGBinding * binding, FGEventData & eventData ); +}; + +class FGAbsAxisEvent : public FGAxisEvent { +public: + FGAbsAxisEvent( FGInputDevice * device, SGPropertyNode_ptr node ) : FGAxisEvent( device, node ) {} +protected: + virtual void fire( SGBinding * binding, FGEventData & eventData ); +}; + typedef class SGSharedPtr FGInputEvent_ptr; /* diff --git a/src/Input/FGLinuxEventInput.cxx b/src/Input/FGLinuxEventInput.cxx index 382a99c8a..183c7b3ab 100644 --- a/src/Input/FGLinuxEventInput.cxx +++ b/src/Input/FGLinuxEventInput.cxx @@ -273,6 +273,11 @@ FGLinuxInputDevice::FGLinuxInputDevice() : { } +static inline bool bitSet( unsigned char * buf, unsigned char bit ) +{ + return (buf[bit/sizeof(bit)/8] >> (bit%(sizeof(bit)*8))) & 1; +} + void FGLinuxInputDevice::Open() { if( fd != -1 ) return; @@ -280,9 +285,38 @@ void FGLinuxInputDevice::Open() throw exception(); } - if( GetGrab() && ioctl( fd, EVIOCGRAB, 2 ) != 0 ) { + if( GetGrab() && ioctl( fd, EVIOCGRAB, 2 ) == -1 ) { SG_LOG( SG_INPUT, SG_WARN, "Can't grab " << devname << " for exclusive access" ); } + + unsigned char buf[ABS_CNT/sizeof(unsigned char)/8]; + // get axes maximums + if( ioctl( fd, EVIOCGBIT(EV_ABS,ABS_MAX), buf ) == -1 ) { + SG_LOG( SG_INPUT, SG_WARN, "Can't get abs-axes for " << devname ); + } else { + for( unsigned i = 0; i < ABS_MAX; i++ ) { + if( bitSet( buf, i ) ) { + struct input_absinfo ai; + if( ioctl(fd, EVIOCGABS(i), &ai) == -1 ) { + SG_LOG( SG_INPUT, SG_WARN, "Can't get abs-axes maximums for " << devname ); + continue; + } + absinfo[i] = ai; + } + } + } +} + +double FGLinuxInputDevice::Normalize( struct input_event & event ) +{ + if( absinfo.count(event.code) > 0 ) { + const struct input_absinfo & ai = absinfo[(unsigned int)event.code]; + if( ai.maximum == ai.minimum ) + return 0.0; + return ((double)event.value-(double)ai.minimum)/((double)ai.maximum-(double)ai.minimum); + } else { + return (double)event.value; + } } void FGLinuxInputDevice::Close() @@ -437,7 +471,6 @@ void FGLinuxEventInput::AddHalDevice( const char * udi ) void FGLinuxEventInput::update( double dt ) { FGEventInput::update( dt ); - // index the input devices by the associated fd and prepare // the pollfd array by filling in the file descriptor struct pollfd fds[input_devices.size()]; @@ -468,6 +501,9 @@ void FGLinuxEventInput::update( double dt ) FGLinuxEventData eventData( event, dt, modifiers ); + if( event.type == EV_ABS ) + eventData.value = devicesByFd[fds[i].fd]->Normalize( event ); + // let the FGInputDevice handle the data devicesByFd[fds[i].fd]->HandleEvent( eventData ); } diff --git a/src/Input/FGLinuxEventInput.hxx b/src/Input/FGLinuxEventInput.hxx index 5f7a58117..3676c48cb 100644 --- a/src/Input/FGLinuxEventInput.hxx +++ b/src/Input/FGLinuxEventInput.hxx @@ -56,9 +56,12 @@ public: int GetFd() { return fd; } + double Normalize( struct input_event & event ); private: string devname; int fd; + + map absinfo; }; class FGLinuxEventInput : public FGEventInput { @@ -71,6 +74,7 @@ public: void AddHalDevice( const char * udi ); protected: LibHalContext *halcontext; + }; #endif -- 2.39.5