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 );
}
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);
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 ) :
class FGInputDevice;
class FGInputEvent : public SGReferenced,FGCommonInput {
public:
+
/*
* Constructor for the class. The arg node shall point
* to the property corresponding to the <event> node
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;
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;
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> FGInputEvent_ptr;
/*
{
}
+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;
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()
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()];
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 );
}
int GetFd() { return fd; }
+ double Normalize( struct input_event & event );
private:
string devname;
int fd;
+
+ map<unsigned int,input_absinfo> absinfo;
};
class FGLinuxEventInput : public FGEventInput {
void AddHalDevice( const char * udi );
protected:
LibHalContext *halcontext;
+
};
#endif