5 Commits

Author SHA1 Message Date
41a2fa7f1e Rewrite in state machine look
- Also add new option to control internal delay of programmatic key
  sequences, when they're necessary.
2020-12-28 23:13:34 -03:00
230f5c70d3 Update README 2020-12-28 18:49:00 -03:00
15636b64e7 Add help message and options
Solves #8 and !2
2020-12-28 18:37:50 -03:00
6ab17c7d1a Update README 2020-12-28 15:27:29 -03:00
220ca0bc71 Update README 2020-12-28 15:23:46 -03:00
2 changed files with 149 additions and 55 deletions

View File

@ -28,19 +28,36 @@ ESC when pressed alone is quite handy, specially in vi.
```
$ git clone git@gitlab.com:interception/linux/plugins/caps2esc.git
$ cd caps2esc
$ mkdir build
$ cd build
$ cmake ..
$ make
$ cmake -B build -DCMAKE_BUILD_TYPE=Release
$ cmake --build build
```
## Execution
```
caps2esc - transforming the most useless key ever in the most useful one
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
1: minimal
- caps as esc/ctrl
2: useful on 60% layouts
- caps as esc/ctrl
- esc as grave accent
- grave accent as caps
```
`caps2esc` is an [_Interception Tools_][interception-tools] plugin. A suggested
`udevmon` job configuration is:
```yaml
- JOB: "intercept -g $DEVNODE | caps2esc | uinput -d $DEVNODE"
- JOB: intercept -g $DEVNODE | caps2esc | uinput -d $DEVNODE
DEVICE:
EVENTS:
EV_KEY: [KEY_CAPSLOCK, KEY_ESC]
@ -50,11 +67,37 @@ $ make
For more information about the [_Interception Tools_][interception-tools], check
the project's website.
## Mouse button support
After _Interception Tools_ 0.3, `caps2esc` can work with mouse clicks. An
example configuration taken from my laptop:
```yaml
SHELL: [zsh, -c]
---
- JOB: mux -c caps2esc
- JOB:
- intercept -g $DEVNODE | mux -o caps2esc
- mux -i caps2esc | caps2esc | uinput -d $DEVNODE
DEVICE:
LINK: /dev/input/by-path/platform-i8042-serio-0-event-kbd
- JOB:
- intercept $DEVNODE | mux -o caps2esc
DEVICE:
LINK: /dev/input/by-path/platform-i8042-serio-4-event-mouse
```
For more information on the topic, check the [_Interception Tools_
README][interception-tools] about usage of the `mux` tool and device specific
setups.
## Installation
I'm maintaining an Archlinux package on AUR:
It's available from [community](https://archlinux.org/packages/community/x86_64/interception-caps2esc/):
- <https://aur.archlinux.org/packages/interception-caps2esc>
```
$ pacman -S interception-caps2esc
```
I don't use Ubuntu and recommend Archlinux instead, as it provides the AUR, so I
don't maintain PPAs. For more information on Ubuntu/Debian installation check
@ -75,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

View File

@ -6,21 +6,34 @@
// 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
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;
void print_usage(FILE *stream, const char *program) {
// clang-format off
fprintf(stream,
"caps2esc - transforming the most useless key ever in the most useful one\n"
"\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"
" 1: minimal\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",
program);
// clang-format on
}
int read_event(struct input_event *event) {
@ -32,9 +45,45 @@ void write_event(const struct input_event *event) {
exit(EXIT_FAILURE);
}
int main(void) {
int capslock_is_down = 0, esc_give_up = 0;
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, 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 = atoi(optarg);
continue;
}
return print_usage(stderr, argv[0]), EXIT_FAILURE;
}
struct input_event input;
enum { START, CAPSLOCK_HELD, CAPSLOCK_IS_CTRL } state = START;
setbuf(stdin, NULL), setbuf(stdout, NULL);
@ -47,38 +96,40 @@ int main(void) {
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 (state) {
case START:
if (input.code == KEY_CAPSLOCK && input.value)
state = CAPSLOCK_HELD;
else
write_event_with_mode(&input, mode);
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;
}
if (input.code == KEY_ESC)
input.code = KEY_CAPSLOCK;
write_event(&input);
}
}