This was written as it happened (though not necessarily in the same order) when I was new to ZMK, on day 1 of getting the Keychron B6 Pro.
Some pros:
* Independence of a web service.
* More permanent configuration of the keyboard (not requiring reloading from a saved configuration after every reset to factory defaults (which also requires the web service))
Installation of ZMK
I initially considered using the standard Docker image for ZMK, but the instructions for installation of Docker itself seemed way too confusing; it wasn’t at all clear how to actually perform the installation (if they could just show a concrete linear example for some popular platform, say, Ubuntu). It is an example of overgeneralised installation instructions (way too abstract).
Instead, I decided to try to follow the official ZMK instructions for a native installation without Docker.
Initially, the installation failed on Ubuntu 20.04 (yes, I know), as expected. Instead, a LMDE 6 system was used.
These are the magic command lines (it is a linear thing (unlike the official instructions which makes “sub routine calls” to the Zephyr instructions (confusing)), and it should be possible to use them blindly, one by one, to get a ZMK environment for Keychron up and running):
# <https://zmk.dev/docs/development/local-toolchain/setup/native> git clone https://github.com/zmkfirmware/zmk.git cd zmk # <https://docs.zephyrproject.org/3.5.0/develop/getting_started/index.html#select-and-update-os> sudo apt update sudo apt upgrade # Install the required dependencies: sudo apt install --no-install-recommends git cmake ninja-build gperf \ ccache dfu-util device-tree-compiler wget \ python3-dev python3-pip python3-setuptools python3-tk python3-wheel xz-utils file \ make gcc gcc-multilib g++-multilib libsdl2-dev libmagic1 # Install a virtual environment (in this case 'venv'), # 'pip', and Git. # 'venv': <https://docs.python.org/3/library/venv.html> # # Notes: # # 1. A "virtual environment" in this context is # a sandboxed Python installation. That is, # isolated from the system Python # installation (which the operating # system heavily relies on; thus it # should not be messed with) # # 2. 'venv' is part of Python's standard # library (since version 3.2) sudo apt install python3-venv python3-pip git # Create a new virtual environment python3 -m venv ~/.ZMK_environment source ~/.ZMK_environment/bin/activate # Inside the virtual environment: # # Install west pip install west # Initialize the application and update to # fetch modules, including Zephyr: west init -l app/ west update # Export a Zephyr CMake package. This allows CMake to automatically # load boilerplate code required for building Zephyr applications. west zephyr-export # Install the additional dependencies found # in Zephyr's requirements-base.txt pip install -r zephyr/scripts/requirements-base.txt # <https://docs.zephyrproject.org/3.5.0/develop/getting_started/index.html#install-zephyr-sdk>: # # Install Zephyr SDK # # The Zephyr Software Development Kit (SDK) contains toolchains for # each of Zephyr's supported architectures, which include # a compiler, assembler, linker and other programs # required to build Zephyr applications. # # # Download and verify the Zephyr SDK bundle # # 1.2 GB... (download size. Compressed) # cd ~ wget https://github.com/zephyrproject-rtos/sdk-ng/releases/download/v0.16.3/zephyr-sdk-0.16.3_linux-x86_64.tar.xz wget -O - https://github.com/zephyrproject-rtos/sdk-ng/releases/download/v0.16.3/sha256.sum | shasum --check --ignore-missing # Extract the Zephyr SDK bundle archive: tar xvf zephyr-sdk-0.16.3_linux-x86_64.tar.xz # Run the Zephyr SDK bundle setup script: cd zephyr-sdk-0.16.3 ./setup.sh #Not yet... # Install udev rules, which allow you to flash most Zephyr # boards as a regular user: sudo cp ~/zephyr-sdk-0.16.3/sysroots/x86_64-pokysdk-linux/usr/share/openocd/contrib/60-openocd.rules /etc/udev/rules.d sudo udevadm control --reload # <https://zmk.dev/docs/development/local-toolchain/build-flash> # # Building and flashing cd ~/zmk/app # Build firmware for a sample keyboard # # </home/embo/zmk/app/boards/arm/planck/planck_rev6.yaml> # Has: # # identifier: planck_rev6 # # </home/embo/zmk/app/boards/arm/planck/planck_rev6.keymap> # </home/embo/zmk/app/boards/arm/planck/planck_rev6.zmk.yml> # </home/embo/zmk/app/boards/arm/planck/planck_rev6.dtsv # # A build folder: # # </home/embo/zmk/app/build/zephyr/boards/boards/arm/planck_rev6> # # cd ~/zmk/app west build -b planck_rev6 find ~/zmk/app | grep elf | xargs ls -l # Keychron B6 Pro # # Note: The Git branch will be "main" after the clone... # Keychron's Git branch is "keychron_bpro" # # And we should clone Keychron's fork, # not the main one... # # <https://github.com/Keychron/zmk/tree/keychron_bpro/app/boards/shields/keychron/b6> # # <https://github.com/Keychron/zmk/blob/keychron_bpro/app/boards/shields/keychron/b6/uk/Kconfig.shield> # Has: 'keychron_b6_uk'? # # Clone the source code repository # cd ~ git clone https://github.com/Keychron/zmk.git zmk_KeychronFork_forReal # The action is in Git branch "keychron_bpro" cd ~/zmk_KeychronFork_forReal git switch keychron_bpro # Or in a single step: # # cd ~ # git clone -b keychron_bpro https://github.com/Keychron/zmk.git zmk_KeychronFork_forReal # Initialize the application and update to # fetch modules, including Zephyr. # # This will take some time... # cd ~/zmk_KeychronFork_forReal west init -l app/ west update # Primary approx. 300 MB. 145496 "objects". # And several Git submodules, e.g. # 'modules/lib/canopennode' # 'modules/hal/stm32' # # Nearly 2000 lines in the screen output. # Export a Zephyr CMake package. This allows CMake to automatically # load boilerplate code required for building Zephyr applications. west zephyr-export # Keyboard Planck in Keychron's fork of ZMK cd ~/zmk_KeychronFork_forReal/app west build -b planck_rev6 # Failed: # # _power.h: No such file or directory # 18 | #include <hal/nrf_power.h> # | ^~~~~~~~~~~~~~~~~ # --pristine due to the previous build of keyboard Planck cd ~/zmk_KeychronFork_forReal/app west build --pristine -b keychron -p -- -DSHIELD=keychron_b6_uk
The blocking build error
FAILED: zephyr/CMakeFiles/zephyr.dir/home/embo/zmk_KeychronFork_forReal/app/src/dfu/tdfu_prv.c.obj ccache /home/embo/zephyr-sdk-0.16.3/arm-zephyr-eabi/bin/arm-zephyr-eabi-gcc -DKERNEL -DNRF52840_XXAA -D_FORTIFY_SOURCE=2 -D__PROGRAM_START -D__ZEPHYR__=1 -I/home/embo/zmk_KeychronFork_forReal/zephyr/kernel/include -I/home/embo/zmk_KeychronFork_forReal/zephyr/arch/arm/include -I/home/embo/zmk_KeychronFork_forReal/zephyr/include -I/home/embo/zmk_KeychronFork_forReal/app/build/zephyr/include/generated -I/home/embo/zmk_KeychronFork_forReal/zephyr/soc/arm/nordic_nrf/nrf52 -I/home/embo/zmk_KeychronFork_forReal/zephyr/soc/arm/nordic_nrf/common/. -I/home/embo/zmk_KeychronFork_forReal/zephyr/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/nrfx_glue -I/home/embo/zmk_KeychronFork_forReal/zephyr/subsys/bluetooth -I/home/embo/zmk_KeychronFork_forReal/zephyr/subsys/usb/device -I/home/embo/zmk_KeychronFork_forReal/zephyr/subsys/settings/include -I/home/embo/zmk_KeychronFork_forReal/modules/hal/cmsis/CMSIS/Core/Include -I/home/embo/zmk_KeychronFork_forReal/modules/hal/nordic/nrfx -I/home/embo/zmk_KeychronFork_forReal/modules/hal/nordic/nrfx/drivers/include -I/home/embo/zmk_KeychronFork_forReal/modules/hal/nordic/nrfx/mdk -I/home/embo/zmk_KeychronFork_forReal/zephyr/modules/hal_nordic/nrfx/. -I/home/embo/zmk_KeychronFork_forReal/modules/crypto/tinycrypt/lib/include -I/home/embo/zmk_KeychronFork_forReal/app/module/include -I/home/embo/zmk_KeychronFork_forReal/app/module/drivers/sensor/battery/. -isystem /home/embo/zmk_KeychronFork_forReal/zephyr/lib/libc/minimal/include -isystem /home/embo/zephyr-sdk-0.16.3/arm-zephyr-eabi/bin/../lib/gcc/arm-zephyr-eabi/12.2.0/include -isystem /home/embo/zephyr-sdk-0.16.3/arm-zephyr-eabi/bin/../lib/gcc/arm-zephyr-eabi/12.2.0/include-fixed -fno-strict-aliasing -Os -imacros /home/embo/zmk_KeychronFork_forReal/app/build/zephyr/include/generated/autoconf.h -ffreestanding -fno-common -g -gdwarf-4 -fdiagnostics-color=always -mcpu=cortex-m4 -mthumb -mabi=aapcs -mfp16-format=ieee --sysroot=/home/embo/zephyr-sdk-0.16.3/arm-zephyr-eabi/arm-zephyr-eabi -imacros /home/embo/zmk_KeychronFork_forReal/zephyr/include/zephyr/toolchain/zephyr_stdint.h -Wall -Wformat -Wformat-security -Wno-format-zero-length -Wno-main -Wno-pointer-sign -Wpointer-arith -Wexpansion-to-defined -Wno-unused-but-set-variable -Werror=implicit-int -fno-pic -fno-pie -fno-asynchronous-unwind-tables -fno-reorder-functions --param=min-pagesize=0 -fno-defer-pop -fmacro-prefix-map=/home/embo/zmk_KeychronFork_forReal/app=CMAKE_SOURCE_DIR -fmacro-prefix-map=/home/embo/zmk_KeychronFork_forReal/zephyr=ZEPHYR_BASE -fmacro-prefix-map=/home/embo/zmk_KeychronFork_forReal=WEST_TOPDIR -ffunction-sections -fdata-sections -std=c99 -nostdinc -Wfatal-errors -MD -MT zephyr/CMakeFiles/zephyr.dir/home/embo/zmk_KeychronFork_forReal/app/src/dfu/tdfu_prv.c.obj -MF zephyr/CMakeFiles/zephyr.dir/home/embo/zmk_KeychronFork_forReal/app/src/dfu/tdfu_prv.c.obj.d -o zephyr/CMakeFiles/zephyr.dir/home/embo/zmk_KeychronFork_forReal/app/src/dfu/tdfu_prv.c.obj -c /home/embo/zmk_KeychronFork_forReal/app/src/dfu/tdfu_prv.c In file included from /home/embo/zmk_KeychronFork_forReal/app/src/dfu/tdfu_prv.c:1: /home/embo/zmk_KeychronFork_forReal/app/src/dfu/tdfu_prv.h:3:10: fatal error: ..\version.h: No such file or directory 3 | #include "..\version.h"//<app_version.h> | ^~~~~~~~~~~~~~ compilation terminated.
And I got the same error, using the final step for actually building for B6 Pro (using the instruction found here):
source ~/.ZMK_environment/bin/activate cd ~/zmk_KeychronFork_forReal/app west build --pristine -b keychron -p -- -DSHIELD=keychron_b6_uk deactivate
Simple keymappings, including modifier keys
Edit the keymap file, /app/boards/shields/keychron/b6/uk/keychron_b6_uk.keymap, for example,
geany '$HOME/zmk_KeychronFork_forReal/app/boards/shields/keychron/b6/uk/keychron_b6_uk.keymap:233'
Appendix A: Key numbers
The source code file for the key map contains a lot of magic numbers, for example key numbers in the keymap. Here is the list of them for the B6 Pro, ISO variant:
Key number | Key | Notes |
---|---|---|
0 | ESC | |
1 | F1 | |
2 | F2 | |
3 | F3 | |
4 | F4 | |
5 | F5 | |
6 | F6 | |
7 | F7 | |
8 | F8 | |
9 | F9 | |
10 | F10 | |
11 | F11 | |
12 | F12 | |
13 | F13 | |
14 | PSCRN | |
15 | SLCK | |
16 | PAUS | |
17 | C_AL_CALC | |
18 | &uc LG(TAB) | |
19 | &uc LG(LC(LEFT)) | |
20 | &uc LG(LC(RIGHT)) | |
21 | GRAVE | |
22 | N1 | |
23 | N2 | |
24 | N3 | |
25 | N4 | |
26 | N5 | |
27 | N6 | |
28 | N7 | |
29 | N8 | |
30 | N9 | |
31 | N0 | |
32 | MINUS | |
33 | EQUAL | |
34 | BSPC | |
35 | INS | |
36 | HOME | |
37 | PG_UP | |
38 | KP_NLCK | |
39 | KP_SLASH | |
40 | KP_ASTERISK | |
41 | KP_MINUS | |
42 | TAB | |
43 | Q | |
44 | W | |
45 | E | |
46 | R | |
47 | T | |
48 | Y | |
49 | U | |
50 | I | |
51 | O | |
52 | P | |
53 | LBKT | |
54 | RBKT | |
55 | DEL | |
56 | END | |
57 | PG_DN | |
58 | KP_N7 | |
59 | KP_N8 | |
60 | KP_N9 | |
61 | KP_PLUS | |
62 | CLCK | |
63 | A | |
64 | S | |
65 | D | |
66 | F | |
67 | G | |
68 | H | |
69 | J | |
70 | K | |
71 | L | |
72 | SEMI | |
73 | SQT | |
74 | NUHS | |
75 | RET | |
76 | KP_N4 | |
77 | KP_N5 | |
78 | KP_N6 | |
79 | LSHFT | |
80 | NUBS | |
81 | Z | |
82 | X | |
83 | C | |
84 | V | |
85 | B | |
86 | N | |
87 | M | |
88 | COMMA | |
89 | DOT | |
90 | FSLH | |
91 | RSHFT | |
92 | UP | |
93 | KP_N1 | |
94 | KP_N2 | |
95 | KP_N3 | |
96 | LCTRL | |
97 | LGUI | |
98 | LALT | |
99 | SPACE | |
100 | RALT | |
101 | RGUI | |
102 | &mo 3 | |
103 | RCTRL | |
104 | LEFT | |
105 | DOWN | |
106 | RIGHT | |
107 | KP_N0 | |
108 | KP_DOT | |
109 | KP_ENTER | |
110 | &none | |
111 | &out OUT_BLE | |
112 | &out OUT_24G | |
113 | &out OUT_CHG | |
114 | &out OUT_CHGD |
References
- ZMK keycodes. For example, RWIN for right Windows key and K_APP for the context menu (the corresponding keycode in QMK is KC_APP; they are probably both aliases)
- ZMK ‘behaviors’. Includes an explanation for, for example, “&kp” (key press), “&none”, “&trans” (transparent), “&mo” (momentary layer; e.g., the Fn key), “&out” (output selection), “&to” (to layer), “&tog” (toggle layer), “&sl” (sticky layer), “<” (layer tap), “&sk” (sticky key), “&mt” (modifier tap), and “&gresc” (grave escape). But not “&uc”…
- ZMK cheat sheet. But it doesn’t have an explanation for “&uc” either… Is it Keychron-specific? An alias of “user_custom” (whatever that is)?
- Keychron B6 Pro keymap (ISO)
- Comparison of pipx to other tools