Blub / netevent

Input-Event device cloning utility. Use it together with ssh/netcat/... to share input devices among different machines.
GNU General Public License v2.0
148 stars 14 forks source link

Patch for different sizes (e.g. Raspberry Pi) #1

Closed frankheckenbach closed 9 years ago

frankheckenbach commented 9 years ago

Thanks for netevent!

A couple of notes and suggestions:

I tried to use it between a PC (amd64) and a Raspberry Pi (armv6l). It didn't work out of the box. I think the problematic line was if (!cin.read(evreadpos, sizeof(ev))) { which should read only strsz[1] bytes if the sizes don't match.

Instead of changing that, I made the following change to make the code a bit more flexible (and not much longer):

Even after this change, I don't think it's fully portable. Even if sizeof(dev) matches, its layout or padding may be different. And different endianness is not handled. It also may not be fully thread-safe; at least atomic access should be used for the shared variables. And maybe more ... But it works for me now.(tm) ;)

Additionally I changed:

Also I found it easier to use socat instead of netcat as suggested, especially on the receiver side, because with "fork" it can handle several connections with one command (and one port). With the following command, you can forward keyboard and mouse (and whatever else you want) all to port 1955. It also works automatically if you restart netevent on the sending side, without a need to restart anything on the other side:

socat tcp-listen:1955,fork exec:"/usr/local/bin/netevent -write"

--- netevent-master/Makefile    2012-04-10 11:45:17.000000000 +0200
+++ netevent-master/Makefile    2015-02-28 08:30:28.000000000 +0100
@@ -1,3 +1,5 @@
+prefix = /usr/local
+bindir = $(prefix)/bin
 CXX = g++
 CC = gcc
 CFLAGS = -Wall -pthread
@@ -26,6 +28,9 @@
 devname: build/devname.o
    $(CC) -o $@ $^

+install: all
+   install -m 755 -p -t "$(DESTDIR)$(bindir)" netevent devname
+
 clean:
    -rm -rf build
    -rm -f netevent devname
--- netevent-master/main.h  2012-04-10 11:45:17.000000000 +0200
+++ netevent-master/main.h  2015-02-28 08:21:06.000000000 +0100
@@ -15,6 +15,7 @@
 #include <errno.h>
 #include <stdlib.h>
 #include <string.h>
+#include <stdint.h>

 #define gerr() std::string err(strerror(errno))
 #define cErr gerr(); cerr
@@ -34,6 +35,14 @@
    std::string command;
 } hotkey_t;

+struct input_event_t {
+   uint64_t tv_sec;
+   uint32_t tv_usec;
+   uint16_t type;
+   uint16_t code;
+   int32_t value;
+};
+
 const char *evname(unsigned int e);
 int evid(const char *name);

--- netevent-master/reader.cpp  2012-04-10 11:45:17.000000000 +0200
+++ netevent-master/reader.cpp  2015-02-28 08:21:49.000000000 +0100
@@ -82,6 +82,7 @@
            cErr << "Failed to open '" << toggle_file << "': " << err << endl;
            break;
        }
+       memset(dat, 0, sizeof(dat));
        read(tfd, dat, sizeof(dat));
        close(tfd);
        dat[sizeof(dat)-1] = 0;
@@ -157,11 +158,9 @@
    cerr << "BusType: " << dev.id.bustype << endl;

    // First thing to write is the size of the structures as a 16 bit uint!
-   uint16_t strsz[3];
-   strsz[0] = sizeof(ev.time);
-   strsz[1] = sizeof(ev);
-   strsz[2] = sizeof(dev);
-   if (!cout.write((const char*)strsz, sizeof(strsz)))
+   uint16_t strsz;
+   strsz = sizeof(dev);
+   if (!cout.write((const char*)&strsz, sizeof(strsz)))
        exit(1);
    if (cout.eof())
        exit(0);
