23 Commits

Author SHA1 Message Date
975bb74284 Passthrough mouse events
To not block mice that have keys, which end up grabbed due to generic
configurations that simply filter anything that responds to CAPSLOCK/ESC.

Fixes #15
2021-01-01 00:18:03 -03:00
8bfd57eda2 Formatting 2020-12-30 23:40:02 -03:00
186b887e7d Make multi device example more robust
The previous one won't work when devices reattach.
2020-12-30 23:16:17 -03:00
c738e8783a Formatting 2020-12-30 21:32:58 -03:00
a062311ffb Formatting 2020-12-30 21:19:31 -03:00
ac6bbe61c2 Update README 2020-12-29 09:26:35 -03:00
12dc2f75c7 Update README 2020-12-29 03:47:41 -03:00
3eaf2bddfe Update README 2020-12-29 03:46:32 -03:00
0c8326646a Expand mouse support
Until now mouse support existed just as side effect of muxing and that
mouse clicks are registered as key events. This expands the support for
mouse wheel and movement.
2020-12-29 02:43:04 -03:00
5c7e6b5a5d Formatting 2020-12-28 23:35:47 -03:00
7428d959e0 Formatting 2020-12-28 23:31:58 -03:00
e5dc581ddf Formatting 2020-12-28 23:24:11 -03:00
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
bb09cd8d9a Discard MSC_SCAN events
Given that only EV_KEY events are being mapped, without their scancode
counterparts, we just drop all scancode events to avoid having to map
them too, to syncing it with the corresponding mapped keys. This is
expected to be harmless.
2017-12-04 02:54:55 -02:00
0d88388a9e Add note about Ubuntu/Debian installation 2017-11-30 13:46:42 -02:00
9f353f96c6 Another evdev protocol infringement
Even though Peter Hutterer commented that it's not technically needed to
send SYN/delay when the sequence of events is of different keys, it
seems to be shown necessary to do so, otherwise events are dropped in
random situations.
2017-11-30 01:58:02 -02:00
27efcbbf96 Fix #4: Correctly follows evdev protocol
SYN events and different event timestamps are necessary for sending
sequential key events of the same key.
2017-11-29 23:59:07 -02:00
6fa3ad14b3 Fix README build instructions 2017-11-24 13:33:03 -02:00
40137670a4 Fix link 2017-08-13 14:25:50 -03:00
2 changed files with 167 additions and 56 deletions

View File

@ -4,9 +4,7 @@ _Transforming the most useless key **ever** in the most useful one._
<sub>_For vi/Vim/NeoVim addicts at least_.</sub>
<a href="http://www.catonmat.net/blog/why-vim-uses-hjkl-as-arrow-keys/">
![ADM-3A terminal](http://www.catonmat.net/images/why-vim-uses-hjkl/lsi-adm3a-full-keyboard.jpg)
<img src="http://www.catonmat.net/images/why-vim-uses-hjkl/lsi-adm3a-full-keyboard.jpg" alt="ADM-3A terminal">
</a>
## What is it?
@ -28,21 +26,38 @@ ESC when pressed alone is quite handy, specially in vi.
## Building
```
$ git clone git@gitlab.com:interception/linux/tools.git
$ cd tools
$ mkdir build
$ cd build
$ cmake ..
$ make
$ git clone git@gitlab.com:interception/linux/plugins/caps2esc.git
$ cd caps2esc
$ 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]
@ -52,11 +67,42 @@ $ make
For more information about the [_Interception Tools_][interception-tools], check
the project's website.
## Mouse Support
After _Interception Tools_ 0.3.1, `caps2esc` can observe for mouse events. An
example configuration taken from my laptop:
```yaml
SHELL: [zsh, -c]
---
- JOB: >
mux -c caps2esc;
mux -i caps2esc | caps2esc | uinput -d /dev/input/by-path/platform-i8042-serio-0-event-kbd
- JOB: intercept -g $DEVNODE | mux -o caps2esc
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, and [this discussion][issue-9-note] for more examples.
## 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
this:
- <https://askubuntu.com/questions/979359/how-do-i-install-caps2esc>
## Caveats
@ -71,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
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
@ -109,4 +155,5 @@ Copyright © 2017 Francisco Lopes da Silva
[x]: https://www.x.org
[interception]: https://github.com/oblitum/Interception
[interception-tools]: https://gitlab.com/interception/linux/tools
[issue-9-note]: https://gitlab.com/interception/linux/plugins/caps2esc/-/issues/9#note_474942893
[key-repeat-fix]: https://github.com/oblitum/caps2esc/issues/1

View File

@ -1,24 +1,39 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <linux/input.h>
// 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},
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) {
@ -30,46 +45,95 @@ 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) {
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 mode = 0, delay = 20000;
for (int opt; (opt = getopt(argc, argv, "ht:m:")) != -1;) {
switch (opt) {
case 'h':
return print_usage(stdout, argv[0]), EXIT_SUCCESS;
case 'm':
mode = atoi(optarg);
continue;
case 't':
delay = 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);
while (read_event(&input)) {
if (input.type != EV_KEY) {
if (input.type == EV_MSC && input.code == MSC_SCAN)
continue;
if (input.type != EV_KEY && input.type != EV_REL &&
input.type != EV_ABS) {
write_event(&input);
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(&esc_up);
continue;
}
if (!esc_give_up && input.value) {
esc_give_up = 1;
write_event(&ctrl_down);
}
} else if (equal(&input, &capslock_down)) {
capslock_is_down = 1;
continue;
switch (state) {
case START:
if (input.type == EV_KEY && input.code == KEY_CAPSLOCK &&
input.value)
state = CAPSLOCK_HELD;
else
write_event_with_mode(&input, mode);
break;
case CAPSLOCK_HELD:
if (input.type == EV_KEY && 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.type == EV_KEY && input.value == 1) ||
input.type == EV_REL || input.type == EV_ABS) {
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.type == EV_KEY && 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);
}
}