A split keyboard layout optimized for Portuguese, English, working with numbers and software programming with VIM plugins.
The image above shows just the most relevant layers. You can see the full diagram here.
The rationale behind the decisions that led to this keymap can be found in this page, but here is a summary:
What are the directives that drive most of my decisions?
- Ergonomics: Split and Columnar Stagger.
- Finger Effort: No lateral movements or uncomfortable stretches.
- Ease of Use: If it is frequent, it should be easy.
- Handness: Trackball in the left hand, heavy load in the right hand.
- Workflows: English, but also Portuguese, plus VIM and Spreadsheets.
What are the workflows that I need to execute with my keyboards?
- Typing: The most basic and essential workflow.
- Numbers: How this keymap makes it easy to work with numbers.
- Shortcut: How to work with so many shortcuts in such minimal keyboards.
- Navigation: Navigating in text, presentations, window management and mouse emulation.
- Programming: Optimizations to make programming easier.
| Diamond | Wired Diamond | Choc Diamond |
![]() |
![]() |
![]() |
| Rommana Remix | Wired Rommana | Corne-ish Zen |
![]() |
![]() |
![]() |
| Dilemma | BM40 (QMK) | XD75 (QMK) |
![]() |
![]() |
![]() |
This keymap is implemented using ZMK, with the following external modules:
- Auto Layer
- Adaptive Key
- Leader Key
- Layer Morph
- Layer HUD
- OS Detection
- Sentence Case
- Vim Mode
- Dongle Display (OLED status and peripheral relay)
A limited port of this keymap is available in the qmk folder, for the BM40 and XD75 keyboards.
Unlike most ZMK users, I don't use GitHub Actions to build the firmware for my keyboards, and since I come from a legacy repo structure, from the time I used QMK and when they didn't even support external userspaces, I use git submodules to import ZMK and everything else I need into my repo, then I build the firmware using a custom script.
To make the local build setup easier, I have a Containerfile that installs all the toolchain into a Ubuntu container, the ZMK one and the QMK one. The init script is then used to run this container. It builds the image only when there is none, so after a change to the Containerfile rebuild it with podman build -t zmk-toolchain:0.17.0 ..
Into the container, I can use my custom zmk script to build the ZMK firmware for all my keyboards.
Here are some usage examples:
# Builds the central left side shield of the Rommana, assuming nice_nano//zmk as board
zmk mabroum/rommana cl
# Builds the left side shield of the Wired Diamond, specifying the board to be used instead of the default
zmk rafaelromao/wired_diamond l -b xiao_rp2040//zmk
# Builds the central dongle shield of the Choc Diamond, specifying an extra shield and an external module to handle the display
zmk rafaelromao/choc_diamond cd -e dongle_display -m rafaelromao/zmk-dongle-displayTo make it even simpler, I have a b script that can be used to build the central sides using default configurations, and the two QMK boards.
Example:
b wd # builds the left side of the wired diamond keyboard, equivalent to the command below
zmk rafaelromao/wired_diamond l -b xiao_rp2040//zmkThe normal b dilemma build keeps the left half as central. To move the central
role to a USB-powered nice!nano dongle without a battery or OLED, build all
three devices with:
b dilemma-dongleThis builds dilemma_central_dongle, dilemma_peripheral_left (OLED), and
dilemma_peripheral_right (Cirque). The right's input is still forwarded to the
central, where the existing pointer transforms and scaling run. b dilemma -c
also includes these optional artifacts. Flash all three matching roles; the
normal central-left firmware cannot be used as a dongle peripheral.
All OLED builds now use the rafaelromao/zmk-dongle-display fork. The original
widget screen and layout remain the default on both 128x32 and 128x64, including
on a peripheral OLED. The dongle relays host connectivity, all half batteries,
layer/name, modifiers, lock indicators and WPM; Bongo Cat animates on the OLED
half from that WPM. All original widget configuration options remain available.
Dilemma's peripheral-left shows the layer name with Bongo Cat and modifiers
disabled; these widgets can still be enabled individually, even on 128x32.
The compact text screen is opt-in only via
CONFIG_ZMK_DONGLE_DISPLAY_STATUS_SCREEN=y.
The Dilemma dongle uses dongle_display_relay, not dongle_display: no display
or local battery sampling is enabled on it. The Zen's separate optional dongle
setup and board-specific e-paper screens are unchanged.
The module comparison records the reviewed
alternatives and why the fork was extended.
Pairing: when changing central roles, reset settings on the dongle and both
halves, then pair the left/OLED first (power the right off until the left
has connected). Battery rows follow pairing order, not physical sides. If the OLED
is already source 1 instead, set
CONFIG_ZMK_DONGLE_DISPLAY_STATUS_RECEIVERS=0x2 in
dilemma_central_dongle.conf. Resetting settings clears host bonds too, so
remove old host pairings and re-pair them. To switch back, flash central-left
plus peripheral-right, reset their settings, and pair again.
b reset builds the nice!nano settings-reset image; flash that before the
matching role firmware when clearing device settings.
init.sh automatically mounts ~/projects/zmk-dongle-display read-only and
uses that local working tree when present, so unpublished module changes are
included. For another container setup, mount it manually and select it with:
# Mount ~/projects/zmk-dongle-display as /display-module in the build container.
ZMK_DONGLE_DISPLAY_MODULE=/display-module bash scripts/b.sh dilemma-donglescripts/zmk.sh -m accepts absolute local module paths without fetching or
checking them out. For an initialized toolchain/module cache, run
ZMK_DONGLE_DISPLAY_MODULE=/display-module bash scripts/validate-displays.sh
inside the container to build all seven affected OLED/receiver targets and
verify generated Dilemma roles. This does not flash devices or measure battery
life; OLED blanking and both peripheral sleep settings remain enabled.
After flashing, verify that both halves report batteries, powering the right
off changes P2 to disconnected, the Cirque still moves/scrolls correctly,
and host output/profile changes appear on the left OLED. Also check that the
OLED blanks after a minute idle and wakes on a left key. Battery-life gains
and physical OLED/BLE operation still need testing on the actual hardware.
The diagrams for my keymap were created using Keymap Drawer.
draw renders every diagram from the container (draw alias); underneath it runs commands like these to draw the svg files and convert them to png:
keymap -c keymap-drawer-config.yaml draw keymap-drawer.yaml > overview.svg
inkscape --export-type png --export-filename overview.png --export-dpi 300 --export-background=white overview.svgMost features implemented here were based on the work referenced below.










