Skip to content

Instantly share code, notes, and snippets.

@notjuliee
Last active September 24, 2019 06:15
Show Gist options
  • Save notjuliee/a8ebc6b0e6858c26b942368aa60cae19 to your computer and use it in GitHub Desktop.
Save notjuliee/a8ebc6b0e6858c26b942368aa60cae19 to your computer and use it in GitHub Desktop.
Key forwarder
# The device you wish to capture
BASE_KBD = "/dev/input/by-id/usb-IBM_Model_M-if03-event-kbd"
# Keys that will be sent to the host device
HOST_KEYS = [
"KEY_A",
]
# Keys that will be sent to both host and guest device
SHARED_KEYS = [
"KEY_B",
]
# Guest gets every other key
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <set>
#include <libevdev/libevdev-uinput.h>
#include <libevdev/libevdev.h>
#include "toml11/toml.hpp"
void c_err(const char* msg, int rc) {
if (rc != 0) {
fprintf(stderr, "[%s] libevdev error: %s\n", msg, strerror(-rc));
exit(rc);
}
}
std::set<int> from_syms(std::vector<std::string> syms) {
std::set<int> out;
for (const auto &sym : syms) {
out.insert(libevdev_event_code_from_name(EV_KEY, sym.c_str()));
}
return out;
}
int main(int argc, char *argv[]) {
const auto data = toml::parse("config.toml");
std::string indev = toml::find<std::string>(data, "BASE_KBD");
auto host_syms = from_syms(toml::find<std::vector<std::string>>(data, "HOST_KEYS"));
auto shared_syms = from_syms(toml::find<std::vector<std::string>>(data, "SHARED_KEYS"));
struct libevdev *in_dev = NULL;
int rc = 1;
int fd = open(indev.c_str(), O_RDONLY | O_NONBLOCK);
c_err("open_base", libevdev_new_from_fd(fd, &in_dev));
libevdev_uinput *guest_dev = nullptr;
libevdev_uinput *host_dev = nullptr;
const char* orig_name = libevdev_get_name(in_dev);
libevdev_set_name(in_dev, "cloned guest device");
c_err("create_guest", libevdev_uinput_create_from_device(in_dev, LIBEVDEV_UINPUT_OPEN_MANAGED, &guest_dev));
libevdev_set_name(in_dev, "cloned host device");
c_err("create_host", libevdev_uinput_create_from_device(in_dev, LIBEVDEV_UINPUT_OPEN_MANAGED, &host_dev));
libevdev_set_name(in_dev, orig_name);
libevdev_grab(in_dev, LIBEVDEV_GRAB);
printf("Guest device: %s\n", libevdev_uinput_get_devnode(guest_dev));
printf("Host device: %s\n", libevdev_uinput_get_devnode(host_dev));
do {
struct input_event ev;
rc = libevdev_next_event(in_dev, LIBEVDEV_READ_FLAG_NORMAL, &ev);
if (rc == 0) {
if (ev.type == EV_KEY) {
if (host_syms.count(ev.code)) {
libevdev_uinput_write_event(host_dev, ev.type, ev.code, ev.value);
libevdev_uinput_write_event(host_dev, EV_SYN, SYN_REPORT, 0);
continue;
} else if (shared_syms.count(ev.code)) {
libevdev_uinput_write_event(host_dev, ev.type, ev.code, ev.value);
libevdev_uinput_write_event(host_dev, EV_SYN, SYN_REPORT, 0);
libevdev_uinput_write_event(guest_dev, ev.type, ev.code, ev.value);
libevdev_uinput_write_event(guest_dev, EV_SYN, SYN_REPORT, 0);
continue;
}
}
libevdev_uinput_write_event(guest_dev, ev.type, ev.code, ev.value);
}
} while (rc == 1 || rc == 0 || rc == -EAGAIN);
libevdev_grab(in_dev, LIBEVDEV_UNGRAB);
libevdev_uinput_destroy(guest_dev);
libevdev_uinput_destroy(host_dev);
libevdev_free(in_dev);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment