On 07/02/2012 11:44 PM, Peter Hutterer wrote:
evemu doesn't export this information and even evemu-device just trawls
through the file system to print this info. So do the same here, noting the
time before evemu_create() and the ctime of the new device file. If the
latter is later than the former and the device names match, we can assume
this is our device.

I just want to point out that it's a deficiency in uinput, not in evemu, in case anyone had any thoughts of trying to fix evemu instead.

Signed-off-by: Peter Hutterer <peter.hutte...@who-t.net>
---
  include/xorg/gtest/evemu/xorg-gtest-device.h |   13 ++++++
  src/device.cpp                               |   65 +++++++++++++++++++++++++-
  2 files changed, 77 insertions(+), 1 deletion(-)

diff --git a/include/xorg/gtest/evemu/xorg-gtest-device.h 
b/include/xorg/gtest/evemu/xorg-gtest-device.h
index 5f8faa2..359e65b 100644
--- a/include/xorg/gtest/evemu/xorg-gtest-device.h
+++ b/include/xorg/gtest/evemu/xorg-gtest-device.h
@@ -75,6 +75,17 @@ class Device {
     */
    void Play(const std::string& path) const;

+  /**
+   * Return the /dev/input/eventX device node for this device.
+   *
+   * Note that evemu doesn't know the device node, so we traverse the file
+   * system looking for it. There is a tiny chance of the device node being
+   * wrong.
+   *
+   * @return The string representing the device node
+   */
+  const char* GetDeviceNode(void);
+
   private:
    struct Private;
    std::auto_ptr<Private> d_;
@@ -82,6 +93,8 @@ class Device {
    /* Disable copy constructor & assignment operator */
    Device(const Device&);
    Device& operator=(const Device&);
+
+  void GuessDeviceNode(time_t ctime);
  };

  } // namespace evemu
diff --git a/src/device.cpp b/src/device.cpp
index 226d4e0..555e3e0 100644
--- a/src/device.cpp
+++ b/src/device.cpp
@@ -28,18 +28,74 @@
  #include "xorg/gtest/evemu/xorg-gtest-device.h"

  #include <fcntl.h>
+#include <dirent.h>

  #include <stdexcept>

  #include <gtest/gtest.h>

+#define SYS_INPUT_DIR "/sys/class/input"
+#define DEV_INPUT_DIR "/dev/input/"
+
  struct xorg::testing::evemu::Device::Private {
-  Private() : fd(-1), device(NULL) {}
+  Private() : fd(-1), device(NULL), device_node() {}

    int fd;
    struct evemu_device* device;
+  std::string device_node;
  };

+static int _event_device_compare(const struct dirent **a,
+                                 const struct dirent **b) {
+  int na, nb;
+
+  sscanf((*a)->d_name, "event%d", &na);
+  sscanf((*b)->d_name, "event%d", &nb);
+
+  return (na > nb) ? 1 : (na < nb) ? -1 : 0;
+
+}
+
+static int _event_device_filter(const struct dirent *d) {
+  return (strncmp("event", d->d_name, sizeof("event") - 1) == 0);
+}
+
+void xorg::testing::evemu::Device::GuessDeviceNode(time_t ctime) {
+  struct dirent **event_devices;
+  int n_event_devices;
+
+  n_event_devices = scandir(SYS_INPUT_DIR, &event_devices,
+                            _event_device_filter, _event_device_compare);
+
+  if (n_event_devices < 0) {
+    std::cerr << "Failed to guess device node." << std::endl;
+    return;
+  }
+
+  bool found = false;
+  for (int i = 0; i < n_event_devices && !found; i++) {
+    std::stringstream s;
+    s << DEV_INPUT_DIR << event_devices[i]->d_name;
+
+    int fd = open(s.str().c_str(), O_RDONLY);
+    char device_name[256];
+
+    ioctl(fd, EVIOCGNAME(sizeof(device_name)), device_name);
+    if (strcmp(device_name, evemu_get_name(d_->device)) == 0) {
+      struct stat buf;
+      if (fstat(fd, &buf) == 0) {
+        if (buf.st_ctime >= ctime) {
+          d_->device_node = s.str();
+          found = true;
+        }
+      }
+    }
+    close(fd);
+    free(event_devices[i]);

We need to free each event device entry, but if we break out of the loops early because we've found a matching device, then we won't free the rest of the devices in the array.

+  }
+  free(event_devices);
+}
+
  xorg::testing::evemu::Device::Device(const std::string& path)
      : d_(new Private) {
    static const char UINPUT_NODE[] = "/dev/uinput";
@@ -68,11 +124,14 @@ xorg::testing::evemu::Device::Device(const std::string& 
path)
      throw std::runtime_error("Failed to open uinput node");
    }

+  time_t ctime = time(NULL);
    if (evemu_create(d_->device, d_->fd) < 0) {
      close(d_->fd);
      evemu_delete(d_->device);
      throw std::runtime_error("Failed to create evemu device");
    }
+
+  GuessDeviceNode(ctime);
  }

  void xorg::testing::evemu::Device::Play(const std::string& path) const {
@@ -88,6 +147,10 @@ void xorg::testing::evemu::Device::Play(const std::string& 
path) const {
    fclose(file);
  }

+const char* xorg::testing::evemu::Device::GetDeviceNode(void) {
+  return d_->device_node.length() > 0 ? d_->device_node.c_str() : NULL;
+}
+
  xorg::testing::evemu::Device::~Device() {
    close(d_->fd);
    evemu_delete(d_->device);


_______________________________________________
xorg-devel@lists.x.org: X.Org development
Archives: http://lists.x.org/archives/xorg-devel
Info: http://lists.x.org/mailman/listinfo/xorg-devel

Reply via email to