mirror of
https://gitlab.com/interception/linux/plugins/caps2esc.git
synced 2025-04-07 06:55:52 +00:00
Compare commits
No commits in common. "master" and "v0.2.0" have entirely different histories.
58
README.md
58
README.md
@ -25,8 +25,8 @@ ESC when pressed alone is quite handy, specially in vi.
|
|||||||
|
|
||||||
## Building
|
## Building
|
||||||
|
|
||||||
```text
|
```
|
||||||
$ git clone https://gitlab.com/interception/linux/plugins/caps2esc.git
|
$ git clone git@gitlab.com:interception/linux/plugins/caps2esc.git
|
||||||
$ cd caps2esc
|
$ cd caps2esc
|
||||||
$ cmake -B build -DCMAKE_BUILD_TYPE=Release
|
$ cmake -B build -DCMAKE_BUILD_TYPE=Release
|
||||||
$ cmake --build build
|
$ cmake --build build
|
||||||
@ -34,14 +34,13 @@ $ cmake --build build
|
|||||||
|
|
||||||
## Execution
|
## Execution
|
||||||
|
|
||||||
```text
|
```
|
||||||
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] [-t delay]]
|
usage: caps2esc [-h] [-m mode]
|
||||||
|
|
||||||
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
|
||||||
@ -54,67 +53,56 @@ options:
|
|||||||
```
|
```
|
||||||
|
|
||||||
`caps2esc` is an [_Interception Tools_][interception-tools] plugin. A suggested
|
`caps2esc` is an [_Interception Tools_][interception-tools] plugin. A suggested
|
||||||
`udevmon` job configuration (check the [_Interception Tools_
|
`udevmon` job configuration is:
|
||||||
README][interception-tools] for alternatives) is:
|
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
- JOB: intercept -g $DEVNODE | caps2esc | uinput -d $DEVNODE
|
- JOB: intercept -g $DEVNODE | caps2esc | uinput -d $DEVNODE
|
||||||
DEVICE:
|
DEVICE:
|
||||||
EVENTS:
|
EVENTS:
|
||||||
EV_KEY: [KEY_CAPSLOCK, KEY_ESC]
|
EV_KEY: [KEY_CAPSLOCK, KEY_ESC]
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
For more information about the [_Interception Tools_][interception-tools], check
|
For more information about the [_Interception Tools_][interception-tools], check
|
||||||
the project's website.
|
the project's website.
|
||||||
|
|
||||||
## Mouse/Touchpad Support
|
## Mouse button support
|
||||||
|
|
||||||
After _Interception Tools_ 0.3.2, `caps2esc` can observe (or replace) mouse
|
After _Interception Tools_ 0.3, `caps2esc` can work with mouse clicks. An
|
||||||
events. An example configuration taken from my laptop:
|
example configuration taken from my laptop:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
SHELL: [zsh, -c]
|
SHELL: [zsh, -c]
|
||||||
---
|
---
|
||||||
- CMD: mux -c caps2esc
|
- JOB: mux -c caps2esc
|
||||||
- JOB: mux -i caps2esc | caps2esc | uinput -c /etc/interception/keyboard.yaml
|
- JOB:
|
||||||
- JOB: intercept -g $DEVNODE | mux -o caps2esc
|
- intercept -g $DEVNODE | mux -o caps2esc
|
||||||
|
- mux -i caps2esc | caps2esc | uinput -d $DEVNODE
|
||||||
DEVICE:
|
DEVICE:
|
||||||
LINK: /dev/input/by-path/platform-i8042-serio-0-event-kbd
|
LINK: /dev/input/by-path/platform-i8042-serio-0-event-kbd
|
||||||
- JOB: intercept $DEVNODE | mux -o caps2esc
|
- JOB:
|
||||||
|
- intercept $DEVNODE | mux -o caps2esc
|
||||||
DEVICE:
|
DEVICE:
|
||||||
LINK: /dev/input/by-path/platform-i8042-serio-4-event-mouse
|
LINK: /dev/input/by-path/platform-i8042-serio-4-event-mouse
|
||||||
```
|
```
|
||||||
|
|
||||||
For more information on the topic, check the [_Interception Tools_
|
For more information on the topic, check the [_Interception Tools_
|
||||||
README][interception-tools] about usage of the `mux` tool and hybrid virtual
|
README][interception-tools] about usage of the `mux` tool and device specific
|
||||||
device configurations.
|
setups.
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
### Archlinux
|
|
||||||
|
|
||||||
It's available from [community](https://archlinux.org/packages/community/x86_64/interception-caps2esc/):
|
It's available from [community](https://archlinux.org/packages/community/x86_64/interception-caps2esc/):
|
||||||
|
|
||||||
```text
|
```
|
||||||
$ pacman -S interception-caps2esc
|
$ pacman -S interception-caps2esc
|
||||||
```
|
```
|
||||||
|
|
||||||
### Void Linux
|
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
|
||||||
|
this:
|
||||||
|
|
||||||
```text
|
- <https://askubuntu.com/questions/979359/how-do-i-install-caps2esc>
|
||||||
$ xbps-install -S caps2esc
|
|
||||||
```
|
|
||||||
|
|
||||||
### Ubuntu ([independent package][ubuntu])
|
|
||||||
|
|
||||||
```text
|
|
||||||
sudo add-apt-repository ppa:deafmute/interception
|
|
||||||
sudo apt install interception-caps2esc
|
|
||||||
```
|
|
||||||
|
|
||||||
<sub>For debian and other derivatives you can download directly at https://launchpad.net/~deafmute/+archive/ubuntu/interception/+packages.</sub>
|
|
||||||
|
|
||||||
[ubuntu]: https://gitlab.com/interception/linux/tools/-/issues/38
|
|
||||||
|
|
||||||
## Caveats
|
## Caveats
|
||||||
|
|
||||||
@ -129,7 +117,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 ESC/CTRL (which can be coupled with OS X system settings that
|
turn CTRL into CTRL/ESC (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
|
||||||
|
126
caps2esc.c
126
caps2esc.c
@ -6,11 +6,16 @@
|
|||||||
|
|
||||||
// clang-format off
|
// clang-format off
|
||||||
const struct input_event
|
const struct input_event
|
||||||
syn = {.type = EV_SYN , .code = SYN_REPORT , .value = 0},
|
esc_up = {.type = EV_KEY, .code = KEY_ESC, .value = 0},
|
||||||
esc_up = {.type = EV_KEY , .code = KEY_ESC , .value = 0},
|
ctrl_up = {.type = EV_KEY, .code = KEY_LEFTCTRL, .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},
|
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) {
|
||||||
@ -18,11 +23,10 @@ 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] [-t delay]]\n"
|
"usage: %s [-h] [-m mode]\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"
|
||||||
@ -36,6 +40,11 @@ void print_usage(FILE *stream, const char *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;
|
||||||
}
|
}
|
||||||
@ -45,47 +54,22 @@ 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) {
|
|
||||||
if (event->type == EV_KEY)
|
|
||||||
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 mode = 0, delay = 20000;
|
int opt, mode = 0;
|
||||||
|
while ((opt = getopt(argc, argv, "hm:")) != -1) {
|
||||||
for (int opt; (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 'm':
|
case 'm':
|
||||||
mode = atoi(optarg);
|
mode = optarg[0] - '0';
|
||||||
continue;
|
|
||||||
case 't':
|
|
||||||
delay = 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);
|
||||||
|
|
||||||
@ -93,48 +77,58 @@ int main(int argc, char *argv[]) {
|
|||||||
if (input.type == EV_MSC && input.code == MSC_SCAN)
|
if (input.type == EV_MSC && input.code == MSC_SCAN)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (input.type != EV_KEY && input.type != EV_REL &&
|
if (input.type != EV_KEY) {
|
||||||
input.type != EV_ABS) {
|
|
||||||
write_event(&input);
|
write_event(&input);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (state) {
|
if (capslock_is_down) {
|
||||||
case START:
|
if (equal(&input, &capslock_down) ||
|
||||||
if (input.type == EV_KEY && input.code == KEY_CAPSLOCK &&
|
equal(&input, &capslock_repeat))
|
||||||
input.value)
|
continue;
|
||||||
state = CAPSLOCK_HELD;
|
|
||||||
else
|
if (equal(&input, &capslock_up)) {
|
||||||
write_event_with_mode(&input, mode);
|
capslock_is_down = 0;
|
||||||
break;
|
if (esc_give_up) {
|
||||||
case CAPSLOCK_HELD:
|
esc_give_up = 0;
|
||||||
if (input.type == EV_KEY && input.code == KEY_CAPSLOCK) {
|
write_event(&ctrl_up);
|
||||||
if (input.value == 0) {
|
continue;
|
||||||
|
}
|
||||||
write_event(&esc_down);
|
write_event(&esc_down);
|
||||||
write_event(&syn);
|
write_event(&syn);
|
||||||
usleep(delay);
|
usleep(20000);
|
||||||
write_event(&esc_up);
|
write_event(&esc_up);
|
||||||
state = START;
|
continue;
|
||||||
}
|
}
|
||||||
} else if ((input.type == EV_KEY && input.value == 1) ||
|
|
||||||
input.type == EV_REL || input.type == EV_ABS) {
|
if (!esc_give_up && input.value) {
|
||||||
|
esc_give_up = 1;
|
||||||
write_event(&ctrl_down);
|
write_event(&ctrl_down);
|
||||||
write_event(&syn);
|
write_event(&syn);
|
||||||
usleep(delay);
|
usleep(20000);
|
||||||
write_event_with_mode(&input, mode);
|
}
|
||||||
state = CAPSLOCK_IS_CTRL;
|
} else if (equal(&input, &capslock_down)) {
|
||||||
} else
|
capslock_is_down = 1;
|
||||||
write_event_with_mode(&input, mode);
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (mode) {
|
||||||
|
case 0:
|
||||||
|
if (input.code == KEY_ESC)
|
||||||
|
input.code = KEY_CAPSLOCK;
|
||||||
break;
|
break;
|
||||||
case CAPSLOCK_IS_CTRL:
|
case 2:
|
||||||
if (input.type == EV_KEY && input.code == KEY_CAPSLOCK) {
|
switch (input.code) {
|
||||||
input.code = KEY_LEFTCTRL;
|
case KEY_ESC:
|
||||||
write_event(&input);
|
input.code = KEY_GRAVE;
|
||||||
if (input.value == 0)
|
break;
|
||||||
state = START;
|
case KEY_GRAVE:
|
||||||
} else
|
input.code = KEY_CAPSLOCK;
|
||||||
write_event_with_mode(&input, mode);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
write_event(&input);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user