summaryrefslogtreecommitdiff
path: root/rcm-server-evdev.c
diff options
context:
space:
mode:
Diffstat (limited to 'rcm-server-evdev.c')
-rw-r--r--rcm-server-evdev.c137
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;
}