caps2esc:logo4alt

Interception tools plugin that maps caps->{esc,ctrl} and logo<->alt
git clone git://git.deurzen.net/caps2esc:logo4alt
Log | Files | Refs | README | LICENSE

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 }