Skip to content

susumuota/zmk-config-KimiBoard

 
 

Repository files navigation

ZMK Config for KimiBoard

KimiBoard switches

This repository is a ZMK firmware configuration for sirocom's KimiBoard, a 4-key Bluetooth/USB keyboard with a PMW3610 trackball built on the Seeed XIAO BLE (nRF52840). It supports up to 3 Bluetooth pairings, mouse gestures (scrolling, forward/back, and window management) via the trackball, and includes an RGB LED status widget.

The KimiBoard is available for purchase at sirocom's BOOTH shop.

Credits

This ZMK config is a fork of sirocominfo/zmk-config-KimiBoard by sirocom. Many thanks to the original author for the hardware design, base configuration, and the header photo.

Default Keymap

Default keymap: Key 0 tap = Switch BT, Key 1 tap = Left click, Key 2 hold = Scroll layer (no tap), Key 3 tap = Right click / hold = Desktop or Window layer, trackball moves the pointer; Key 0 + Key 3 clears Bluetooth pairing; Key 2 + Key 3 switches Key 3 hold between the Desktop and Window gestures

Keys 0, 1, and 3 have a tap action. Key 3 is a hold-tap (200 ms): a quick tap sends a mouse click, while holding activates a momentary gesture layer. Key 2 has no tap — pressing it immediately enters the Scroll layer and releasing it exits. In the diagram above, white pills are tap actions and blue pills are hold actions. On the default layer, the trackball moves the pointer.

Key Tap Hold
0 Switch Bluetooth connection (cycle through BT1 → BT2 → BT3 → BT1...) -
1 Left click -
2 - Scroll gesture layer (press to enter, release to exit)
3 Right click Desktop gesture layer, or Window gesture layer after the Key 2 + Key 3 switch

Pressing two keys together triggers a combo:

Combo Action
0 + 3 Clear the current Bluetooth pairing
2 + 3 Switch Key 3 hold between the Desktop and Window gestures (press again to switch back)

Scroll gestures (hold Key 2)

