Commit 9bf895eb authored by Peter Hutterer's avatar Peter Hutterer
Browse files

Add Device::GetDeviceNode() to return device node path from an evemu device



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.
Signed-off-by: Peter Hutterer's avatarPeter Hutterer <peter.hutterer@who-t.net>
Reviewed-by: default avatarChase Douglas <chase.douglas@canonical.com>
parent fbafda2e
......@@ -75,6 +75,18 @@ 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, or the device disappearing before we find it. If the device
* node cannot be found, an empty string is returned.
*
* @return The string representing the device node
*/
const std::string& GetDeviceNode(void);
private:
struct Private;
std::auto_ptr<Private> d_;
......@@ -82,6 +94,8 @@ class Device {
/* Disable copy constructor & assignment operator */
Device(const Device&);
Device& operator=(const Device&);
void GuessDeviceNode(time_t ctime);
};
} // namespace evemu
......
......@@ -28,18 +28,76 @@
#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);
}
for (int i = 0; i < n_event_devices; i++)
free(event_devices[i]);
free(event_devices);
}
xorg::testing::evemu::Device::Device(const std::string& path)
: d_(new Private) {
static const char UINPUT_NODE[] = "/dev/uinput";
......@@ -68,11 +126,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 +149,10 @@ void xorg::testing::evemu::Device::Play(const std::string& path) const {
fclose(file);
}
const std::string& xorg::testing::evemu::Device::GetDeviceNode(void) {
return d_->device_node;
}
xorg::testing::evemu::Device::~Device() {
close(d_->fd);
evemu_delete(d_->device);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment