caps2esc.c (4806B)
1 #include <stdio.h> 2 #include <stdlib.h> 3 4 #include <unistd.h> 5 #include <linux/input.h> 6 7 // clang-format off 8 const struct input_event 9 syn = {.type = EV_SYN , .code = SYN_REPORT , .value = 0}, 10 esc_up = {.type = EV_KEY , .code = KEY_ESC , .value = 0}, 11 ctrl_up = {.type = EV_KEY , .code = KEY_LEFTCTRL , .value = 0}, 12 esc_down = {.type = EV_KEY , .code = KEY_ESC , .value = 1}, 13 ctrl_down = {.type = EV_KEY , .code = KEY_LEFTCTRL , .value = 1}; 14 // clang-format on 15 16 void print_usage(FILE *stream, const char *program) { 17 // clang-format off 18 fprintf(stream, 19 "caps2esc - transforming the most useless key ever in the most useful one\n" 20 "\n" 21 "usage: %s [-h | [-m mode] [-t delay]]\n" 22 "\n" 23 "options:\n" 24 " -h show this message and exit\n" 25 " -t delay used for key sequences (default: 20000 microseconds)\n" 26 " -m mode 0: default\n" 27 " - caps as esc/ctrl\n" 28 " - esc as caps\n" 29 " 1: minimal\n" 30 " - caps as esc/ctrl\n" 31 " 2: useful on 60%% layouts\n" 32 " - caps as esc/ctrl\n" 33 " - esc as grave accent\n" 34 " - grave accent as caps\n", 35 program); 36 // clang-format on 37 } 38 39 int read_event(struct input_event *event) { 40 return fread(event, sizeof(struct input_event), 1, stdin) == 1; 41 } 42 43 void write_event(const struct input_event *event) { 44 if (fwrite(event, sizeof(struct input_event), 1, stdout) != 1) 45 exit(EXIT_FAILURE); 46 } 47 48 void write_event_with_mode(struct input_event *event, int mode) { 49 if (event->type == EV_KEY) 50 switch (mode) { 51 case 0: 52 if (event->code == KEY_ESC) 53 event->code = KEY_CAPSLOCK; 54 break; 55 case 2: 56 switch (event->code) { 57 case KEY_ESC: 58 event->code = KEY_GRAVE; 59 break; 60 case KEY_GRAVE: 61 event->code = KEY_CAPSLOCK; 62 break; 63 } 64 break; 65 } 66 write_event(event); 67 } 68 69 int main(int argc, char *argv[]) { 70 int mode = 0, delay = 20000; 71 72 for (int opt; (opt = getopt(argc, argv, "ht:m:")) != -1;) { 73 switch (opt) { 74 case 'h': 75 return print_usage(stdout, argv[0]), EXIT_SUCCESS; 76 case 'm': 77 mode = atoi(optarg); 78 continue; 79 case 't': 80 delay = atoi(optarg); 81 continue; 82 } 83 84 return print_usage(stderr, argv[0]), EXIT_FAILURE; 85 } 86 87 struct input_event input; 88 enum { START, CAPSLOCK_HELD, CAPSLOCK_IS_CTRL } state = START; 89 90 setbuf(stdin, NULL), setbuf(stdout, NULL); 91 92 while (read_event(&input)) { 93 if (input.type == EV_MSC && input.code == MSC_SCAN) 94 continue; 95 96 if (input.type != EV_KEY && input.type != EV_REL && 97 input.type != EV_ABS) { 98 write_event(&input); 99 continue; 100 } 101 102 switch (state) { 103 case START: 104 if (input.type == EV_KEY && input.code == KEY_CAPSLOCK && 105 input.value) 106 state = CAPSLOCK_HELD; 107 else 108 write_event_with_mode(&input, mode); 109 break; 110 case CAPSLOCK_HELD: 111 if (input.type == EV_KEY && input.code == KEY_CAPSLOCK) { 112 if (input.value == 0) { 113 write_event(&esc_down); 114 write_event(&syn); 115 usleep(delay); 116 write_event(&esc_up); 117 state = START; 118 } 119 } else if ((input.type == EV_KEY && input.value == 1) || 120 input.type == EV_REL || input.type == EV_ABS) { 121 write_event(&ctrl_down); 122 write_event(&syn); 123 usleep(delay); 124 write_event_with_mode(&input, mode); 125 state = CAPSLOCK_IS_CTRL; 126 } else 127 write_event_with_mode(&input, mode); 128 break; 129 case CAPSLOCK_IS_CTRL: 130 if (input.type == EV_KEY && input.code == KEY_CAPSLOCK) { 131 input.code = KEY_LEFTCTRL; 132 write_event(&input); 133 if (input.value == 0) 134 state = START; 135 } else 136 write_event_with_mode(&input, mode); 137 break; 138 } 139 } 140 }