@@ -272,7 +271,13 @@
                toggle_hook();
        }
        else if (on) {
-           if (!cout.write((const char*)&ev, sizeof(ev)))
+           input_event_t et;
+           et.tv_sec = ev.time.tv_sec;
+           et.tv_usec = ev.time.tv_usec;
+           et.type = ev.type;
+           et.code = ev.code;
+           et.value = ev.value;
+           if (!cout.write((const char*)&et, sizeof(et)))
                exit(1);
            if (cout.eof())
                exit(0);
--- netevent-master/write.cpp   2012-04-10 11:45:17.000000000 +0200
+++ netevent-master/write.cpp   2015-02-28 08:22:17.000000000 +0100
@@ -11,7 +11,7 @@
 };
 static const size_t uinput_cnt = sizeof(uinput_file) / sizeof(uinput_file[0]);

-static uint16_t strsz[3];
+static uint16_t strsz;

 int spawn_device()
 {
@@ -33,26 +33,13 @@

    struct uinput_user_dev dev;
    struct input_event ev;
-   char *evreadpos = (char*)&ev;

-   cin.read((char*)strsz, sizeof(strsz));
-   if (strsz[2] != sizeof(uinput_user_dev)) {
+   cin.read((char*)&strsz, sizeof(strsz));
+   if (strsz != sizeof(uinput_user_dev)) {
        cerr << "Device information field sizes do not match. Sorry." << endl;
        return 1;
    }

-   if (strsz[1] != sizeof(ev)) {
-       cerr << "Beware, devices may be incompatible\n" <<
-           "Host input_event: size: " << strsz[1] <<
-           ", timeval size: " << sizeof(ev) << std::endl;
-   }
-
-   if ((sizeof(ev) - sizeof(ev.time)) != (strsz[1] - strsz[0]))
-   {
-       cerr << "input-event sizes are incompatible, sorry." << endl;
-       return 1;
-   }
-
    memset(&dev, 0, sizeof(dev));
    cin.read((char*)dev.name, sizeof(dev.name));
    cin.read((char*)&dev.id, sizeof(dev.id));
@@ -131,24 +118,19 @@
    }

    cerr << "Transferring input events." << endl;
-   char field[512];
-   memset(field, -1, sizeof(field));
-   if (sizeof(ev) == strsz[1])
-       evreadpos = (char*)&ev;
-   else
-       evreadpos = (char*)field;
    while (true) {
+       input_event_t et;
        int dummy;
        waitpid(0, &dummy, WNOHANG);
-       if (!cin.read(evreadpos, sizeof(ev))) {
+       if (!cin.read((char*)&et, sizeof(et))) {
            cerr << "End of data" << endl;
            break;
        }
-       if (evreadpos != (char*)&ev)
-       {
-           memcpy(((char*)&ev) + sizeof(ev.time), evreadpos + strsz[0], sizeof(ev) - sizeof(ev.time));
-           gettimeofday(&ev.time, 0);
-       }
+       ev.time.tv_sec = et.tv_sec;
+       ev.time.tv_usec = et.tv_usec;
+       ev.type = et.type;
+       ev.code = et.code;
+       ev.value = et.value;
        if (hotkey_hook(ev.type, ev.code, ev.value))
            continue;
        if (write(fd, &ev, sizeof(ev)) < (ssize_t)sizeof(ev)) {
Blub commented 9 years ago

Thanks I'll give it a testrun and apply the patch later. I'm aware of the portability issues. Even with sizes and endianess of values defined it will still only work as long as the values mean the same on both ends. As I'm using ArchBSD on my desktop now, which has no uinput and no evdev, I currently actually lack a use case which is why I haven't touched the code in a long time.

For me it was mostly a convenience tool while having laptop and desktop with both running ArchLinux x8_64 ;)

Blub commented 9 years ago

Sorry for the delay. As I said I don't have the setup anymore where I need it.

frankheckenbach commented 9 years ago

No problem. Thanks for applying it!