From 5f4d7c1d77850b59f104e2efc1b9018cbd320267 Mon Sep 17 00:00:00 2001 From: simsalaba Date: Wed, 29 Apr 2026 16:16:26 +0200 Subject: [PATCH] Restore Swedish symbol keycodes, add local build script - Restore original Swedish-layout keycodes in Symbols layer (RS/RA combos) that were accidentally replaced with US keycodes in an earlier commit - Increase press debounce from 1ms to 3ms to prevent ghost key repeats - Add build.sh: GitHub Actions build+download (default) or local Docker build - Update KEYMAP.md with build instructions and Swedish layout note Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .gitignore | 4 + KEYMAP.md | 25 ++++++ build.sh | 210 ++++++++++++++++++++++++++++++++++++++++++++ config/corne.keymap | 12 +-- 4 files changed, 245 insertions(+), 6 deletions(-) create mode 100755 build.sh diff --git a/.gitignore b/.gitignore index e43b0f9..c0aaf44 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,5 @@ .DS_Store +firmware/ +build/ +.west_cache/ +.zmk_build/ diff --git a/KEYMAP.md b/KEYMAP.md index b409097..a6c18bc 100644 --- a/KEYMAP.md +++ b/KEYMAP.md @@ -7,6 +7,27 @@ ## 🔌 Flashing Firmware +### Building + +```bash +# Recommended: build via GitHub Actions (fast) +./build.sh + +# Or build locally with Docker (slow on Apple Silicon) +./build.sh local + +# Build only one half locally +./build.sh local left + +# Clean build cache +./build.sh clean +``` + +The default `./build.sh` pushes your current branch, triggers GitHub Actions, +waits for the build, and downloads the `.uf2` files to `firmware/`. + +### Flashing + 1. Download both `.uf2` files from the latest GitHub Actions build 2. Connect one half via USB 3. **Double-tap the reset button** → a USB drive called `NICENANO` appears @@ -94,6 +115,10 @@ Activated by holding the **left thumb middle key** (NUM). Activated by holding the **right thumb middle key** (CHARS). +> **Note:** This layer uses Swedish-specific HID keycodes (e.g., `RS(N6)` for `&`, +> `RA(N2)` for `@`). The comments show the actual character produced on a +> Swedish OS keyboard layout. + ``` ┌──────┬──────┬──────┬──────┬──────┬──────┐ ┌──────┬──────┬──────┬──────┬──────┬──────┐ │ & │ * │ @ │ { │ } │ | │ │ + │ - │ │ │ = │ DEL │ diff --git a/build.sh b/build.sh new file mode 100755 index 0000000..aed28cf --- /dev/null +++ b/build.sh @@ -0,0 +1,210 @@ +#!/usr/bin/env bash +# ZMK firmware build script +# Supports two build methods: +# ./build.sh → trigger GitHub Actions build and download firmware +# ./build.sh local → build locally using Docker (slow on Apple Silicon!) +# ./build.sh clean → clean local build cache +# +# GitHub Actions mode (default): +# Commits and pushes current changes to a build branch, triggers CI, +# waits for completion, and downloads the .uf2 files to firmware/ +# +# Local Docker mode: +# Uses zmkfirmware/zmk-build-arm Docker image. First build takes ~30 min +# to download ZMK+Zephyr deps. Subsequent builds are faster (~2 min). +# NOTE: Very slow on Apple Silicon Macs due to x86 emulation via Rosetta. + +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +OUTPUT_DIR="$SCRIPT_DIR/firmware" + +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +CYAN='\033[0;36m' +NC='\033[0m' + +#────────────────────────────────────────────── +# GitHub Actions build (default) +#────────────────────────────────────────────── +build_ci() { + echo -e "${YELLOW}▶ Building via GitHub Actions...${NC}" + + # Get repo info from git remote + local remote_url + remote_url=$(git -C "$SCRIPT_DIR" remote get-url origin 2>/dev/null) + local owner repo + if [[ "$remote_url" =~ github.com[:/]([^/]+)/([^/.]+) ]]; then + owner="${BASH_REMATCH[1]}" + repo="${BASH_REMATCH[2]}" + else + echo -e "${RED}✗ Could not parse GitHub owner/repo from remote: $remote_url${NC}" + exit 1 + fi + + # Check for uncommitted changes + if ! git -C "$SCRIPT_DIR" diff --quiet HEAD 2>/dev/null; then + echo -e "${YELLOW} You have uncommitted changes. Commit them first.${NC}" + exit 1 + fi + + # Push current branch + local branch + branch=$(git -C "$SCRIPT_DIR" rev-parse --abbrev-ref HEAD) + echo -e "${CYAN} Pushing ${branch} to origin...${NC}" + git -C "$SCRIPT_DIR" push origin "$branch" 2>&1 | tail -3 + + # Wait for workflow to start + echo -e "${CYAN} Waiting for GitHub Actions workflow to start...${NC}" + sleep 5 + + # Find the latest workflow run + local run_id status conclusion + for i in $(seq 1 60); do + run_id=$(gh api "repos/$owner/$repo/actions/runs?branch=$branch&per_page=1" \ + --jq '.workflow_runs[0].id' 2>/dev/null || echo "") + status=$(gh api "repos/$owner/$repo/actions/runs?branch=$branch&per_page=1" \ + --jq '.workflow_runs[0].status' 2>/dev/null || echo "") + + if [ -n "$run_id" ] && [ "$status" = "completed" ]; then + conclusion=$(gh api "repos/$owner/$repo/actions/runs/$run_id" \ + --jq '.conclusion' 2>/dev/null || echo "") + break + elif [ -n "$run_id" ] && [ "$status" != "completed" ]; then + printf "\r ⏳ Run #%s status: %-15s (attempt %d/60)" "$run_id" "$status" "$i" + sleep 10 + else + printf "\r ⏳ Waiting for run to appear... (attempt %d/60)" "$i" + sleep 5 + fi + done + echo "" + + if [ "$conclusion" != "success" ]; then + echo -e "${RED}✗ Build failed (conclusion: $conclusion)${NC}" + echo -e "${RED} Check: https://github.com/$owner/$repo/actions/runs/$run_id${NC}" + exit 1 + fi + + echo -e "${GREEN}✓ Build succeeded!${NC}" + + # Download artifacts + mkdir -p "$OUTPUT_DIR" + echo -e "${CYAN} Downloading firmware artifacts...${NC}" + cd "$OUTPUT_DIR" + gh run download "$run_id" -R "$owner/$repo" 2>&1 || true + + # Move .uf2 files to firmware root + find . -name "*.uf2" -mindepth 2 -exec mv {} . \; 2>/dev/null + find . -type d -empty -delete 2>/dev/null + + echo "" + echo -e "${GREEN}═══════════════════════════════════════════${NC}" + echo -e "${GREEN} Firmware ready in: firmware/ ${NC}" + echo -e "${GREEN}═══════════════════════════════════════════${NC}" + ls -lh "$OUTPUT_DIR"/*.uf2 2>/dev/null || echo " (no .uf2 files found)" +} + +#────────────────────────────────────────────── +# Local Docker build +#────────────────────────────────────────────── +build_local() { + local DOCKER_IMAGE="zmkfirmware/zmk-build-arm:3.5" + local WORKSPACE="$SCRIPT_DIR/.zmk_build" + local BOARD="nice_nano_v2" + local side="${1:-both}" + + # Warn on Apple Silicon + if [ "$(uname -m)" = "arm64" ]; then + echo -e "${YELLOW}⚠ Apple Silicon detected — Docker build uses x86 emulation (slow!)${NC}" + echo -e "${YELLOW} Consider using './build.sh' (GitHub Actions) instead.${NC}" + echo "" + fi + + echo -e "${YELLOW}▶ Checking Docker image...${NC}" + if ! docker image inspect "$DOCKER_IMAGE" &>/dev/null; then + echo -e "${YELLOW} Pulling ${DOCKER_IMAGE} (first time only)...${NC}" + docker pull "$DOCKER_IMAGE" + fi + + mkdir -p "$WORKSPACE" + + local shields_left="corne_left nice_view_adapter nice_view" + local shields_right="corne_right nice_view_adapter nice_view" + + build_docker_side() { + local s=$1 shields=$2 + echo -e "${YELLOW}▶ Building ${s} half...${NC}" + docker run --rm \ + -v "$WORKSPACE:/zmk_ws" \ + -v "$SCRIPT_DIR/config:/zmk_ws/config" \ + -w /zmk_ws \ + "$DOCKER_IMAGE" \ + sh -c " + set -e + if [ ! -f .west/config ]; then + echo '==> Initializing west workspace...' + west init -l config + fi + echo '==> Updating modules...' + west update + west zephyr-export + echo '==> Building ${s}...' + west build -s zmk/app -b ${BOARD} -d build/${s} -p auto \ + -- -DSHIELD=\"${shields}\" -DZMK_CONFIG=/zmk_ws/config + " + local uf2="$WORKSPACE/build/${s}/zephyr/zmk.uf2" + if [ -f "$uf2" ]; then + mkdir -p "$OUTPUT_DIR" + cp "$uf2" "$OUTPUT_DIR/${BOARD}-${s}.uf2" + echo -e "${GREEN}✓ ${s} → firmware/${BOARD}-${s}.uf2${NC}" + else + echo -e "${RED}✗ ${s} build failed${NC}" + return 1 + fi + } + + case "$side" in + left) build_docker_side "left" "$shields_left" ;; + right) build_docker_side "right" "$shields_right" ;; + both) + build_docker_side "left" "$shields_left" + build_docker_side "right" "$shields_right" + ;; + esac + + echo "" + echo -e "${GREEN}═══════════════════════════════════════════${NC}" + echo -e "${GREEN} Firmware ready in: firmware/ ${NC}" + echo -e "${GREEN}═══════════════════════════════════════════${NC}" + ls -lh "$OUTPUT_DIR"/*.uf2 2>/dev/null || true +} + +#────────────────────────────────────────────── +# Main +#────────────────────────────────────────────── +case "${1:-ci}" in + ci|"") build_ci ;; + local) build_local "${2:-both}" ;; + clean) + echo -e "${YELLOW}▶ Cleaning local build cache...${NC}" + rm -rf "$SCRIPT_DIR/.zmk_build/build" "$OUTPUT_DIR" + echo -e "${GREEN}✓ Cleaned${NC}" + ;; + help|-h|--help) + echo "Usage: ./build.sh [command]" + echo "" + echo "Commands:" + echo " (default) Build via GitHub Actions (fast, recommended)" + echo " local [side] Build locally with Docker (side: left|right|both)" + echo " clean Remove local build cache and firmware" + echo " help Show this help" + ;; + *) + echo "Unknown command: $1 (try: ./build.sh help)" + exit 1 + ;; +esac + + diff --git a/config/corne.keymap b/config/corne.keymap index 94abe1e..1319f87 100644 --- a/config/corne.keymap +++ b/config/corne.keymap @@ -114,18 +114,18 @@ ZMK_LAYER(Numbers, ZMK_LAYER(Symbols, - // RAISE Layer: Special Chars + // RAISE Layer: Special Chars (Swedish OS layout keycodes) // .--------------------------------------------------------------. .-----------------------------------------------------------. - // | & | * | @ | { | } | | | | + | - | | | | DEL | - &kp AMPERSAND &kp ASTERISK &kp AT &kp LEFT_BRACE &kp RIGHT_BRACE &kp PIPE &kp PLUS &kp MINUS ___ ___ &kp EQUAL &kp DELETE + // | & | * | @ | { | } | | | | + | - | | | = | DEL | + &kp RS(N6) &kp RS(BSLH) &kp RA(N2) &kp RS(RA(N8)) &kp RS(RA(N9)) &kp RA(N7) &kp MINUS &kp RS(FSLH) ___ ___ &kp RS(N0) &kp DELETE // |--------------+---------+--------+--------+---------+---------| |-------+---------+---------+---------+----------+----------| // | # | | $ | ( | ) | ` | | ! | _ | | / | \ | ' | - &kp HASH ___ &kp DOLLAR &kp LPAR &kp RPAR &kp GRAVE &kp EXCLAMATION &kp UNDERSCORE ___ &kp SLASH &kp BACKSLASH &kp APOSTROPHE + &kp RS(N3) ___ &kp RA(N4) &kp RS(N8) &kp RS(N9) &kp RS(EQUAL) &kp RS(N1) &kp FSLH ___ &kp RS(N7) &kp RS(RA(N7)) &kp BSLH // |--------------+---------+--------+--------+---------+---------| |-------+---------+---------+---------+----------+----------| // | % | | ^ | [ | ] | ~ | | ? | = | , | < | > | "" | - &kp PERCENT ___ &kp CARET &kp LEFT_BRACKET &kp RIGHT_BRACKET &kp TILDE &kp QUESTION &kp EQUAL &kp COMMA &kp LESS_THAN &kp GREATER_THAN &kp DQT + &kp RS(N5) ___ &kp RS(RBKT) &kp RA(N8) &kp RA(N9) &kp RA(RBKT) &kp RS(MINUS) &kp RS(N0) &kp COMMA &kp GRAVE &kp RS(GRAVE) &kp RS(N2) // '---------------------------------+--------+---------+---------+ |-------+---------+---------+-------------------------------' - // | | | | | | | | + // | | NUM | | | | | | ___ &mo 1 ___ ___ ___ ___ // '--------+---------+---------' '-------+---------+---------' )