diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 000000000..94324fa7f --- /dev/null +++ b/.prettierrc @@ -0,0 +1,2 @@ +proseWrap: "always" +editorconfig: true diff --git a/readme.md b/readme.md index a657e3f9c..fd8c67ea5 100644 --- a/readme.md +++ b/readme.md @@ -1,8 +1,8 @@ # urob's zmk-config -This is my personal [ZMK firmware](https://github.com/zmkfirmware/zmk/) configuration. -It consists of a 34-keys base layout that is re-used for various boards, including my -Corneish Zen and my Planck. +This is my personal [ZMK firmware](https://github.com/zmkfirmware/zmk/) +configuration. It consists of a 34-keys base layout that is re-used for various +boards, including my Corneish Zen and my Planck. This branch is updated for the latest ZMK using Zephyr 3.5. A legacy version compatible with Zephyr 3.0 is available @@ -15,16 +15,19 @@ compatible with Zephyr 3.0 is available - the base keymap and combo setup are independent of the physical location of keys and are re-used for multiple keyboards. The configuration is fit onto larger boards by padding it via a modular structure of "extra keys" -- ["timeless" homerow mods](#timeless-homerow-mods) +- ["timeless" homerow mods](#timeless-homerow-mods) - combos replacing the symbol layer - smart numbers and smart mouse layers that automatically toggle off when done -- sticky shift on right thumb, double-tap (or shift + tap)[^1] activates caps-word +- sticky shift on right thumb, double-tap (or shift + tap)[^1] activates + caps-word - arrow-cluster doubles as home, end, begin/end of document on long-press -- more intuitive shift-actions: , ;, . : and ? ! +- more intuitive shift-actions: , ;, . : and ? + ! - shift + space morphs into dotspacesticky-shift -- "Greek" layer for mathematical typesetting (activated as sticky-layer via a combo) +- "Greek" layer for mathematical typesetting (activated as sticky-layer via a + combo) - modified Github Actions workflow that recognizes git-submodules - automated [build-scripts](https://github.com/urob/zmk-config/tree/main/scripts#readme) @@ -34,13 +37,13 @@ compatible with Zephyr 3.0 is available ## Timeless homerow mods -[Homerow mods](https://precondition.github.io/home-row-mods) (aka "HRMs") can -be a game changer -- at least in theory. In practice, they require some finicky -timing: In its most naive implementation, in order to produce a "mod", they -must be held *longer* than `tapping-term-ms`. In order to produce a "tap", they -must be held *less* than `tapping-term-ms`. This requires very consistent -typing speeds that, alas, I do not possess. Hence my quest for a "timer-less" -HRM setup.[^2] +[Homerow mods](https://precondition.github.io/home-row-mods) (aka "HRMs") can be +a game changer -- at least in theory. In practice, they require some finicky +timing: In its most naive implementation, in order to produce a "mod", they must +be held _longer_ than `tapping-term-ms`. In order to produce a "tap", they must +be held _less_ than `tapping-term-ms`. This requires very consistent typing +speeds that, alas, I do not possess. Hence my quest for a "timer-less" HRM +setup.[^2] After months of tweaking, I eventually ended up with a HRM setup that is essentially timer-less, resulting in virtually no misfires. Yet it provides a @@ -50,54 +53,53 @@ Let's suppose for a moment we set `tapping-term-ms` to something ridiculously large, say 5 seconds. This makes the configuration timer-less of sorts. But it has two problems: (1) To activate a mod we will have to hold the HRM keys for what feels like eternity. (2) During regular typing, there are delays between -the press of a key and the time it appears on the screen.[^3] Enter two my favorite -ZMK features: -* To address the first problem, I use ZMK's `balanced` flavor, which produces a +the press of a key and the time it appears on the screen.[^3] Enter two my +favorite ZMK features: + +- To address the first problem, I use ZMK's `balanced` flavor, which produces a "hold" if another key is both pressed and released within the tapping-term. - Because that is exactly what I normally do with HRMs, there is virtually - never a need to wait past my long tapping term (see below for two - exceptions). -* To address the typing delay, I use ZMK's `require-prior-idle-ms` property, which - immediately resolves a HRM as "tap" when it is pressed shortly *after* + Because that is exactly what I normally do with HRMs, there is virtually never + a need to wait past my long tapping term (see below for two exceptions). +- To address the typing delay, I use ZMK's `require-prior-idle-ms` property, + which immediately resolves a HRM as "tap" when it is pressed shortly _after_ another key has been tapped. This all but completely eliminates the delay. This is great but there are still a few rough edges: -* When rolling keys, I sometimes unintentionally end up with "nested" key +- When rolling keys, I sometimes unintentionally end up with "nested" key sequences: `key 1` down, `key 2` down and up, `key 1` up. Because of the `balanced` flavor, this would falsely register `key 1` as a mod. As a remedy, I use ZMK's `positional hold-tap` feature to force HRMs to always resolve as - "tap" when the *next* key is on the same side of the keyboard. Problem - solved. -* ... or at least almost. By default, positional-hold-tap - performs the positional check when the next key is *pressed*. This is not - ideal, because it prevents combining multiple modifiers on the same hand. To - fix this, I use the `hold-trigger-on-release` setting, which delays the - positional-hold-tap decision until the next key's *release*. With the setting, - multiple mods can be combined when held, while I still get the benefit from - positional-hold-tap when keys are tapped. -* So far, nothing of the configuration depends on the duration of + "tap" when the _next_ key is on the same side of the keyboard. Problem solved. +- ... or at least almost. By default, positional-hold-tap performs the + positional check when the next key is _pressed_. This is not ideal, because it + prevents combining multiple modifiers on the same hand. To fix this, I use the + `hold-trigger-on-release` setting, which delays the positional-hold-tap + decision until the next key's _release_. With the setting, multiple mods can + be combined when held, while I still get the benefit from positional-hold-tap + when keys are tapped. +- So far, nothing of the configuration depends on the duration of `tapping-term-ms`. In practice, there are two reasons why I don't set it to infinity: - 1. Sometimes, in rare circumstances, I want to combine a mod with a - alpha-key *on the same hand* (e.g., when using the mouse with the other - hand). My positional hold-tap configuration prevents this *within* the - tapping term. By setting the tapping term to something large but not crazy - large (I use 280ms), I can still use same-hand `mod` + `alpha` shortcuts by - holding the mod for just a little while before tapping the alpha-key. - 2. Sometimes, I want to press a modifier without another key (e.g., on - Windows, tapping `Win` opens the search menu). Because the `balanced` - flavour only kicks in when another key is pressed, this also requires - waiting past `tapping-term-ms`. -* Finally, it is worth noting that this setup works best in combination with a + 1. Sometimes, in rare circumstances, I want to combine a mod with a alpha-key + _on the same hand_ (e.g., when using the mouse with the other hand). My + positional hold-tap configuration prevents this _within_ the tapping term. + By setting the tapping term to something large but not crazy large (I use + 280ms), I can still use same-hand `mod` + `alpha` shortcuts by holding the + mod for just a little while before tapping the alpha-key. + 2. Sometimes, I want to press a modifier without another key (e.g., on + Windows, tapping `Win` opens the search menu). Because the `balanced` + flavour only kicks in when another key is pressed, this also requires + waiting past `tapping-term-ms`. +- Finally, it is worth noting that this setup works best in combination with a dedicated shift for capitalization during normal typing (I like sticky-shift on a home-thumb). This is because shifting alphas is the one scenario where pressing a mod may conflict with `require-prior-idle-ms`, which may result in false negatives when typing fast. -Here's my configuration (I use a bunch of [helper -macros](https://github.com/urob/zmk-nodefree-config) to simplify the syntax, but they -are not necessary): +Here's my configuration (I use a bunch of +[helper macros](https://github.com/urob/zmk-nodefree-config) to simplify the +syntax, but they are not necessary): ```C++ /* use helper macros to define left and right hand keys */ @@ -131,57 +133,61 @@ ZMK_BEHAVIOR(hmr, hold_tap, ### Required firmware -After a recent round of patches, the above configuration now works with -upstream ZMK. +After a recent round of patches, the above configuration now works with upstream +ZMK. Other parts of my configuration still require a few PRs that aren't yet in upstream ZMK. My personal [ZMK fork](https://github.com/urob/zmk) includes all PRs needed to compile my configuration. If you prefer to maintain your own fork -with a custom selection of PRs, you might find this [ZMK-centric introduction -to Git](https://gist.github.com/urob/68a1e206b2356a01b876ed02d3f542c7) helpful. +with a custom selection of PRs, you might find this +[ZMK-centric introduction to Git](https://gist.github.com/urob/68a1e206b2356a01b876ed02d3f542c7) +helpful. ### Troubleshooting -Hopefully, the above configuration "just works". If it doesn't, here's a -few smaller (and larger) things to try. +Hopefully, the above configuration "just works". If it doesn't, here's a few +smaller (and larger) things to try. -* **Noticeable delay when tapping HRMs:** Increase `require-prior-idle-ms`. As a rule of thumb, - you want to set it to at least `10500/x` where `x` is your (relaxed) WPM for English prose.[^4] -* **False negatives (same-hand):** Reduce `tapping-term-ms` (or disable +- **Noticeable delay when tapping HRMs:** Increase `require-prior-idle-ms`. As a + rule of thumb, you want to set it to at least `10500/x` where `x` is your + (relaxed) WPM for English prose.[^4] +- **False negatives (same-hand):** Reduce `tapping-term-ms` (or disable `hold-trigger-key-positions`) -* **False negatives (cross-hand):** Reduce `require-prior-idle-ms` (or set flavor - to `hold-preferred` -- to continue using `hold-trigger-on-release`, you must - also [patch - ZMK](https://github.com/celejewski/zmk/commit/d7a8482712d87963e59b74238667346221199293) +- **False negatives (cross-hand):** Reduce `require-prior-idle-ms` (or set + flavor to `hold-preferred` -- to continue using `hold-trigger-on-release`, you + must also + [patch ZMK](https://github.com/celejewski/zmk/commit/d7a8482712d87963e59b74238667346221199293) or use [an already patched branch](https://github.com/urob/zmk)) -* **False positives (same-hand):** Increase `tapping-term-ms` -* **False positives (cross-hand):** Increase `require-prior-idle-ms` (or set +- **False positives (same-hand):** Increase `tapping-term-ms` +- **False positives (cross-hand):** Increase `require-prior-idle-ms` (or set flavor to `tap-preferred`, which requires holding HRMs past tapping term to activate) ## Using combos instead of a symbol layer -I am a big fan of combos for all sort of things. In terms of comfort, I much prefer them -over accessing layers that involve lateral thumb movements to be activated, especially -when switching between different layers in rapid succession. +I am a big fan of combos for all sort of things. In terms of comfort, I much +prefer them over accessing layers that involve lateral thumb movements to be +activated, especially when switching between different layers in rapid +succession. One common concern about overloading the layout with combos is that they lead to -misfires. Fortunately, the above-mentioned `require-prior-idle-ms` option also works -for combos, which in my experience all but completely eliminates the problem -- even -when rolling keys on the home row! +misfires. Fortunately, the above-mentioned `require-prior-idle-ms` option also +works for combos, which in my experience all but completely eliminates the +problem -- even when rolling keys on the home row! -My combo layout aims to place the most used symbols in easy-to-access -locations while also making them easy to remember. Specifically: +My combo layout aims to place the most used symbols in easy-to-access locations +while also making them easy to remember. Specifically: - the top vertical-combo row matches the symbols on a standard numbers row (except `+` and `&` being swapped) - the bottom vertical-combo row is symmetric to the top row (subscript `_` aligns with superscript `^`; minus `-` aligns with `+`; division `/` aligns with multiplication `*`; logical-or `|` aligns with logical-and `&`) -- parenthesis, braces, brackets are set up symmetrically as horizontal combos with `<`, - `>`, `{` and `}` being accessed from the Navigation layer (or when combined with `Shift`) -- left-hand side combos for `tap`, `esc`, `enter`, `cut` (on X + D), - `copy` and `paste` that go well with right-handed mouse usage +- parenthesis, braces, brackets are set up symmetrically as horizontal combos + with `<`, `>`, `{` and `}` being accessed from the Navigation layer (or when + combined with `Shift`) +- left-hand side combos for `tap`, `esc`, `enter`, `cut` (on X + + D), `copy` and `paste` that go well with right-handed mouse usage - L + Y switches to the Greek layer for a single key press, L + U + Y activates one-shot shift in addition @@ -193,49 +199,51 @@ locations while also making them easy to remember. Specifically: Inspired by Jonas Hietala's [Numword](https://www.jonashietala.se/blog/2021/06/03/the-t-34-keyboard-layout/#where-are-the-digits) -for QMK, I implemented my own version of [Smart-layers for -ZMK](https://github.com/zmkfirmware/zmk/pull/1451). It is triggered via a -single tap on "Smart-Num". Numword continues to be activated as long as I -type numbers, and deactivates automatically on any other keypress (holding it activates -a non-sticky num layer). - -After using Numword for more than a year now, I have been overall very happy with it. When -typing single digits, it effectively is a sticky-layer but with the added advantage that -I can also use it to type multiple digits. - -The main downside is that if a sequence of numbers is *immediately* followed by any of the -letters on which my numpad is located (WFPRSTXCD), then the automatic deactivation won't -work. But this is rare -- most number sequences are terminated by `space`, `return` or some form -of punctuation/delimination. To deal with the rare cases where they aren't, there is a -`CANCEL` key on the navigation-layer that deactivates Numword, Capsword and Smart-mouse. -(It also toggles off when pressing `Numword` again, but I find it cognitively easier to -have a dedicated "off-switch" than keeping track of which modes are currently active.) - +for QMK, I implemented my own version of +[Smart-layers for ZMK](https://github.com/zmkfirmware/zmk/pull/1451). It is +triggered via a single tap on "Smart-Num". Numword continues to be activated as +long as I type numbers, and deactivates automatically on any other keypress +(holding it activates a non-sticky num layer). + +After using Numword for more than a year now, I have been overall very happy +with it. When typing single digits, it effectively is a sticky-layer but with +the added advantage that I can also use it to type multiple digits. + +The main downside is that if a sequence of numbers is _immediately_ followed by +any of the letters on which my numpad is located (WFPRSTXCD), then the automatic +deactivation won't work. But this is rare -- most number sequences are +terminated by `space`, `return` or some form of punctuation/delimination. To +deal with the rare cases where they aren't, there is a `CANCEL` key on the +navigation-layer that deactivates Numword, Capsword and Smart-mouse. (It also +toggles off when pressing `Numword` again, but I find it cognitively easier to +have a dedicated "off-switch" than keeping track of which modes are currently +active.) ##### Smart-Mouse Similarly to Numword, I have a smart-mouse layer (activated by comboing -W + P), which replaces the navigation cluster with -scroll and mouse-movements, and replaces the right thumbs with mouse buttons. -Pressing any other key automatically deactivates the layer. +W + P), which replaces the navigation cluster with scroll +and mouse-movements, and replaces the right thumbs with mouse buttons. Pressing +any other key automatically deactivates the layer. ##### Capsword -My right thumb triggers three variations of shift: Tapping yields -sticky-shift (used to capitalize alphas), holding activates a regular shift, and +My right thumb triggers three variations of shift: Tapping yields sticky-shift +(used to capitalize alphas), holding activates a regular shift, and double-tapping (or equivalently shift + tap) activates ZMK's Caps-word behavior. -One minor technical detail: While it would be possible to implement the double-tap functionality -as a tap-dance, this would add a delay when using single taps. To avoid the delays, I -instead implemented the double-tap functionality as a mod-morph. +One minor technical detail: While it would be possible to implement the +double-tap functionality as a tap-dance, this would add a delay when using +single taps. To avoid the delays, I instead implemented the double-tap +functionality as a mod-morph. ##### Multi-purpose Navigation cluster -To economize on keys, I am using hold-taps on my navigation cluster, which yield `home`, `end`, -`begin/end of document`, and `delete word forward/backward` on long-presses. The exact -implementation is tweaked so that `Ctrl` is silently absorbed in combination with `home` and `end` -to avoid accidental document-wide operations (which are accessible via the dedicated `begin/end -document keys`.) +To economize on keys, I am using hold-taps on my navigation cluster, which yield +`home`, `end`, `begin/end of document`, and `delete word forward/backward` on +long-presses. The exact implementation is tweaked so that `Ctrl` is silently +absorbed in combination with `home` and `end` to avoid accidental document-wide +operations (which are accessible via the dedicated `begin/end document keys`.) ##### Swapper @@ -245,19 +253,20 @@ one-handed Alt-Tab switcher (`PWin` and `NWin`). ##### Repeat -I recently switched to 25g-chocs on one of my keyboards. I already was very happy with -my combos prior to that (even with heavy-ish MX-switches). But with the light chocs, I -find that I can now even use them for regular typing. While I haven't yet tried -placing alphas on combos, I am currently experimenting with a `repeat` combo on -my home row that I use to reduce SFUs when typing double-letter words. +I recently switched to 25g-chocs on one of my keyboards. I already was very +happy with my combos prior to that (even with heavy-ish MX-switches). But with +the light chocs, I find that I can now even use them for regular typing. While I +haven't yet tried placing alphas on combos, I am currently experimenting with a +`repeat` combo on my home row that I use to reduce SFUs when typing +double-letter words. ## Issues and workarounds Since I switched from QMK to ZMK I have been very impressed with how easy it is -to set up relatively complex layouts in ZMK. For the most parts I don't miss -any functionality (to the contrary, I found that ZMK supports many features -natively that would require complex user-space implementations in QMK). Below -are a few remaining issues: +to set up relatively complex layouts in ZMK. For the most parts I don't miss any +functionality (to the contrary, I found that ZMK supports many features natively +that would require complex user-space implementations in QMK). Below are a few +remaining issues: - ZMK does not yet support "tap-only" combos ([#544](https://github.com/zmkfirmware/zmk/issues/544)), requiring a brief @@ -267,8 +276,8 @@ are a few remaining issues: dynamically adding/removing mods doesn't work well). Having a native solution akin to QMK's "COMBO_MUST_TAP" property would be fantastic. - Another item on my wishlist are adaptive keys - ([#1624](https://github.com/zmkfirmware/zmk/issues/1624)). This would open - the door for things like spacespace becoming + ([#1624](https://github.com/zmkfirmware/zmk/issues/1624)). This would open the + door for things like spacespace becoming .spacesticky-shift. (Using tap-dance isn't really an option here due to the delay it adds) - A minor thing is that ZMK doesn't yet support any keys on the @@ -278,29 +287,34 @@ are a few remaining issues: - Very minor: `&bootloader` doesn't work with stm32 boards like the Planck ([#1086](https://github.com/zmkfirmware/zmk/issues/1086)) -[^1]: Really what's happening is that `Shift` + my right home-thumb morph into - caps-word. This gives me two separate ways of activating it: (1) Holding the - homerow-mod shift on my left index-finger and then pressing my right home-thumb, which - is my new preferred way. Or, (2) double-tapping the right home-thumb, which also works - because the first tap yields sticky-shift, activating the mod-morph upon the second - tap. But even when only activating via double-tapping, this implementation is advantageous - compared to using tap-dance as it does not create any delay when single-tapping the key. - -[^2]: I call it "timer-less", because the large tapping-term makes the behavior - insensitive to the precise timings. One may say that there is still the - `require-prior-idle` timeout. However, with both a large tapping-term and - positional-hold-taps, the behavior is *not* actually sensitive to the - `require-prior-idle` timing: All it does is reduce the delay in typing; i.e., variations - in typing speed won't affect *what* is being typed but merely *how fast* it appears on - the screen. - -[^3]: The delay is determined by how quickly a key is released and is not - directly related to the tapping-term. But regardless of its length, most - people still find it noticable and disruptive. - -[^4]: E.g, if your WPM is 70 or larger, then the default of 150ms (=10500/70) +[^1]: + Really what's happening is that `Shift` + my right home-thumb morph into + caps-word. This gives me two separate ways of activating it: (1) Holding the + homerow-mod shift on my left index-finger and then pressing my right + home-thumb, which is my new preferred way. Or, (2) double-tapping the right + home-thumb, which also works because the first tap yields sticky-shift, + activating the mod-morph upon the second tap. But even when only activating + via double-tapping, this implementation is advantageous compared to using + tap-dance as it does not create any delay when single-tapping the key. + +[^2]: + I call it "timer-less", because the large tapping-term makes the behavior + insensitive to the precise timings. One may say that there is still the + `require-prior-idle` timeout. However, with both a large tapping-term and + positional-hold-taps, the behavior is _not_ actually sensitive to the + `require-prior-idle` timing: All it does is reduce the delay in typing; + i.e., variations in typing speed won't affect _what_ is being typed but + merely _how fast_ it appears on the screen. + +[^3]: + The delay is determined by how quickly a key is released and is not directly + related to the tapping-term. But regardless of its length, most people still + find it noticable and disruptive. + +[^4]: + E.g, if your WPM is 70 or larger, then the default of 150ms (=10500/70) should work well. The rule of thumb is based on an average character length of 4.7 for English words. Taking into account 1 extra tap for `space`, this - yields a minimum `require-prior-idle-ms` of (60 * 1000) / (5.7 * x) ≈ 10500 / x - milliseconds. The approximation errs on the safe side, - as in practice home row taps tend to be faster than average. + yields a minimum `require-prior-idle-ms` of (60 _ 1000) / (5.7 _ x) ≈ 10500 + / x milliseconds. The approximation errs on the safe side, as in practice + home row taps tend to be faster than average. diff --git a/scripts/readme.md b/scripts/readme.md index fd1794fa6..79263ce5b 100644 --- a/scripts/readme.md +++ b/scripts/readme.md @@ -1,22 +1,23 @@ -This folder contains scripts that automate installing and building using a -local toolchain. The scripts provide an alternative to using [Github -Actions](https://zmk.dev/docs/user-setup#installing-the-firmware) and the -[developer toolchain](https://zmk.dev/docs/development/setup). +This folder contains scripts that automate installing and building using a local +toolchain. The scripts provide an alternative to using +[Github Actions](https://zmk.dev/docs/user-setup#installing-the-firmware) and +the [developer toolchain](https://zmk.dev/docs/development/setup). -If the zmk-config repo contains a `combos.dtsi` file, the script will also automatically -update the `MAX_COMBOS_PER_KEY` and `MAX_KEYS_PER_COMBO` settings for all boards, -depending on the combos specified in `combos.dtsi`. +If the zmk-config repo contains a `combos.dtsi` file, the script will also +automatically update the `MAX_COMBOS_PER_KEY` and `MAX_KEYS_PER_COMBO` settings +for all boards, depending on the combos specified in `combos.dtsi`. ## Build steps ### 1. Clone the ZMK repository -Clone the ZMK repository and checkout the branch that you want to build -against. By default the build script will look for the ZMK repo in `~/zmk`. -Other locations can be specified with `--host-zmk-dir` or by changing the -default location for `HOST_ZMK_DIR` inside the script. +Clone the ZMK repository and checkout the branch that you want to build against. +By default the build script will look for the ZMK repo in `~/zmk`. Other +locations can be specified with `--host-zmk-dir` or by changing the default +location for `HOST_ZMK_DIR` inside the script. For example, to build against my `main-3.2` branch, run: + ```bash cd "$HOME" git clone https://github.com/urob/zmk @@ -25,11 +26,12 @@ git checkout main-3.2 ### 2. Clone your zmk-config repository -By default the build script will look for the zmk-config repo in -`~/zmk-config`. Other locations can be specified with `--host-config-dir` or by -changing the default location for `HOST_CONFIG_DIR` inside the script. +By default the build script will look for the zmk-config repo in `~/zmk-config`. +Other locations can be specified with `--host-config-dir` or by changing the +default location for `HOST_CONFIG_DIR` inside the script. For example, to use my zmk-config repo, run: + ```bash cd "$HOME" git clone https://github.com/urob/zmk-config @@ -41,47 +43,48 @@ The build script can be used to install either a "docker" or a "local" toolchain. If unsure, I recommend using the docker toolchain. Depending on your installation choice, do **one** of the following: -1. Install Docker or Podman (recommended) and, if using Podman, configure the docker - registry. On Debian or Ubuntu, you can do both by running: +1. Install Docker or Podman (recommended) and, if using Podman, configure the + docker registry. On Debian or Ubuntu, you can do both by running: ```bash sudo apt-get install podman echo 'unqualified-search-registries = ["docker.io"]' > $XDG_CONFIG_HOME/containers/registries.conf ``` -2. Install a local [developer - toolchain](https://zmk.dev/docs/development/setup). The +2. Install a local + [developer toolchain](https://zmk.dev/docs/development/setup). The `zmk_local_install.sh` script in this repository automates the process for Debian-based operating system. ### 4. Run the build script Run the `zmk_build.sh` script to build your boards. By default, the script will -build all boards specified in `build.yaml` in your `zmk-config` repo. The default can be -overwritten with the `-b` option. +build all boards specified in `build.yaml` in your `zmk-config` repo. The +default can be overwritten with the `-b` option. -If using docker/podman, the script will pull down the required dependencies the first -time it is used. The script will automatically detect whether the build -requirement have changed, and will only re-download the dependencies if needed. +If using docker/podman, the script will pull down the required dependencies the +first time it is used. The script will automatically detect whether the build +requirement have changed, and will only re-download the dependencies if needed. In order to easily switch between multiple ZMK branches that have different build requirements, one can specify the desired Zephyr version using the `-v` option. Docker container and volumes are index by the Zephyr version, so switching between Zephyr version won't require re-downloading new dependencies. -In order to force re-installing all build requirements, pass the `-c` option, which will -wipe out the Docker container and volume. +In order to force re-installing all build requirements, pass the `-c` option, +which will wipe out the Docker container and volume. By default the script will copy the firmware into the `OUTPUT_DIR` folder specified in the script. Other locations can be specified using the `--output-dir` argument. -To switch between Docker and Podman, set the `DOCKER_BIN` variable in the -script (defaults to `podman`). If using Docker and the user is not in the -docker-group, then one can use Docker in sudo-mode by using the `-s` flag for -the script. If using Podman, running in rootless mode is recommended. +To switch between Docker and Podman, set the `DOCKER_BIN` variable in the script +(defaults to `podman`). If using Docker and the user is not in the docker-group, +then one can use Docker in sudo-mode by using the `-s` flag for the script. If +using Podman, running in rootless mode is recommended. One can pass custom options to `west` by preluding them with `--`. For example, to build my boards using Zephyr version 3.2 in sudo mode and pass the "pristine" option to west, run: + ```bash zmk_build.sh -s -v 3.2 -- -p ``` @@ -91,11 +94,12 @@ See the script for a full set of options. ## Developing interactively using Docker The docker container can be entered interactively using with all the necessary -mounts using: The script shares a build environment with the build script -(again indexed by Zephyr versions). +mounts using: The script shares a build environment with the build script (again +indexed by Zephyr versions). For example, to start an interactive Docker session in sudo mode using Zephyr version 3.2, run: + ```bash zmk_run_docker.sh -s -v 3.2 ``` diff --git a/scripts/zmk_build.sh b/scripts/zmk_build.sh index b39163094..db44101d7 100755 --- a/scripts/zmk_build.sh +++ b/scripts/zmk_build.sh @@ -3,74 +3,74 @@ # Parse input arguments while [[ $# -gt 0 ]]; do case $1 in - # needed when user isn't in docker group - -s|--su) - SUDO="sudo" - ;; - - -l|--local) - RUNWITH_DOCKER="false" - ;; - - -m|--multithread) - MULTITHREAD="true" - ;; - - -c|--clear-cache) - CLEAR_CACHE="true" - ;; - - # comma or space separated list of boards (use quotes if space separated) - # if ommitted, will compile list of boards in build.yaml - -b|--board) - BOARDS="$2" - shift - ;; - - -v|--version) - ZEPHYR_VERSION="$2" - shift - ;; - - -o|--output-dir) - OUTPUT_DIR="$2" - shift - ;; - - --log-dir) - LOG_DIR="$2" - shift - ;; - - --host-config-dir) - HOST_CONFIG_DIR="$2" - shift - ;; - - --host-zmk-dir) - HOST_ZMK_DIR="$2" - shift - ;; - - --docker-config-dir) - DOCKER_CONFIG_DIR="$2" - shift - ;; - - --docker-zmk-dir) - DOCKER_ZMK_DIR="$2" - shift - ;; - - --) - WEST_OPTS="${@:2}" - break - ;; - - *) - echo "Unknown option $1" - exit 1 - ;; + # needed when user isn't in docker group + -s | --su) + SUDO="sudo" + ;; + + -l | --local) + RUNWITH_DOCKER="false" + ;; + + -m | --multithread) + MULTITHREAD="true" + ;; + + -c | --clear-cache) + CLEAR_CACHE="true" + ;; + + # comma or space separated list of boards (use quotes if space separated) + # if ommitted, will compile list of boards in build.yaml + -b | --board) + BOARDS="$2" + shift + ;; + + -v | --version) + ZEPHYR_VERSION="$2" + shift + ;; + + -o | --output-dir) + OUTPUT_DIR="$2" + shift + ;; + + --log-dir) + LOG_DIR="$2" + shift + ;; + + --host-config-dir) + HOST_CONFIG_DIR="$2" + shift + ;; + + --host-zmk-dir) + HOST_ZMK_DIR="$2" + shift + ;; + + --docker-config-dir) + DOCKER_CONFIG_DIR="$2" + shift + ;; + + --docker-zmk-dir) + DOCKER_ZMK_DIR="$2" + shift + ;; + + --) + WEST_OPTS="${@:2}" + break + ;; + + *) + echo "Unknown option $1" + exit 1 + ;; esac shift @@ -103,24 +103,23 @@ DOCKER_BIN="$SUDO podman" cd "$HOST_CONFIG_DIR" -if [[ -f config/combos.dtsi ]] +if [[ -f config/combos.dtsi ]]; then # update maximum combos per key - then - count=$( \ - tail -n +10 config/combos.dtsi | \ - grep -Eo '[LR][TMBH][0-9]' | \ - sort | uniq -c | sort -nr | \ - awk 'NR==1{print $1}' \ + count=$( + tail -n +10 config/combos.dtsi | + grep -Eo '[LR][TMBH][0-9]' | + sort | uniq -c | sort -nr | + awk 'NR==1{print $1}' ) sed -Ei "/CONFIG_ZMK_COMBO_MAX_COMBOS_PER_KEY/s/=.+/=$count/" config/*.conf echo "Setting MAX_COMBOS_PER_KEY to $count" # update maximum keys per combo - count=$( \ - tail -n +10 config/combos.dtsi | \ - grep -o -n '[LR][TMBH][0-9]' | \ - cut -d : -f 1 | uniq -c | sort -nr | \ - awk 'NR==1{print $1}' \ + count=$( + tail -n +10 config/combos.dtsi | + grep -o -n '[LR][TMBH][0-9]' | + cut -d : -f 1 | uniq -c | sort -nr | + awk 'NR==1{print $1}' ) sed -Ei "/CONFIG_ZMK_COMBO_MAX_KEYS_PER_COMBO/s/=.+/=$count/" config/*.conf echo "Setting MAX_KEYS_PER_COMBO to $count" @@ -130,8 +129,7 @@ fi # | BUILD THE FIRMWARE | # +--------------------+ -if [[ $RUNWITH_DOCKER = true ]] -then +if [[ $RUNWITH_DOCKER = true ]]; then echo "Build mode: docker" # DOCKER_CMD="$DOCKER_BIN run --name zmk-$ZEPHYR_VERSION --rm \ DOCKER_CMD="$DOCKER_BIN run --rm \ @@ -143,8 +141,7 @@ then --mount type=volume,source=zmk-zephyr-tools-$ZEPHYR_VERSION,target=$DOCKER_ZMK_DIR/tools" # Reset volumes - if [[ $CLEAR_CACHE = true ]] - then + if [[ $CLEAR_CACHE = true ]]; then $DOCKER_BIN volume rm $($DOCKER_BIN volume ls -q | grep "^zmk-.*-$ZEPHYR_VERSION$") fi @@ -170,19 +167,17 @@ else fi # usage: compile_board board -compile_board () { +compile_board() { BUILD_DIR="${1}_$SUFFIX" LOGFILE="$LOG_DIR/zmk_build_$1.log" [[ $MULTITHREAD = "true" ]] || echo -en "\n$(tput setaf 2)Building $1... $(tput sgr0)" [[ $MULTITHREAD = "true" ]] && echo -e "$(tput setaf 2)Building $1... $(tput sgr0)" $DOCKER_PREFIX west build -d "build/$BUILD_DIR" -b $1 $WEST_OPTS \ - -- -DZMK_CONFIG="$CONFIG_DIR" -Wno-dev > "$LOGFILE" 2>&1 - if [[ $? -eq 0 ]] - then + -- -DZMK_CONFIG="$CONFIG_DIR" -Wno-dev >"$LOGFILE" 2>&1 + if [[ $? -eq 0 ]]; then [[ $MULTITHREAD = "true" ]] || echo "$(tput setaf 2)done$(tput sgr0)" echo "Build log saved to \"$LOGFILE\"." - if [[ -f $HOST_ZMK_DIR/app/build/$BUILD_DIR/zephyr/zmk.uf2 ]] - then + if [[ -f $HOST_ZMK_DIR/app/build/$BUILD_DIR/zephyr/zmk.uf2 ]]; then TYPE="uf2" else TYPE="bin" @@ -200,25 +195,22 @@ compile_board () { cd "$HOST_ZMK_DIR/app" if [[ $MULTITHREAD = "true" ]]; then i=1 - for board in $(echo $BOARDS | sed 's/,/ /g') - do + for board in $(echo $BOARDS | sed 's/,/ /g'); do compile_board $board & eval "T${i}=\${!}" - eval "B${i}=\$board" # Store the board name in a corresponding variable + eval "B${i}=\$board" # Store the board name in a corresponding variable ((i++)) done echo "Starting $(($i - 1)) background threads:" - for ((x=1; x