diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/binding.c | 45 | ||||
-rw-r--r-- | src/binding.h | 23 | ||||
-rw-r--r-- | src/bindings_file.c | 128 | ||||
-rw-r--r-- | src/bindings_file.h | 13 | ||||
-rw-r--r-- | src/main.c | 132 |
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 @@ -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); } } } |