#include <poll.h>
#include <linux/input.h>
#include <dbus/dbus.h>
+#include <fcntl.h>
+
struct TypeCode {
unsigned type;
{ { EV_SW, SW_MICROPHONE_INSERT }, "switch-microphone-insert" },
#endif
#ifdef SW_DOCK
- { { EV_SW, SW_DOCK }, "swtich-dock" },
+ { { EV_SW, SW_DOCK }, "switch-dock" },
#endif
{ { EV_LED, LED_NUML}, "led-numlock" },
};
+static struct enbet {
+ unsigned type;
+ const char * name;
+} EVENT_NAMES_BY_EVENT_TYPE[] = {
+ { EV_SYN, "syn" },
+ { EV_KEY, "button" },
+ { EV_REL, "rel" },
+ { EV_ABS, "abs" },
+ { EV_MSC, "msc" },
+ { EV_SW, "button" },
+ { EV_LED, "led" },
+ { EV_SND, "snd" },
+ { EV_REP, "rep" },
+ { EV_FF, "ff" },
+ { EV_PWR, "pwr" },
+ { EV_FF_STATUS, "ff-status" }
+};
+
+
+class EventNameByEventType : public map<unsigned,const char*> {
+public:
+ EventNameByEventType() {
+ for( unsigned i = 0; i < sizeof(EVENT_NAMES_BY_EVENT_TYPE)/sizeof(EVENT_NAMES_BY_EVENT_TYPE[0]); i++ )
+ (*this)[EVENT_NAMES_BY_EVENT_TYPE[i].type] = EVENT_NAMES_BY_EVENT_TYPE[i].name;
+ }
+};
+static EventNameByEventType EVENT_NAME_BY_EVENT_TYPE;
+
class EventNameByType : public map<TypeCode,const char*> {
public:
EventNameByType() {
- for( int i = 0; i < sizeof(EVENT_TYPES)/sizeof(EVENT_TYPES[0]); i++ )
+ for( unsigned i = 0; i < sizeof(EVENT_TYPES)/sizeof(EVENT_TYPES[0]); i++ )
(*this)[EVENT_TYPES[i].typeCode] = EVENT_TYPES[i].name;
}
};
struct ltstr {
bool operator()(const char * s1, const char * s2 ) const {
- return strcmp( s1, s2 ) < 0;
+ return string(s1).compare( s2 ) < 0;
}
};
class EventTypeByName : public map<const char *,TypeCode,ltstr> {
public:
EventTypeByName() {
- for( int i = 0; i < sizeof(EVENT_TYPES)/sizeof(EVENT_TYPES[0]); i++ )
+ for( unsigned i = 0; i < sizeof(EVENT_TYPES)/sizeof(EVENT_TYPES[0]); i++ )
(*this)[EVENT_TYPES[i].name] = EVENT_TYPES[i].typeCode;
}
};
FGLinuxInputDevice::FGLinuxInputDevice( string aName, string aDevname ) :
FGInputDevice(aName),
- fd(-1),
- devname( aDevname )
-
+ devname( aDevname ),
+ fd(-1)
{
}
{
}
+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;
if( (fd = ::open( devname.c_str(), O_RDWR )) == -1 ) {
throw exception();
}
-/*
- input_event evt;
- evt.type=EV_LED;
- evt.code = 8;
- evt.value = 1;
- evt.time.tv_sec = 0;
- evt.time.tv_usec = 0;
- write( fd, &evt, sizeof(evt) );
-*/
+
+ 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()
{
- if( fd != -1 ) ::close(fd);
+ if( fd != -1 ) {
+ if( GetGrab() && ioctl( fd, EVIOCGRAB, 0 ) != 0 ) {
+ SG_LOG( SG_INPUT, SG_WARN, "Can't ungrab " << devname );
+ }
+ ::close(fd);
+ }
fd = -1;
}
typeCode.type = linuxEventData.type;
typeCode.code = linuxEventData.code;
if( EVENT_NAME_BY_TYPE.count(typeCode) == 0 ) {
- sprintf( ugly_buffer, "unknown-%u-%u", (unsigned)linuxEventData.type, (unsigned)linuxEventData.code );
+ // event not known in translation tables
+ if( EVENT_NAME_BY_EVENT_TYPE.count(linuxEventData.type) == 0 ) {
+ // event type not known in translation tables
+ sprintf( ugly_buffer, "unknown-%u-%u", (unsigned)linuxEventData.type, (unsigned)linuxEventData.code );
+ return ugly_buffer;
+ }
+ sprintf( ugly_buffer, "%s-%u", EVENT_NAME_BY_EVENT_TYPE[linuxEventData.type], (unsigned)linuxEventData.code );
return ugly_buffer;
}
}
#endif
-void FGLinuxEventInput::init()
+void FGLinuxEventInput::postinit()
{
- FGEventInput::init();
+ FGEventInput::postinit();
DBusConnection * connection;
DBusError dbus_error;
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()];
// do no more than maxpolls in a single loop to prevent locking
int maxpolls = 100;
while( maxpolls-- > 0 && ::poll( fds, i, 0 ) > 0 ) {
- for( int i = 0; i < sizeof(fds)/sizeof(fds[0]); i++ ) {
+ for( unsigned i = 0; i < sizeof(fds)/sizeof(fds[0]); i++ ) {
if( fds[i].revents & POLLIN ) {
// if this device reports data ready, it should be a input_event struct
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 );
}