Hold Key 2 and move the trackball: up = scroll down, down = scroll up, left flick = Forward (⌘]), right flick = Back (⌘[)

This layer emulates the macOS two-finger trackpad gestures with the trackball. Hold Key 2 to enter the scroll layer. While held, the cursor stays still: move the trackball up or down to scroll the page, or flick left or right to navigate forward or back. The forward/back shortcuts target Chrome on macOS:

Trackball Action Shortcut
Scroll down -
Scroll up -
← flick Forward ⌘]
→ flick Back ⌘[

The up/down mapping may look reversed, but it follows macOS-style natural scrolling: pushing the trackball up is like swiping two fingers up on a trackpad (the page content follows your finger), so the view scrolls down.

Desktop gestures (hold Key 3)

Hold Key 3 and flick the trackball: up = Mission Control (⌃↑), down = App Exposé (⌃↓), left = Move one Space right (⌃→), right = Move one Space left (⌃←)

This layer emulates the macOS three-finger trackpad gestures with the trackball. By default, hold Key 3 to enter it. While held, the cursor stays still: flick the trackball in any direction to trigger a macOS Spaces & Mission Control shortcut. Use the Key 2 + Key 3 combo to switch Key 3 hold to the Window gestures instead.

Trackball Action Shortcut
Mission Control ⌃↑
App Exposé ⌃↓
Move one Space right ⌃→
Move one Space left ⌃←

Window gestures (hold Key 3)

Hold Key 3 and flick the trackball: up = Previous tab (⌃⇧⇥), down = Next tab (⌃⇥), left = Left 1/3 (⌃⌥D), right = Right 2/3 (⌃⌥T)

After the Key 2 + Key 3 switch, Key 3 hold enters this layer instead of the Desktop layer (press the combo again to switch back). While held, the cursor stays still: flick left or right for a Rectangle.app window-split shortcut, or up or down to switch browser tabs.

Trackball Action Shortcut
Previous tab ⌃⇧⇥
Next tab ⌃⇥
Left 1/3 ⌃⌥D
Right 2/3 ⌃⌥T

Customization

KimiBoard's behavior is defined in the shield files under config/boards/shields/kimi/. After editing any of them, rebuild and reflash the firmware (see Building and Flashing the Firmware) for the changes to take effect.

Trackball feel

Pointer speed is the trackball's CPI (counts per inch), set by the PMW3610 driver's res-cpi property in kimiboard.overlay:

res-cpi = <400>;

Raise the value for a faster pointer, lower it for finer control. Valid values range from 200 to 3200 in increments of 200 (other values are rounded down).

Scroll speed and direction are controlled by the SCROLL layer's input processors in kimiboard.keymap:

input-processors = <&zip_scroll_gesture &zip_x_scaler 0 1 &zip_xy_to_scroll_mapper &zip_scroll_scaler (-1) 48>;

The scaler takes a multiplier and a divisor, scaling each scroll value as value × multiplier ÷ divisor. So &zip_scroll_scaler (-1) 48 scales the scroll speed to -1/48:

  • The negative sign inverts the direction to match macOS natural scrolling; use 1 instead of -1 to reverse.
  • The divisor 48 sets the speed. A larger number scrolls slower, and a smaller number scrolls faster.

Here zip_x_scaler and zip_scroll_scaler are ZMK scaler processors and zip_xy_to_scroll_mapper is a code mapper, while zip_scroll_gesture comes from the zmk-mouse-gesture module.

Gesture sensitivity is the stroke-size property on each gesture node (zip_scroll_gesture, zip_desktop_gesture, and zip_window_gesture) in kimiboard.keymap:

stroke-size = <100>;  // default: 200

It sets how far the trackball must travel (in raw counts) to register one directional stroke of a gesture. Lower it so flicks trigger with a shorter, lighter movement; raise it to require a longer, more deliberate flick and avoid accidental gestures. Note stroke-size is measured in raw counts, not physical distance, so changing res-cpi also changes how far you physically move for a given stroke-size.

Gesture cooldown is the gesture-cooldown-ms property on the same gesture nodes in kimiboard.keymap:

gesture-cooldown-ms = <200>;  // default: 500

After a gesture fires, processing pauses for this many milliseconds before the next gesture can be recognized, which prevents an accidental double trigger from one continuous flick. Lower it to fire repeated gestures (such as moving across several Spaces) more quickly; raise it if a single flick sometimes registers twice.

Keys and layers

Tap actions are the default_layer bindings in kimiboard.keymap, listed left to right as Keys 0 to 3:

&bt BT_NXT  &mkp LCLK  &mo SCROLL  &mo_mkp DESKTOP RCLK

Keys 0 and 1 are plain taps: Key 0 cycles the Bluetooth connection (&bt) and Key 1 sends a mouse click (&mkp). Key 2 has no tap: it is a plain momentary layer (&mo SCROLL), so pressing it enters the Scroll layer immediately with no hold delay. Key 3 uses the mo_mkp hold-tap, where the first parameter is the hold layer and the second is the tap mouse click. For example, swap LCLK for RCLK to make Key 1 a right click, or change DESKTOP to set which layer Key 3 holds into.

Hold vs. tap timing for Key 3 is set by the mo_mkp hold-tap behavior in the same file:

flavor = "tap-preferred";
tapping-term-ms = <200>;

Lower tapping-term-ms to trigger the gesture layer (hold) sooner; raise it to leave more time for a clean click (tap). This affects only Key 3 — Key 2 is a plain &mo with no tapping term, so its Scroll layer activates instantly.

Combo timing is the timeout-ms of each combo in kimiboard.keymap:

timeout-ms = <50>;  // default: 50

Both keys of a combo must be pressed within this many milliseconds to register together. Lower it to make accidental combos less likely (the two keys must be hit closer to simultaneously); raise it if a combo is hard to trigger reliably.

Key 3's hold layer defaults to Desktop. The Key 2 + Key 3 combo switches it to Window. See Default Keymap for details.

Building and Flashing the Firmware

For reproducible builds, this config pins its upstream dependencies (zmk, zmk-rgbled-widget, and zmk-mouse-gesture) to fixed commit SHAs in config/west.yml. See Updating Pinned Versions to bump them.

GitHub Actions (CI)

GitHub Actions builds the firmware automatically on every push and pull request, producing two .uf2 images you can download from the Actions run page. See the ZMK user setup guide for the standard GitHub Actions download flow:

  • kimiboard: main firmware with ZMK Studio support
  • settings_reset: utility firmware to reset stored settings

Local Build (macOS + colima + Dev Container)

Based on the ZMK Container Setup and Build & Flash documentation.

Install the prerequisites

Install the tools this guide relies on with Homebrew: colima (the Docker runtime), docker (the CLI), and devcontainer (the Dev Container CLI).

brew install colima docker devcontainer

Prepare the sources

First, create a workspace directory, cd into it, and clone this repository. All commands below are run from the workspace directory, which holds zmk-config-KimiBoard, zmk, and zmk-modules as siblings.

mkdir -p kimiboard-workspace
cd kimiboard-workspace

git clone https://github.com/susumuota/zmk-config-KimiBoard.git

Next, read this config's pinned SHAs into shell variables so the rest of the setup checks out exactly those commits. The awk commands below pull each SHA from the revision value of the matching project in config/west.yml, where this config keeps them.

ZMK_REV=$(awk '/name: zmk$/{f=1} f&&/revision:/{print $2; exit}' zmk-config-KimiBoard/config/west.yml)
RGBLED_REV=$(awk '/name: zmk-rgbled-widget/{f=1} f&&/revision:/{print $2; exit}' zmk-config-KimiBoard/config/west.yml)
MOUSEGESTURE_REV=$(awk '/name: zmk-mouse-gesture/{f=1} f&&/revision:/{print $2; exit}' zmk-config-KimiBoard/config/west.yml)

echo "ZMK_REV: $ZMK_REV"
echo "RGBLED_REV: $RGBLED_REV"
echo "MOUSEGESTURE_REV: $MOUSEGESTURE_REV"

Then, clone the ZMK firmware source and extra modules, checking out the same pinned commits so local builds match CI:

git clone https://github.com/zmkfirmware/zmk.git
(cd zmk && git checkout "$ZMK_REV")

git clone https://github.com/caksoylar/zmk-rgbled-widget.git zmk-modules/zmk-rgbled-widget
(cd zmk-modules/zmk-rgbled-widget && git checkout "$RGBLED_REV")

git clone https://github.com/kot149/zmk-mouse-gesture.git zmk-modules/zmk-mouse-gesture
(cd zmk-modules/zmk-mouse-gesture && git checkout "$MOUSEGESTURE_REV")

Start the build container

Start colima and create Docker volumes to mount the config and modules into the container. The colima start flags allocate 2 CPUs (-c 2), 4 GB RAM (-m 4), and a 100 GB disk (-d 100), and use the macOS vz virtualization backend (-t vz).

colima start -c 2 -m 4 -d 100 -t vz

docker volume create --driver local -o o=bind -o type=none \
  -o device="$(pwd)/zmk-config-KimiBoard" zmk-config

docker volume create --driver local -o o=bind -o type=none \
  -o device="$(pwd)/zmk-modules" zmk-modules

docker volume ls

Start the Dev Container:

devcontainer up --workspace-folder "$(pwd)/zmk"
docker ps -a

Initialize the Zephyr workspace

Run this once from the host, after creating the container workspace:

devcontainer exec --workspace-folder "$(pwd)/zmk" bash -lc 'west init -l app/'
devcontainer exec --workspace-folder "$(pwd)/zmk" bash -lc 'west update'

west update clones the Zephyr tree and all module dependencies, so it can take several minutes (sometimes longer on a slow connection). This is expected — let it run to completion.

Build the firmware

Run the local build script from the host with devcontainer exec. scripts/build-local.py locally emulates ZMK's reusable user config build workflow. It reads build.yaml, runs each build inside the container, and writes the resulting .uf2 files to firmware/ using the same artifact names as GitHub Actions. For fallback artifact names, spaces are replaced with underscores.

devcontainer exec --workspace-folder "$(pwd)/zmk" bash -lc \
  'cd /workspaces/zmk-config && python3 scripts/build-local.py'

To inspect the generated west build commands without building, add --dry-run.

Each target builds incrementally in its own directory under /tmp/zmk-build/ inside the container, so rebuilding after a keymap or config edit only recompiles what changed. This build directory lives on the container's filesystem rather than the virtiofs-mounted source tree, which keeps the build from being bottlenecked by host I/O. To put the build elsewhere, pass --build-root <path>.

Because builds are incremental, a few changes need a clean (pristine) rebuild to be picked up reliably: switching board or shield, bumping the pinned dependencies (west update), adding or removing source/overlay files, or recovering from an interrupted build. Editing the contents of .keymap, .conf, or .overlay files does not require this. To force a clean build, delete the build directory first:

devcontainer exec --workspace-folder "$(pwd)/zmk" bash -lc 'rm -rf /tmp/zmk-build'

Flash the firmware

Put the board into bootloader mode (double-tap reset), then copy the firmware to the board. The -X flag is macOS only and prevents extended attribute errors with UF2 mass storage.

Flash the settings reset firmware first:

cp -X zmk-config-KimiBoard/firmware/settings_reset-xiao_ble__zmk-zmk.uf2 /Volumes/XIAO-SENSE/

Put the board into bootloader mode again, then flash the main firmware:

cp -X zmk-config-KimiBoard/firmware/kimiboard_rgbled_adapter-xiao_ble__zmk-zmk.uf2 /Volumes/XIAO-SENSE/

Stop the build container

Stop and remove the Dev Container:

docker ps -a
docker stop <container_id>
docker rm <container_id>
docker ps -a

Remove Docker volumes created by the setup and the Dev Container:

docker volume ls
docker volume rm zmk-config zmk-modules \
  zmk-root-user zmk-zephyr zmk-zephyr-modules zmk-zephyr-tools
docker volume ls

Stop colima:

colima status
colima stop
colima status

To also delete the colima VM:

colima list
colima delete
colima list

Updating Pinned Versions

To move the pinned dependencies to newer upstream commits:

  1. Find the SHAs you want. For the latest commit on each project's tracked branch (main for zmk and zmk-rgbled-widget, v1 for zmk-mouse-gesture):
git ls-remote https://github.com/zmkfirmware/zmk.git refs/heads/main
git ls-remote https://github.com/caksoylar/zmk-rgbled-widget.git refs/heads/main
git ls-remote https://github.com/kot149/zmk-mouse-gesture.git refs/heads/v1
  1. Update the three revision values in config/west.yml.
  2. Update the workflow ref in .github/workflows/build.yml to the same SHA as the zmk revision (these must stay in sync).
  3. Commit the changes.

About

A ZMK firmware configuration for sirocom's KimiBoard, a 4-key Bluetooth/USB keyboard with a PMW3610 trackball built on the Seeed XIAO BLE (nRF52840).

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages

  • Python 100.0%