Keyboard Overlay
Windows-first оверлей клавиатуры для записи экрана и стриминга: пассивный always-on-top оверлей с QWERTY-легендами, настройкой прозрачности и доступом через tray.
Требования
- Rust 1.97.1 (pinned; см.
rust-toolchain.toml:rustfmt,clippy, targetx86_64-pc-windows-gnu) - Windows 10/11 — целевая платформа (ввод, click-through, tray, финальная проверка оверлея)
- Linux — сборка, unit-тесты и CI (без проверки реального оверлея/GPU/tray в headless)
Релизы (Windows x86_64)
При push тега v* Gitea Actions публикует портативный ZIP и NSIS-установщик (per-user, без autostart по умолчанию). Подробности: docs/release.md.
Кратко для Windows:
- Скачайте
keyboard-overlay-<version>-windows-x86_64.zip(portable) илиkeyboard-overlay-<version>-windows-x86_64-setup.exe(installer) из Releases. - Portable: распакуйте архив (
keyboard-overlay.exe+assets/). Installer: установка в%LOCALAPPDATA%\Programs\keyboard-overlay(настройки в%APPDATA%\keyboard-overlayне затрагиваются). - Запустите
keyboard-overlay.exe.KEYBOARD_OVERLAY_ASSETSне нужен, еслиassets/лежит рядом с exe.
SmartScreen / подпись: бинарники и установщик не подписаны; Windows может показать предупреждение SmartScreen — ожидаемо для FOSS без code-signing. Проверяйте SHA256 из SHA256SUMS.txt.
Autostart: opt-in из Settings → «Start with Windows» → Save (HKCU Run). Установщик autostart не включает.
Поддерживаемые артефакты CI: PR собирает Windows GNU + ZIP + NSIS (без публикации); релиз — Windows x86_64. macOS runner отсутствует.
Сборка и запуск
# из корня репозитория
cargo fmt --all -- --check
cargo build --workspace
cargo test --workspace
cargo clippy --workspace --all-targets -- -D warnings
cargo clippy -p keyboard-overlay-app --target x86_64-pc-windows-gnu -- -D warnings
# запуск (нужен дисплей / WGPU-адаптер)
# из dev-сборки assets берутся из корня репозитория или задаются явно:
export KEYBOARD_OVERLAY_ASSETS="$PWD/assets" # опционально для cargo run из произвольного cwd
cargo run -p keyboard-overlay-app
Windows (PowerShell):
$env:KEYBOARD_OVERLAY_ASSETS = "$PWD\assets"
cargo run -p keyboard-overlay-app
Откроется оверлей (клавиши + легенды из layout JSON). Окно настроек по умолчанию скрыто — откройте его через иконку в системном трее (Show settings). Закрытие окна настроек скрывает его, не завершая приложение (Quit — только из tray). В Settings есть Show overlay и глобальная комбинация переключения (по умолчанию Ctrl+Shift+F12); настройка комбинации и показ работают сразу, Save settings сохраняет их. Окно Settings не уменьшается меньше 500×500 logical px.
Переменные окружения
| Переменная | Назначение |
|---|---|
KEYBOARD_OVERLAY_CONFIG_DIR |
База пользовательского конфига (по умолчанию %APPDATA% / ~/.config) |
KEYBOARD_OVERLAY_ASSETS |
Каталог поставляемых JSON; при первом запуске они копируются в пользовательские layouts/ и themes/, если файлов с теми же именами ещё нет |
Структура workspace
| Crate | Назначение |
|---|---|
keyboard-overlay-config |
Чистая схема JSON/TOML, валидация, пути |
keyboard-overlay-app |
winit/wgpu/egui, оверлей, Windows-ввод |
Поставка содержит JSON-файлы: два layout — assets/layouts/60-ansi-en-v1.json (60% EN reference) и assets/layouts/60-ansi-ru-v1.json (60% RU reference, те же physical id); три theme — assets/themes/default-v1.json, assets/themes/finger-standard-v1.json, assets/themes/finger-touch-reference-v1.json. При первом запуске они появляются в пользовательском каталоге конфигурации. Settings показывает только эти JSON-файлы и пользовательские JSON, добавленные вручную в layouts/ или themes/; кнопок Open, Import и Save copy нет. Кнопка Restore built-in layouts and themes… после подтверждения снова копирует поставляемые JSON, заменяя только файлы с теми же именами и сохраняя прочие пользовательские JSON.
Reference 60% EN + RU (defaults и dual-legend)
По умолчанию активен 60-ansi-en-v1 + default-v1. Для EN/RU dual-legend выберите в Settings:
| Параметр | Значение |
|---|---|
| Layout | 60% ANSI EN (Reference) |
| Secondary layout | 60% ANSI RU (Reference) |
| Theme | Finger Touch (Reference) (опционально) |
Компактная 60% геометрия (58 keys, 15×5 grid) без Esc, стрелок, навигации, Win и Fn. Физическая клавиша Ё/backquote (VK_OEM_3) подсвечивает id grave. Ячейки сетки квадратные по построению: KEY_UNIT_BASE задаёт одинаковую ширину и высоту grid-единицы, padding симметричен.
Dual-legend: primary upper-left, secondary lower-right. На number row inline Shift-легенды (secondary_label в JSON): EN 1/!, RU 3/№ и т.д. При EN+RU cross-layout: буквы Q/Й, grave `/Ё, number row — inline Shift (1/!) имеет приоритет над cross-layout. Модификаторы и utility keys — single-centered, без secondary_label.
Миграция settings (при загрузке settings.toml): старые bundled-ссылки сначала сопоставляются, затем становятся обычными ссылками на JSON-файлы в пользовательских каталогах.
| Было (bundled) | Стало |
|---|---|
active 65-ansi-v1 |
60-ansi-en-v1 |
active 65-ansi-ru-v1 |
60-ansi-ru-v1 |
active 60-ansi-ru-number-legends-v1 |
60-ansi-ru-v1 |
active 60-ansi-en-ru-secondary-v1 |
60-ansi-ru-v1 |
secondary 60-ansi-ru-number-legends-v1 |
none |
secondary 60-ansi-en-ru-secondary-v1 |
60-ansi-ru-v1 если primary EN, иначе none |
secondary 65-ansi-ru-v1 |
60-ansi-ru-v1 если primary EN (после миграции primary), иначе none |
secondary 65-ansi-v1 |
60-ansi-en-v1 если primary RU (после миграции primary), иначе none |
Ограничения JSON-схемы (намеренно не воспроизводятся): точки homing на Ф/А (F/J) и круговой индикатор нажатия из референс-скрина — вне layout/theme JSON. Подсветка нажатой клавиши — тот же RGB, что у зоны/фона клавиши (resolve_key_rgb); отличие idle/pressed — только alpha через Pressed opacity, а не кольцевой overlay.
Пользовательский конфиг:
keyboard-overlay/
├── settings.toml
├── layouts/*.json
└── themes/*.json
Профили JSON v1
Layout (keyboard-overlay.layout, version 1)
- Уникальные
idклавиш - Геометрия в grid-единицах:
x,y,w,h> 0 - Опционально
secondary_label— inline Shift-легенда (lower-right); запрещена на utility/modifier/navigation keys
Theme (keyboard-overlay.theme, version 1 or 2)
segments: 1..=8 цветов#RRGGBB(fallback base / reserved / label)- v2 (optional):
palette+keys— per-key цвета по индексу палитры (или массиву индексов для равной L→R раскраски; finger themes). v1 themes без этих полей работают как раньше.
Восстановление профилей
Если settings.toml ссылается на отсутствующий layout или theme, приложение до запуска показывает явное окно с путём каталога и предлагает восстановить встроенные JSON. После подтверждения оно копирует поставляемые файлы и автоматически выбирает первый доступный layout/theme, если прежняя ссылка по-прежнему отсутствует. Отказ не скрывается: приложение показывает явную ошибку вместо тихого завершения.
Ошибки чтения settings.toml, создания пользовательских каталогов, копирования или разбора JSON также показываются в native error dialog.
Save settings (settings.toml) сохраняет активные ссылки и параметры оверлея: позиция, масштаб, видимость, hotkey, Idle opacity (idle_opacity), Pressed opacity (pressed_opacity) и Text contrast (text_contrast: off / outline, по умолчанию outline). По умолчанию: idle 20%, pressed 100% — приглушённая клавиатура в покое, нажатая клавиша полностью непрозрачна. Outline добавляет 1px auto-contrast halo вокруг ink легенд (чёрный на светлом fill, белый на тёмном). Позиция, масштаб, opacity и text contrast применяются live в том же цикле redraw настроек; Save settings записывает текущие значения на диск. Устаревшие поля TOML opacity и key_alpha при загрузке мигрируют в idle_opacity; отсутствующий text_contrast мигрирует в outline (не off); label_alpha сохраняется для совместимости, но не влияет на live-рендер.
Features
native-dialogs(по умолчанию) —rfdдля явных ошибок и подтверждений восстановления; отключить:--no-default-features
Документация
- CONTRIBUTING.md — ветки, PR, release policy, CI checks
- docs/release.md — CI/CD, секрет
RELEASE_TOKEN, скачивание Windows ZIP - docs/architecture.md — границы модулей и платформы
- docs/decisions/0001-rust-winit-wgpu.md — ADR по стеку
Ограничения / ручная проверка
- Windows-ввод реализован за
cfg(windows); на Linux — stub без реального polling. На Windows RAlt (AltGr) синтезирует LCtrl — overlay скрывает synthetic LCtrl через per-frame modifier snapshot (ModifierTracker), сохраняя реальный LCtrl и не скрывая RAlt. Ограничение API:GetAsyncKeyStateне различает повторное физическое LCtrl и synthetic LCtrl после сценария Ctrl→RAlt с отпусканием Ctrl при удержанном RAlt; overlay детерминированно скрывает LCtrl до отпускания RAlt (приоритет — корректный RAlt-alone и начальный Ctrl-before-RAlt chord). Точное различение потребовало бы raw input / low-level hook. - Tray и Win32 extended styles (click-through, topmost) — только Windows; Linux CI их не исполняет
- GPU-рендер и tray не покрыты headless-автотестами; на Windows нужна ручная проверка: легенды видны и не перевёрнуты, ink optically centered на single keys, click-through работает, idle/pressed opacity live, Text contrast Outline/Off live (outline halo виден на светлом/тёмном fill, Off без halo), minimize settings без panic, tray Show/Quit, RU layout и finger theme в ComboBox, RAlt подсвечивает только RAlt (не LCtrl), LCtrl+RAlt chord показывает оба, LAlt без артефактов