diff options
| author | David Härdeman <david@hardeman.nu> | 2015-08-12 14:10:45 +0200 | 
|---|---|---|
| committer | David Härdeman <david@hardeman.nu> | 2015-08-12 14:10:45 +0200 | 
| commit | 7c0458da18dd7ff129967084f893b2361eb2c2a1 (patch) | |
| tree | 01b9111d184ccef61ee92672492aa7a44d5d0df1 /rcm-server-evdev.c | |
| parent | 852e65956abc14f3591df70e8868635e2ed5dac9 (diff) | |
Move evdev_read from rcm-server-main to rcm-server-evdev
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;  } | 
