Skip to main content

ZMK State Of The Firmware #6

· 13 min read
Cem Aksoylar

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

This update will cover all the major activity since SOTF #5. That was over a year ago (again!), so there are many new exciting features and plenty of improvements to cover!

Recent Activity

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

Keymaps/Behaviors

Hold-tap improvements

andrewjrae added the require-prior-idle-ms property to the hold-tap behavior in #1187 and #1387, which prevents the hold behavior from triggering if it hasn't been a certain duration since the last key press. This is a useful feature to prevent accidental hold activations during quick typing and made its way into many keymaps! The same property was added to combos as well to help prevent false combo activations.

Note that an earlier iteration of this feature was supported with the global-quick-tap property, which did not allow customizing the timeout and used the value of quick-tap-ms for it. This property is now deprecated and users are encouraged to use require-prior-idle-ms instead.

urob added the hold-trigger-on-release property in #1423. This significantly increases the usefulness of positional constraints on hold-taps, since it allows combining multiple holds such as different modifiers for home row mods usage.

Masking mods in mod-morphs

aumuell, vrinek and urob contributed to improving the behavior of mod-morphs by masking the triggering modifiers and added keep-mods property in #1412. This unlocks more use cases for mod-morphs, since you are no longer constrained to emitting keycodes that work well with the triggering modifier keycodes.

As an example, you can now define a mod-morph that swaps ; and : so that the former is the shifted version of the latter, which wasn't previously possible:

        col_semi: colon_semicolon {
compatible = "zmk,behavior-mod-morph";
#binding-cells = <0>;
bindings = <&kp COLON>, <&kp SEMI>;
mods = <(MOD_LSFT|MOD_RSFT)>;
};

Parameterized macros

petejohanson added macros that can be parameterized with one or two parameters in #1232. This allows users to define macros in a more modular way and is a nice quality-of-life improvement.

As a simple example, you could define a macro that puts any keycode provided between double quotes as below, then use it like &ql A in your keymap:

        ql: quoted_letter {
#binding-cells = <1>;
compatible = "zmk,behavior-macro-one-param";
bindings =
<&kp DQT>,
<&macro_param_1to1 &kp MACRO_PLACEHOLDER>,
<&kp DQT>;
};

Please see the documentation page linked above for usage and more examples.

Arbitrary behaviors on encoder rotation

nickconway and petejohanson added sensor rotation behaviors to allow invoking arbitrary behaviors from encoders #1758. Previously encoder rotations could only invoke the key-press behavior &kp through the &inc_dec_kp binding, whereas now you can define new sensor rotation behaviors to invoke others.

