A module and CLI tool to help parse and draw keyboard layouts.
Project description
Parse QMK & ZMK keymaps and draw them in vector graphics (SVG) format, with support for visualizing hold-taps and combos that are commonly used with smaller keyboards.
Available as a command-line tool or a web application.
Features
- Draw keymap representations consisting of multiple layers, hold-tap keys and combos
- Uses a human-editable YAML format for specifying the keymap
- Non-adjacent or 3+ key combos can be visualized by specifying its positioning relative to the keys, with automatically drawn dendrons to keys
- Alternatively, output a separate diagram per combo if you have tricky key position combinations
- Bootstrap the YAML representation by automatically parsing QMK or ZMK keymap files
- Arbitrary physical keyboard layouts (with rotated keys!) supported, along with parametrized ortho layouts
- Both parsing and drawing are customizable with a config file, see "Customization" section
- Custom glyph support: render custom SVG icons and not just unicode text
See examples in the live web demo for example inputs and outputs.
Compared to to visual editors like KLE, keymap-drawer
takes a more programmatic approach.
It also decouples the physical keyboard layout from the keymap (i.e., layer and combo definitions) and provides the tooling to bootstrap it quickly from existing firmware configuration.
Usage
Try it as a web application
You can try the keymap parsing and drawing functionalities with a Streamlit web application available at https://caksoylar.github.io/keymap-drawer. Below instructions mostly apply for the web interface, where subcommands and option flags are mapped to different widgets in the UX.
Command-line tool installation
The recommended way to install keymap-drawer
is through pipx, which sets up an isolated environment and installs the application with a single command:
pipx install keymap-drawer
This will make the keymap
command available in your PATH
to use:
keymap --help
Alternatively, you can pip install keymap-drawer
in a virtual environment or install into your user install directory with pip install --user keymap-drawer
.
See the development section for instructions to install from source.
ℹ️ Windows command-line issues
If you are running on Windows, using the
-o
/--output
parameter to save command outputs to files is recommended instead of redirecting stdout. Otherwise you might run into text encoding issues related to unicode characters in YAMLs and SVGs.
Bootstrapping your keymap representation
keymap parse
command helps to parse an existing QMK or ZMK keymap file into the keymap YAML representation the draw
command uses to generate SVGs.
-c
/--columns
is an optional parameter that specifies the total number of columns in the keymap to better reorganize output layers.
-
QMK: Only json-format keymaps are supported, which can be exported from QMK Configurator, converted from
keymap.c
viaqmk c2json
, or from a VIA backup json viaqmk via2json
:# from keymap.c qmk c2json ~/qmk_firmware/keyboards/ferris/keymaps/username/keymap.c | keymap parse -c 10 -q - >sweep_keymap.yaml # from VIA backup qmk via2json -kb ferris/sweep sweep_via_backup.json | keymap parse -c 10 -q - >sweep_keymap.yaml
Due to current limitations of the
keymap.json
format, combos and#define
'd layer names will not be present in the parsing output. However you can manually specify layer names using the layer names parameter, e.g.keymap parse --layer-names Base Sym Nav ...
. -
ZMK:
.keymap
files are used for parsing. These will be preprocessed similar to the ZMK build system, so#define
's and#include
s will be expanded.keymap parse -c 10 -z ~/zmk-config/config/cradio.keymap >sweep_keymap.yaml
Currently combos, hold-taps, mod-morphs, sticky keys and layer names can be determined via parsing. For layer names, the value of the
display-name
property will take precedence over the layer's node name if provided.
As an alternative to parsing, you can also check out the examples to find a layout similar to yours to use as a starting point.
Tweaking the produced keymap representation
While the parsing step aims to create a decent starting point, you will likely want to make certain tweaks to the produced keymap representation. Please refer to the keymap schema specification while making changes:
- (If starting from a QMK keymap) Add combo definitions using key position indices.
- Tweak the display form of parsed keys, e.g., replacing
&bootloader
withBOOT
. (See the customization section to modify parser's behavior.) - If you have combos between non-adjacent keys or 3+ key positions, add
align
and/oroffset
properties in order to position them better - Add or modify
type
specifiers for certain keys, like"ghost"
for keys optional to the layout
It might be beneficial to start by draw
'ing the current representation and iterate over these changes, especially for tweaking combo positioning.
ℹ️ Preserving manual modifications
If you need to re-parse a firmware file after it was changed, you can provide the previous parse output that you tweaked to the parse command via
keymap parse -b old_keymap.yaml ... >new_keymap.yaml
and the tool will try to preserve your manual tweaks.
Producing the SVG
Final step is to produce the SVG representation using the keymap draw
command.
However to do that, we need to specify the physical layout of the keyboard, i.e., how many keys there are, where each key is positioned etc.
If you produced your keymap YAML through keymap parse
, it will have tried to guess the proper layout in the layout
field of your keymap.
If you like you can tweak the field value according to the spec, then finally call the draw command:
keymap draw sweep_keymap.yaml >sweep_keymap.ortho.svg
And you are done! You can view the output SVG on your browser or use a tool like CairoSVG or Inkscape to convert to a different format.
ℹ️ Specifying layouts in the CLI
If you like you can override the layout specification on the command line. For instance you can provide a QMK keyboard name with
-k
/--qmk-keyboard
and layout with-l
/--layout-name
, or an ortho layout with--ortho-layout
(using YAML syntax for the value) or-n
/--cols-thumbs-notation
. Seekeymap draw --help
for details.
Customization
Both parsing and drawing can be customized using a configuration file passed to the keymap
executable.
This allows you to, for instance, change the default keycode-to-symbol mappings while parsing, or change font sizes, colors etc. while drawing the SVG.
Start by dumping the default configuration settings to a file:
keymap dump-config >my_config.yaml
Then, edit the file to change the settings, referring to CONFIGURATION.md. You can delete from the file the settings you don't want to change.
You can then pass this file to either draw
and parse
subcommands with the -c
/--config
argument (note the location before the subcommand):
keymap -c my_config.yaml parse [...] >my_keymap.yaml
keymap -c my_config.yaml draw [...] my_keymap.yaml >my_keymap.svg
Since configuration classes are Pydantic settings they can also be overridden by environment variables with a KEYMAP_
prefix:
KEYMAP_raw_binding_map='{"&bootloader": "BOOT"}' keymap parse -z zmk-config/config/cradio.keymap >cradio.yaml
Drawing parameters that are specified in the draw_config
field can also be overridden in the keymap YAML.
Using this you can preserve your style customizations along with your keymap in a single file.
Custom SVG Glyphs
keymap-drawer
can also use SVG glyphs for legends, in addition to plain or unicode text. The easiest way to do this is
to use the $$source:id$$
notation certain source
s, which will automatically fetch
the SVGs from a given remote source
, e.g. using $$mdi:volume-mute$$
will insert the
mute icon from Material Design Icons.
The following source
values are currently supported:
mdi
: Pictogrammers Material Design Icons (use icon name asid
)mdil
: Pictogrammers Material Design Icons Light (use icon name asid
)material
: Google Material Symbols (use value in "Android" tab asid
)tabler
: Tabler Icons ("Outline" style, use icon name asid
)phosphor
: Phosphor Icons (use<weight>/<name>
asid
, e.g.$$phosphor:bold/lock$$
)
Fetched SVGs will be cached by default to speed up future runs.
The height of the SVG is bound by the config properties glyph_{tap,hold,shifted}_size
and width will maintain the aspect ratio.
To allow for customization, glyphs are assigned CSS classes glyph
and <glyph_name>
.
SVG glyphs currently cannot be used alongside other text in the same legend field.
Instead of automatically fetching them from remote sources, you can also define custom SVG blocks under draw_config
.
After a glyph is defined this way it can be used in key fields via the glyph name surrounded by $$
, e.g. $$vol_up$$
.
The provided SVG must specify a viewBox
, given that positional or dimensional properties will be calculated by keymap-drawer
:
draw_config:
# specify the size to bound the vertical dimension of your glyph, below are defaults
glyph_tap_size: 14
glyph_hold_size: 12
glyph_shifted_size: 10
glyphs: # mapping of glyph name to be used to svg definition
vol_up: |
<svg viewBox="2 3 34 33">
<path style="stroke: black; fill: black;" d="M23.41,25.25a1,1,0,0,1-.54-1.85,6.21,6.21,0,0,0-.19-10.65,1,1,0,1,1,1-1.73,8.21,8.21,0,0,1,.24,14.06A1,1,0,0,1,23.41,25.25Z"/>
<path style="stroke: black; fill: black;" d="M25.62,31.18a1,1,0,0,1-.45-1.89A12.44,12.44,0,0,0,25,6.89a1,1,0,1,1,.87-1.8,14.44,14.44,0,0,1,.24,26A1,1,0,0,1,25.62,31.18Z"/>
<path style="stroke: black; fill: black;" d="M18.33,4,9.07,12h-6a1,1,0,0,0-1,1v9.92a1,1,0,0,0,1,1H8.88l9.46,8.24A1,1,0,0,0,20,31.43V4.72A1,1,0,0,0,18.33,4Z"/>
</svg>
layers:
Media:
- ["", "$$vol_up$$", "", "", ""]
Setting up an automated drawing workflow
If you use a ZMK config repo, you can set up an automated workflow that parses and draws your keymaps, then commits the YAML parse outputs and produced SVGs to your repo.
To do that you can add a new workflow to your repo at .github/workflows/draw-keymaps.yml
that refers to the reusable keymap-drawer
workflow:
# Example for using the keymap-drawer ZMK user config workflow
name: Draw ZMK keymaps
on:
workflow_dispatch: # can be triggered manually
push: # automatically run on changes to following paths
paths:
- "config/*.keymap"
- "config/*.dtsi"
- "keymap_drawer.config.yaml"
# - 'boards/*/*/*.keymap'
jobs:
draw:
uses: caksoylar/keymap-drawer/.github/workflows/draw-zmk.yml@main
permissions:
contents: write # allow workflow to commit to the repo
with:
keymap_patterns: "config/*.keymap" # path to the keymaps to parse
config_path: "keymap_drawer.config.yaml" # config file, ignored if not exists
output_folder: "keymap-drawer" # path to save produced SVG and keymap YAML files
parse_args: "" # map of extra args to pass to `keymap parse`, e.g. "corne:'-l Def Lwr Rse' cradio:''"
draw_args: "" # map of extra args to pass to `keymap draw`, e.g. "corne:'-k corne_rotated' cradio:'-k paroxysm'"
Modifying the workflow-generated commit
The workflow will add the generated SVG and keymap representation YAML files to the output_folder
, and generate a new commit with commit message "keymap-drawer render" by default. You can modify this commit message with the commit_message
input param, e.g.:
jobs:
draw:
uses: caksoylar/keymap-drawer/.github/workflows/draw-zmk.yml@main
with:
# Use the triggering commit's message, prepending the "[Draw]" tag
commit_message: "[Draw] ${{ github.event.head_commit.message }}"
# …other inputs
Alternatively, you can choose to amend the triggering commit instead of generating a new one by using the amend_commit: true
option. In this case the triggering commit's message will be used by default, and the commit_message
input will be ignored. E.g.:
jobs:
draw:
uses: caksoylar/keymap-drawer/.github/workflows/draw-zmk.yml@main
with:
amend_commit: true
# …other inputs
⚠️ Rewriting history
You should understand the implications of rewriting history if you amend a commit that has already been published. See remarks in
git-rebase
documentation.
Community
Below are a few tools and example usages from the community that might be inspirational, whether they are doing unique things with styling, configuration or legends used, or integrate keymap-drawer
into other workflows.
Tools
- YellowAfterlife's Vial To Keymap Drawer: Parser to convert Vial .vil files to keymap YAMLs
- jbarr21's
keymap-display
: Uses a converter script to convert QMKkeymap.c
to a keymap YAML - hnaderi's fork: Contains an example Dockerfile and publishes unofficial Docker images
Examples
- minusfive's ZMK config: Uses an extensive config file for great results out of the automated drawing workflow, with plenty of SVG glyphs
- SethMilliken's ZMK config: Another config using the automated workflow with a nice configuration and SVG glyphs
- englmaxi's ZMK config: Using key sides setting and CSS tricks to position multiple SVG glyphs in one key
- casuanoob's keymap: Many useful unicode and SVG glyphs in the keymap YAML
- rafaelromao's keymap: Advanced keymap with many glyphs and a Inkscape-based PNG conversion command
- possumvibes's keymap: Separate layer and combo diagrams
- infused-kim's ZMK config: Defines a script to tweak the keymap between parsing and drawing
- crides's Fissure write-up: Custom physical layout with non-square keys and unique SVG styling
If you use keymap-drawer
, tag your Github repo with the keymap-drawer
topic and it will show up for anyone else searching for it!
Development
This project requires Python 3.10+ and uses Poetry for packaging.
To get started, install Poetry, clone this repo, then install dependencies with the poetry
command:
git clone https://github.com/caksoylar/keymap-drawer.git
cd keymap-drawer
poetry install # --with dev,lsp optional dependencies
poetry shell
will activate a virtual environment with the keymap_drawer
module in Python path and keymap
executable available.
Changes you make in the source code will be reflected when using the module or the command.
If you prefer not to use Poetry, you can get an editable install with pip install --editable .
inside the keymap-drawer
folder.
The source code for the Streamlit app lives in the keymap-drawer-web
repo.
Questions? Feedback?
If you have any questions on usage or feedback for new or existing features, please check out the Discussions tab and feel free to create a new one!
Related projects
- @nickcoutsos's ZMK keymap editor
- The original
keymap
- @jbarr21's keymap parser
- @leiserfg's ZMK parser
- Keymapviz
Keymap YAML specification
This page documents the YAML-format keymap representation that is output by keymap parse
and used by keymap draw
.
At the root, four fields can be specified which are detailed in respective sections. A typical keymap will have the following structure:
layout: # physical layout specs, optional if used in CLI
...
layers: # ordered mapping of layer name to contents
layer_1: # list of (lists of) key specs
- [Q, W, ...]
...
layer_2:
...
combos: # list of combo specs, optional
- ...
draw_config: # config overrides for drawing, optional
- ...
layout
This field provides information about the physical layout of the keyboard, i.e., the location and sizes of individual keys.
keymap-drawer
understands three types of physical layout descriptions, with corresponding sub-fields under the layout
field.
QMK info.json
specification
This is the official QMK format for physical key descriptions
that every info.json
file in the QMK firmware repository uses. keymap-drawer
only uses the x
, y
, r
, rx
and ry
fields.
Note that keymap-editor
utilizes the same format for info.json
.
QMK spec also lets you specify multiple "layouts" per keyboard corresponding to different layout macros to support physical variations.
Following physical layout parameters can be specified either in the command line or under this field definition as key-value pairs:
-
qmk_keyboard
(equivalent to-k
/--qmk-keyboard
on the command line): Specifies the keyboard name to use with QMKinfo.json
format layout definition, retrieved from following sources in order of preference:<keyboard>.json
(with/
's in<keyboard>
replaced by@
) underresources/qmk_layouts
, if it exists- QMK keyboard metadata API that QMK Configurator also uses
Example:
layout: {qmk_keyboard: crkbd/rev1}
-
qmk_info_json
(equivalent to-j
/--qmk-info-json
on the command line): Specifies the path to a local QMK formatinfo.json
file to use (exclusive withqmk_keyboard
).Example:
layout: {qmk_info_json: my_special_layout.json}
-
layout_name
(equivalent to-l
/--layout-name
on the command line): This argument is shared with the ZMKdts_layout
below and when used with either of above two options, it specifies the layout macro to be used among the ones defined in the QMK info file. Defaults to first one specified if not used, should be used alongside one of the above three options.Example:
layout: {qmk_keyboard: crkbd/rev1, layout_name: LAYOUT_split_3x5_3}
Hint: You can use the QMK Configurator to search for qmk_keyboard
and layout_name
values, and preview the physical layout.
You can create your own physical layout definitions in QMK format to use with keymap-drawer
, which accepts JSONs with the official schema that
has layouts listed under the layout
key, or one that directly consists of a list of key specs as a shortcut. The best way to generate one is to use
the interactive Keymap Layout Helper tool tool by @nickcoutsos. This web app is useful to
visualize a given JSON definition, re-order keys using the "Re-order" tool and generate one from scratch from various formats such as KLE or Kicad
PCBs using the "Import" tool.[^1]
[^1]:
The behavior of the layout helper and keymap-drawer
differs for rotated keys when omitting rx
, ry
parameters --
keymap-drawer
assumes rotation around the key center and layout helper assumes rotation around the top left of the key.
For this reason it is recommended to explicitly specify rx
, ry
fields if r
is specified. You might also want to omit the fields
besides x
, y
, r
, rx
and ry
in your final JSON since they won't be used by keymap-drawer
.
ZMK physical layout specification
This is the official ZMK format for specifying physical layouts, which are written in devicetree format and included in keyboard definitions. It lets you specify multiple "layouts" per keyboard corresponding to different devicetree nodes to support physical variations, similar to QMK format. The fields to specify each layout are described in the docs linked.
ZMK physical layouts in devicetree files can be specified via either in the command line or under this field definition as key-value pairs:
-
dts_layout
(equivalent to-d
/--dts-layout
on the command line): Specifies the path to a local devicetree file containing ZMK physical layouts.Example:
layout: {dts_layout: my_keyboard-layouts.dtsi}
-
layout_name
(equivalent to-l
/--layout-name
on the command line): This argument is shared with the QMK options and when used withdts_layout
, specifies the node label for in the devicetree ZMK physical layouts file to be used for display. Defaults to first one specified if not used.Example:
layout: {dts_layout: path/to/kyria-layouts.dtsi, layout_name: splitkb_kyria_5col_layout}
Parametrized ortholinear layout specification
This option lets you specify a set of parameters to automatically generate a split or non-split ortholinear layout.
Following physical layout parameter can be specified either in the command line or under this field definition as a key-value pair:
-
ortho_layout
(equivalent to--ortho-layout
on the command line): Specifies a mapping of parameters to values to generate an ortholinear physical layout, with schema:field name type default value description split
bool
False
whether the layout is a split keyboard or not, affects a few other options below rows
int
required how many rows are in the keyboard, excluding the thumb row if split columns
int
required how many columns are in the keyboard, only applies to one half if split thumbs
int | "MIT" | "2x2u"
0
the number thumb keys per half if split; for non-splits can only take special values MIT
or2x2u
[^2]drop_pinky
bool
False
whether the pinky (outermost) columns have one fewer key, N/A for non-splits drop_inner
bool
False
whether the inner index (innermost) columns have one fewer key, N/A for non-splits Example:
layout: {ortho_layout: {split: true, rows: 3, columns: 5, thumbs: 3}}
[^2]: Corresponding to bottom row arrangements of a single 2u
key, or two neighboring 2u
keys, respectively.
Cols+Thumbs notation specification
Using the "cols+thumbs" notation is another way to generate a layout parametrically, but via a special syntax string that describes the
key counts in each column and thumb cluster of the keyboard. This is more flexible than the ortho_layout
option
if special MIT/2x2u thumbs aren't needed.
Following physical layout parameter can be specified either in the command line or under this field definition as a key-value pair:
-
cols_thumbs_notation
(equivalent to-n
/--cols-thumbs-notation
on the command line): Specifies a specially formatted string to describe an ortholinear keyboard layout. This string is composed of a number of digits corresponding to each column in the keyboard, optionally augmented by a count of thumb keys. This can be repeated to specify split keyboards with two or more halves, separated by a space or underscore.Example:
layout: {cols_thumbs_notation: 33333+1 2+33332}
Above example specifies an asymmetric 32 key split keyboard with 3 rows and 5 columns on the left side, and a right-aligned thumb cluster with a single key. The right half has a left-aligned thumb cluster with two keys, 5 columns with 3 rows but has a key dropped on the last column.
Normally each column will be centered vertically, but you can also add modifier characters after each column count to tweak this:
v
or d
(for ↓/"down") pushes the column down by half a key height, and ^
or u
(for ↑/"up") pushes it up by the same amount.
These modifiers can be repeated to push further.
Similarly, you can use >
or r
to push a thumb row right by half a key width, or <
or l
to push it left.
As an advanced example, notation 2v333+2> 3+13332^ 33
will result in a physical layout that looks like below:
x x x x x x x x x
x x x x x x x x x x x
x x x x x x x x x
x x x x x
ℹ️ CLI+keymap YAML specification
If the physical layout parameters are specified in both command line and under the
layout
section, the former will take precedence.
layers
This field is an ordered mapping of layer names to a list of LayoutKey
specs that represent the keys on that layer.
A LayoutKey
can be defined with either a string value or with a mapping with the following fields:
field name (alias) | type | default value | description |
---|---|---|---|
tap (t) |
str |
"" |
the tap action of a key, drawn on the center of the key; spaces will be converted to line breaks[^3] |
hold (h) |
str |
"" |
the hold action of a key, drawn on the bottom of the key |
shifted (s) |
str |
"" |
the "shifted" action of a key, drawn on the top of the key |
type |
str |
"" |
the styling of the key that corresponds to the SVG class[^4]. predefined types are held (a red shading to denote held down keys), ghost (dashed outline to denote optional keys in a layout), trans (lighter text for transparent keys) |
[^3]: You can prevent line breaks by using double spaces " "
to denote a single non-breaking space.
[^4]: Text styling can be overridden in the svg_extra_style
field under draw_config
using the "tap"
, "hold"
and "shifted"
CSS classes if desired.
Using a string value such as "A"
for a key spec is equivalent to defining a mapping with only the tap field, i.e., {tap: "A"}
.
It is meant to be used as a shortcut for keys that do not need hold
or type
fields.
You can use the special $$..$$
syntax to refer to custom SVG glyphs in tap
/hold
/shifted
fields, however note that they cannot be used with other text or glyphs inside the same field value.
See the custom glyphs section for more information.
layers
field also flattens any lists that are contained in its value: This allows you to semantically divide keys to "rows," if you prefer to do so.
The two layers in the following example are functionally identical:
layers:
flat_layer: ["7", "8", "9", "4", "5", "6", "1", "2", "3", {t: "0", h: Fn}]
nested_layer:
- ["7", "8", "9"]
- ["4", "5", "6"]
- ["1", "2", "3"]
- {t: "0", h: Fn}
combos
This is an optional field that contains a list of ComboSpec
s, each of which is a mapping that can have the following fields:
field name (alias) | type | default value | description |
---|---|---|---|
key_positions (p) |
list[int] |
required | list of key indices that trigger the combo[^5] |
key (k) |
LayoutKey [^6] |
required | key produced by the combo when triggered, LayoutKey 's type field will be combined with the type field of ComboSpec |
layers (l) |
list[str] |
[] [^7] |
list of layers the combo can trigger on, specified using layer names in layers field |
align (a) |
"mid" | "top" | "bottom" | "left" | "right" |
"mid" |
where to draw the combo: mid draws on the mid-point of triggering keys' center coordinates, or to the top /bottom /left /right of the triggering keys |
offset (o) |
float |
0.0 |
additional offset to top /bottom /left /right positioning, specified in units of key width/height: useful for combos that would otherwise overlap |
dendron (d) |
null | bool |
null |
whether to draw dendrons going from combo to triggering key coordinates, default is to draw for non-mid alignments and draw for mid if key coordinates are far from the combo |
slide (s) |
null | float (-1 <= val <= 1) |
null |
slide the combo box along an axis between keys -- can be used for moving top /bottom combo boxes left/right, left /right boxes up/down, or mid combos between two keys |
arc_scale |
float |
1.0 |
scale the arcs going left/right for top /bottom or up/down for left /right aligned combos |
type |
str |
"" |
the styling of the key that corresponds to the CSS class, see LayoutKey definition above |
width (w) |
float |
null |
the width of the combo box (in pixels), defaults to draw_config.combo_w if null |
height (h) |
float |
null |
the height of the combo box (in pixels), defaults to draw_config.combo_h if null |
rotation (r) |
float |
0.0 |
the rotation of the combo box in degrees -- only applies to the box itself and not any dendrons |
draw_separate |
null | bool |
null |
whether to draw the combo separate from layers, using a dedicated diagram. defaults to draw_config.separate_combo_diagrams if null |
hidden |
bool |
false |
do not draw this combo at all -- useful when you have the combo in the parse output but you want to ignore it through your config |
All fields except key_positions
, key
, type
and hidden
are ignored when combo is drawn in a separate diagram using draw_separate
or draw_config.separate_combo_diagrams
.
[^5]: Key indices start from 0
on the first key position and increase by columns and then rows, corresponding to their ordering in the layers
field. This matches the key-positions
property in ZMK combo definitions.
[^6]: Just like for keys in a layer under the layers
field, key
field can be specified with a string value as a shortcut, or a mapping (where the type
field will be ignored).
[^7]: The default value of empty list corresponds to all layers in the keymap, similar to the layers
property in ZMK.
Example:
combos:
- { p: [0, 1], k: Tab, l: [Qwerty] }
- { p: [1, 2], k: Esc, l: [Qwerty] }
draw_config
This optional field lets you override config parameters for SVG drawing.
This way you can specify drawing configuration for a specific layout and store in the keymap specification.
It is a mapping from field names in DrawConfig
class to values.
Example:
draw_config:
key_h: 60
combo_h: 22
combo_w: 24
Configuration options
This page details the configuration options available for parsing and drawing, which can be provided to the CLI or can be set in the web UI in the "Configuration" box. Also see the customization section in the README for usage.
Draw Configuration
These settings are nested under the draw_config
field and applies to keymap draw
subcommand in the CLI, as well as the conversion from keymap YAML input to SVG in the web app.
In addition to the configuration file, this field can also be set in the keymap YAML which overrides the former.
key_w
, key_h
Key dimensions. Non-ortho layouts (e.g. via qmk_keyboard
) use key_h
for both width and height, whereas ortho_layout
and cols_thumbs_notation
use both.
Type: float
Default: 60
, 56
split_gap
The gap between two halves of a split keyboard, only used for physical layouts specified via ortho_layout
and cols_thumbs_notation
.
Type: float
Default: 30
combo_w
, combo_h
Dimensions of combo boxes that are drawn on layer diagrams.
Type: float
Default: 28
, 26
key_rx
, key_ry
Curvature of rounded key rectangles, used both for key and combo boxes
Type: float
Default: 6
dark_mode
Turn on dark mode which applies the CSS overrides in svg_style_dark
config.
Setting it to "auto"
enables adapting to the web page or OS light/dark theme setting.
Type: bool | "auto"
Default: false
n_columns
Number of layer columns in the output drawing. For example if this is set to 2, two layers will be shown side-by-side and layers will go right then down.
Type: int
Default: 1
separate_combo_diagrams
When set, visualize combos using separate mini-layout diagrams rather than drawing them on layers.
This sets the default behavior, which can be overridden by the draw_separate
field of the ComboSpec
.
Type: bool
Default: false
combo_diagrams_scale
For combos visualized separate from layers, this is the scale factor for the mini-layout used to show their key positions.
Type: int
Default: 2
inner_pad_w
, inner_pad_h
The amount of padding between adjacent keys, in two axes.
Type: float
Default: 2
, 2
outer_pad_w
, outer_pad_h
Padding amount between layer diagrams, in two axes.
Type: float
Default: 30
, 56
line_spacing
Spacing between multi-line text in key labels in units of em
.
Type: float
Default: 1.2
arc_radius
Radius of the curve for combo dendrons that are drawn from the combo box to the key positions.
Type: float
Default: 6
append_colon_to_layer_header
Whether to add a colon after layer name while printing the layer header.
Type: bool
Default: true
small_pad
Padding from edge of a key representation to top ("shifted") and bottom ("hold") legends.
Type: float
Default: 2
legend_rel_x
, legend_rel_y
Position of center ("tap") key legend relative to the center of the key.
Can be useful to tweak when draw_key_sides
is used.
Type: float
Default: 0
, 0
draw_key_sides
Draw "key sides" on key representations, which can be made to look like keycap profiles.
The shape is determined by key_side_pars
.
Type: bool
Default: false
key_side_pars
A mapping of certain field names to their values, characterizing key side drawing. Valid fields:
rel_x
,rel_y
(type:float
): Position of internal key rectangle relative to the center of the key. Default:0
,4
rel_w
,rel_y
(type:float
): Delta dimension between external key rectangle and internal key rectangle. Default:12
,12
rx
,ry
(type:float
): Curvature of the rounded internal key rectangle. Default:4
,4
svg_style
[^1]
[^1]: Excluded from keymap dump-config
by default, can be modified by manually adding it to the config file.
The CSS used for the SVG styling. This includes font settings, styling of key and combo rectangles and texts within them, along with some tweaks for external SVG glyphs.
Users are encouraged to not change the default value and use svg_extra_style
to specify overrides instead.
Type: string
Default: See config.py
svg_style_dark
[^1]
The set of CSS overrides that are added when dark_mode
is enabled, and conditionally added with @media (prefers-color-scheme: dark)
when it is "auto"
.
Type: string
Default: See config.py
svg_extra_style
Extra CSS that will be appended to svg_style
, enabling augmenting and overriding properties.
Type: string
Default: Empty
footer_text
Footer text that will be displayed at the bottom of the drawing, right aligned.
The value will be placed inside <text>
tags and can have certain SVG elements in it.
Type: string
Default: Empty
shrink_wide_legends
Shrink font size for legends wider than this many chars, set to 0 to disable.
Ideal value depends on the font size defined in svg_style
/svg_extra_style
and width of the boxes.
Type: int
Default: 7
style_layer_activators
Detect layer names in legends and style them specially: By default they are underlined and
link to the corresponding layer. Styling can be customized using the layer-activator
CSS class.
Type: bool
Default: true
glyph_tap_size
, glyph_hold_size
, glyph_shifted_size
Height in px
for SVG glyphs, in different key fields.
Type: int
Default: 14
, 12
, 10
glyphs
Mapping of glyph names to be used in key fields to their SVG definitions.
Type: dict[str, str]
Default: Empty
glyph_urls
[^1]
Mapping of sources to (possibly templated) URLs for fetching SVG glyphs.
For instance, $$material:settings$$
will use the value for material
and replace {}
in the value with settings
.
Type: dict[str, str]
Default: See config.py
use_local_cache
[^1]
Use a local filesystem cache on an OS-specific location for downloaded QMK keyboard jsons and SVG glyphs.
Type: bool
Default: true
Parse configuration
These settings are nested under the parse_config
field and applies to keymap parse
subcommand in the CLI, as well as the conversion from "Parse from..." input forms to the keymap YAML text area in the web app.
preprocess
Run C preprocessor on ZMK keymaps.
Type: bool
Default: true
skip_binding_parsing
Do not do any keycode/binding parsing (except as specified by raw_binding_map
).
Type: bool
Default: false
raw_binding_map
Convert raw keycode/binding strings specified as keys to the representations given by their values.[^2]
[^2]: The value can be a LayoutKey
mapping or a string representing the tap legend.
If a conversion was made, shortcut any further processing.
E.g. {"QK_BOOT": "BOOT", "&bootloader": "BOOT"}
.
Type: dict[str, str | dict]
Default: {}
sticky_label
Display text to place in hold field for sticky/one-shot keys.
Type: str
Default: "sticky"
toggle_label
Display text to place in hold field for toggled keys.
Type: str
Default: "toggle"
tap_toggle_label
Display text to place in hold field for tap-toggle (TT) keys.
Type: str
Default: "tap-toggle"
trans_legend
Legend to output for transparent keys.[^2]
Type: str | dict
Default: {"t": "▽", "type": "trans"}
layer_legend_map
For layer names specified, replace their representation on keys with the specified string.
The layer names should match the form that they would normally be displayed as, i.e. the
provided names if keymap parse --layer-names
is used, otherwise the layer names inferred during parsing.
Type: dict[str, str]
Default: {}
mark_alternate_layer_activators
Rather than only marking the first sequence of key positions to reach a layer as "held", mark all of the sequences to reach a given layer. This is disabled by default because it creates ambiguity: you cannot tell if all the marked keys need to be held down while a layer is active (which is the default behavior) or any of them (with this option).
The additional keys that are added by enabling this option get the key type "held alternate",
so that you can override their styling in svg_extra_style
with CSS selector .held.alternate
.
Type: bool
Default: false
modifier_fn_map
Convert modifiers in modifier functions (used in keycodes with built-in modifiers like LC(V)
in ZMK or LCTL(KC_V)
in QMK) to given symbols -- set to null
to disable the mapping. Valid fields:
-
left_ctrl
,right_ctrl
,left_shift
,right_shift
,left_alt
,right_alt
,left_gui
,right_gui
(type:str
): Mapping of each modifier to their corresponding display forms.Default:
"Ctl"
,"Ctl"
,"Sft"
,"Sft"
,"Alt"
,"AGr"
,"Gui"
,"Gui"
-
keycode_combiner
(type:str
): Pattern to join modifier functions with the modified keycode, must contain{mods}
and{key}
.Default:
"{mods}+ {key}"
-
mod_combiner
(type:str
): Pattern to join multiple modifier function strings, must contain{mod_1}
and{mod_2}
.Default:
"{mod_1}+{mod_2}"
-
special_combinations
(type:dict[str, str]
): Special look-up for combinations of mods, mod order is ignored. Keys must be modifier names joined by+
.Default:
{"left_ctrl+left_alt+left_gui+left_shift": "Hyper", "left_ctrl+left_alt+left_shift": "Meh"}
qmk_remove_keycode_prefix
Remove these prefixes from QMK keycodes before further processing.
Can be augmented with other locale prefixes, e.g. "DE_"
for German locale headers.
Type: list[str]
Default: ["KC_"]
qmk_keycode_map
Mapping to convert QMK keycodes to their display forms, applied after removing prefixes in qmk_remove_keycode_prefix
.[^2]
Type: dict[str, str | dict]
Default: See config.py
zmk_remove_keycode_prefix
Remove these prefixes from ZMK keycodes before further processing.
Can be augmented with other locale prefixes, e.g. "DE_"
for German locale headers generated by zmk-locale-generator
.
Type: list[str]
Default: []
zmk_keycode_map
Mapping to convert ZMK keycodes to their display forms, applied after removing prefixes in zmk_remove_keycode_prefix
.[^2]
Type: dict[str, str | dict]
Default: See config.py
zmk_combos
Mapping to augment the output field for parsed combos. The key names are the devicetree node names for
combos in the keymap and the value is a dict containing fields from the ComboSpec
.
E.g. {"combo_esc": {"align": "top", "offset": 0.5}}
would add these two fields to the output for combo that has node name combo_esc
.
Type: dict[str, dict]
Default: {}
zmk_preamble
A string to prepend to ZMK keymaps before parsing that can be used to influence the parsed content.
Also used for parsing DTS format physical layouts specified with --dts-layout
.
The default defines a KEYMAP_DRAWER
symbol which can be used for checks with preprocessor directives.
Type: string
Default: "#define KEYMAP_DRAWER"
zmk_additional_includes
A list of paths to add as search paths to the preprocessor for #include
directives.
This can be needed if you use Zephyr modules such as zmk-helpers
since they require augmenting the search path.
Also used for parsing DTS format physical layouts specified with --dts-layout
.
Type: list[str]
Default: []
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
File details
Details for the file keymap_drawer-0.19.0.tar.gz
.
File metadata
- Download URL: keymap_drawer-0.19.0.tar.gz
- Upload date:
- Size: 81.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/5.1.1 CPython/3.12.7
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | ffe4168435c9792fea246cc76fc2bd15ae44caa125e732368adfef3e5f40b4ee |
|
MD5 | 8375667be4647f20da7e27d46ce1e5f7 |
|
BLAKE2b-256 | 0256a1035114c10757074cf238b67d7b4622ee68bfdaa793f96e94c2b187f5ef |
Provenance
The following attestation bundles were made for keymap_drawer-0.19.0.tar.gz
:
Publisher:
publish-release.yml
on caksoylar/keymap-drawer
-
Statement type:
https://in-toto.io/Statement/v1
- Predicate type:
https://docs.pypi.org/attestations/publish/v1
- Subject name:
keymap_drawer-0.19.0.tar.gz
- Subject digest:
ffe4168435c9792fea246cc76fc2bd15ae44caa125e732368adfef3e5f40b4ee
- Sigstore transparency entry: 150943490
- Sigstore integration time:
- Predicate type:
File details
Details for the file keymap_drawer-0.19.0-py3-none-any.whl
.
File metadata
- Download URL: keymap_drawer-0.19.0-py3-none-any.whl
- Upload date:
- Size: 84.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/5.1.1 CPython/3.12.7
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 29c6265d89bd898f524632f86dae7d131d06d4881e487e3adff2c1cdf611fadb |
|
MD5 | 73801fbd1950df4722d51aa59e8cf968 |
|
BLAKE2b-256 | 31ebdeeffee01427298294c53fe5b1bb33f6f2467bd3b1bbfafb4c9d40259177 |
Provenance
The following attestation bundles were made for keymap_drawer-0.19.0-py3-none-any.whl
:
Publisher:
publish-release.yml
on caksoylar/keymap-drawer
-
Statement type:
https://in-toto.io/Statement/v1
- Predicate type:
https://docs.pypi.org/attestations/publish/v1
- Subject name:
keymap_drawer-0.19.0-py3-none-any.whl
- Subject digest:
29c6265d89bd898f524632f86dae7d131d06d4881e487e3adff2c1cdf611fadb
- Sigstore transparency entry: 150943491
- Sigstore integration time:
- Predicate type: