mirror of
https://gitlab.com/interception/linux/plugins/caps2esc.git
synced 2025-04-04 22:09:24 +00:00
Rewrite in state machine look
- Also add new option to control internal delay of programmatic key sequences, when they're necessary.
This commit is contained in:
parent
230f5c70d3
commit
41a2fa7f1e
17
README.md
17
README.md
@ -37,19 +37,20 @@ $ cmake --build build
|
||||
```
|
||||
caps2esc - transforming the most useless key ever in the most useful one
|
||||
|
||||
usage: caps2esc [-h] [-m mode]
|
||||
usage: caps2esc [-h] [-m mode] [-t delay]
|
||||
|
||||
options:
|
||||
-h show this message and exit
|
||||
-t delay used for key sequences (default: 20000 microseconds)
|
||||
-m mode 0: default
|
||||
- caps as esc/ctrl
|
||||
- esc as caps
|
||||
- caps as esc/ctrl
|
||||
- esc as caps
|
||||
1: minimal
|
||||
- caps as esc/ctrl
|
||||
- caps as esc/ctrl
|
||||
2: useful on 60% layouts
|
||||
- caps as esc/ctrl
|
||||
- esc as grave accent
|
||||
- grave accent as caps
|
||||
- caps as esc/ctrl
|
||||
- esc as grave accent
|
||||
- grave accent as caps
|
||||
```
|
||||
|
||||
`caps2esc` is an [_Interception Tools_][interception-tools] plugin. A suggested
|
||||
@ -117,7 +118,7 @@ As always, there's always a caveat:
|
||||
I can't recall when I started using CAPSLOCK as both ESC and CTRL but it has
|
||||
been quite some time already. It started when I was on OS X where it was quite
|
||||
easy to achieve using the [Karabiner][], which already provides an option to
|
||||
turn CTRL into CTRL/ESC (which can be coupled with OS X system settings that
|
||||
turn CTRL into ESC/CTRL (which can be coupled with OS X system settings that
|
||||
turn CAPSLOCK into CTRL).
|
||||
|
||||
Moving on, permanently making Linux my home, I searched and tweaked a similar
|
||||
|
143
caps2esc.c
143
caps2esc.c
@ -6,16 +6,11 @@
|
||||
|
||||
// clang-format off
|
||||
const struct input_event
|
||||
esc_up = {.type = EV_KEY, .code = KEY_ESC, .value = 0},
|
||||
ctrl_up = {.type = EV_KEY, .code = KEY_LEFTCTRL, .value = 0},
|
||||
capslock_up = {.type = EV_KEY, .code = KEY_CAPSLOCK, .value = 0},
|
||||
esc_down = {.type = EV_KEY, .code = KEY_ESC, .value = 1},
|
||||
ctrl_down = {.type = EV_KEY, .code = KEY_LEFTCTRL, .value = 1},
|
||||
capslock_down = {.type = EV_KEY, .code = KEY_CAPSLOCK, .value = 1},
|
||||
esc_repeat = {.type = EV_KEY, .code = KEY_ESC, .value = 2},
|
||||
ctrl_repeat = {.type = EV_KEY, .code = KEY_LEFTCTRL, .value = 2},
|
||||
capslock_repeat = {.type = EV_KEY, .code = KEY_CAPSLOCK, .value = 2},
|
||||
syn = {.type = EV_SYN, .code = SYN_REPORT, .value = 0};
|
||||
syn = {.type = EV_SYN, .code = SYN_REPORT, .value = 0},
|
||||
esc_up = {.type = EV_KEY, .code = KEY_ESC, .value = 0},
|
||||
ctrl_up = {.type = EV_KEY, .code = KEY_LEFTCTRL, .value = 0},
|
||||
esc_down = {.type = EV_KEY, .code = KEY_ESC, .value = 1},
|
||||
ctrl_down = {.type = EV_KEY, .code = KEY_LEFTCTRL, .value = 1};
|
||||
// clang-format on
|
||||
|
||||
void print_usage(FILE *stream, const char *program) {
|
||||
@ -23,28 +18,24 @@ void print_usage(FILE *stream, const char *program) {
|
||||
fprintf(stream,
|
||||
"caps2esc - transforming the most useless key ever in the most useful one\n"
|
||||
"\n"
|
||||
"usage: %s [-h] [-m mode]\n"
|
||||
"usage: %s [-h] [-m mode] [-t delay]\n"
|
||||
"\n"
|
||||
"options:\n"
|
||||
" -h show this message and exit\n"
|
||||
" -t delay used for key sequences (default: 20000 microseconds)\n"
|
||||
" -m mode 0: default\n"
|
||||
" - caps as esc/ctrl\n"
|
||||
" - esc as caps\n"
|
||||
" - caps as esc/ctrl\n"
|
||||
" - esc as caps\n"
|
||||
" 1: minimal\n"
|
||||
" - caps as esc/ctrl\n"
|
||||
" - caps as esc/ctrl\n"
|
||||
" 2: useful on 60%% layouts\n"
|
||||
" - caps as esc/ctrl\n"
|
||||
" - esc as grave accent\n"
|
||||
" - grave accent as caps\n",
|
||||
" - caps as esc/ctrl\n"
|
||||
" - esc as grave accent\n"
|
||||
" - grave accent as caps\n",
|
||||
program);
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
int equal(const struct input_event *first, const struct input_event *second) {
|
||||
return first->type == second->type && first->code == second->code &&
|
||||
first->value == second->value;
|
||||
}
|
||||
|
||||
int read_event(struct input_event *event) {
|
||||
return fread(event, sizeof(struct input_event), 1, stdin) == 1;
|
||||
}
|
||||
@ -54,22 +45,45 @@ void write_event(const struct input_event *event) {
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
void write_event_with_mode(struct input_event *event, int mode) {
|
||||
switch (mode) {
|
||||
case 0:
|
||||
if (event->code == KEY_ESC)
|
||||
event->code = KEY_CAPSLOCK;
|
||||
break;
|
||||
case 2:
|
||||
switch (event->code) {
|
||||
case KEY_ESC:
|
||||
event->code = KEY_GRAVE;
|
||||
break;
|
||||
case KEY_GRAVE:
|
||||
event->code = KEY_CAPSLOCK;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
write_event(event);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
int opt, mode = 0;
|
||||
while ((opt = getopt(argc, argv, "hm:")) != -1) {
|
||||
int opt, mode = 0, delay = 20000;
|
||||
while ((opt = getopt(argc, argv, "ht:m:")) != -1) {
|
||||
switch (opt) {
|
||||
case 'h':
|
||||
return print_usage(stdout, argv[0]), EXIT_SUCCESS;
|
||||
case 't':
|
||||
delay = atoi(optarg);
|
||||
continue;
|
||||
case 'm':
|
||||
mode = optarg[0] - '0';
|
||||
mode = atoi(optarg);
|
||||
continue;
|
||||
}
|
||||
|
||||
return print_usage(stderr, argv[0]), EXIT_FAILURE;
|
||||
}
|
||||
|
||||
int capslock_is_down = 0, esc_give_up = 0;
|
||||
struct input_event input;
|
||||
enum { START, CAPSLOCK_HELD, CAPSLOCK_IS_CTRL } state = START;
|
||||
|
||||
setbuf(stdin, NULL), setbuf(stdout, NULL);
|
||||
|
||||
@ -82,53 +96,40 @@ int main(int argc, char *argv[]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (capslock_is_down) {
|
||||
if (equal(&input, &capslock_down) ||
|
||||
equal(&input, &capslock_repeat))
|
||||
continue;
|
||||
|
||||
if (equal(&input, &capslock_up)) {
|
||||
capslock_is_down = 0;
|
||||
if (esc_give_up) {
|
||||
esc_give_up = 0;
|
||||
write_event(&ctrl_up);
|
||||
continue;
|
||||
}
|
||||
write_event(&esc_down);
|
||||
write_event(&syn);
|
||||
usleep(20000);
|
||||
write_event(&esc_up);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!esc_give_up && input.value) {
|
||||
esc_give_up = 1;
|
||||
write_event(&ctrl_down);
|
||||
write_event(&syn);
|
||||
usleep(20000);
|
||||
}
|
||||
} else if (equal(&input, &capslock_down)) {
|
||||
capslock_is_down = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (mode) {
|
||||
case 0:
|
||||
if (input.code == KEY_ESC)
|
||||
input.code = KEY_CAPSLOCK;
|
||||
switch (state) {
|
||||
case START:
|
||||
if (input.code == KEY_CAPSLOCK && input.value)
|
||||
state = CAPSLOCK_HELD;
|
||||
else
|
||||
write_event_with_mode(&input, mode);
|
||||
break;
|
||||
case 2:
|
||||
switch (input.code) {
|
||||
case KEY_ESC:
|
||||
input.code = KEY_GRAVE;
|
||||
break;
|
||||
case KEY_GRAVE:
|
||||
input.code = KEY_CAPSLOCK;
|
||||
break;
|
||||
}
|
||||
case CAPSLOCK_HELD:
|
||||
if (input.code == KEY_CAPSLOCK) {
|
||||
if (input.value == 0) {
|
||||
write_event(&esc_down);
|
||||
write_event(&syn);
|
||||
usleep(delay);
|
||||
write_event(&esc_up);
|
||||
state = START;
|
||||
}
|
||||
} else if (input.value == 1) {
|
||||
write_event(&ctrl_down);
|
||||
write_event(&syn);
|
||||
usleep(delay);
|
||||
write_event_with_mode(&input, mode);
|
||||
state = CAPSLOCK_IS_CTRL;
|
||||
} else
|
||||
write_event_with_mode(&input, mode);
|
||||
break;
|
||||
case CAPSLOCK_IS_CTRL:
|
||||
if (input.code == KEY_CAPSLOCK) {
|
||||
input.code = KEY_LEFTCTRL;
|
||||
write_event(&input);
|
||||
if (input.value == 0)
|
||||
state = START;
|
||||
} else
|
||||
write_event_with_mode(&input, mode);
|
||||
break;
|
||||
}
|
||||
|
||||
write_event(&input);
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user