From 176962c292ac1ef2595aa2791bf7efd9f55f6874 Mon Sep 17 00:00:00 2001 From: Patrick Surry Date: Thu, 7 Dec 2023 18:53:59 -0500 Subject: [PATCH 1/3] adds inline qmk_info --- KEYMAP_SPEC.md | 19 +++++++++++++++++-- examples/tidbit.yaml | 16 ++++++++++++++++ keymap_drawer/physical_layout.py | 11 ++++++----- 3 files changed, 39 insertions(+), 7 deletions(-) create mode 100644 examples/tidbit.yaml diff --git a/KEYMAP_SPEC.md b/KEYMAP_SPEC.md index 8061283..f18f5ad 100644 --- a/KEYMAP_SPEC.md +++ b/KEYMAP_SPEC.md @@ -26,7 +26,10 @@ This field provides information about the physical layout of the keyboard, i.e., 1. **QMK `info.json` `layout` specification**: This is the [official QMK format](https://docs.qmk.fm/#/reference_info_json?id=layout-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. + that every `info.json` file in the QMK firmware repository uses. + `keymap-drawer` only uses the `x`, `y`, `w`, `h`, `r`, `rx` and `ry` fields. + The `x, y, w, h` specifies the key location and size (width, height) in `1u` units, + with `r` indicating the key rotation in degrees, centered at `rx, ry`. Note that `keymap-editor` utilizes [the same format](https://github.com/nickcoutsos/keymap-editor/wiki/Defining-keyboard-layouts) for `info.json`. QMK spec also lets you specify multiple "layouts" per keyboard corresponding to different layout macros to support physical variations. @@ -37,10 +40,22 @@ This field provides information about the physical layout of the keyboard, i.e., 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. + Alternatively you can write QMK layout inline with the `qmk_info` parameter + according to the official schema or a simple of key specs. For example: + +```yaml +layout: + qmk_info: [ + {x: 1, y: 0}, {x: 2, y: 0}, {x: 3, y: 0}, + {x: 0, y: 1}, {x: 1, y: 1}, {x: 2, y: 1}, {x: 3, y: 1, h: 2}, + ... + ] +``` + Note that 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`. + besides `x`, `y`, `w`, `h`, `r`, `rx` and `ry` in your final JSON since they won't be used by `keymap-drawer`. 2. **Parametrized ortholinear layouts**: This lets you specify parameters to automatically generate a split or non-split ortholinear layout. diff --git a/examples/tidbit.yaml b/examples/tidbit.yaml new file mode 100644 index 0000000..5640b73 --- /dev/null +++ b/examples/tidbit.yaml @@ -0,0 +1,16 @@ +layout: + qmk_info: [ + {x: 1, y: 0}, {x: 2, y: 0}, {x: 3, y: 0}, + {x: 0, y: 1}, {x: 1, y: 1}, {x: 2, y: 1}, {x: 3, y: 1, h: 2}, + {x: 0, y: 2}, {x: 1, y: 2}, {x: 2, y: 2}, # ^^ double height + {x: 0, y: 3}, {x: 1, y: 3}, {x: 2, y: 3}, {x: 3, y: 3, h: 2}, + {x: 0, y: 4, w: 2}, {x: 2, y: 4} # ^^ double height + ] + +layers: + default: + - [ Esc, '*', '-'] + - ['7', '8', '9', '+'] + - ['4', '5', '6'] + - ['1', '2', '3', Enter] + - ['0', '.'] diff --git a/keymap_drawer/physical_layout.py b/keymap_drawer/physical_layout.py index d2719cc..c334420 100644 --- a/keymap_drawer/physical_layout.py +++ b/keymap_drawer/physical_layout.py @@ -162,26 +162,27 @@ def __rmul__(self, other: int | float) -> "PhysicalLayout": return PhysicalLayout(keys=[other * k for k in self.keys]) -def layout_factory( +def layout_factory( # pylint: disable=too-many-arguments config: DrawConfig, qmk_keyboard: str | None = None, qmk_info_json: Path | None = None, + qmk_info: dict | None = None, qmk_layout: str | None = None, ortho_layout: dict | None = None, ) -> PhysicalLayout: """Create and return a physical layout, as determined by the combination of arguments passed.""" - if len([arg for arg in (qmk_keyboard, qmk_info_json, ortho_layout) if arg is not None]) != 1: + if len([arg for arg in (qmk_keyboard, qmk_info_json, qmk_info, ortho_layout) if arg is not None]) != 1: raise ValueError( 'Please provide exactly one of "qmk_keyboard", "qmk_info_json" or "ortho_layout" specs for physical layout' ) - if qmk_keyboard or qmk_info_json: + if qmk_keyboard or qmk_info_json or qmk_info: if qmk_keyboard: qmk_info = _get_qmk_info(qmk_keyboard, config.use_local_cache) - else: # qmk_info_json - assert qmk_info_json is not None + elif qmk_info_json: with open(qmk_info_json, "rb") as f: qmk_info = json.load(f) + assert qmk_info is not None if isinstance(qmk_info, list): assert qmk_layout is None, "Cannot use qmk_layout with a list-format QMK spec" From 5176ecbcc6748231e9a702227075f97e30ca4b02 Mon Sep 17 00:00:00 2001 From: Patrick Surry Date: Fri, 8 Dec 2023 07:41:32 -0500 Subject: [PATCH 2/3] Adds encoder type with circle style --- KEYMAP_SPEC.md | 2 +- examples/tidbit.yaml | 2 +- keymap_drawer/config.py | 5 +++++ 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/KEYMAP_SPEC.md b/KEYMAP_SPEC.md index f18f5ad..ddcb94d 100644 --- a/KEYMAP_SPEC.md +++ b/KEYMAP_SPEC.md @@ -113,7 +113,7 @@ A `LayoutKey` can be defined with either a string value or with a mapping with t | `tap (t)` | `str` | `""` | the tap action of a key, drawn on the center of the key; spaces will be converted to line breaks[^2] | | `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](CONFIGURATION.md#svg_style)[^3]. 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) | +| `type` | `str` | `""` | the styling of the key that corresponds to the [SVG class](CONFIGURATION.md#svg_style)[^3]. 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), and `encoder` (circled outline) | [^2]: You can prevent line breaks by using double spaces `" "` to denote a single non-breaking space. [^3]: Text styling can be overridden in the SVG config using the `"tap"`, `"hold"` and `"shifted"` classes if desired. diff --git a/examples/tidbit.yaml b/examples/tidbit.yaml index 5640b73..1cbb93c 100644 --- a/examples/tidbit.yaml +++ b/examples/tidbit.yaml @@ -9,7 +9,7 @@ layout: layers: default: - - [ Esc, '*', '-'] + - [ {tap: Esc, type: encoder}, '*', '-'] - ['7', '8', '9', '+'] - ['4', '5', '6'] - ['1', '2', '3', Enter] diff --git a/keymap_drawer/config.py b/keymap_drawer/config.py index 78a0cc1..f8aa9c6 100644 --- a/keymap_drawer/config.py +++ b/keymap_drawer/config.py @@ -125,6 +125,11 @@ class KeySidePars(BaseModel): stroke-width: 2; } + rect.encoder { + rx: 50%; + ry: 50%; + } + text { text-anchor: middle; dominant-baseline: middle; From ead92ce21bdd46a13980df452acd29c1aed605c7 Mon Sep 17 00:00:00 2001 From: Patrick Surry Date: Fri, 8 Dec 2023 11:59:42 -0500 Subject: [PATCH 3/3] black --- keymap_drawer/physical_layout.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/keymap_drawer/physical_layout.py b/keymap_drawer/physical_layout.py index c334420..bae12cc 100644 --- a/keymap_drawer/physical_layout.py +++ b/keymap_drawer/physical_layout.py @@ -162,7 +162,7 @@ def __rmul__(self, other: int | float) -> "PhysicalLayout": return PhysicalLayout(keys=[other * k for k in self.keys]) -def layout_factory( # pylint: disable=too-many-arguments +def layout_factory( # pylint: disable=too-many-arguments config: DrawConfig, qmk_keyboard: str | None = None, qmk_info_json: Path | None = None,