Skip to content

Multi-keyboard ZMK configuration that use most keys of all keyboards it supports

Notifications You must be signed in to change notification settings

Townk/zmk-config

 
 

Repository files navigation

ZMK Custom Layouts

ZMK version Firmware build

This repository contains the ZMK user configuration for all my keyboards that use the ZMK firmware.

The way I organize the keyboards' layouts is to have a single master layout, with more keys defined than any keyboard I have. Then, each individual Keyboard configuration would define a “layer adapter” mapping the keys in the layout that it uses to its physical position.

Every keyboard layout has its layout documentation (located under the docs directory), but since they all share the majority of my layout, you should expect plenty of repeating texts between them.

My suggestion is to read the layout documentation for the keyboard you're looking for, then, when you understand it, go check out the other docs. This way, you won't have to read the same text twice, or explanations for things you aren't concerned with in the first place.

Currently, in this repository, I have layout for:

If you did not click on any of the layout links yet, there is some general information I would like you to have to help you understand them better.

Symbols Glossary

Inside the keymap files and on the layout map images, you'll see a series of symbols that are not well-used in ZMK configurations out there, so to understand the layout easily, here is a table with all the symbols I use:

Symbols Description
Command Command (Super)
Control Control (Ctrl)
Option Option (Alt / Meta)
Caps Word
Shift Shift
Globe Globe
Caps-Word Turn On Caps-Word
Space Space
Return Enter (Return / Ret)
Backspace Delete backwards (Backspace / Bksp)
Forward Delete Delete forward (Del)
Home
Page Up
Page Down
End
Backtab Backtab
Tab Tab
Volume up Volume up
Volume down Volume down
Volume off Mute
Brightness up Screen brightness up
Brightness down Screen brightness down
Backlight off Keyboard backlight off
Backlight down Keyboard backlight decrease
Backlight up Keyboard backlight increase
Skip back Previous song
Play or pause Play / pause
Skip forward Next song
Stop Stop media
Launchpad Launchpad
Mission Control Mission Control (⌘ ⌃ ↑)
Show all windows Show application windows (⌘ ⌃ ↓)
Spotlight Spotlight
Cut Cut (⌘ X)
Copy Copy (⌘ C)
Paste Paste (⌘ V)
Undo Undo (⌘ Z)
Redo Redo (⇧ ⌘ Z)
Search Find Next (⌘ G)
Search Find Previous (⇧ ⌘ G)
Previous word Previous word (⌥ ←)
Next word Next word (⌥ →)
Line start Beginning of line (⌘ ←)
Line end End of line (⌘ →)
Virtual desktop Go to Virtual Desktop on the Right (⌘ ⌃ →)
Virtual desktop Go to Virtual Desktop on the Left (⌘ ⌃ ←)
Window Next window (⌘ `)
Window Previous window (⌘ ~)
Keyboard Alternate layout (COLEMAK)
Bluetooth profile Bluetooth profile
Bluetooth clear Bluetooth profile clear
Keyboard power Toggle OLED display
LED underglow actions LED RGB underglow actions
USB Output mode (USB / BLE)
Computer power Turn off host computer
Keyboard reset Reset firmware
Bootload Bootload mode
Layer 1 Numbers Layer
Layer 2 Symbols Layer
Layer 3 Navigation Layer
Layer 4 Media Layer
Layer 5 Buttons Layer
Layer 6 System Layer
Layer lock Lock layer in place

Key Representation

When looking at the layout map images, you'll see that some keys have their background highlighted with different colors than the rest; many of them, also have more than one symbol as their labels.

To understand what all those symbols mean, let's first, look at how a key that has a single purpose is represented:

Simple key representation

This key has nothing special about it. When I tap it, it will output a, and if I hold it down, it will output a repeatedly, until I release it.

My layouts, like virtually every other keyboard layout in the world (including the standard ones that most people use), have keys that are used exclusively to alter what other keys output when held-down. When that happens, we say that the key caused the keyboard to “switch layers”, for instance:

Shift key representation

This is the Shift key, which forces other keys to output the uppercase version of itself, or in certain cases, it can force the key to output an entirely different symbol than the normal one (e.g., the number keys in most standard keyboards).

When a key outputs a different symbol than the uppercase version of the normal output while holding down the Shift key, it has the extra symbol drawn above the normal one, for instance:

Number 2 key representation

When tapped while no other hey is held-down, it will output 2, but if the Shift key is held-down while tapping it, it will output @.

Now, there is a special type of key that you don't find in standard keyboards easily. Those keys output their normal value when tapped, and a different one when held-down. These keys are called “Hold-Tap” keys. Most custom layouts use them, specially layouts for keyboards with less than 50 keys.

When those keys are shown in my layout maps, they have the “hold-down” value displayed below the normal symbol. For instance:

Tap-hold key “F” and “Shift”

This key is a normal F key that output f when tapped, and F when tapped while holding down the “Shift” key. However, when I hold this key down, it behaves like the “Shift” key, meaning that if I hold it down, and then press the key for number 2, the keyboard will output a @ character.

Note

Unfortunately, Keymap Drawer does not support representations of Mod-Morph or Tap-Dance, so I had to come up with a syntax to represent them:

Special labels on key representation

When you see a symbol followed by :, followed by another symbol on either, the shifted symbol or held symbol positions, it is indicating a morph behavior, meaning: <morph trigger>: <output symbol>. In the example above, when the A key is tapped while holding down the Command key, the result output will be the ` key.

When you see a counter in the form of <N>x, followed by :, followed by a symbol on either the held symbol or shifted symbol positions, it indicates a tap-dance behavior, meaning: <tap count>x: <output symbol>. In the example above, when the A key is tapped twice, it will output a CAPS_LOCK.

When we put all this together, and we see the following key in a layout map:

Tap-hold key “Backspace” and “Forward Delete”

We know that this key is a normal “Delete Backwards” when tapped by itself, and a “Forward Delete” when tapped while holding down “Shift”. But when I hold it down, it will be like I'm holding down the “Command” key on my macOS.

Tap-Hold Behavior

Usually, a tap and hold key goes into the “hold” mode when the key is held-down, which prevents the user from holding the key down and having its output repeated until the key is released.

To solve this issue, I used a (relatively new) feature of ZMK called quick-tap-ms, which always produces the “tap” behavior when the key is pressed twice in quick succession. This allows me to have repeatable keys, even when they're a “tap-hold” type of key.

For instance, let's assume the F tap-hold key shown in the previous section. The sequence of taps and their output would be:

  • F down, F up :: it will output a single f;
  • F down :: it will output a “Shift” key;
  • F down, F up, F down :: it outputs ffffffffff… until the key is released.

Globe Key

Around 2021, Apple made the (FN)/Globe key a standard key on all its keyboards, so as an Apple user, I wanted to have the same ability to access some features using my keyboard as I can using a standard Apple keyboard.

ZMK has partial support for the Globe key (check issue #937 for details on the mater), it can only be used as a “holding” key.

Caps Lock

I think CAPS_LOCK is evil. No keyboard should ever have that key available. That being said, I admit that sometime is very convenient to type a fully capitalized word without having to hold down the Shift key.

Fortunately, ZMK solved this by allowing us to use the CAPS_WORD behavior, where, when tapped, it will turn on the CAPS_LOCK just to the next word typed. Thereafter, the keyboard will put you on a normal typing mode again.

In this layout configuration, the CAPS_WORD feature is triggered when I press both “Shift” keys together.

My methodology

You may be asking yourself (probably not, but I'll pretend you are) what is my process to choose where keys go in all these layouts?

In all honesty, I don't have one. I usually use the keyboard and try to note repetitive mistakes or things that require a bigger effort to accomplish. When they become somewhat highly noticeable, I think about where the keys causing this issue should be for me to have less of these mistakes happening. Then, I change the layout to match my new hypothesis, flash the keyboard, and use the layout as if nothing happened.

Over time, the fixes that worked will fade in the background while new issues that deserve my attention, as well as the fixes that did not work, will show up again and again. When that happens… Rinse and repeat.

Local build

If you want to build this configuration locally, first, follow ZMK's instructions to be able to build the firmware itself.

Then, get a Python environment ready (you can use your OS Python, or you can create a virtual environment just for the project), and install the required dependencies to it:

$ pip install -r support/requirements.txt

You can build the firmware for all keyboards I have with the following command:

$ west build -p -d build/corne-left -b nice_nano_v2 -- \
    -DSHIELD=corne_left \
    -DDTS_EXTRA_CPPFLAGS="-DUSE_MOLOCK=1" \
    -DZMK_CONFIG="$TOWNK_ZMK_CONFIG_DIR/config" \
  && west build -p -d build/corne-right -b nice_nano_v2 -- \
    -DSHIELD=corne_right \
    -DDTS_EXTRA_CPPFLAGS="-DUSE_MOLOCK=1" \
    -DZMK_CONFIG="$TOWNK_ZMK_CONFIG_DIR/config" \
  && west build -p -d build/lily-left -b nice_nano_v2 -- \
    -DSHIELD="lily58_left nice_view_adapter nice_view" \
    -DDTS_EXTRA_CPPFLAGS="-DUSE_MOLOCK=1" \
    -DZMK_CONFIG="$TOWNK_ZMK_CONFIG_DIR/config" \
  && west build -p -d build/lily-right -b nice_nano_v2 -- \
    -DSHIELD="lily58_right nice_view_adapter nice_view" \
    -DDTS_EXTRA_CPPFLAGS="-DUSE_MOLOCK=1" \
    -DZMK_CONFIG="$TOWNK_ZMK_CONFIG_DIR/config" \
  && west build -p -d build/settings-reset -b nice_nano_v2 -- \
    -DSHIELD="settings_reset" \
    -DZMK_CONFIG="$TOWNK_ZMK_CONFIG_DIR/config"

After the first build, you can simplify the build command to the following:

$ west build -d build/corne-left \
  && west build -d build/corne-right \
  && west build -d build/lily-left \
  && west build -d build/lily-right \
  && west build -d build/settings-reset

And if you make any modifications to the keymap, make sure you update the assets used in the documentation, by running the update-layout-maps.sh script from the support directory:

$ cd "$TOWNK_ZMK_CONFIG_DIR"
$ ./support/update-layout-maps.sh

Disclaimers

Layout map images are all generated with Keymap-Drawer from Cem Aksoylar. If you have your custom ZMK or QMK configuration, I highly recommend you to check it out.

My homerow mod configuration is based on the fantastic “timeless homerow mods” from Robert U (@urob)'s ZMK Configuration. You should absolutely check this configuration for examples.

The pattern I used to share my layout across multiple keyboards was a suggestion from Rafael Romão (@rafaelromao) and Cem Aksoylar (@caksoylar) on the ZMK Discord server, so I spent some time digging through their ZMK configurations to learn, and copy the pattern into my layout.

Unfortunately, due to the nature of my layout, you cannot use this configuration with Nick Coutsos Keymap-Editor.

About

Multi-keyboard ZMK configuration that use most keys of all keyboards it supports

Topics

Resources

Stars

Watchers

Forks

Languages

  • Shell 71.6%
  • Python 22.9%
  • Nix 5.5%