mod-morph fix

This commit is contained in:
Crispy 2022-09-17 16:29:38 +02:00
parent 86b9271ab4
commit 0dcf5ee6d9
15 changed files with 1009 additions and 4 deletions

View file

@ -2,6 +2,8 @@
#include <dt-bindings/zmk/keys.h>
#include <dt-bindings/zmk/bt.h>
#include "../zmk-nodefree-config/helper.h"
#define L0 0
#define L1 1
#define L2 2

View file

@ -1,11 +1,11 @@
manifest:
remotes:
- name: zmkfirmware
url-base: https://github.com/zmkfirmware
- name: urob
url-base: https://github.com/urob
projects:
- name: zmk
remote: zmkfirmware
revision: main
remote: urob
revision: fix-mod-morph
import: app/west.yml
self:
path: config

2
zmk-nodefree-config/.gitattributes vendored Normal file
View file

@ -0,0 +1,2 @@
*.dtsi linguist-language=C++
*.keymap linguist-language=C++

View file

@ -0,0 +1,403 @@
# zmk-nodefree-config
ZMK lets user customize their keyboard layout by providing a Devicetree file
(`.keymap`). The specific syntax requirements of the Devicetree file format can,
however, make this process a bit daunting for new users.
This repository provides simple convenience macros that simplify the configuration for
many common use cases. It results in a "node-free" user configuration with a more
streamlined syntax. Check out [example.keymap](example.keymap) to see it in action.
See [changelog](#changelog) for latest changes.
## Overview
The following convenience macros are provided:
1. `ZMK_BEHAVIOR` creates behaviors such as hold-taps, tap-dances or
ZMK macros [\[doc\]](#zmk_behavior)
2. `ZMK_LAYER` adds layers to the keymap [\[doc\]](#zmk_layer)
3. `ZMK_COMBO` defines combos [\[doc\]](#zmk_combo)
4. `ZMK_CONDITIONAL_LAYER` sets up "tri-layer" conditions [\[doc\]](#zmk_conditional_layer)
5. `ZMK_UNICODE_SINGLE` and `ZMK_UNICODE_PAIR` create unicode characters [\[doc\]](#zmk_unicode)
6. `international_chars` provides character definitions for some non-English languages
[\[doc\]](#international-characters)
7. `keypos_def` provides human-readable key position shortcuts for some popular
keyboards that simplify the configuration of combos and positional hold-taps
[\[doc\]](#key-position-helpers)
## Quickstart
1. Copy this repository into the root folder of your zmk-config. The
folder structure should look as follows:
```
zmk-config
├── config
│ ├── your.keyboard.conf
│ ├── your_keyboard.keymap
│ └── ...
├── zmk-nodefree-config
│ ├── helper.h
│ ├── ...
```
2. Source `helper.h` near the top of your `.keymap` file:
```C++
#include "../zmk-nodefree-config/helper.h"
```
3. Customize your keyboard's `.keymap` file. See [example.keymap](example.keymap) or [my
personal zmk-config](https://github.com/urob/zmk-config/blob/main/config/base.keymap)
for a complete configuration, and read the documentation below for details.
## Configuration details
### ZMK\_BEHAVIOR
`ZMK_BEHAVIOR` can be used to create any of the following ZMK behaviors: caps-word,
hold-tap, key-repeat, macro, mod-morph, sticky-key or tap-dance
**Syntax:** `ZMK_BEHAVIOR(name, type, specification)`
* `name`: a unique string chosen by the user (e.g., `my_behavior`). The new behavior can
be added to the keymap using `&name` (e.g., `&my_behavior`).
* `type`: the behavior to be created. It must be one of the following:
`caps_word`, `hold_tap`, `key_repeat`, `macro`, `mod_morph`, `sticky_key` or
`tap_dance`. Note that two-word types are separated by underscores (`_`).
* `specification`: the custom behavior code. It should contain the
body of the corresponding [ZMK behavior configuration](https://zmk.dev/docs/config/behaviors)
without the `label`, `#binding-cells` and `compatible` properties and without the
surrounding node-specification.
#### Example 1: Creating a custom "homerow mod" tap-hold behavior
```C++
ZMK_BEHAVIOR(hrm, hold_tap,
flavor = "balanced";
tapping-term-ms = <280>;
quick-tap-ms = <125>;
global-quick-tap;
bindings = <&kp>, <&kp>;
)
```
This creates a custom "homerow mod" that can be added to the keymap using `&hrm`. For example,
`&hrm LSHIFT T` creates a key that yields `T` on tap and `LSHIFT` on hold.
#### Example 2: Creating a custom tap-dance key
```C++
ZMK_BEHAVIOR(ss_cw, tap_dance,
tapping-term-ms = <200>;
bindings = <&sk LSHFT>, <&caps_word>;
)
```
This behavior yields sticky-shift on tap and caps-word on double tap. It can be added to
the keymap using `&ss_cw`.
#### Example 3: Creating a custom "win-sleep" macro
```C++
ZMK_BEHAVIOR(win_sleep, macro,
wait-ms = <100>;
tap-ms = <5>;
bindings = <&kp LG(X) &kp U &kp S>;
)
```
This creates a "Windows sleep macro" that can be added to the keymap using `&win_sleep`.
### ZMK\_LAYER
`ZMK_LAYER` adds new keymap layers to the configuration.
**Syntax:** `ZMK_LAYER(name, layout)`
* `name`: a unique identifier string chosen by the user (usually there is no reason to reference this elsewhere)
* `layout`: the layout specification using the same syntax as the `bindings`
property of the [ZMK keymap configuration](https://zmk.dev/docs/config/keymap)
Multiple layers can be added with repeated calls of `ZMK_LAYER`. They will be ordered
in the same order in which they are created, with the first-specified layer being
the "lowest" one ([see here for details](https://zmk.dev/docs/features/keymaps#layers)).
#### Example usage
```C++
ZMK_KEYMAP(default_layer,
// ╭─────────────┬─────────────┬─────────────┬─────────────┬─────────────╮ ╭─────────────┬─────────────┬─────────────┬─────────────┬─────────────╮
&kp Q &kp W &kp F &kp P &kp B &kp J &kp L &kp U &kp Y &kp SQT
// ├─────────────┼─────────────┼─────────────┼─────────────┼─────────────┤ ├─────────────┼─────────────┼─────────────┼─────────────┼─────────────┤
&hrm LGUI A &hrm LALT R &hrm LCTRL S &hrm LSHFT T &kp G &kp M &hrm RSHFT N &hrm LCTRL E &hrm LALT I &hrm LGUI O
// ├─────────────┼─────────────┼─────────────┼─────────────┼─────────────┤ ├─────────────┼─────────────┼─────────────┼─────────────┼─────────────┤
&kp Z &kp X &kp C &kp D &kp V &kp K &kp H &kp COMMA &kp DOT &kp SEMI
// ╰─────────────┼─────────────┼─────────────┼─────────────┼─────────────┤ ├─────────────┼─────────────┼─────────────┼─────────────┼─────────────┤
&kp ESC &lt NAV SPACE &kp TAB &kp RET &ss_cw &bs_del_num
// ╰─────────────┴──── ────────┴─────────────╯ ╰─────────────┴─────────────┴─────────────╯
)
```
### ZMK\_COMBO
`ZMK_COMBO` defines new combos.
**Syntax:** `ZMK_COMBO(name, bindings, keypos, layers)`
* `name`: a unique identifier string chosen by the user (usually there is not reason to reference this elsewhere)
* `binding`: the binding triggered by the combo (this can be any stock or previously defined behavior)
* `keypos`: a list of 2 or more key positions that trigger the combo (e.g., `12
13`). Note that the mapping from key positions to keys depends on your keyboard. To facilitate
the combo setup and increase portability, one can use key-position helpers instead.
See [below](#key-position-helpers) on how to use them.
* `layers`: a list of layers for which the combo is active (e.g., `0 1` for the first
two layers). If set to `ALL` the combo is active on all layers.
By default, the timeout for combos created with `ZMK_COMBO` is 30ms. If `COMBO_TERM` is
reset prior to calling `ZMK_COMBO`, the new value of `COMBO_TERM` is used instead.
Alternatively, one can use `ZMK_COMBO_ADV` which allows to specify the combo-timeout directly
as 5th argument.
Note: with older ZMK versions, using different combo-timeouts would result in keys
getting stuck. If this is an issue, try updating to the latest ZMK version.
#### Example: copy and paste combos
```C++
#undef COMBO_TERM
#define COMBO_TERM 50
ZMK_COMBO(copy, &kp LC(C), 12 13, ALL)
ZMK_COMBO(paste, &kp LC(V), 13 14, ALL)
```
This sets the combo timeout to 50ms, and then creates two combos which both are
active on all layers. The first combo is triggered when the
12th and 13th keys are pressed jointly within the `COMBO_TERM`, sending <kbd>Ctrl</kbd> + <kbd>C</kbd>. The
second combo is triggered when the 13th and 14th keys are pressed jointly, sending
<kbd>Ctrl</kbd> + <kbd>V</kbd>.
### ZMK\_CONDITIONAL\_LAYER
This sets up tri-layer conditions.
**Syntax:** `ZMK_CONDITIONAL_LAYER(if_layers, then_layers)`
* `if_layers`: a list of layers which trigger the `then_layer` if simultaneously active
* `then_layer`: the layer which is activated when the if-condition is met. Due to ZMK's
layering model, it should generally have a higher number than the `if_layers`
For instance, this triggers "layer 3" if layers "1" and "2" are
simultaneously active.
```C++
ZMK_CONDITIONAL_LAYER(1 2, 3)
```
Mind that ZMK's layer numbering starts at 0. One can use layer
definitions, as demonstrated in [example.keymap](example.keymap), to simplify life.
### ZMK\_UNICODE
There are two macros that create new unicode characters that
can be added to the keymap. `ZMK_UNICODE_SINGLE` creates single unicode characters such
as <kbd></kbd>, and `ZMK_UNICODE_PAIR` creates pairs of shifted/unshifted unicode
characters that are useful for specifying international characters such as
<kbd>ä</kbd>/<kbd>Ä</kbd> or <kbd>δ</kbd>/<kbd>Δ</kbd>.
**Syntax:** `ZMK_UNICODE_SINGLE(name, L0, L1, L2, L3)`
* `name:` a unique string chosen by the user (e.g., `my_char`). The unicode character can
be added to the keymap using `&name` (e.g., `&my_char`)
* `L0` to `L3`: a 4-digit sequence defining the unicode string using standard [ZMK key
codes](https://zmk.dev/docs/codes/keyboard-keypad)
**Syntax:** `ZMK_UNICODE_PAIR(name, L0, L1, L2, L3, U0, U1, U2, U3)`
* `name:` a unique string chosen by the user (e.g., `my_char`). The unicode character can
be added to the keymap using `&name` (e.g., `&my_char`)
* `L0` to `L3`: a 4-digit sequence defining the unshifted unicode string
* `U0` to `U3`: a 4-digit sequence defining the shifted unicode string (which is send when
holding <kbd>Shift</kbd> while pressing <kbd>&name</kbd>)
Note: 5-digit unicode characters are currently not supported (but would be easy to add
if there is interest).
#### Example 1: Euro sign (€)
```C++
ZMK_UNICODE_SINGLE(euro_sign, N2, N0, A, C)
```
This creates a Euro character that can be added to the keymap using `&euro_sign`.
#### Example 2: German umlauts (ä/Ä, ö/Ö, ü/Ü)
```C++
// name unshifted shifted
ZMK_UNICODE_PAIR( de_ae, N0, N0, E, N4, N0, N0, C, N4 )
ZMK_UNICODE_PAIR( de_oe, N0, N0, F, N6, N0, N0, D, N6 )
ZMK_UNICODE_PAIR( de_ue, N0, N0, F, C, N0, N0, D, C )
```
The creates "umlaut" pairs that can be added to the keymap using `&de_ae`, `&de_oe` and `&de_ue`.
#### Dependencies for unicode
* `ZMK_UNICODE_PAIR` requires ZMK patched with [PR
#1412](https://github.com/zmkfirmware/zmk/pull/1412). If you need help maintaining
your own ZMK repository, check out [this
guide](https://gist.github.com/urob/68a1e206b2356a01b876ed02d3f542c7). If you don't
want to maintain your own ZMK repository, you can use ZMK's [beta
testing](https://zmk.dev/docs/features/beta-testing) feature to configure Github
Actions to build against a patched remote branch of ZMK. To do so, replace the
contents of `west.yml` in your `zmk-config/config` directory with the following
contents, which adds the required patch:
```
manifest:
remotes:
- name: urob
url-base: https://github.com/urob
projects:
- name: zmk
remote: urob
revision: fix-mod-morph
import: app/west.yml
self:
path: config
```
* The input of unicode characters differs across operating systems. By
default, `ZMK_UNICODE` is configured for Windows (using WinCompose). To set it up
for another OS, set the variable
`HOST_OS` **before** sourcing `helper.h`.
For Linux use:
```C++
#define HOST_OS 1 // set to 1 for Linux, default is 0 (Windows)
#include helper.h
```
For macOS/Windows-Alt-Codes use:
```C++
#define HOST_OS 2 // set to 2 for macOS/Windows-Alt-Codes, default is 0 (Windows)
#include helper.h
```
This will send unicode characters using the OS's default input channels.
For non-default input channels or for other operating systems, one can instead set the
variables `OS_UNICODE_LEAD` and `OS_UNICODE_TRAIL` to the character sequences that
initialize/terminate the unicode input.[^1]
* On Windows and macOS there are additional requirements for unicode input to work. On
Windows, one must install [WinCompose](https://github.com/samhocevar/wincompose) for
full support (or use Win-Alt-Codes for limited support in select software). On
macOS one must enable unicode input in the system preferences.
### International characters
There are pre-defined definitions for international characters for a few
languages --- currently German, Greek and Swedish (contributions are welcome)[^2]. These can be
loaded by sourcing the corresponding files; e.g.:
```C++
#include "../zmk-nodefree-config/international_chars/german.dtsi"
#include "../zmk-nodefree-config/international_chars/greek.dtsi"
#include "../zmk-nodefree-config/international_chars/swedish.dtsi"
```
Once sourced, international characters can be added to the
keymap using, e.g., `&de_ae`, `&el_alpha` or `&sv_ao`
(each language has its own prefix; see the language files for a complete list of available characters).
**Dependencies:** These definitions make use of unicode in the background,
see the unicode section above for [prerequisites](#dependencies-for-unicode).
**Note:** Windows-Alt-Codes use different keycode sequences than the
usual unicode sequences, requiring different definitions. Currently, they are
pre-defined for German:
```C++
#include "../zmk-nodefree-config/international_chars/german_alt.dtsi"
```
### Key-position helpers
Certain configuration options such as combos and positional hold-taps are based on the
physical position of keys on the keyboard. This can be cumbersome and reduces
portability of configuration files across keyboards with different layouts.
To increase portability and ease of use, this repo provides optional key-position
helpers for some popular keyboard layouts (48-key boards such as Planck, 42-key
boards such as Corne, 36-key boards and 34-key boards).
These key-position helpers provide a map from the physical key positions to human-readable shortcuts.
All shortcuts are of the following form:
* `L/R` for **L**eft/**R**ight hand
* `T/M/B/H` for **T**op/**M**iddle/**B**ottom and t**H**umb row.
* `0/1/2/3/4` for the finger position starting from the inside (`0` is the inner
index-finger column, `1` is the home position of the index finger, ..., `4` is the home
position of the pinkie)
For instance, the shortcuts layout for a 36-key board looks as follows:
```
╭─────────────────────┬─────────────────────╮
│ LT4 LT3 LT2 LT1 LT0 │ RT0 RT1 RT2 RT3 RT4 │
│ LM4 LM3 LM2 LM1 LM0 │ RM0 RM1 RM2 RM3 RM4 │
│ LB4 LB3 LB2 LB1 LB0 │ RB0 RB1 RB2 RB3 RB4 │
╰───────╮ LH2 LH1 LH0 │ RH0 RH1 RH2 ╭───────╯
╰─────────────┴─────────────╯
```
Schematics for all supported keyboards can be found in the corresponding
definition files in the `keypos_def` folder.
To use these key-position helpers, source the definition file for your keyboard
into your `.keymap` file. E.g., for a 36-key board, use:
```C++
#include "../zmk-nodefree-config/keypos_def/keypos_36keys.h"
```
#### Example 1: Defining combos using key-position helpers
```C++
ZMK_COMBO(copy, &kp LC(C), LB2 LB3, ALL)
ZMK_COMBO(paste, &kp LC(V), LB1 LB2, ALL)
```
This defines a "copy"-combo for the middle + ring finger on the left bottom row, and a
"paste"-combo for the index + middle finger on the left bottom row. Both combos are active on all layers.
#### Example 2: Home-row mods with positional hold-taps
Here we use ZMK's [positional
hold-tap](https://zmk.dev/docs/behaviors/hold-tap#positional-hold-tap-and-hold-trigger-key-positions)
feature to make home-row mods only trigger with "opposite hand" keys. Using
key-position helpers makes this straightforward:
```C++
#define KEYS_L LT0 LT1 LT2 LT3 LT4 LM0 LM1 LM2 LM3 LM4 LB0 LB1 LB2 LB3 LB4 // left-hand keys
#define KEYS_R RT0 RT1 RT2 RT3 RT4 RM0 RM1 RM2 RM3 RM4 RB0 RB1 RB2 RB3 RB4 // right-hand keys
#define THUMBS LH2 LH1 LH0 RH0 RH1 RH2 // thumb keys
ZMK_BEHAVIOR(hml, hold_tap, // left-hand HRMs
flavor = "balanced";
tapping-term-ms = <280>;
quick-tap-ms = <125>;
global-quick-tap;
bindings = <&kp>, <&kp>;
hold-trigger-key-positions = <KEYS_R THUMBS>;
)
ZMK_BEHAVIOR(hmr, hold_tap, // right-hand HRMs
flavor = "balanced";
tapping-term-ms = <280>;
quick-tap-ms = <125>;
global-quick-tap;
bindings = <&kp>, <&kp>;
hold-trigger-key-positions = <KEYS_L THUMBS>;
)
```
## Changelog
* **9/11/2022:** Support for Windows-Alt-Codes
* **8/05/2022:** New combo macro `ZMK_COMBO_ADV` for "advanced" combo setups. Compared
to the regular `ZMK_COMBO` macro, it takes the combo-timeout as fifth argument.
Moreover, if `COMBO_HOOK` is defined, it includes its definition as additional
options. For example, to use the new global-quick-tap for combos option introduced in
[PR #1387](https://github.com/andrewjrae/zmk/tree/min-prior-ms), one would set
`#define COMBO_HOOK global-quick-tap-ms = <125>;` before calling `ZMK_COMBO_ADV`.
See [my personal combo
setup](https://github.com/urob/zmk-config/blob/main/config/combos.dtsi) for examples.
* **7/31/2022:** Switch unicode dependency from PR #1114 to
[PR #1412](https://github.com/zmkfirmware/zmk/pull/1412)
[^1]: The default for Windows is `OS_UNICODE_LEAD` set to tap <kbd>Right Alt</kbd>
followed by <kbd>U</kbd> and `OS_UNICODE_TRAIL` set to tap <kbd>Return</kbd>.
The default for Linux is `OS_UNICODE_LEAD` set to tap <kbd>Shift</kbd> +
<kbd>Ctrl</kbd> + <kbd>U</kbd> and `OS_UNICODE_TRAIL` set to tap <kbd>Space</kbd>.
The default for macOS is `OS_UNICODE_LEAD` set to hold <kbd>Left Alt</kbd>
and `OS_UNICODE_TRAIL` set to release <kbd>Left Alt</kbd>.
[^2]: Swedish language support was added by discord user "captainwoot".

View file

@ -0,0 +1,109 @@
#include <behaviors.dtsi>
#include <dt-bindings/zmk/keys.h>
#include "../zmk-nodefree-config/helper.h"
#include "../zmk-nodefree-config/keypos_def/keypos_36keys.h"
#include "../zmk-nodefree-config/international_chars/german.dtsi"
/* layer and key shortcuts */
#define ___ &trans
#define DEF 0 // layer shortcuts, must match order in which they are defined below
#define NAV 1
#define NUM 2
#define GER 3
/* custom behaviors */
// homerow mods
ZMK_BEHAVIOR(hrm, hold_tap,
flavor = "balanced";
tapping-term-ms = <280>;
quick-tap-ms = <125>;
global-quick-tap;
bindings = <&kp>, <&kp>;
)
// tap: sticky shift | double tap: capsword
ZMK_BEHAVIOR(ss_cw, tap_dance,
tapping-term-ms = <200>;
bindings = <&sk LSHFT>, <&caps_word>;
)
// tap: backspace | shift + tap: delete | hold: num layer
ZMK_BEHAVIOR(bs_del_num, mod_morph,
bindings = <&lt NUM BSPC>, <&kp DEL>;
mods = <(MOD_LSFT|MOD_RSFT)>;
)
// windows sleep macro
ZMK_BEHAVIOR(win_sleep, macro,
wait-ms = <100>;
tap-ms = <5>;
bindings = <&kp LG(X) &kp U &kp S>;
)
// euro sign
ZMK_UNICODE_SINGLE(euro_sign, N2, N0, A, C) // €
// replace a/o/u/s with German umlauts when NAV and NUM are held jointly
ZMK_CONDITIONAL_LAYER(NAV NUM, GER)
// combos
#undef COMBO_TERM
#define COMBO_TERM 40 // timeout of 40ms (default is 30ms if omitted)
ZMK_COMBO(combo_sleep, &win_sleep, RT3 RT4, NAV) // custom sleep macro, only active on NAV layer
ZMK_COMBO(combo_copy, &kp LC(C), LB2 LB3, ALL) // Ctrl + C, active on all layers
ZMK_COMBO(combo_paste, &kp LC(V), LB1 LB2, ALL) // Ctrl + V, active on all layers
/* keymap */
ZMK_LAYER(default_layer,
// ╭─────────────┬─────────────┬─────────────┬─────────────┬─────────────╮ ╭─────────────┬─────────────┬─────────────┬─────────────┬─────────────╮
&kp Q &kp W &kp F &kp P &kp B &kp J &kp L &kp U &kp Y &kp SQT
// ├─────────────┼─────────────┼─────────────┼─────────────┼─────────────┤ ├─────────────┼─────────────┼─────────────┼─────────────┼─────────────┤
&hrm LGUI A &hrm LALT R &hrm LCTRL S &hrm LSHFT T &kp G &kp M &hrm RSHFT N &hrm LCTRL E &hrm LALT I &hrm LGUI O
// ├─────────────┼─────────────┼─────────────┼─────────────┼─────────────┤ ├─────────────┼─────────────┼─────────────┼─────────────┼─────────────┤
&kp Z &kp X &kp C &kp D &kp V &kp K &kp H &kp COMMA &kp DOT &kp SEMI
// ╰─────────────┼─────────────┼─────────────┼─────────────┼─────────────┤ ├─────────────┼─────────────┼─────────────┼─────────────┼─────────────┤
&kp ESC &lt NAV SPACE &kp TAB &kp RET &bs_del_num &ss_cw
// ╰─────────────┴─────────────┴─────────────╯ ╰─────────────┴─────────────┴─────────────╯
)
ZMK_LAYER(nav_layer,
// ╭─────────────┬─────────────┬─────────────┬─────────────┬─────────────╮ ╭─────────────┬─────────────┬─────────────┬─────────────┬─────────────╮
___ ___ ___ ___ ___ &kp PG_UP &kp HOME &kp UP &kp END &kp INS
// ├─────────────┼─────────────┼─────────────┼─────────────┼─────────────┤ ├─────────────┼─────────────┼─────────────┼─────────────┼─────────────┤
&sk LGUI &sk LALT &sk LCTRL &sk LSHFT ___ &kp PG_DN &kp LEFT &kp DOWN &kp RIGHT &kp DEL
// ├─────────────┼─────────────┼─────────────┼─────────────┼─────────────┤ ├─────────────┼─────────────┼─────────────┼─────────────┼─────────────┤
___ ___ ___ ___ ___ ___ &kp LC(X) &kp LC(INS) &kp LS(INS) ___
// ╰─────────────┼─────────────┼─────────────┼─────────────┼─────────────┤ ├─────────────┼─────────────┼─────────────┼─────────────┼─────────────┤
___ ___ ___ ___ ___ ___
// ╰─────────────┴─────────────┴─────────────╯ ╰─────────────┴─────────────┴─────────────╯
)
ZMK_LAYER(num_layer,
// ╭─────────────┬─────────────┬─────────────┬─────────────┬─────────────╮ ╭─────────────┬─────────────┬─────────────┬─────────────┬─────────────╮
&kp ESC &kp N7 &kp N8 &kp N9 &kp STAR ___ ___ ___ ___ ___
// ├─────────────┼─────────────┼─────────────┼─────────────┼─────────────┤ ├─────────────┼─────────────┼─────────────┼─────────────┼─────────────┤
&kp TAB &kp N4 &kp N5 &kp N6 &kp PLUS ___ &sk RSHFT &sk LCTRL &sk LALT &sk LGUI
// ├─────────────┼─────────────┼─────────────┼─────────────┼─────────────┤ ├─────────────┼─────────────┼─────────────┼─────────────┼─────────────┤
&kp RET &kp N1 &kp N2 &kp N3 &kp FSLH ___ ___ ___ ___ ___
// ╰─────────────┼─────────────┼─────────────┼─────────────┼─────────────┤ ├─────────────┼─────────────┼─────────────┼─────────────┼─────────────┤
&kp DOT &kp N0 &kp MINUS ___ ___ ___
// ╰─────────────┴─────────────┴─────────────╯ ╰─────────────┴─────────────┴─────────────╯
)
ZMK_LAYER(german_layer,
// ╭─────────────┬─────────────┬─────────────┬─────────────┬─────────────╮ ╭─────────────┬─────────────┬─────────────┬─────────────┬─────────────╮
___ ___ ___ ___ ___ ___ ___ &de_ue ___ ___
// ├─────────────┼─────────────┼─────────────┼─────────────┼─────────────┤ ├─────────────┼─────────────┼─────────────┼─────────────┼─────────────┤
&de_ae ___ &de_eszett ___ ___ ___ ___ &euro_sign ___ &de_oe
// ├─────────────┼─────────────┼─────────────┼─────────────┼─────────────┤ ├─────────────┼─────────────┼─────────────┼─────────────┼─────────────┤
___ ___ ___ ___ ___ ___ ___ ___ ___ ___
// ╰─────────────┼─────────────┼─────────────┼─────────────┼─────────────┤ ├─────────────┼─────────────┼─────────────┼─────────────┼─────────────┤
___ ___ ___ ___ ___ ___
// ╰─────────────┴─────────────┴─────────────╯ ╰─────────────┴─────────────┴─────────────╯
)

View file

@ -0,0 +1,152 @@
/*
* helper.h
*
* Convenience macros simplifying ZMK's keymap configuration.
* See https://github.com/urob/zmk-nodefree-config for documentation.
*/
#pragma once
#define ZMK_HELPER_STRINGIFY(x) #x
/* ZMK_BEHAVIOR */
#define ZMK_BEHAVIOR_CORE_caps_word compatible = "zmk,behavior-caps-word"; #binding-cells = <0>
#define ZMK_BEHAVIOR_CORE_hold_tap compatible = "zmk,behavior-hold-tap"; #binding-cells = <2>
#define ZMK_BEHAVIOR_CORE_key_repeat compatible = "zmk,behavior-key-repeat"; #binding-cells = <0>
#define ZMK_BEHAVIOR_CORE_macro compatible = "zmk,behavior-macro"; #binding-cells = <0>
#define ZMK_BEHAVIOR_CORE_mod_morph compatible = "zmk,behavior-mod-morph"; #binding-cells = <0>
#define ZMK_BEHAVIOR_CORE_sticky_key compatible = "zmk,behavior-sticky-key"; #binding-cells = <1>
#define ZMK_BEHAVIOR_CORE_tap_dance compatible = "zmk,behavior-tap-dance"; #binding-cells = <0>
#define ZMK_BEHAVIOR(name, type, ...) \
/ { \
behaviors { \
name: name { \
label = ZMK_HELPER_STRINGIFY(ZB_ ## name); \
ZMK_BEHAVIOR_CORE_ ## type; \
__VA_ARGS__ \
}; \
}; \
};
/* ZMK_LAYER */
#define ZMK_LAYER(name, layout) \
/ { \
keymap { \
compatible = "zmk,keymap"; \
name { \
bindings = <layout>; \
}; \
}; \
};
/* ZMK_COMBOS */
#define ALL 0xff
#if !defined COMBO_TERM
#define COMBO_TERM 30
#endif
#define ZMK_COMBO(name, combo_bindings, keypos, combo_layers) \
/ { \
combos { \
compatible = "zmk,combos"; \
combo_ ## name { \
timeout-ms = <COMBO_TERM>; \
bindings = <combo_bindings>; \
key-positions = <keypos>; \
layers = <combo_layers>; \
}; \
}; \
};
#if !defined COMBO_HOOK
#define COMBO_HOOK
#endif
#define ZMK_COMBO_ADV(name, combo_bindings, keypos, combo_layers, combo_timeout) \
/ { \
combos { \
compatible = "zmk,combos"; \
combo_ ## name { \
timeout-ms = <combo_timeout>; \
bindings = <combo_bindings>; \
key-positions = <keypos>; \
layers = <combo_layers>; \
COMBO_HOOK \
}; \
}; \
};
/* ZMK_CONDITIONAL_LAYER */
#define ZMK_CONDITIONAL_LAYER(if_layers, then_layer) \
/ { \
conditional_layers { \
compatible = "zmk,conditional-layers"; \
tri_layer { \
if-layers = <if_layers>; \
then-layer = <then_layer>; \
}; \
}; \
};
/* ZMK_UNICODE */
#if !defined OS_UNICODE_LEAD
#if HOST_OS == 2
#define OS_UNICODE_LEAD &macro_press &kp LALT // macOS/Windows-Alt-Codes
#elif HOST_OS == 1
#define OS_UNICODE_LEAD &macro_tap &kp LS(LC(U)) // Linux
#else
#define OS_UNICODE_LEAD &macro_tap &kp RALT &kp U // Windows + WinCompose (default)
#endif
#endif
#if !defined OS_UNICODE_TRAIL
#if HOST_OS == 2
#define OS_UNICODE_TRAIL &macro_release &kp LALT // macOS/Windows-Alt-Codes
#elif HOST_OS == 1
#define OS_UNICODE_TRAIL &macro_tap &kp SPACE // Linux
#else
#define OS_UNICODE_TRAIL &macro_tap &kp RET // Windows + WinCompose (default)
#endif
#endif
#define UC_MACRO(name, unicode_bindings) \
/ { \
macros { \
name: name { \
compatible = "zmk,behavior-macro"; \
label = ZMK_HELPER_STRINGIFY(UC_MACRO_ ## name); \
wait-ms = <0>; \
tap-ms = <0>; \
#binding-cells = <0>; \
bindings = <OS_UNICODE_LEAD>, <&macro_tap unicode_bindings>, <OS_UNICODE_TRAIL>; \
}; \
}; \
};
#define UC_MODMORPH(name, uc_binding, shifted_uc_binding) \
/ { \
behaviors { \
name: name { \
compatible = "zmk,behavior-mod-morph"; \
label = ZMK_HELPER_STRINGIFY(UC_MORPH_ ## name); \
#binding-cells = <0>; \
bindings = <uc_binding>, <shifted_uc_binding>; \
mods = <(MOD_LSFT|MOD_RSFT)>; \
masked-mods = <(MOD_LSFT|MOD_RSFT)>; \
}; \
}; \
};
#define ZMK_UNICODE_SINGLE(name, L0, L1, L2, L3) \
UC_MACRO(name ## _lower, &kp L0 &kp L1 &kp L2 &kp L3) \
UC_MODMORPH(name, &name ## _lower, &none)
#define ZMK_UNICODE_PAIR(name, L0, L1, L2, L3, U0, U1, U2, U3) \
UC_MACRO(name ## _lower, &kp L0 &kp L1 &kp L2 &kp L3) \
UC_MACRO(name ## _upper, &kp U0 &kp U1 &kp U2 &kp U3) \
UC_MODMORPH(name, &name ## _lower, &name ## _upper)

View file

@ -0,0 +1,6 @@
/* German umlauts */
ZMK_UNICODE_PAIR( de_ae, N0, N0, E, N4, N0, N0, C, N4)
ZMK_UNICODE_PAIR( de_oe, N0, N0, F, N6, N0, N0, D, N6)
ZMK_UNICODE_PAIR( de_ue, N0, N0, F, C, N0, N0, D, C)
ZMK_UNICODE_SINGLE( de_eszett, N0, N0, D, F)

View file

@ -0,0 +1,5 @@
/* German umlauts for Windows-Alt-Codes */
ZMK_UNICODE_PAIR( de_ae, KP_N0, KP_N2, KP_N2, KP_N8, KP_N0, KP_N1, KP_N9, KP_N6)
ZMK_UNICODE_PAIR( de_oe, KP_N0, KP_N2, KP_N4, KP_N6, KP_N0, KP_N2, KP_N1, KP_N4)
ZMK_UNICODE_PAIR( de_ue, KP_N0, KP_N2, KP_N5, KP_N2, KP_N0, KP_N2, KP_N2, KP_N0)
ZMK_UNICODE_SINGLE( de_eszett, KP_N0, KP_N2, KP_N2, KP_N3)

View file

@ -0,0 +1,26 @@
/* Greek letters */
ZMK_UNICODE_PAIR(el_alpha, N0, N3, B, N1, N0, N3, N9, N1)
ZMK_UNICODE_PAIR(el_beta, N0, N3, B, N2, N0, N3, N9, N2)
ZMK_UNICODE_PAIR(el_gamma, N0, N3, B, N3, N0, N3, N9, N3)
ZMK_UNICODE_PAIR(el_delta, N0, N3, B, N4, N0, N3, N9, N4)
ZMK_UNICODE_PAIR(el_epsilon, N0, N3, F, N5, N0, N3, N9, N5) // varepsilon = 03B5
ZMK_UNICODE_PAIR(el_zeta, N0, N3, B, N6, N0, N3, N9, N6)
ZMK_UNICODE_PAIR(el_eta, N0, N3, B, N7, N0, N3, N9, N7)
ZMK_UNICODE_PAIR(el_theta, N0, N3, B, N8, N0, N3, N9, N8)
ZMK_UNICODE_PAIR(el_iota, N0, N3, B, N9, N0, N3, N9, N9)
ZMK_UNICODE_PAIR(el_kappa, N0, N3, B, A, N0, N3, N9, A)
ZMK_UNICODE_PAIR(el_lambda, N0, N3, B, B, N0, N3, N9, B)
ZMK_UNICODE_PAIR(el_mu, N0, N3, B, C, N0, N3, N9, C)
ZMK_UNICODE_PAIR(el_nu, N0, N3, B, D, N0, N3, N9, D)
ZMK_UNICODE_PAIR(el_xi, N0, N3, B, E, N0, N3, N9, E)
ZMK_UNICODE_PAIR(el_omikron, N0, N3, B, F, N0, N3, N9, F)
ZMK_UNICODE_PAIR(el_pi, N0, N3, C, N0, N0, N3, A, N0)
ZMK_UNICODE_PAIR(el_rho, N0, N3, C, N1, N0, N3, A, N1)
ZMK_UNICODE_PAIR(el_sigma, N0, N3, C, N3, N0, N3, A, N3)
ZMK_UNICODE_PAIR(el_tau, N0, N3, C, N4, N0, N3, A, N4)
ZMK_UNICODE_PAIR(el_upsilon, N0, N3, C, N5, N0, N3, A, N5)
ZMK_UNICODE_PAIR(el_phi, N0, N3, C, N6, N0, N3, A, N6) // varphi = 03C6
ZMK_UNICODE_PAIR(el_chi, N0, N3, C, N7, N0, N3, A, N7)
ZMK_UNICODE_PAIR(el_psi, N0, N3, C, N8, N0, N3, A, N8)
ZMK_UNICODE_PAIR(el_omega, N0, N3, C, N9, N0, N3, A, N9)

View file

@ -0,0 +1,5 @@
/* Swedish letters */
ZMK_UNICODE_PAIR(sv_ae, N0, N0, E, N4, N0, N0, C, N4)
ZMK_UNICODE_PAIR(sv_ao, N0, N0, E, N5, N0, N0, C, N5)
ZMK_UNICODE_PAIR(sv_oe, N0, N0, F, N6, N0, N0, D, N6)

View file

@ -0,0 +1,53 @@
/* 34 KEY MATRIX / LAYOUT MAPPING
0 1 2 3 4 5 6 7 8 9 LT4 LT3 LT2 LT1 LT0 RT0 RT1 RT2 RT3 RT4
10 11 12 13 14 15 16 17 18 19 LM4 LM3 LM2 LM1 LM0 RM0 RM1 RM2 RM3 RM4
20 21 22 23 24 25 26 27 28 29 LB4 LB3 LB2 LB1 LB0 RB0 RB1 RB2 RB3 RB4
30 31 32 33 LH1 LH0 RH0 RH1
*/
#pragma once
#define LT0 4 // left-top row
#define LT1 3
#define LT2 2
#define LT3 1
#define LT4 0
#define RT0 5 // right-top row
#define RT1 6
#define RT2 7
#define RT3 8
#define RT4 9
#define LM0 14 // left-middle row
#define LM1 13
#define LM2 12
#define LM3 11
#define LM4 10
#define RM0 15 // right-middle row
#define RM1 16
#define RM2 17
#define RM3 18
#define RM4 19
#define LB0 24 // left-bottom row
#define LB1 23
#define LB2 22
#define LB3 21
#define LB4 20
#define RB0 25 // right-bottom row
#define RB1 26
#define RB2 27
#define RB3 28
#define RB4 29
#define LH0 31 // left thumb keys
#define LH1 30
#define RH0 32 // right thumb keys
#define RH1 33

View file

@ -0,0 +1,55 @@
/* 36 KEY MATRIX / LAYOUT MAPPING
0 1 2 3 4 5 6 7 8 9 LT4 LT3 LT2 LT1 LT0 RT0 RT1 RT2 RT3 RT4
10 11 12 13 14 15 16 17 18 19 LM4 LM3 LM2 LM1 LM0 RM0 RM1 RM2 RM3 RM4
20 21 22 23 24 25 26 27 28 29 LB4 LB3 LB2 LB1 LB0 RB0 RB1 RB2 RB3 RB4
30 31 32 33 34 35 LH2 LH1 LH0 RH0 RH1 RH2
*/
#pragma once
#define LT0 4 // left-top row
#define LT1 3
#define LT2 2
#define LT3 1
#define LT4 0
#define RT0 5 // right-top row
#define RT1 6
#define RT2 7
#define RT3 8
#define RT4 9
#define LM0 14 // left-middle row
#define LM1 13
#define LM2 12
#define LM3 11
#define LM4 10
#define RM0 15 // right-middle row
#define RM1 16
#define RM2 17
#define RM3 18
#define RM4 19
#define LB0 24 // left-bottom row
#define LB1 23
#define LB2 22
#define LB3 21
#define LB4 20
#define RB0 25 // right-bottom row
#define RB1 26
#define RB2 27
#define RB3 28
#define RB4 29
#define LH0 32 // left thumb keys
#define LH1 31
#define LH2 30
#define RH0 33 // right thumb keys
#define RH1 34
#define RH2 35

View file

@ -0,0 +1,61 @@
/* 42 KEY MATRIX / LAYOUT MAPPING
0 1 2 3 4 5 6 7 8 9 10 11 LT5 LT4 LT3 LT2 LT1 LT0 RT0 RT1 RT2 RT3 RT4 RT5
12 13 14 15 16 17 18 19 20 21 22 23 LM5 LM4 LM3 LM2 LM1 LM0 RM0 RM1 RM2 RM3 RM4 RM5
24 25 26 27 28 29 30 31 32 33 34 35 LB5 LB4 LB3 LB2 LB1 LB0 RB0 RB1 RB2 RB3 RB4 RB5
36 37 38 39 40 41 LH2 LH1 LH0 RH0 RH1 RH2
*/
#pragma once
#define LT0 5 // left-top row
#define LT1 4
#define LT2 3
#define LT3 2
#define LT4 1
#define LT5 0
#define RT0 6 // right-top row
#define RT1 7
#define RT2 8
#define RT3 9
#define RT4 10
#define RT5 11
#define LM0 17 // left-middle row
#define LM1 16
#define LM2 15
#define LM3 14
#define LM4 13
#define LM5 12
#define RM0 18 // right-middle row
#define RM1 19
#define RM2 20
#define RM3 21
#define RM4 22
#define RM5 23
#define LB0 29 // left-bottom row
#define LB1 28
#define LB2 27
#define LB3 26
#define LB4 25
#define LB5 24
#define RB0 30 // right-bottom row
#define RB1 31
#define RB2 32
#define RB3 33
#define RB4 34
#define RB5 35
#define LH0 38 // left thumb keys
#define LH1 37
#define LH2 36
#define RH0 39 // right thumb keys
#define RH1 40
#define RH2 41

View file

@ -0,0 +1,67 @@
/* 48 KEY MATRIX / LAYOUT MAPPING
0 1 2 3 4 5 6 7 8 9 10 11 LT5 LT4 LT3 LT2 LT1 LT0 RT0 RT1 RT2 RT3 RT4 RT5
12 13 14 15 16 17 18 19 20 21 22 23 LM5 LM4 LM3 LM2 LM1 LM0 RM0 RM1 RM2 RM3 RM4 RM5
24 25 26 27 28 29 30 31 32 33 34 35 LB5 LB4 LB3 LB2 LB1 LB0 RB0 RB1 RB2 RB3 RB4 RB5
36 37 38 39 40 41 42 43 44 45 46 47 LH5 LH4 LH3 LH2 LH1 LH0 RH0 RH1 RH2 RH3 RH4 RH5
*/
#pragma once
#define LT0 5 // left-top row
#define LT1 4
#define LT2 3
#define LT3 2
#define LT4 1
#define LT5 0
#define RT0 6 // right-top row
#define RT1 7
#define RT2 8
#define RT3 9
#define RT4 10
#define RT5 11
#define LM0 17 // left-middle row
#define LM1 16
#define LM2 15
#define LM3 14
#define LM4 13
#define LM5 12
#define RM0 18 // right-middle row
#define RM1 19
#define RM2 20
#define RM3 21
#define RM4 22
#define RM5 23
#define LB0 29 // left-bottom row
#define LB1 28
#define LB2 27
#define LB3 26
#define LB4 25
#define LB5 24
#define RB0 30 // right-bottom row
#define RB1 31
#define RB2 32
#define RB3 33
#define RB4 34
#define RB5 35
#define LH0 41 // left thumb keys
#define LH1 40
#define LH2 39
#define LH3 38
#define LH4 37
#define LH5 36
#define RH0 42 // right thumb keys
#define RH1 43
#define RH2 44
#define RH3 45
#define RH4 46
#define RH5 47

View file

@ -0,0 +1,59 @@
/* 48 KEY MATRIX / WIDE LAYOUT MAPPING
0 1 2 3 4 5 6 7 8 9 10 11 LT4 LT3 LT2 LT1 LT0 --- --- RT0 RT1 RT2 RT3 RT4
12 13 14 15 16 17 18 19 20 21 22 23 LM4 LM3 LM2 LM1 LM0 --- --- RM0 RM1 RM2 RM3 RM4
24 25 26 27 28 29 30 31 32 33 34 35 LB4 LB3 LB2 LB1 LB0 --- --- RB0 RB1 RB2 RB3 RB4
36 37 38 39 40 41 42 43 44 45 46 47 LH4 LH3 LH2 LH1 LH0 --- --- RH0 RH1 RH2 RH3 RH4
*/
#pragma once
#define LT0 4 // left-top row
#define LT1 3
#define LT2 2
#define LT3 1
#define LT4 0
#define RT0 7 // right-top row
#define RT1 8
#define RT2 9
#define RT3 10
#define RT4 11
#define LM0 16 // left-middle row
#define LM1 15
#define LM2 14
#define LM3 13
#define LM4 12
#define RM0 19 // right-middle row
#define RM1 20
#define RM2 21
#define RM3 22
#define RM4 23
#define LB0 28 // left-bottom row
#define LB1 27
#define LB2 26
#define LB3 25
#define LB4 24
#define RB0 31 // right-bottom row
#define RB1 32
#define RB2 33
#define RB3 34
#define RB4 35
#define LH0 40 // left thumb keys
#define LH1 39
#define LH2 38
#define LH3 37
#define LH4 36
#define RH0 43 // right thumb keys
#define RH1 44
#define RH2 45
#define RH3 46
#define RH4 47