On Tue, Jul 03, 2012 at 11:40:25AM -0700, Chase Douglas wrote: > 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.
I did try. This could easily be part of evemu, running this exact same code right after the UI_DEV_CREATE call. Unfortunately evemu_create() takes a const struct so we can't save it easily without breaking ABI. [memleak fixed, thanks for pointing this out] Cheers, Peter > >Signed-off-by: Peter Hutterer <[email protected]> > >--- > > 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); > > > _______________________________________________ [email protected]: X.Org development Archives: http://lists.x.org/archives/xorg-devel Info: http://lists.x.org/mailman/listinfo/xorg-devel
