|
#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; |
|
} |