feat: initial release of SplitOverlay (KeyOverlay 1.0.0)
CI / build-and-test (push) Canceled after 0s

Semi-transparent always-on-top Windows overlay that shows the keymap of a
Vial/QMK split keyboard (Silakka54).

- draws all layers from a Vial .vil layout, transparent keys fall through
- detects the active layer from the keyboard via a Raw HID command (firmware/)
- shows characters of the active Windows input language
- can split the two halves into separate, independently movable windows
- highlights pressed keys; tray menu for opacity, size and options
- Inno Setup installer and portable build; GitHub-style CI workflow
This commit is contained in:
2026-10-20 09:43:17 +03:00
commit 292d61bb47
48 changed files with 2952 additions and 0 deletions
+6
View File
@@ -0,0 +1,6 @@
# Build image for the Vial firmware: QMK base container + ARM toolchain + qmk CLI.
FROM ghcr.io/qmk/qmk_base_container:latest
RUN apt-get update \
&& apt-get install -y --no-install-recommends gcc-arm-none-eabi binutils-arm-none-eabi libnewlib-arm-none-eabi \
&& rm -rf /var/lib/apt/lists/* \
&& pip3 install --break-system-packages --root-user-action=ignore -q qmk
+53
View File
@@ -0,0 +1,53 @@
# Прошивка Silakka54 (LED, v1.4led) с командой «какой слой активен»
Это исходники релиза [v1.4led](https://github.com/Squalius-cephalus/silakka54/releases/tag/v1.4led)
(keymap `vial_led`, подсветка слоёв) плюс файл `keyoverlay_hid.c`. Он добавляет HID-команду `0xE0`:
оверлей спрашивает плату, и плата отвечает номером активного слоя. Раскладку и LED команда не затрагивает,
работает и при заблокированном Vial.
## Протокол
Запрос (хост → клавиатура, Raw HID, 32 байта): `[0xE0, 0x01, ...]`
Ответ: `[0xE0, 0x01, highest_layer, layer_state (u32 LE), default_layer_state (u32 LE), ...]`
Номер `0xE0` не пересекается с командами VIA (`0x01..0x1F`), Vial (`0xFE`) и «не обработано» (`0xFF`).
Прошивка только читает состояние. Слой отдаёт та половина, которая подключена к ПК (главная).
## Готовые файлы
Собранные `.uf2` лежат в Releases (в git они не хранятся):
- `silakka54_vial_led_keyoverlay_LEFT.uf2` — в левую половину, собран с `MASTER_LEFT`
- `silakka54_vial_led_keyoverlay_RIGHT.uf2` — в правую половину, собран с `MASTER_RIGHT`
LEFT и RIGHT различаются тем, какая половина считается главной (определяет, в какую USB-розетку
втыкать кабель), как и в оригинальных релизах проекта.
## Прошивка платы (RP2040)
1. В Vial: File → Save current layout. После обновления прошивки раскладка может сброситься.
2. Закрой Vial и оверлей. Отключи кабель между половинами (TRRS) на время прошивки.
3. Зажми BOOT на плате и подключи USB (или дважды быстро нажми reset). Появится диск RPI-RP2.
4. Скопируй на него файл своей половины. Плата перезагрузится сама. Повтори для второй половины.
5. Подключи половины обратно. В Vial загрузи сохранённую раскладку (File → Load saved layout), если слои пропали.
Откат: прошей оригинальные `silakka54_vial_led_LEFT.uf2` / `..._RIGHT.uf2` из
[релиза v1.4led](https://github.com/Squalius-cephalus/silakka54/releases/tag/v1.4led) тем же способом.
## Сборка
Нужны Git, bash и Docker.
```
bash firmware/prepare-source.sh # клонирует vial-qmk и silakka54 (v1.4led) в .firmware-work/ и добавляет команду
docker build -t keyoverlay-fw-build firmware
docker run --rm -v "$PWD/.firmware-work/vial-qmk:/qmk_firmware" -v "$PWD/firmware:/fw" -w /qmk_firmware keyoverlay-fw-build sh /fw/build-in-container.sh
```
(В PowerShell вместо `$PWD/...` используй полные пути: `-v C:\путь\.firmware-work\vial-qmk:/qmk_firmware`.)
Готовые файлы появятся в `.firmware-work/vial-qmk/` как `silakka54_vial_led_keyoverlay_LEFT.uf2` и `..._RIGHT.uf2`.
Первая сборка долгая (десятки минут на смонтированной папке Windows), повторные быстрее.
Образ Docker (`Dockerfile`) добавляет к базовому образу QMK компилятор ARM и утилиту `qmk`.
Файл `keyoverlay_hid.c` распространяется под GPL-2.0-or-later, как и QMK/Vial, в который он собирается.
+18
View File
@@ -0,0 +1,18 @@
#!/bin/sh
# Runs inside the keyoverlay-fw-build image with vial-qmk mounted at /qmk_firmware.
# Builds the silakka54 vial_led keymap twice: MASTER_LEFT (left half, USB side) and MASTER_RIGHT.
set -e
cd /qmk_firmware
git config --global --add safe.directory '*'
KEYMAP_CFG=keyboards/silakka54led/keymaps/vial_led/config.h
sed -i "/MASTER_/d" "$KEYMAP_CFG" # drop leftovers from an interrupted run
cp "$KEYMAP_CFG" /tmp/config.h.orig
for SIDE in LEFT RIGHT; do
cp /tmp/config.h.orig "$KEYMAP_CFG"
printf '\n#define MASTER_%s\n' "$SIDE" >> "$KEYMAP_CFG"
make silakka54led:vial_led
cp silakka54led_vial_led.uf2 "silakka54_vial_led_keyoverlay_$SIDE.uf2"
done
cp /tmp/config.h.orig "$KEYMAP_CFG"
ls -la silakka54_vial_led_keyoverlay_*.uf2
+31
View File
@@ -0,0 +1,31 @@
// SPDX-License-Identifier: GPL-2.0-or-later
//
// KeyOverlay: lets the host ask which layer is active.
//
// Request (host -> keyboard): [0xE0, 0x01, ...]
// Response (keyboard -> host): [0xE0, 0x01, highest_layer, layer_state (u32 LE), default_layer_state (u32 LE), ...]
//
// 0xE0 is outside the ids used by VIA (0x01..0x1F), Vial (0xFE) and "unhandled" (0xFF).
// Only reads state; it changes nothing on the keyboard and works while Vial is locked.
#include QMK_KEYBOARD_H
#include "raw_hid.h"
#include <string.h>
#define KEYOVERLAY_CMD 0xE0
#define KEYOVERLAY_PROTOCOL 0x01
#define KEYOVERLAY_ID_UNHANDLED 0xFF
#define KEYOVERLAY_MIN_LENGTH 11
void raw_hid_receive_kb(uint8_t *data, uint8_t length) {
if (data[0] != KEYOVERLAY_CMD || length < KEYOVERLAY_MIN_LENGTH) {
data[0] = KEYOVERLAY_ID_UNHANDLED;
return;
}
const uint32_t active = (uint32_t)layer_state;
const uint32_t default_ = (uint32_t)default_layer_state;
data[1] = KEYOVERLAY_PROTOCOL;
data[2] = get_highest_layer(layer_state | default_layer_state);
memcpy(&data[3], &active, sizeof(active));
memcpy(&data[7], &default_, sizeof(default_));
}
+32
View File
@@ -0,0 +1,32 @@
#!/usr/bin/env bash
# Prepares the firmware source tree: vial-qmk + the Silakka54 LED keymap (v1.4led) + the KeyOverlay HID command.
# Usage: bash firmware/prepare-source.sh [work-dir] (default work-dir: .firmware-work next to this repo)
# Safe to run again: sources are only cloned once, copied files are refreshed.
set -euo pipefail
HERE="$(cd "$(dirname "$0")" && pwd)"
WORK="${1:-$HERE/../.firmware-work}"
QMK="$WORK/vial-qmk"
SRC="$WORK/silakka54-src"
DEST="$QMK/keyboards/silakka54led"
mkdir -p "$WORK"
if [ ! -d "$QMK" ]; then
git clone --depth 1 --branch vial https://github.com/vial-kb/vial-qmk.git "$QMK"
git -C "$QMK" submodule update --init --depth 1 --recursive
fi
if [ ! -d "$SRC" ]; then
git clone --depth 1 --branch v1.4led https://github.com/Squalius-cephalus/silakka54.git "$SRC"
fi
# The LED keymap lives in the silakka54 repo, not in vial-qmk: copy it in as its own keyboard folder.
mkdir -p "$DEST"
cp -r "$SRC/firmware/." "$DEST/"
cp "$HERE/keyoverlay_hid.c" "$DEST/keymaps/vial_led/"
RULES="$DEST/keymaps/vial_led/rules.mk"
grep -q "keyoverlay_hid.c" "$RULES" || printf '\nSRC += keyoverlay_hid.c\n' >> "$RULES"
echo "Firmware source ready in: $QMK"
echo "Next: docker build -t keyoverlay-fw-build firmware, then run firmware/build-in-container.sh (see firmware/README.md)"