summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorpapush!2025-07-04 23:21:14 +0200
committerpapush!2025-07-04 23:25:07 +0200
commit0d1f4776521b286cb7c0091ac5bcd659cdc87132 (patch)
tree5b04bd12c45f6f30c34356241616496c5cb025e2 /src
parentff5e9f826d6e89f5ab1adb09e959afd5d1e17a5f (diff)
add multikey binds support
Diffstat (limited to 'src')
-rw-r--r--src/binding.c45
-rw-r--r--src/binding.h23
-rw-r--r--src/bindings_file.c128
-rw-r--r--src/bindings_file.h13
-rw-r--r--src/main.c132
5 files changed, 231 insertions, 110 deletions
diff --git a/src/binding.c b/src/binding.c
new file mode 100644
index 0000000..1680a1b
--- /dev/null
+++ b/src/binding.c
@@ -0,0 +1,45 @@
+#include "binding.h"
+#include <stdio.h>
+
+
+int has_key(uint64_t keys[static KEYS_SIZE], int code)
+{
+ return (keys[code/64] & 1ULL << code % 64) > 0;
+}
+
+void set_key(uint64_t keys[static KEYS_SIZE], int code)
+{
+ keys[code/64] |= 1ULL << (code % 64);
+}
+
+void clear_key(uint64_t keys[static KEYS_SIZE], int code)
+{
+ keys[code/64] &= ~(1ULL << code % 64);
+}
+
+int is_keys_subset_of(uint64_t a[static KEYS_SIZE], uint64_t b[static KEYS_SIZE])
+{
+ for (size_t i = 0; i < KEYS_SIZE; i++)
+ {
+ if ((a[i] & b[i]) != a[i])
+ {
+ return 0;
+ }
+ }
+ return 1;
+}
+
+void print_keys(uint64_t keys[static KEYS_SIZE])
+{
+ for (size_t i = 0; i < KEYS_SIZE; i++)
+ {
+ for (size_t j = 0; j < 64; j++)
+ {
+ if (keys[i] & 1ULL<<j)
+ {
+ printf("%d ", i * 64 + j);
+ }
+ }
+ }
+ putchar('\n');
+}
diff --git a/src/binding.h b/src/binding.h
new file mode 100644
index 0000000..d86cf87
--- /dev/null
+++ b/src/binding.h
@@ -0,0 +1,23 @@
+#ifndef BINDING_H
+#define BINDING_H
+
+#include <linux/input.h>
+#include <stdint.h>
+
+#define KEYS_SIZE KEY_CNT/64
+
+struct binding
+{
+ uint64_t keys[KEYS_SIZE];
+ enum {RELEASED=0, PRESSED=1} value;
+ char *cmd;
+};
+
+int has_key(uint64_t keys[static KEYS_SIZE], int code);
+void set_key(uint64_t keys[static KEYS_SIZE], int code);
+void clear_key(uint64_t keys[static KEYS_SIZE], int code);
+int is_keys_subset_of(uint64_t a[static KEYS_SIZE], uint64_t b[static KEYS_SIZE]);
+void print_keys(uint64_t keys[static KEYS_SIZE]);
+
+
+#endif
diff --git a/src/bindings_file.c b/src/bindings_file.c
new file mode 100644
index 0000000..4eab11f
--- /dev/null
+++ b/src/bindings_file.c
@@ -0,0 +1,128 @@
+#include "bindings_file.h"
+#include "binding.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <ctype.h>
+#include <string.h>
+
+
+struct binding *bindings = NULL;
+size_t nbindings = 0;
+
+void skip_space(char **c)
+{
+ for (; **c && isspace(**c); (*c)++);
+}
+
+int read_int(char **c, int out[static 1])
+{
+ if (!isdigit(**c))
+ {
+ return -1;
+ }
+ errno = 0;
+ char *end = NULL;
+ *out = strtol(*c, &end, 10);
+ if (errno)
+ {
+ return -1;
+ }
+ *c = end;
+ return 0;
+}
+
+void parse_bindings_file(const char path[static 1])
+{
+ size_t cap = 512;
+ bindings = malloc(sizeof (struct binding) * cap);
+ FILE *f = fopen(path, "r");
+ if (f == NULL)
+ {
+ fprintf(stderr, "failed to open bindings file: %s: %s\n", path,
+ strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+
+ size_t line_nb = 0;
+ char *line = NULL;
+ size_t n;
+ while (getline(&line, &n, f) != -1)
+ {
+ line_nb++;
+ struct binding binding = {0};
+ char *end = strchr(line, '#');
+ if (end == NULL)
+ {
+ end = line + strlen(line);
+ }
+ *end = '\0';
+ char *c = line;
+
+ skip_space(&c);
+ if (c == end) continue;
+
+ /* code */
+ int code;
+ for (;;)
+ {
+ if (read_int(&c, &code) < 0 || c >= end)
+ {
+ goto fail;
+ }
+ set_key(binding.keys, code);
+ if (*c++ != '+')
+ {
+ c--;
+ break;
+ }
+ }
+
+ /* press | release */
+ skip_space(&c);
+ if (strncmp(c, "press", strlen("press")) == 0)
+ {
+ c += strlen("press");
+ binding.value = PRESSED;
+ }
+ else if (strncmp(c, "release", strlen("release")) == 0)
+ {
+ c += strlen("release");
+ binding.value = RELEASED;
+ }
+ else
+ {
+ goto fail;
+ }
+
+ /* cmd */
+ skip_space(&c);
+ if (c >= end)
+ {
+ goto fail;
+ }
+ binding.cmd = malloc(end - c + 1);
+ memcpy(binding.cmd, c, end - c + 1);
+
+ if (nbindings >= cap)
+ {
+ cap *= 2;
+ bindings = realloc(bindings, cap * sizeof (struct binding));
+ }
+ bindings[nbindings++] = binding;
+ }
+ if (!feof(f))
+ {
+ fprintf(stderr, "failed to read bindings file: %s: %s\n", path,
+ strerror(errno));
+ }
+ free(line);
+ fclose(f);
+ return;
+
+fail:
+ fprintf(stderr, "syntax error at line %ld\n", line_nb);
+ exit(EXIT_FAILURE);
+}
+
diff --git a/src/bindings_file.h b/src/bindings_file.h
new file mode 100644
index 0000000..a7d1791
--- /dev/null
+++ b/src/bindings_file.h
@@ -0,0 +1,13 @@
+#ifndef BINDINGS_FILE_H
+#define BINDINGS_FILE_H
+
+#include <stddef.h>
+
+
+extern struct binding *bindings;
+extern size_t nbindings;
+
+void parse_bindings_file(const char path[static 1]);
+
+
+#endif \ No newline at end of file
diff --git a/src/main.c b/src/main.c
index 7ecfc15..00c6eb2 100644
--- a/src/main.c
+++ b/src/main.c
@@ -1,4 +1,8 @@
#define _DEFAULT_SOURCE
+
+#include "binding.h"
+#include "bindings_file.h"
+
#include <stdlib.h>
#include <errno.h>
#include <string.h>
@@ -7,8 +11,6 @@
#include <unistd.h>
#include <fcntl.h>
#include <dirent.h>
-#include <ctype.h>
-#include <linux/input.h>
#include <linux/limits.h>
#include <sys/inotify.h>
#include <pwd.h>
@@ -16,18 +18,10 @@
#define NPFDS 4096
-struct binding
-{
- int code;
- int value;
- char *cmd;
-};
-
struct pollfd pfds[NPFDS] = {0};
int test_mode = 0;
-size_t nbindings = 0;
-struct binding *bindings = NULL;
+uint64_t keys[KEYS_SIZE] = {0};
void add_device(const char name[static 1])
@@ -77,120 +71,38 @@ void process_inotify_watch(int inotify_fd)
}
}
-void skip_space(char **c)
+void run_binding(struct binding *binding)
{
- for (; **c && isspace(**c); (*c)++);
-}
-
-int read_int(char **c, int out[static 1])
-{
- if (!isdigit(**c))
- {
- return -1;
- }
- errno = 0;
- char *end = NULL;
- *out = strtol(*c, &end, 10);
- if (errno)
+ if (fork() == 0)
{
- return -1;
+ execl("/bin/sh", "/bin/sh", "-c", binding->cmd);
}
- *c = end;
- return 0;
}
-void parse_bindings_file(const char path[static 1])
+void process_key_event(int code, int value)
{
- size_t cap = 512;
- bindings = malloc(sizeof (struct binding) * cap);
- FILE *f = fopen(path, "r");
- if (f == NULL)
+ uint64_t old_keys[KEYS_SIZE];
+ for (size_t i = 0; i < KEYS_SIZE; i++)
{
- fprintf(stderr, "failed to open bindings file: %s: %s\n", path,
- strerror(errno));
- exit(EXIT_FAILURE);
+ old_keys[i] = keys[i];
}
-
- size_t line_nb = 0;
- char *line = NULL;
- size_t n;
- while (getline(&line, &n, f) != -1)
+ if (value == RELEASED)
{
- line_nb++;
- struct binding binding;
- char *end = strchr(line, '#');
- if (end == NULL)
- {
- end = line + strlen(line);
- }
- *end = '\0';
- char *c = line;
-
- skip_space(&c);
- if (c == end) continue;
-
- /* code */
- if (read_int(&c, &binding.code) < 0 || c >= end)
- {
- goto fail;
- }
-
- /* press | release */
- skip_space(&c);
- if (strncmp(c, "press", strlen("press")) == 0)
- {
- c += strlen("press");
- binding.value = 1;
- }
- else if (strncmp(c, "release", strlen("release")) == 0)
- {
- c += strlen("release");
- binding.value = 0;
- }
- else
- {
- goto fail;
- }
-
- /* cmd */
- skip_space(&c);
- if (c >= end)
- {
- goto fail;
- }
- binding.cmd = malloc(end - c + 1);
- memcpy(binding.cmd, c, end - c + 1);
-
- if (nbindings >= cap)
- {
- cap *= 2;
- bindings = realloc(bindings, cap * sizeof (struct binding));
- }
- bindings[nbindings++] = binding;
+ clear_key(keys, code);
}
- if (!feof(f))
+ else if (value == PRESSED)
{
- fprintf(stderr, "failed to read bindings file: %s: %s\n", path,
- strerror(errno));
+ set_key(keys, code);
}
- free(line);
- fclose(f);
- return;
-
-fail:
- fprintf(stderr, "syntax error at line %ld\n", line_nb);
- exit(EXIT_FAILURE);
-}
-
-void run_binding(int code, int value)
-{
for (size_t i = 0; i < nbindings; i++)
{
- if (bindings[i].code == code && bindings[i].value == value)
+ if (bindings[i].value == value)
{
- if (fork() == 0)
+ uint64_t *match_target = value == PRESSED ? keys : old_keys;
+ if (is_keys_subset_of(bindings[i].keys, match_target)
+ && has_key(bindings[i].keys, code))
{
- execl("/bin/sh", "/bin/sh", "-c", bindings[i].cmd);
+ run_binding(bindings + i);
}
}
}
@@ -212,7 +124,7 @@ void process_input_device(int fd)
}
else
{
- run_binding(event.code, event.value);
+ process_key_event(event.code, event.value);
}
}
}