diff options
Diffstat (limited to 'fakeimp.c')
-rw-r--r-- | fakeimp.c | 171 |
1 files changed, 171 insertions, 0 deletions
diff --git a/fakeimp.c b/fakeimp.c new file mode 100644 index 0000000..b590450 --- /dev/null +++ b/fakeimp.c @@ -0,0 +1,171 @@ +#define _POSIX_C_SOURCE 200809L +#define _DEFAULT_SOURCE +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <wayland-client.h> +#include <ext-action-binder-v1-protocol.h> +#include <xcb/xcb.h> +#include <xcb/xtest.h> +#include <xcb/xcb_keysyms.h> +#include <xkbcommon/xkbcommon.h> + +struct state; +struct binding { + struct state *state; + struct ext_action_binding_v1 *binding; + xcb_keycode_t *code; +}; + +struct state { + struct wl_display *dpy; + struct wl_registry *reg; + struct ext_action_binder_v1 *binder; + struct { + size_t len, cap; + struct binding *data; + } bindings; + + xcb_connection_t *conn; + xcb_key_symbols_t *syms; +}; + +static void binding_bound(void *data, struct ext_action_binding_v1 *ext_action_binding_v1, const char *trigger) { +} + +static void binding_rejected(void *data, struct ext_action_binding_v1 *ext_action_binding_v1) { + (void) data; + ext_action_binding_v1_destroy(ext_action_binding_v1); +} + +static void binding_triggered(void *data, struct ext_action_binding_v1 *ext_action_binding_v1, uint32_t time, uint32_t type) { + (void) ext_action_binding_v1; + struct binding *binding = data; + xcb_connection_t *conn = binding->state->conn; + switch ((enum ext_action_binding_v1_trigger_type) type) { + case EXT_ACTION_BINDING_V1_TRIGGER_TYPE_ONE_SHOT: + xcb_request_check(conn, + xcb_test_fake_input_checked(conn, XCB_KEY_PRESS, *binding->code, time, XCB_NONE, 0, 0, 0)); + xcb_request_check(conn, + xcb_test_fake_input_checked(conn, XCB_KEY_RELEASE, *binding->code, time, XCB_NONE, 0, 0, 0)); + break; + case EXT_ACTION_BINDING_V1_TRIGGER_TYPE_PRESSED: + xcb_request_check(conn, + xcb_test_fake_input_checked(conn, XCB_KEY_PRESS, *binding->code, time, XCB_NONE, 0, 0, 0)); + break; + case EXT_ACTION_BINDING_V1_TRIGGER_TYPE_RELEASED: + xcb_request_check(conn, + xcb_test_fake_input_checked(conn, XCB_KEY_RELEASE, *binding->code, time, XCB_NONE, 0, 0, 0)); + break; + } +} + +static struct ext_action_binding_v1_listener binding_listener = { + .bound = binding_bound, + .rejected = binding_rejected, + .triggered = binding_triggered +}; + +static void registry_global(void *data, struct wl_registry *wl_registry, + uint32_t name, const char *interface, uint32_t version) { + struct state *state = data; + (void) version; + if (strcmp(interface, ext_action_binder_v1_interface.name) == 0) { + state->binder = wl_registry_bind(wl_registry, name, &ext_action_binding_v1_interface, 1); + } +} + +static void registry_global_remove(void *data, struct wl_registry *wl_registry, uint32_t name) { + (void) data; + (void) wl_registry; + (void) name; +} + +static struct wl_registry_listener registry_listener = { + .global = registry_global, + .global_remove = registry_global_remove +}; + +static inline struct binding *add_binding(struct state *state, struct binding binding) { + if (state->bindings.len + 1 < state->bindings.cap) + state->bindings.data = reallocarray(state->bindings.data, state->bindings.cap *= 2, sizeof(*state->bindings.data)); + state->bindings.data[state->bindings.len] = binding; + return &state->bindings.data[state->bindings.len++]; +} + +int main(void) { + struct state *state = calloc(1, sizeof(*state)); + + state->dpy = wl_display_connect(NULL); + if (!state->dpy) { + fputs("failed to connect to wayland display.\n", stderr); + return -1; + } + + state->reg = wl_display_get_registry(state->dpy); + wl_registry_add_listener(state->reg, ®istry_listener, state); + + wl_display_roundtrip(state->dpy); + + if (!state->binder) { + fputs("failed to bind to ext-action-binder-v1\n", stderr); + return -1; + } + + state->conn = xcb_connect(NULL, NULL); + if (xcb_connection_has_error(state->conn)) { + fputs("failed to open display\n", stderr); + return -1; + } + + state->syms = xcb_key_symbols_alloc(state->conn); + + FILE *fp = fopen("fakeimp.cfg", "r"); + if (!fp) { + fputs("failed to open config file\n", stderr); + return -1; + } + + char *line = NULL; + size_t n; + while (getline(&line, &n, fp) != -1) { + char *name = NULL, *namespace = NULL, *keys = NULL; + size_t num; + if ((num = sscanf(line, "%ms %ms %ms", &name, &namespace, &keys) != 3)) { + fprintf(stderr, "failed to parse line %s. %ld\n", line, num); + free(name); + free(namespace); + free(keys); + continue; + } + + printf("state->binder = %p -- %ld", (void*)state->binder, (intptr_t)state->binder); + struct ext_action_binding_v1 *bind = ext_action_binder_v1_create_binding(state->binder); + printf("bind = %p -- %ld", (void*)bind, (intptr_t)bind); + + // parse the keybind silly + struct binding binding = { + .state = state, + .binding = ext_action_binder_v1_create_binding(state->binder), + .code = xcb_key_symbols_get_keycode(state->syms, 'q') + }; + + if (!binding.binding) { + fputs("binding is null.\n", stderr); + return -1; + } + + ext_action_binding_v1_set_name(binding.binding, namespace, name); + ext_action_binding_v1_add_listener(binding.binding, &binding_listener, add_binding(state, binding)); + } + free(line); + + if (state->bindings.len == 0) { + fputs("no bindings set, exiting.\n", stderr); + return 0; + } + + ext_action_binder_v1_commit(state->binder); + + while (wl_display_dispatch(state->dpy) != -1); +} |