Initial commit

This commit is contained in:
Francisco Lopes 2017-07-24 18:42:11 -03:00
commit 60ce0b8cc5
7 changed files with 364 additions and 0 deletions

17
.clang-format Normal file
View File

@ -0,0 +1,17 @@
BasedOnStyle: Google
Standard: Cpp11
SortIncludes: false
AccessModifierOffset: -4
PointerBindsToType: false
DerivePointerBinding: false
AllowShortLoopsOnASingleLine: false
AllowShortBlocksOnASingleLine : false
AllowShortIfStatementsOnASingleLine: false
AlwaysBreakTemplateDeclarations: false
AlignConsecutiveAssignments: true
AlignEscapedNewlinesLeft: true
AlignTrailingComments: true
AlignOperands: true
ColumnLimit: 80
IndentWidth: 4
TabWidth: 4

12
.editorconfig Normal file
View File

@ -0,0 +1,12 @@
root = true
[*]
charset = utf-8
end_of_line = lf
indent_size = 4
indent_style = space
insert_final_newline = true
trim_trailing_whitespace = true
[*.{md}]
trim_trailing_whitespace = false
[*.{c,cpp}]
max_line_length = 80

114
.gitignore vendored Normal file
View File

@ -0,0 +1,114 @@
# Created by https://www.gitignore.io/api/c,c++,vim,linux
### C ###
# Prerequisites
*.d
# Object files
*.o
*.ko
*.obj
*.elf
# Linker output
*.ilk
*.map
*.exp
# Precompiled Headers
*.gch
*.pch
# Libraries
*.lib
*.a
*.la
*.lo
# Shared objects (inc. Windows DLLs)
*.dll
*.so
*.so.*
*.dylib
# Executables
*.exe
*.out
*.app
*.i*86
*.x86_64
*.hex
# Debug files
*.dSYM/
*.su
*.idb
*.pdb
# Kernel Module Compile Results
*.mod*
*.cmd
modules.order
Module.symvers
Mkfile.old
dkms.conf
### C++ ###
# Prerequisites
# Compiled Object files
*.slo
# Precompiled Headers
# Compiled Dynamic libraries
# Fortran module files
*.mod
*.smod
# Compiled Static libraries
*.lai
# Executables
### Vim ###
# swap
[._]*.s[a-v][a-z]
[._]*.sw[a-p]
[._]s[a-v][a-z]
[._]sw[a-p]
# session
Session.vim
# temporary
.netrwhist
*~
# auto-generated tag files
tags
### Linux ###
# temporary files which can be created if a process still has a handle open of a deleted file
.fuse_hidden*
# KDE directory preferences
.directory
# Linux trash folder which might appear on any partition or disk
.Trash-*
# .nfs files are created when an open file is removed but is still being accessed
.nfs*
# End of https://www.gitignore.io/api/c,c++,vim,linux
### Custom ###
.lvimrc
.tmuxp.yaml
.gdb_history
.ycm_extra_conf.py

8
CMakeLists.txt Normal file
View File

@ -0,0 +1,8 @@
cmake_minimum_required(VERSION 3.0)
project(caps2esc)
add_executable(caps2esc caps2esc.c)
target_compile_options(caps2esc PRIVATE -Wall -Wextra)
install(TARGETS caps2esc RUNTIME DESTINATION bin)

26
LICENSE.md Normal file
View File

@ -0,0 +1,26 @@
The MIT License (MIT)
=====================
Copyright © `2017` `Francisco Lopes da Silva`
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the “Software”), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.

112
README.md Normal file
View File

@ -0,0 +1,112 @@
# caps2esc
_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)
</a>
## What is it?
- **Put what's useless in its place**
<sub>_By moving the CAPSLOCK function to the far ESC location_</sub>
- **Make what's useful comfortably present, just below your Pinky**
<sub>_By moving both ESC and CTRL functions to the CAPSLOCK location_</sub>
## Why?!
Because CAPSLOCK is just "right there" and making it CTRL when key-chording and
ESC when pressed alone is quite handy, specially in vi.
## Dependencies
- [Interception Tools][interception-tools]
## Building
```
$ git clone git@gitlab.com:interception/linux/tools.git
$ cd tools
$ mkdir build
$ cd build
$ cmake ..
$ make
```
## Execution
`caps2esc` is an [_Interception Tools_][interception-tools] plugin. A suggested
`udevmon` job configuration is:
```yaml
- JOB: "intercept -g $DEVNODE | caps2esc | uinput -d $DEVNODE"
DEVICE:
EVENTS:
EV_KEY: [KEY_CAPSLOCK, KEY_ESC]
```
For more information about the [_Interception Tools_][interception-tools], check
the project's website.
## Installation
I'm maintaining an Archlinux package on AUR:
- <https://aur.archlinux.org/packages/interception-caps2esc>
## Caveats
As always, there's always a caveat:
- `intercept -g` will "grab" the detected devices for exclusive access.
- If you tweak your key repeat settings, check whether they get reset.
Please check [this report][key-repeat-fix] about the resolution.
## History
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 CAPSLOCK into CTRL).
Moving on, permanently making Linux my home, I searched and tweaked a similar
solution based on [xmodmap][] and [xcape][]:
- <https://github.com/alexandre/caps2esc>
It's a simple solution but with many annoying drawbacks I couldn't stand in the
end:
- It resets any time a device change happens (bluetooth, usb, any) or the
laptop lid is closed or when logging off and needs to be re-executed.
- It depends on [X][]. Doesn't work on TTY (bare terminal based machine,
CTRL-ALT F2, etc).
Meanwhile on Windows land, I had a definitive solution based on my
[Interception library][interception] that always works perfectly, no hiccups.
It made me envy enough, so I ported the
[Windows Interception caps2esc][caps2esc-windows] sample to Linux based upon
the [_Interception Tools_][interception-tools].
## License
<a href="https://gitlab.com/interception/linux/plugins/caps2esc/blob/master/LICENSE.md">
<img src="https://upload.wikimedia.org/wikipedia/commons/thumb/0/0b/License_icon-mit-2.svg/120px-License_icon-mit-2.svg.png" alt="MIT">
</a>
Copyright © 2017 Francisco Lopes da Silva
[caps2esc-windows]: https://github.com/oblitum/Interception/blob/master/samples/caps2esc/caps2esc.cpp
[karabiner]: https://pqrs.org/osx/karabiner/
[xmodmap]: https://www.x.org/releases/X11R7.7/doc/man/man1/xmodmap.1.xhtml
[xcape]: https://github.com/alols/xcape
[x]: https://www.x.org
[interception]: https://github.com/oblitum/Interception
[interception-tools]: https://gitlab.com/interception/linux/tools
[key-repeat-fix]: https://github.com/oblitum/caps2esc/issues/1

75
caps2esc.c Normal file
View File

@ -0,0 +1,75 @@
#include <stdio.h>
#include <stdlib.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};
// 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;
}
void write_event(const struct input_event *event) {
if (fwrite(event, sizeof(struct input_event), 1, stdout) != 1)
exit(EXIT_FAILURE);
}
int main(void) {
int capslock_is_down = 0, esc_give_up = 0;
struct input_event input;
setbuf(stdin, NULL), setbuf(stdout, NULL);
while (read_event(&input)) {
if (input.type != EV_KEY) {
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;
}
if (input.code == KEY_ESC)
input.code = KEY_CAPSLOCK;
write_event(&input);
}
}