#include "evdev.h"
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <linux/input.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sstream>
-const struct EvDev::device_enumeration *
-EvDev::enumerate(std::size_t &)
+// Remove extra spaces from string, in place.
+char *
+clean_string(char * string)
{
- return 0;
+ char * s = string;
+
+ while ( *s != 0 ) {
+ if ( *s == ' ' && s[1] == ' ' ) {
+ s++;
+ char * end = s;
+ while ( *end == ' ' )
+ end++;
+ memmove(s, end, strlen(end) + 1);
+ }
+ s++;
+ }
+
+ const std::size_t length = strlen(string);
+
+ if ( length > 1 && string[length - 1] == ' ' )
+ string[length - 1] = '\0';
+
+ return string;
+}
+
+void
+EvDev::delete_enumeration(
+ EvDev::device_enumeration * data,
+ std::size_t count)
+{
+ for ( std::size_t i = 0; i < count; i++ ) {
+ delete data[i].special_file;
+ delete data[i].name;
+ }
+ delete data;
+}
+
+struct EvDev::device_enumeration *
+EvDev::enumerate(std::size_t & count)
+{
+ struct device_enumeration devices[100];
+
+ count = 0;
+
+ for ( int i = 0; sizeof(devices) / sizeof(*devices); i++ ) {
+ std::ostringstream str;
+
+ str << "/dev/input/event" << i;
+
+ const char * const special_file = str.str().c_str();
+
+ const int fd = open(special_file, O_RDONLY);
+
+ if ( fd >= 0 ) {
+ if ( enumerate_device(special_file, fd, devices[count]) )
+ count++;
+ close(fd);
+ }
+ }
+ device_enumeration * const r = new device_enumeration[count];
+
+ memcpy(r, devices, count * sizeof(*r));
+
+ return r;
+}
+
+bool
+EvDev::enumerate_device(
+ const char * special_file,
+ int fd,
+ device_enumeration & device)
+{
+ char buf[100];
+ std::ostringstream str;
+
+ device.special_file = strdup(special_file);
+
+ if ( ioctl(fd, EVIOCGNAME(sizeof(buf)), buf) < 0
+ || ioctl(fd, EVIOCGBIT(0, sizeof(device.event_types)), device.event_types)
+ < 0 )
+ return false;
+
+ str << clean_string(buf);
+
+ if ( ioctl(fd, EVIOCGUNIQ(sizeof(buf)), buf) >= 0 )
+ str << ' ' << clean_string(buf);
+
+ if ( ioctl(fd, EVIOCGPHYS(sizeof(buf)), buf) >= 0 )
+ str << " at " << clean_string(buf);
+
+ device.name = strdup(str.str().c_str());
+
+ return true;
}
const char * const *
EvDev::EnumerateButtonDevices()
{
+ std::size_t count = 0;
+ std::size_t length = 0;
+ device_enumeration * const devices = enumerate(count);
+
+ for ( std::size_t i = 0; i < count; i++ ) {
+ if ( test_bit(EV_KEY, devices[i].event_types) )
+ length++;
+ }
+
+ delete_enumeration(devices, count);
return 0;
}
#define test_bit(bit, array) ((array[LONG(bit)] >> OFF(bit)) & 1)
class EvDev {
+protected:
+ struct device_enumeration {
+ const char * special_file;
+ const char * name;
+ uint8_t event_types[(EV_MAX + 7) / 8];
+ };
+
private:
EvDev(const EvDev &);
EvDev & operator =(const EvDev &);
+ static bool enumerate_device(
+ const char * name,
+ int fd,
+ struct device_enumeration & device);
+
protected:
- struct device_enumeration {
- const char * device;
- const char * name;
- uint8_t event_types[(EV_MAX + 7) / 8];
- };
+ static void delete_enumeration(
+ device_enumeration * data,
+ std::size_t count);
- static const device_enumeration *
- enumerate(std::size_t & size);
+ static device_enumeration *
+ enumerate(std::size_t & count);
public:
static const char * const *