Skip to main content

ZMK State Of The Firmware #4

· 7 min read
Pete Johanson
Project Creator

Welcome to the fourth ZMK "State Of The Firmware" (SOTF)!

This update will cover all the major activity since SOTF #3.

Recent Activity#

Here's a summary of the various major changes since last time, broken down by theme:


Since last time, there have been several new powerful keymap features and behaviors added, including one of the most asked for features, combos!


The initial combos work has landed! The amazing okke-formsma has once again delivered another powerful feature for ZMK. Combos are "position based", and are configured in a new toplevel node next to they keymap node in user's keymap files.

An example, that would send the ESC keycode when pressing both the first and second positions on your keyboard:

/ {    combos {        compatible = "zmk,combos";        combo_esc {            timeout-ms = <50>;            key-positions = <0 1>;            bindings = <&kp ESC>;        };    };};

Combos currently are "global", and not scoped to a given active layer. There is future planned work to allow enabling a certain combo for only certain active layers.

Sticky Keys (One-Shot Mods/Layers) Behavior#

okke-formsma also contributed the initial "sticky keys" behavior, which can be used for functionality sometimes called "one shot mods" or "one shot layers". In your keymap, this would like like:


for a sticky key/modifier, or:

&sl NAV

for a sticky layer.

&to Layer Behavior#

mcrosson contributed the new &to layer related behavior. This can be used to completely replace the active layer with a new one.

This is most frequently used when using multiple core base layers with different layouts, e.g. QWERTY and DVORAK, to switch between them.

Grave Escape Behavior#

okke-formsma added an implementation of the "Grave Escape" behavior, developing a more generic "mod-morph" behavior to do so. Adding


to your keymap will send ESC when pressed on its own, but will send ` when pressed with a GUI or Shift modifier held.

RGB Underglow Color Selection#

mcrosson updated the RGB Underglow behavior to allow binding an explicit color selection to a key position.

Keymap Upgrader#

joelspadin completed the Keymap Upgrader which can be used to update your keymap to using the latest supported codes, and move away from the old deprecated codes.

If you've made keymap customizations, please make sure to run your keymaps through the upgrader, since the old deprecated codes will be removed in a future version of ZMK.


There has been lots of work to get display support complete enough for use by end users. Although not quite ready for prime time, it is incredibly close, and we are looking forward to having the last few items completed and the feature documented!

Idle Blanking#

petejohanson added idle blanking for displays, which ensures they will go blank, and into low power mode, after a short period of inactivity from the user. This ensures we avoid burn-in for OLEDs, and helps improve battery life.

Battery and Output Widgets#

petejohanson implemented the first two complete, dynamic "widgets" for the displays for ZMK, adding a small battery indicator, which includes charging status, and a small output indicator, showing the currently active output (USB or BLE). When using BLE, the indicator also shows the active profile slot, as well as if the profile slot is open, awaiting connection from the paired host, or is actively connected to the host for that profile slot.

Highest Layer Display#

mcrosson has contributed the next display widget, showing the highest active layer in the keymap. petejohanson then added a small follow up to allow layers in keymaps to add a label property to each layer, e.g. label = "Nav"; and have that label be displayed in the widget instead of the numeric layer number.


New contributor allymparker added our fourth widget, a words-per-minute display! This widget work also included creating the core state logic for tracking the WPM.

For now, this widget is only working on the central side of split keyboards.


Zephyr 2.4#

innovaker is at it again with some crucial core fixes, helping prepare and test the upgrade of ZMK to Zephyr 2.4. The updated Zephyr release brings with it some key BLE stability fixes, as well as various other core improvements that improve ZMK. This was a huge undertaking!

BLE Deadlock Fixes#

petejohanson was heads down diagnosing and fixing a deadlock issue on BLE that was frustrating and plaguing many users. After finally pinpointing the underlying root cause, he developed a fix and roped in many testers on Discord to help stress test things before merging.

Central/Peripheral Selection#

Previously overriding the selection of left as central, and right as peripheral for wireless splits required making local edits to the configuration files, and maintaining them in a ZMK fork.

petejohanson updated the config files to allow users to override this in their <board>_left.conf/<board>_right.conf files in their user repos.

Improved Docker Containers#

As part of the Zephyr 2.4. prep work, innovaker, along with lots of testing and input from mcrosson, developed a brand new pair of Docker images which is now published to Docker Hub as zmkfirmware/zmk-build-arm and zmkfirmware/zmk-dev-arm.

The previously blogged VSCode + Docker integration, as well as our GH Action build automation was all moved over to the new images.

Settings Debounce#

nicell contributed settings debounce work, to help avoid unnecessary extra writes to flash when making various changes that should be saved, such as the active BLE profile, external VCC on/off, etc.

New Shields#

New Boards#


Since it's inception, quite a few users have inquired whether they could sponsor any of the contributors involved in ZMK. Although we are not intending to directly fund any individual contributors for their work on ZMK, there is good that can come from folks sponsoring ZMK.

You can see the full discussion on #497, but some items that are being considered with sponsorship funds:

  • Hiring a designer to complete the logo/mascot work.
  • Creating stickers to send as thank-yous to first time contributors.
  • Hosting costs for GitHub Pro.
  • Other hosting costs, e.g. Docker Hub.

For anyone looking to contribute, you can find the ZMK Firmware project is now set up on Open Collective.

Coming Soon!#

Some items listed in the last coming soon section are still under active development.

  • A power profiler page for the website, to help users estimate their battery life for a given keyboard - Nicell
  • Behavior "locality", allowing improved split usage for things like &reset, and controlling external power and RGB underglow for both sides - petejohanson
  • More modular approach to external boards/shields, custom code, user keymaps, etc.
  • More shields and boards


Some statistics of interest for ZMK:

  • GitHub (lifetime stats)
    • 389 Closed PRs
    • 199 Stars
    • 163 Forks
  • Discord Chat
    • 702 total registered
  • Website (last 30 days)
    • 11.5K page views
    • 1K new users


Thanks again to the numerous contributors, testers, and users who have made working on ZMK such a pleasure!