diff options
Diffstat (limited to 'bin/capsremap.c')
| -rw-r--r-- | bin/capsremap.c | 110 |
1 files changed, 110 insertions, 0 deletions
diff --git a/bin/capsremap.c b/bin/capsremap.c new file mode 100644 index 0000000..8a78f4b --- /dev/null +++ b/bin/capsremap.c @@ -0,0 +1,110 @@ +// SPDX-FIleCopyrightText: 2017 Francisco Lopes da Silva +// SPDX-FIleCopyrightText: 2023 Sam Nystrom <sam@samnystrom.dev> +// SPDX-License-Identifier: MIT + +// Map the caps lock key to escape and caps+hjkl to the arrow keys + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <stdbool.h> +#include <linux/input.h> + +const struct input_event +syn = {.type = EV_SYN, .code = SYN_REPORT, .value = 0}, +esc_up = {.type = EV_KEY, .code = KEY_ESC , .value = 0}, +esc_down = {.type = EV_KEY, .code = KEY_ESC , .value = 1}; + +const int delay = 10000; + +void hjkl_to_arrow(struct input_event *event) { + switch (event->code) { + case KEY_H: + event->code = KEY_LEFT; + break; + case KEY_J: + event->code = KEY_DOWN; + break; + case KEY_K: + event->code = KEY_UP; + break; + case KEY_L: + event->code = KEY_RIGHT; + break; + } +} + +int main(int argc, char** argv) { + setbuf(stdin, NULL); + setbuf(stdout, NULL); + + enum { START, CAPSLOCK_HELD, CAPSLOCK_IS_MODIFIER } state = START; + + // Handle cases where caps lock is released before hjkl is released so + // the subsequent hjkl release is properly rewritten as an arrow key + int down_key = KEY_RESERVED; + + struct input_event event; + while (fread(&event, sizeof(event), 1, stdin) == 1) { + if (event.type == EV_MSC && event.code == MSC_SCAN) { + continue; + } + if (event.type != EV_KEY && event.type != EV_REL && event.type != EV_ABS) { + fwrite(&event, sizeof(event), 1, stdout); + continue; + } + + switch (state) { + case START: + if (event.type == EV_KEY && event.code == KEY_CAPSLOCK && event.value) { + state = CAPSLOCK_HELD; + } else { + if (event.type == EV_KEY && event.code == down_key && event.value == 0) { + hjkl_to_arrow(&event); + down_key = KEY_RESERVED; + } + fwrite(&event, sizeof(event), 1, stdout); + } + break; + case CAPSLOCK_HELD: + if (event.type == EV_KEY && event.code == KEY_CAPSLOCK) { + if (event.value == 0) { + fwrite(&esc_down, sizeof(esc_down), 1, stdout); + fwrite(&syn, sizeof(syn), 1, stdout); + usleep(delay); + fwrite(&esc_up, sizeof(esc_up), 1, stdout); + state = START; + } + } else { + if (event.type == EV_KEY && event.value) { + down_key = event.code; + hjkl_to_arrow(&event); + state = CAPSLOCK_IS_MODIFIER; + } + if (event.type == EV_KEY && event.code == down_key && event.value == 0) { + down_key = KEY_RESERVED; + hjkl_to_arrow(&event); + } + fwrite(&event, sizeof(event), 1, stdout); + } + break; + case CAPSLOCK_IS_MODIFIER: + if (event.type == EV_KEY && event.code == KEY_CAPSLOCK) { + if (event.value == 0) { + state = START; + } + } else { + if (event.type == EV_KEY && event.value) { + down_key = event.code; + hjkl_to_arrow(&event); + } + if (event.type == EV_KEY && event.code == down_key && event.value == 0) { + down_key = KEY_RESERVED; + hjkl_to_arrow(&event); + } + fwrite(&event, sizeof(event), 1, stdout); + } + break; + } + } +} |
