- Python 100%
| cutekey | ||
| README.md | ||
CuteKey
An adorable key daemon... in early development. Don't use it yet
Features
All the simple features you could want from a key daemon!
The features we have :party:
- Remap combination of keys
<XX>to<YY>, with left/right modifier support - Remapping in stages
- Application-specific remaps (process-specific for console)
- Remapping keycodes directly with
<\001> - Importing other files using
@include - Works on wayland, x11, and the console
The features we don't have :tear:
- Vim-style layers. That's best left to a hotkey daemon
- Running shell commands on keystrokes. Also best for a hotkey daemon
- Keyboard-specific remaps. Considered for later
Methodology
Stages
To avoid recursive mappings while still allowing for "precedence" in mappings, we introduce a staging mechanism. This makes it clear what keycodes are coming in and going out
For example, if you want your capslock key to be indistinguishable from a
control key in all cases, map it at [Stage 0] with <capslock> = <C->. Then
if a mapping on [Stage 1] or higher maps control to something else, the
capslock will already appear as a control on that stage!
Stages are numbered 0 through 100. They do not have to be consecutive
App-specific remaps
Under each [Stage X] heading, a subheading [[ app_title ]] can be added.
These keys apply only when that app is focused. Multiple app titles, space
separated, can be included this way
If the first "title" is a !, the match is negated. These keys will apply to
all apps that aren't listed in the heading. All matches are case-insensitive
[Stage 4] # App-specific sub-headings can be used under any stage
[[ Alacritty xTeRm kiTTy ]] # Applies to these 3 terminal apps
[[ ! Chromium firefox ]] # Any apps other than chromium and firefox
Including files
Sometimes it's helpful to have slightly different configurations per-system or
per-keyboard, though with most mappings shared between the two. The @include
directive inserts a file by adding the current stage to all stages in that file
For example given file gimp_keys.tomlish
# This file is at ~/gimp_keys.tomlish
[Stage 0]
<e> = <a>
[Stage 4]
[[ Gimp ]]
<C-a> = <C-r>
When we include it in another file like
[Stage 2]
[[ Chromium ]]
@include ~/gimp_keys.tomlish
<C-v> = <C-S-v>
The other file effectively expands to
[Stage 2]
[[ Chromium ]]
<e> = <a>
<C-v> = <C-S-v>
[Stage 6]
[[ Chromium Gimp ]]
<C-a> = <C-r>
Notice how the @include inherits the app scope and the stage scope from where
it's placed. This means placing an @include under [Stage 0] will import is
"as is". I recommend not making too many stages in files that are @included.
Keep them atomic
Syntax
The configuration file is very similar to a TOML. Some differences include:
- Headings can include spaces
- All variables must start with
<and end with>on the left - Right side isn't quoted
- The
@includedirective
Keys use vim-ish syntax, see :h key-notation for the idea. Also supports fully
qualified names from libxkb. Names themselves are case-insensitive, though
modifiers are preferred to be capital
Keys can be discovered using wev for wayland or xev for xorg. We use the
lowercase name under the "sym" heading, except for modifier keys
Modifiers:
rC # Right control
lC # Left control
# Using the (left/right) prefix is optional and applies to all modifiers
M # Meta/super/logo
A # Alt
S # Shift
You can also specify keys through their scancodes. Add a \ in front of the
number. These are the numbers under the key heading in wev and xev. The
following expressions are all identical:
<rA-k>
<rA-\37>
Example
[Stage 0]
<capslock> = <C-> # Globally remap capslock to ctrl
<lC-> = <esc> # Globally remap the bottom left control to escape
<esc> = <grave> # Notice, no conflict is present with the previous mapping
# The following mapping won't cause recursion. Note here that the side is
# preserved, so the right alt will be mapped to the right meta
<A-> = <M-> # Globally remap both Alts to the corresponding Meta
<M-> = <A-> # Globally remap both Metas to the corresponding Alt
# We can't map Alt or Meta on this stage, since the above implicity remaps all
# keystrokes involving Alt and Meta
[Stage 1]
# The ! negates the match. Here, this binding will apply to all apps except
# alacritty, xterm, and kitty
[[ ! Alacritty Xterm Kitty ]]
<C-bracketleft> = <esc>
<C-p> = <up>
<C-n> = <down>
<C-j> = <left>
<C-f> = <right>
# In this example we're remapping to control modifier to itself
<C-w> = <C-right>
# The above is shorthand for the following:
# <lC-w> = <lC-right>
# <rC-w> = <rC-right>
# That is the "side" of the control is preserved
<C-b> = <C-left>
<C-a> = <home>
<C-e> = <end>
<C-i> = <S-end>
<C-u> = <C-S-left>
<C-h> = <backspace>
<C-d> = <delete>
[Stage 2]
# The following line inserts another config file at this stage. Note that stage
# 0 in the included file becomes stage 2. Stage 1 becomes stage 3 and so on...
# It's recommended to only have `[Stage 0]` in included files
@include /home/emiliko/.config/cutekey_nofn.toml
[[ Chromium Firefox ]] # This mapping applies to both firefox and chromium
<C-k> = <S-end>
<A-n> = <C-n>
<A-w> = <C-w>
<A-j> = <C-S-tab>
<A-k> = <C-tab>
<C-grave> = <grave> # Prevents accidental midnight discord calls
<A-f> = <C-f>
<A-l> = <C-l>
[[ Chromium ]]
<A-S-n> = <C-S-n>
[[ Firefox ]]
<A-S-n> = <C-S-p>