summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--fakeimp.c171
-rw-r--r--fakeimp.cfg1
-rw-r--r--meson.build38
3 files changed, 210 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, &registry_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);
+}
diff --git a/fakeimp.cfg b/fakeimp.cfg
new file mode 100644
index 0000000..af3b6d7
--- /dev/null
+++ b/fakeimp.cfg
@@ -0,0 +1 @@
+discord mute q
diff --git a/meson.build b/meson.build
new file mode 100644
index 0000000..7b33b3a
--- /dev/null
+++ b/meson.build
@@ -0,0 +1,38 @@
+project('fakeimp', 'c',
+ version : '0.1',
+ default_options : ['warning_level=3', 'c_std=c2x'])
+
+sources = [
+ 'fakeimp.c'
+]
+
+wl_protocols = dependency('wayland-protocols').get_variable('pkgdatadir')
+wl_scanner = find_program(dependency('wayland-scanner').get_variable('wayland_scanner'))
+
+protos = {
+ 'ext-action-binder': wl_protocols / 'staging/ext-action-binder/ext-action-binder-v1.xml'
+}
+
+foreach name, path : protos
+ sources += custom_target(
+ name.underscorify() + '_c',
+ input: path,
+ output: '@BASENAME@-protocol.c',
+ command: [wl_scanner, 'private-code', '@INPUT@', '@OUTPUT@']
+ )
+ sources += custom_target(
+ name.underscorify() + '_h',
+ input: path,
+ output: '@BASENAME@-protocol.h',
+ command: [wl_scanner, 'client-header', '@INPUT@', '@OUTPUT@']
+ )
+endforeach
+
+exe = executable('fakeimp', sources,
+ dependencies: [
+ dependency('wayland-client'),
+ dependency('xcb'),
+ dependency('xcb-keysyms'),
+ dependency('xcb-xtest')
+ ],
+ install : true)