]> git.mxchange.org Git - flightgear.git/blobdiff - src/Input/FGLinuxEventInput.cxx
Remove dead file.
[flightgear.git] / src / Input / FGLinuxEventInput.cxx
index ec0f23da2c6b4843a751c80ddf09e48ac419e675..43256aadd485a167c2042eb2c215d9e94f517bf6 100644 (file)
 // You should have received a copy of the GNU General Public License
 // along with this program; if not, write to the Free Software
 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
-//
-// $Id$
 
 #ifdef HAVE_CONFIG_H
 #  include <config.h>
 #endif
 
+#include <cstring>
+#include <sys/types.h>
+#include <sys/stat.h>
 #include "FGLinuxEventInput.hxx"
 
+#include <libudev.h>
 #include <poll.h>
 #include <linux/input.h>
-#include <dbus/dbus.h>
+#include <fcntl.h>
+
+#include <string.h>
 
 struct TypeCode {
   unsigned type;
@@ -38,7 +42,7 @@ struct TypeCode {
     return (unsigned long)type << 16 | (unsigned long)code;
   }
 
-  bool operator < ( const TypeCode other) const {
+  bool operator < ( const TypeCode other) const {
     return hashCode() < other.hashCode();
   }
 };
@@ -198,10 +202,38 @@ static struct EventTypes {
 
 };
 
-class EventNameByType : public map<TypeCode,const char*> {
+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 std::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 std::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;
   }
 };
@@ -210,25 +242,24 @@ static EventNameByType EVENT_NAME_BY_TYPE;
 
 struct ltstr {
   bool operator()(const char * s1, const char * s2 ) const {
-    return strcmp( s1, s2 ) < 0;
+    return std::string(s1).compare( s2 ) < 0;
   }
 };
 
-class EventTypeByName : public map<const char *,TypeCode,ltstr> {
+class EventTypeByName : public std::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;
   }
 };
 static EventTypeByName EVENT_TYPE_BY_NAME;
 
 
-FGLinuxInputDevice::FGLinuxInputDevice( string aName, string aDevname ) :
+FGLinuxInputDevice::FGLinuxInputDevice( std::string aName, std::string aDevname ) :
   FGInputDevice(aName),
-  fd(-1),
-  devname( aDevname )
-
+  devname( aDevname ),
+  fd(-1)
 {
 }
 
@@ -246,17 +277,118 @@ FGLinuxInputDevice::FGLinuxInputDevice() :
 {
 }
 
+static inline bool bitSet( unsigned char * buf, unsigned bit )
+{
+  return (buf[bit/sizeof(unsigned char)/8] >> (bit%(sizeof(unsigned char)*8))) & 1;
+}
+
 void FGLinuxInputDevice::Open()
 {
   if( fd != -1 ) return;
   if( (fd = ::open( devname.c_str(), O_RDWR )) == -1 ) { 
-    throw exception();
+    throw std::exception();
+  }
+
+  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;
+/*
+          SG_LOG( SG_INPUT, SG_INFO, "Axis #" << i <<
+            ": value=" << ai.value << 
+            ": minimum=" << ai.minimum << 
+            ": maximum=" << ai.maximum << 
+            ": fuzz=" << ai.fuzz << 
+            ": flat=" << ai.flat << 
+            ": resolution=" << ai.resolution );
+*/
+
+          // kick an initial event
+          struct input_event event;
+          event.type = EV_ABS;
+          event.code = i;
+          event.value = ai.value;
+          FGLinuxEventData eventData( event, 0, 0 );
+          eventData.value = Normalize( event );
+          HandleEvent(eventData);
+        }
+      }
+    }
+  }
+  {
+    unsigned char mask[KEY_CNT/sizeof(unsigned char)/8];
+    unsigned char flag[KEY_CNT/sizeof(unsigned char)/8];
+    memset(mask,0,sizeof(mask));
+    memset(flag,0,sizeof(flag));
+    if( ioctl( fd, EVIOCGKEY(sizeof(flag)), flag ) == -1 ||
+        ioctl( fd, EVIOCGBIT(EV_KEY, sizeof(mask)), mask ) == -1 ) {
+      SG_LOG( SG_INPUT, SG_WARN, "Can't get keys for " << devname );
+    } else {
+      for( unsigned i = 0; i < KEY_MAX; i++ ) {
+        if( bitSet( mask, i ) ) {
+          struct input_event event;
+          event.type = EV_KEY;
+          event.code = i;
+          event.value = bitSet(flag,i);
+          FGLinuxEventData eventData( event, 0, 0 );
+          HandleEvent(eventData);
+        }
+      }
+    }
+  }
+  {
+    unsigned char buf[SW_CNT/sizeof(unsigned char)/8];
+    if( ioctl( fd, EVIOCGSW(sizeof(buf)), buf ) == -1 ) {
+      SG_LOG( SG_INPUT, SG_WARN, "Can't get switches for " << devname );
+    } else {
+      for( unsigned i = 0; i < SW_MAX; i++ ) {
+        if( bitSet( buf, i ) ) {
+          struct input_event event;
+          event.type = EV_SW;
+          event.code = i;
+          event.value = 1;
+          FGLinuxEventData eventData( event, 0, 0 );
+          HandleEvent(eventData);
+        }
+      }
+    }
+  }
+}
+
+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;
 }
 
