diff options
Diffstat (limited to 'rcm-server-evdev.c')
-rw-r--r-- | rcm-server-evdev.c | 137 |
1 files changed, 134 insertions, 3 deletions
diff --git a/rcm-server-evdev.c b/rcm-server-evdev.c index bc8361e..74cae10 100644 --- a/rcm-server-evdev.c +++ b/rcm-server-evdev.c @@ -6,6 +6,9 @@ #include <systemd/sd-bus.h> #include <errno.h> #include <linux/input.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> #include "utils.h" #include "shared.h" @@ -33,7 +36,7 @@ struct rc_keymap_entry { }; #define RKE_SIZE (sizeof(struct rc_scancode)) -const char * +static const char * evdev_guess_protocol(struct device *device, uint64_t scancode, uint32_t keycode) { struct rc_keymap_entry rke; @@ -137,15 +140,134 @@ evdev_set_keymap(struct device *device, struct keymap *keymap) return 0; } +static int +evdev_read(sd_event_source *s, int fd, uint32_t revents, void *userdata) +{ + struct device *device = userdata; + struct input_event ev; + static struct linux_input_keycode *keycode = NULL; + static bool pressed = false; + static uint32_t scancode; + static bool scancode_recv = false; + unsigned i; + + if (fd != device->evdev_fd) + fprintf(stderr, "evdev fd mismatch: %i != %i\n", device->evdev_fd, fd); + + if (revents & EPOLLHUP) { + fprintf(stderr, "evdev connection closed!\n"); + close(fd); + device->evdev_fd = -1; + return 0; + } + + if (!(revents & EPOLLIN)) { + fprintf(stderr, "unexpected evdev event: %" PRIu32 "\n", revents); + return 0; + } + + while (read(fd, &ev, sizeof(ev)) == sizeof(ev)) { + switch (ev.type) { + case EV_KEY: + if (keycode) + printf("Reading from evdev - multiple keycodes?\n"); + + for (i = 0; linux_input_keycodes[i].name; i++) { + if (linux_input_keycodes[i].value == ev.code) + break; + } + + if (!linux_input_keycodes[i].name) { + printf("evdev - unknown keycode (%u)\n", ev.code); + break; + } + + keycode = &linux_input_keycodes[i]; + if (ev.value) + pressed = true; + break; + + case EV_MSC: + if (ev.code == MSC_SCAN) { + if (scancode_recv) + printf("Reading from evdev - multiple scancodes?\n"); + scancode_recv = true; + scancode = ev.value; + } + break; + + case EV_SYN: + if (keycode || scancode_recv) { + const char *protocol; + + /* FIXME: protocol reporting needs kernel support */ + if (scancode_recv) + protocol = evdev_guess_protocol(device, scancode, keycode ? keycode->value : KEY_RESERVED); + + printf("evdev -"); + + if (scancode_recv) { + printf(" protocol %s (guessed)", protocol); + printf(" scancode 0x%08x", scancode); + } + + if (keycode) { + printf(" keycode %s (%u)", keycode->name, keycode->value); + printf(" %s", pressed ? "pressed" : "released"); + } + + printf("\n"); + + if (scancode_recv) + sd_bus_emit_signal(device->mgr->bus, + device->path, + "org.gnome.RemoteControlManager.Device", + "KeyPressed", + "sts", protocol, scancode, + keycode ? keycode->name : "KEY_RESERVED"); + + else if (keycode && !pressed) + sd_bus_emit_signal(device->mgr->bus, + device->path, + "org.gnome.RemoteControlManager.Device", + "KeyReleased", + "s", keycode->name); + } + + scancode_recv = false; + pressed = false; + keycode = NULL; + break; + + default: + break; + } + } + + return 0; +} + int -evdev_setup(struct device *device) +evdev_setup(struct manager *mgr, struct device *device, const char *path) { int r; struct keymap *keymap; - if (!device || device->evdev_fd < 0) + if (!device) return -EINVAL; + if (device->evdev_fd >= 0) { + printf("Multiple evdev devices!?\n"); + return 0; + } + + device->evdev_fd = open(path, O_RDONLY | O_NONBLOCK); + if (device->evdev_fd < 0) { + printf("Failed to open evdev device %s: %s\n", + path, strerror(errno)); + return -errno; + } + printf("Performing evdev setup for device %s\n", device->path); r = evdev_clear_keymap(device); if (r < 0) @@ -154,6 +276,15 @@ evdev_setup(struct device *device) list_for_each_entry(keymap, &device->keymaps, list) r = evdev_set_keymap(device, keymap); + if (sd_event_add_io(mgr->event, &device->evdev_ev, + device->evdev_fd, EPOLLIN, evdev_read, device) < 0) { + printf("Failed to add event source for evdev device %s: %s\n", + path, strerror(errno)); + close(device->evdev_fd); + device->evdev_fd = -1; + return -errno; + } + return r; } |