#define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include "utils.h" #include "shared.h" #include "rcm-server-main.h" #include "rcm-server-evdev.h" #include "rcm-server-keymap.h" struct rc_scancode { __u16 protocol; __u16 reserved[3]; __u64 scancode; }; #define INPUT_KEYMAP_BY_INDEX (1 << 0) struct rc_keymap_entry { __u8 flags; __u8 len; __u16 index; __u32 keycode; union { struct rc_scancode rc; __u8 raw[32]; }; char end[]; }; #define RKE_SIZE (sizeof(struct rc_scancode)) static const char * evdev_get_protocol_name(__u16 protocol) { if (protocol > ARRAY_SIZE(rc_protocols)) return NULL; return rc_protocols[protocol]; } static const char * evdev_guess_protocol(struct rc_device *rcdev, uint64_t scancode, uint32_t keycode) { struct rc_keymap_entry rke; unsigned i; if (!rcdev) return NULL; if (rcdev->evdev_fd < 0) return NULL; for (i = 0; ; i++) { memset(&rke, 0, sizeof(rke)); rke.len = RKE_SIZE; rke.index = i; rke.flags = INPUT_KEYMAP_BY_INDEX; if (ioctl(rcdev->evdev_fd, EVIOCGKEYCODE_V2, &rke)) break; if (rke.rc.scancode != scancode) continue; if (rke.keycode != keycode) continue; return evdev_get_protocol_name(rke.rc.protocol); } return NULL; } int evdev_get_mapping(struct rc_device *rcdev, unsigned index, unsigned *ret_protocol, uint64_t *ret_scancode, struct linux_input_keycode **ret_lik) { struct rc_keymap_entry rke; struct linux_input_keycode *lik; memset(&rke, 0, sizeof(rke)); rke.len = RKE_SIZE; rke.index = index; rke.flags = INPUT_KEYMAP_BY_INDEX; if (ioctl(rcdev->evdev_fd, EVIOCGKEYCODE_V2, &rke)) return 0; lik = get_linux_keycode_by_value(rke.keycode); if (!lik) { printf("unknown keycode: %" PRIu32 "\n", rke.keycode); return -EINVAL; } *ret_protocol = rke.rc.protocol; *ret_scancode = rke.rc.scancode; *ret_lik = lik; return 1; } int evdev_set_mapping(struct rc_device *rcdev, unsigned protocol, uint64_t scancode, struct linux_input_keycode *lik) { struct rc_keymap_entry rke; int r; memset(&rke, 0, sizeof(rke)); rke.len = RKE_SIZE; rke.rc.protocol = protocol; rke.rc.scancode = scancode; if (lik) rke.keycode = lik->value; else rke.keycode = KEY_RESERVED; if (ioctl(rcdev->evdev_fd, EVIOCSKEYCODE_V2, &rke)) { r = -errno; printf("EVIOCSKEYCODE_V2 failed (%s)\n", strerror(errno)); } return r; } static int evdev_clear_keymap(struct rc_device *rcdev) { struct rc_keymap_entry rke; unsigned count = 0; int r = 0; printf("Clearing keymap..."); while (true) { memset(&rke, 0, sizeof(rke)); rke.len = RKE_SIZE; rke.index = 0; rke.flags = INPUT_KEYMAP_BY_INDEX; if (ioctl(rcdev->evdev_fd, EVIOCGKEYCODE_V2, &rke)) { printf("done (%u entries removed)\n", count); break; } /* printf(" Clearing 0x%08llX (0x%02X) to 0x%02X\n", rke.u.rc.scancode, rke.u.rc.protocol, rke.keycode); */ rke.keycode = KEY_RESERVED; if (ioctl(rcdev->evdev_fd, EVIOCSKEYCODE_V2, &rke)) { r = -errno; printf("failed (%s)\n", strerror(errno)); break; } count++; } return r; } static void set_keycode_new(struct rc_device *rcdev, __u16 protocol, __u64 scancode, __u32 keycode) { struct rc_keymap_entry rke; memset(&rke, 0, sizeof(rke)); rke.len = RKE_SIZE; rke.rc.protocol = protocol; rke.rc.scancode = scancode; rke.keycode = keycode; printf("Setting keycode (new ioctl) 0x%08llX (0x%02X) to 0x%02X\n", rke.rc.scancode, rke.rc.protocol, rke.keycode); if (ioctl(rcdev->evdev_fd, EVIOCSKEYCODE_V2, &rke)) { printf("Unable to call SETKEYCODE2 ioctl\n"); exit(EXIT_FAILURE); } } static int evdev_set_keymap(struct rc_device *rcdev, struct keymap *keymap) { unsigned i; printf("\tSetting up keymap: %s\n", keymap->name); for (i = 0; i < keymap->keycode_count; i++) set_keycode_new(rcdev, keymap->keycodes[i].protocol, keymap->keycodes[i].scancode, keymap->keycodes[i].lik->value); printf("\tDone: %u entries added\n", i); return 0; } static int evdev_read(sd_event_source *s, int fd, uint32_t revents, void *userdata) { struct rc_device *rcdev = 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; static uint32_t protocol; static bool protocol_recv = false; int r; if (fd != rcdev->evdev_fd) fprintf(stderr, "evdev fd mismatch: %i != %i\n", rcdev->evdev_fd, fd); if (revents & EPOLLHUP) { fprintf(stderr, "evdev connection closed!\n"); evdev_close(rcdev); return 0; } if (!(revents & EPOLLIN)) { fprintf(stderr, "unexpected evdev event: %" PRIu32 "\n", revents); return 0; } do { char buf[100]; r = libevdev_next_event(rcdev->evdev_dev, LIBEVDEV_READ_FLAG_NORMAL, &ev); if (r != LIBEVDEV_READ_STATUS_SUCCESS) continue; snprintf(buf, sizeof(buf), "Event: %s %s %u (0x%08x)\n", libevdev_event_type_get_name(ev.type), libevdev_event_code_get_name(ev.type, ev.code), ev.value, ev.value); sd_bus_emit_signal(rcdev->mgr->bus, rcdev->path, "org.gnome.RemoteControlManager.Device", "Event", "s", buf); printf(buf); switch (ev.type) { case EV_KEY: if (keycode) printf("Reading from evdev - multiple keycodes?\n"); keycode = get_linux_keycode_by_value(ev.code); if (!keycode) { printf("evdev - unknown keycode (%u)\n", ev.code); break; } 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; } else if (ev.code == MSC_RAW) { if (protocol_recv) printf("Reading from evdev - multiple protocols?\n"); protocol_recv = true; protocol = ev.value; } break; case EV_SYN: if (keycode || scancode_recv) { const char *protocol_name = NULL; printf("evdev -"); /* FIXME: protocol reporting will change */ if (scancode_recv) { if (!protocol_recv) { protocol_name = evdev_guess_protocol(rcdev, scancode, keycode ? keycode->value : KEY_RESERVED); printf(" protocol %s (guessed)", protocol_name); } else { protocol_name = evdev_get_protocol_name(protocol); printf(" protocol %s", protocol_name); } 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 && protocol_name) sd_bus_emit_signal(rcdev->mgr->bus, rcdev->path, "org.gnome.RemoteControlManager.Device", "KeyPressed", "sts", protocol_name, scancode, keycode ? keycode->name : "KEY_RESERVED"); else if (keycode && !pressed) sd_bus_emit_signal(rcdev->mgr->bus, rcdev->path, "org.gnome.RemoteControlManager.Device", "KeyReleased", "s", keycode->name); } scancode_recv = false; protocol_recv = false; pressed = false; keycode = NULL; break; default: break; } } while (r == LIBEVDEV_READ_STATUS_SUCCESS || r == LIBEVDEV_READ_STATUS_SYNC); return 0; } int evdev_setup(struct rc_device *rcdev, const char *path) { int r; struct keymap *keymap; /* FIXME: Fixup error handling */ if (!rcdev) return -EINVAL; if (rcdev->evdev_fd >= 0) { printf("Multiple evdev devices!?\n"); return 0; } rcdev->evdev_fd = open(path, O_RDONLY | O_NONBLOCK); r = libevdev_new_from_fd(rcdev->evdev_fd, &rcdev->evdev_dev); if (r < 0) { printf("Failed to open evdev device %s: %s\n", path, strerror(-r)); evdev_close(rcdev); return r; } rcdev->input_name = strdup(libevdev_get_name(rcdev->evdev_dev)); printf("Performing evdev setup for device %s (%s)\n", rcdev->path, libevdev_get_name(rcdev->evdev_dev)); r = evdev_clear_keymap(rcdev); if (r < 0) return r; list_for_each_entry(keymap, &rcdev->keymaps, list) r = evdev_set_keymap(rcdev, keymap); if (sd_event_add_io(rcdev->mgr->event, &rcdev->evdev_ev, rcdev->evdev_fd, EPOLLIN, evdev_read, rcdev) < 0) { printf("Failed to add event source for evdev device %s: %s\n", path, strerror(errno)); r = -errno; evdev_close(rcdev); return r; } return r; } void evdev_close(struct rc_device *rcdev) { if (!rcdev) return; if (rcdev->evdev_fd < 0) return; close(rcdev->evdev_fd); rcdev->evdev_fd = -1; }