@@ -291,116 +423,71 @@ const char * FGLinuxInputDevice::TranslateEventName( FGEventData & eventData )
   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;
   }
 
   return EVENT_NAME_BY_TYPE[typeCode];
 }
 
-void FGLinuxInputDevice::SetDevname( string name )
+void FGLinuxInputDevice::SetDevname( const std::string & name )
 {
   this->devname = name; 
 }
 
-FGLinuxEventInput::FGLinuxEventInput() : 
-  halcontext(NULL)
+FGLinuxEventInput::FGLinuxEventInput()
 {
 }
 
 FGLinuxEventInput::~FGLinuxEventInput()
-{
-  if( halcontext != NULL ) {
-    libhal_ctx_shutdown( halcontext, NULL);
-    libhal_ctx_free( halcontext );
-    halcontext = NULL;
-  }
-}
-
-#if 0
-//TODO: enable hotplug support
-static void DeviceAddedCallback (LibHalContext *ctx, const char *udi)
-{
-  FGLinuxEventInput * linuxEventInput = (FGLinuxEventInput*)libhal_ctx_get_user_data (ctx);
-  linuxEventInput->AddHalDevice( udi );
-}
-
-static void DeviceRemovedCallback (LibHalContext *ctx, const char *udi)
 {
 }
-#endif
 
-void FGLinuxEventInput::init()
+void FGLinuxEventInput::postinit()
 {
-  FGEventInput::init();
-
-  DBusConnection * connection;
-  DBusError dbus_error;
-
-  dbus_error_init(&dbus_error);
-  connection = dbus_bus_get (DBUS_BUS_SYSTEM, &dbus_error);
-  if (dbus_error_is_set(&dbus_error)) {
-    SG_LOG( SG_INPUT, SG_ALERT, "Can't connect to system bus " << dbus_error.message);
-    dbus_error_free (&dbus_error);
-    return;
-  }
-
-  halcontext = libhal_ctx_new();
-
-  libhal_ctx_set_dbus_connection (halcontext, connection );
-  dbus_error_init (&dbus_error);
+  FGEventInput::postinit();
 
-  if( libhal_ctx_init( halcontext,  &dbus_error )) {
+  struct udev * udev = udev_new();
 
-      int num_devices = 0;
-      char ** devices = libhal_find_device_by_capability(halcontext, "input", &num_devices, NULL);
-
-      for ( int i = 0; i < num_devices; i++)
-        AddHalDevice( devices[i] );
-
-      libhal_free_string_array (devices);
-
-//TODO: enable hotplug support
-//      libhal_ctx_set_user_data( halcontext, this );
-//      libhal_ctx_set_device_added( halcontext, DeviceAddedCallback );
-//      libhal_ctx_set_device_removed( halcontext, DeviceRemovedCallback );
-    } else {
-      if(dbus_error_is_set (&dbus_error) ) {
-        SG_LOG( SG_INPUT, SG_ALERT, "Can't connect to hald: " << dbus_error.message);
-        dbus_error_free (&dbus_error);
-      } else {
-        SG_LOG( SG_INPUT, SG_ALERT, "Can't connect to hald." );
-      }
+  struct udev_enumerate *enumerate = udev_enumerate_new(udev);
+  udev_enumerate_add_match_subsystem(enumerate, "input");
+  udev_enumerate_scan_devices(enumerate);
+  struct udev_list_entry *devices = udev_enumerate_get_list_entry(enumerate);
+  struct udev_list_entry *dev_list_entry;
 
-      libhal_ctx_free (halcontext);
-      halcontext = NULL;
-    }
-}
+  udev_list_entry_foreach(dev_list_entry, devices) {
+    const char * path = udev_list_entry_get_name(dev_list_entry);
+    struct udev_device *dev = udev_device_new_from_syspath(udev, path);
+    const char * node = udev_device_get_devnode(dev);
+    dev = udev_device_get_parent( dev );
+    const char * name = udev_device_get_sysattr_value(dev,"name");
 
-void FGLinuxEventInput::AddHalDevice( const char * udi )
-{
-  char * device = libhal_device_get_property_string( halcontext, udi, "input.device", NULL);
-  char * product = libhal_device_get_property_string( halcontext, udi, "input.product", NULL);
+    SG_LOG(SG_INPUT,SG_DEBUG, "name=" << (name?name:"<null>") << ", node=" << (node?node:"<null>"));
+    if( name && node )
+      AddDevice( new FGLinuxInputDevice(name, node) );
 
-  if( product != NULL && device != NULL ) 
-    AddDevice( new FGLinuxInputDevice(product, device) );
-  else
-    SG_LOG( SG_INPUT, SG_ALERT, "Can't get device or product property of " << udi );
+    udev_device_unref(dev);
+  }
 
-  if( device != NULL ) libhal_free_string( device );
-  if( product != NULL ) libhal_free_string( product );
+  udev_unref(udev);
 
 }
 
 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()];
-  map<int,FGLinuxInputDevice*> devicesByFd;
-  map<int,FGInputDevice*>::const_iterator it;
+  std::map<int,FGLinuxInputDevice*> devicesByFd;
+  std::map<int,FGInputDevice*>::const_iterator it;
   int i;
   for( i=0, it = input_devices.begin(); it != input_devices.end(); ++it, i++ ) {
     FGInputDevice* p = (*it).second;
@@ -415,7 +502,7 @@ void FGLinuxEventInput::update( double dt )
   // 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
@@ -426,9 +513,13 @@ 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 );
       }
     }
   }
 }
+