mirror of
https://gitlab.com/interception/linux/plugins/caps2esc.git
synced 2025-04-05 14:22:54 +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
|
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:
|
options:
|
||||||
-h show this message and exit
|
-h show this message and exit
|
||||||
|
-t delay used for key sequences (default: 20000 microseconds)
|
||||||
-m mode 0: default
|
-m mode 0: default
|
||||||
- caps as esc/ctrl
|
- caps as esc/ctrl
|
||||||
- esc as caps
|
- esc as caps
|
||||||
1: minimal
|
1: minimal
|
||||||
- caps as esc/ctrl
|
- caps as esc/ctrl
|
||||||
2: useful on 60% layouts
|
2: useful on 60% layouts
|
||||||
- caps as esc/ctrl
|
- caps as esc/ctrl
|
||||||
- esc as grave accent
|
- esc as grave accent
|
||||||
- grave accent as caps
|
- grave accent as caps
|
||||||
```
|
```
|
||||||
|
|
||||||
`caps2esc` is an [_Interception Tools_][interception-tools] plugin. A suggested
|
`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
|
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
|
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
|
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).
|
turn CAPSLOCK into CTRL).
|
||||||
|
|
||||||
Moving on, permanently making Linux my home, I searched and tweaked a similar
|
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
|
// clang-format off
|
||||||
const struct input_event
|
const struct input_event
|
||||||
esc_up = {.type = EV_KEY, .code = KEY_ESC, .value = 0},
|
syn = {.type = EV_SYN, .code = SYN_REPORT, .value = 0},
|
||||||
ctrl_up = {.type = EV_KEY, .code = KEY_LEFTCTRL, .value = 0},
|
esc_up = {.type = EV_KEY, .code = KEY_ESC, .value = 0},
|
||||||
capslock_up = {.type = EV_KEY, .code = KEY_CAPSLOCK, .value = 0},
|
ctrl_up = {.type = EV_KEY, .code = KEY_LEFTCTRL, .value = 0},
|
||||||
esc_down = {.type = EV_KEY, .code = KEY_ESC, .value = 1},
|
esc_down = {.type = EV_KEY, .code = KEY_ESC, .value = 1},
|
||||||
ctrl_down = {.type = EV_KEY, .code = KEY_LEFTCTRL, .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};
|
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
void print_usage(FILE *stream, const char *program) {
|
void print_usage(FILE *stream, const char *program) {
|
||||||
@ -23,28 +18,24 @@ void print_usage(FILE *stream, const char *program) {
|
|||||||
fprintf(stream,
|
fprintf(stream,
|
||||||
"caps2esc - transforming the most useless key ever in the most useful one\n"
|
"caps2esc - transforming the most useless key ever in the most useful one\n"
|
||||||
"\n"
|
"\n"
|
||||||
"usage: %s [-h] [-m mode]\n"
|
"usage: %s [-h] [-m mode] [-t delay]\n"
|
||||||
"\n"
|
"\n"
|
||||||
"options:\n"
|
"options:\n"
|
||||||
" -h show this message and exit\n"
|
" -h show this message and exit\n"
|
||||||
|
" -t delay used for key sequences (default: 20000 microseconds)\n"
|
||||||
" -m mode 0: default\n"
|
" -m mode 0: default\n"
|
||||||
" - caps as esc/ctrl\n"
|
" - caps as esc/ctrl\n"
|
||||||
" - esc as caps\n"
|
" - esc as caps\n"
|
||||||
" 1: minimal\n"
|
" 1: minimal\n"
|
||||||
" - caps as esc/ctrl\n"
|
" - caps as esc/ctrl\n"
|
||||||
" 2: useful on 60%% layouts\n"
|
" 2: useful on 60%% layouts\n"
|
||||||
" - caps as esc/ctrl\n"
|
" - caps as esc/ctrl\n"
|
||||||
" - esc as grave accent\n"
|
" - esc as grave accent\n"
|
||||||
" - grave accent as caps\n",
|
" - grave accent as caps\n",
|
||||||
program);
|
program);
|
||||||
// clang-format on
|
// 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) {
|
int read_event(struct input_event *event) {
|
||||||
return fread(event, sizeof(struct input_event), 1, stdin) == 1;
|
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);
|
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 main(int argc, char *argv[]) {
|
||||||
int opt, mode = 0;
|
int opt, mode = 0, delay = 20000;
|
||||||
while ((opt = getopt(argc, argv, "hm:")) != -1) {
|
while ((opt = getopt(argc, argv, "ht:m:")) != -1) {
|
||||||
switch (opt) {
|
switch (opt) {
|
||||||
case 'h':
|
case 'h':
|
||||||
return print_usage(stdout, argv[0]), EXIT_SUCCESS;
|
return print_usage(stdout, argv[0]), EXIT_SUCCESS;
|
||||||
|
case 't':
|
||||||
|
delay = atoi(optarg);
|
||||||
|
continue;
|
||||||
case 'm':
|
case 'm':
|
||||||
mode = optarg[0] - '0';
|
mode = atoi(optarg);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
return print_usage(stderr, argv[0]), EXIT_FAILURE;
|
return print_usage(stderr, argv[0]), EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
int capslock_is_down = 0, esc_give_up = 0;
|
|
||||||
struct input_event input;
|
struct input_event input;
|
||||||
|
enum { START, CAPSLOCK_HELD, CAPSLOCK_IS_CTRL } state = START;
|
||||||
|
|
||||||
setbuf(stdin, NULL), setbuf(stdout, NULL);
|
setbuf(stdin, NULL), setbuf(stdout, NULL);
|
||||||
|
|
||||||
@ -82,53 +96,40 @@ int main(int argc, char *argv[]) {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (capslock_is_down) {
|
switch (state) {
|
||||||
if (equal(&input, &capslock_down) ||
|
case START:
|
||||||
equal(&input, &capslock_repeat))
|
if (input.code == KEY_CAPSLOCK && input.value)
|
||||||
continue;
|
state = CAPSLOCK_HELD;
|
||||||
|
else
|
||||||
if (equal(&input, &capslock_up)) {
|
write_event_with_mode(&input, mode);
|
||||||
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;
|
|
||||||
break;
|
break;
|
||||||
case 2:
|
case CAPSLOCK_HELD:
|
||||||
switch (input.code) {
|
if (input.code == KEY_CAPSLOCK) {
|
||||||
case KEY_ESC:
|
if (input.value == 0) {
|
||||||
input.code = KEY_GRAVE;
|
write_event(&esc_down);
|
||||||
break;
|
write_event(&syn);
|
||||||
case KEY_GRAVE:
|
usleep(delay);
|
||||||
input.code = KEY_CAPSLOCK;
|
write_event(&esc_up);
|
||||||
break;
|
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;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
write_event(&input);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user