#define _POSIX_C_SOURCE 200809L #define _DEFAULT_SOURCE #include #include #include #include #include #include #include #include #include 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); }