(Note that currently behaviors that have "locality" such as &rgb_ug do not work as expected via encoder rotation bindings in split keyboards, due to issue #1494.)

Pre-releasing already pressed keys

andrewjrae contributed a tweak to emitting keycodes in #1828, where rolling multiple keys that involve the same keycode now releases the keycode before sending a press event again. While this might sound like a technical distinction, it leads to more correct behavior when quickly typing sequences like += and makes the key repeat behavior work properly when it is pressed before the previous key is released.

Key toggle behavior

cgoates added the key toggle behavior in #1278, which can be used via its &kt binding to toggle the state of a keycode between pressed and released.

Apple Globe key

ReFil added support for the C_AC_NEXT_KEYBOARD_LAYOUT_SELECT keycode with alias GLOBE which acts as the Globe key in macOS and iOS in #1938. Note that this keycode doesn't exactly behave like a Globe key that is present on an Apple keyboard and its limitations are documented in this comment thanks to testing by SethMilliken. These limitations will be noted in the official keycodes documentation shortly.

Bug fixes and other improvements

petejohanson, andrewjrae and okke-formsma tracked down and fixed an issue causing stuck keys when there are combos on key positions involving hold-tap behaviors in #1411. This was an elusive bug that took a lot of effort from the community to nail down and fix!

nguyendown and joelspadin tracked down and fixed a couple issues causing stuck keys with sticky keys in #1586, #1745.

okke-formsma fixed an issue allowing tap dances to be invoked by combos in #1518.

petejohanson tweaked the caps word behavior to ignore modifiers in #1330.

HelloThisIsFlo documented a bug with combos involving overlapping keys and different timeouts, produced a reproducing unit test, then proceeded to fix it in #1945.

Bluetooth and Split Improvements

Multiple peripherals

xudongzheng contributed to add support for more than one peripheral per keyboard in #836. This allows setups such as split keyboards with more than two halves, or enable a BLE-based "dongle mode" via a third device running ZMK that can stay connected to a computer via USB.

Note that documentation is still lacking for utilizing more than one peripheral and there will potentially be future changes in the build system to allow for more seamless configuration.

Pairing passkey requirement

petejohanson added the option to require passkey input while pairing to new devices in #1822. Enabling this will require you to enter a six digit passcode via the number keys on your keymap and press enter when pairing to a new device, enhancing security during the pairing procedure.

Split keyboard improvements

petejohanson contributed a fix to release held keys on peripheral disconnect #1340, which makes scenarios where a split disconnects unexpectedly less painful.

petejohanson also improved the settings_reset shield by making it clear bonds more reliably, and allow it to build for all boards in #1879.

petejohanson and xudongzheng contributed additional split connectivity improvements, via using directed advertising in #1913 and improving the robustness of central scanning in #1912.

Hardware Support

Encoders

petejohanson contributed a major refactor of encoder (and more generally sensor) functionality in #1039. While the documentation for these changes are still in progress, check out the dedicated blog post for more details.

This refactor paved way to implementing a long-awaited feature, encoder support in peripheral halves of split keyboards! Building upon the work by stephen in #728, petejohanson implemented support in #1841.

Direct GPIO driver

joelspadin extended the comprehensive debouncing framework used for matrix scan driver to the direct GPIO driver in #1288.

kurtis-lew added toggle mode support for direct GPIO driver in #1305. This allows for adding toggle switches to a keyboard, by properly reading their initial state on boot and making sure the power use is efficient.

IO peripheral drivers

petejohanson added support for the 595 shift register commonly used with smaller controllers like Seeeduino Xiaos, in #1325.

zhiayang added the driver for the MAX7318 GPIO expander in #1295.

Underglow auto-off options

ReFil added two new RGB auto off options, one using an idle timeout and the other USB status in #1010.

nice!view support

nicell added support for nice!view, a memory display optimized for low power use in #1462. He also contributed a custom vertically-oriented status screen that is automatically enabled when the nice_view shield is used in #1768, since the default status screen has a horizontal orientation. Please see the instructions in the nice!view README if you would like to restore the stock status screen.

E-paper display initialization

petejohanson contributed EPD initialization improvements in #1098, which makes the keyboards using slow refresh displays such as the Corne-ish Zen much more responsive during initial boot.

Xiao BLE improvements

Various improvements were made for the Seeeduino Xiao BLE board in #1293, d0176f36, #1545 and #1927 by petejohanson and caksoylar, enabling features necessary for ZMK and improving its power use.

Zephyr 3.2 Upgrade

petejohanson once again contributed the massive work necessary for upgrading ZMK to Zephyr 3.2 in #1499, with review help from joelspadin and testing by the community. This Zephyr release brings with it upgrades to the display library LVGL, adds official support for the RP2040 controllers and many internal refactors to help future development. Check out the dedicated blog post for more details!

Documentation

Configuration docs

joelspadin, through a massive amount of work in #722, contributed a whole new section to the documentation: configuration! It enumerates the configuration options for each ZMK feature that might be relevant to users in dedicated pages, making it a very handy reference.

In addition, the overview page presents an overview of how configuration works in Zephyr in the context of ZMK, in terms of devicetree files (like the keymap files or shield overlays), and Kconfig ones (like the .conf files). It is very helpful in de-mystifying what the various files do and what syntax is expected in them.

New behavior guide

For users or future contributors that might want to dive into writing their own ZMK behaviors, kurtis-lew wrote a useful guide on how to create new behaviors in #1268.

Tap dance and hold-tap documentation improvements

kurtis-lew also improved the documentation for these two behaviors in #1298, by updating the diagrams to better clarify how their timings work and adding examples for scenarios that are frequently asked by users.

Battery sensor documentation

joelspadin also added documentation for setting up battery sensors, typically required for new boards, in #868.

Shield interconnects

petejohanson updated the new shield guide for non-Pro Micro interconnects including Xiao, Arduino Uno and Blackpill in #1607.

Bluetooth feature page

petejohanson and caksoylar added a new Bluetooth feature page as part of #1499 and in #1818, detailing ZMK's Bluetooth implementation and troubleshooting for common problems.

In addition to the specific contributions listed above, various improvements and fixes to documentation are made by many users from the community, including but not limited to kurtis-lew, joelspadin, filterpaper, byran.tech, dxmh and caksoylar. These contributions are are all very appreciated!

Miscellaneous

Reusable GitHub build workflow

elagil helped switch the build workflow used by the user config repos to a reusable one in #1183 and it was further tweaked by filterpaper in #1258. This allows any changes in the workflow to be propagated automatically to users, rather than requiring them to make the updates. The build workflow can be customized by the users using input parameters if desired.

Pre-commit hooks

joelspadin added various pre-commit hooks and added checks to the repo to run them for each commit in #1651. These hooks and resulting updates standardize formatting across devicetree and other source files, reducing busywork on both contributors and reviewers.

Zephyr usage and other refactors

joelspadin also contributed a few refactor PRs such as #1269, #1255 and #1803, generally improving code quality and bringing the codebase in line with the latest Zephyr conventions.

petejohanson refactored the drivers structure to bring it in line with the current Zephyr conventions for out-of-tree drivers in #1919.

Updated USB polling interval default

USB HID polling interval now defaults to 1 ms, i.e. a 1000Hz polling rate, thanks to joelspadin's tweak in #1271.

Additional display config options

caksoylar added a couple configuration options for displays, including a setting to invert display colors in #1754 and an option to display the battery percentage for the stock status screen in #1563.

New Shields

New Boards

Coming Soon!

Some items listed in the last coming soon section are still under active development and other new exciting items are in progress:

  • Automatic/simple BLE profile management
  • Soft off support for turning the keyboard "off" through firmware
  • Improved automatic power management for devices with multiple peripherals, e.g. OLED displays and RGB LEDs
  • Caps/Scroll/Num Lock LED support
  • Mouse keys
  • Wired split support
  • More modular approach to external boards/shields, custom code, user keymaps, etc.
  • More shields and boards

Statistics

Some statistics of interest for ZMK:

  • GitHub (lifetime stats)
    • 166 Contributors
    • 1256 Closed PRs
    • 1883 Stars
    • 1949 Forks
  • Discord Chat
    • 8055 total registered (130% up from last SOTF!)
  • Website (last 30 days)
    • 52K page views
    • 4.7K new users

Sponsorship

While ZMK is an open source project that uses the permissive MIT license, below are opportunities for anyone who would like to show their support to the project financially.

Open Collective

The ZMK project has an Open Collective sponsorship that has been going for two and a half years. This fund helps pay for project costs like domain registration or development of hardware such as the ZMK Uno shield. Note that donations to this fund do not pay for the work of any individual contributor directly.

Contributor sponsorships

Project creator and lead Pete Johanson has a GitHub sponsorship set up that you can contribute to, in order to directly support his time and efforts in developing and maintaining ZMK. He has also been traveling full time while focusing on ZMK and keyboard hardware design for more than a year now! If you are curious, you can check out his blog post on deciding to embark on this adventure, in addition to his thoughts on contributor vs. project sponsorship, and sustainability of open source projects in general.

Thanks!

As the first person to author a State Of The Firmware post besides Pete, I'd like to take the opportunity to thank him for his efforts on leading and developing ZMK, along with fostering a great community of contributors and users around it.

Also a big thank you to contributors that submit patches and perform reviews, testers that help validate changes, and users that take time out of their day to help out folks with ZMK usage on Discord channels, GitHub issues and other communities.

Article Updates

  • 12/2023: Removed the deprecated label property from code snippets.