- Rust 96.2%
- C 1.7%
- NSIS 1.4%
- PowerShell 0.7%
| docs | ||
| packaging | ||
| protocol | ||
| src | ||
| .gitignore | ||
| build.rs | ||
| Cargo.lock | ||
| Cargo.toml | ||
| LICENSE | ||
| README.md | ||
kb-layerd
kb-layerd is a small daemon that reads layer telemetry from a QMK
keyboard using a custom protocol and makes the current state available locally.
For those looking for more information on this protocol and how to implement it
in their own keyboard's firmware, see the protocol directory.
This package builds two shared and one Windows-specific binary:
kb-layerd: the daemonkb-layerctl: a CLI for checking status and watching updateskb-layerui: a Windows-only per-user supervisor process
Configuration
By default, kb-layerd looks for a config file at:
- Linux:
$XDG_CONFIG_HOME/kb-layerd/config.toml - Linux fallback:
~/.config/kb-layerd/config.toml - Windows:
%APPDATA%\kb-layerd\config.toml - Windows fallback:
%LOCALAPPDATA%\kb-layerd\config.toml
Windows UI-specific settings live in a separate file beside the main config:
- Windows UI config:
%APPDATA%\kb-layerd\ui.toml - Windows UI fallback:
%LOCALAPPDATA%\kb-layerd\ui.toml
Example:
[device]
vid = 0x1234
pid = 0xabcd
# serial = "EXAMPLE0000000001"
[polling]
interval_ms = 10
read_timeout_ms = 100
[runtime]
ipc_path = "$XDG_RUNTIME_DIR/kb-layerd/socket"
[logging]
level = "warn"
You must set either:
device.serial- or both
device.vidanddevice.pid
You can also let kb-layerctl create or update the config file for you.
After changing the config file, restart the daemon so it picks up the new
settings. The exact restart command depends on how you installed or launched
the daemon. If you run it as a Linux user unit, that is typically:
systemctl --user restart kb-layerd
[logging]:
- default:
warn - verbose file logging:
debug
On Windows, kb-layerd writes to %LOCALAPPDATA%\kb-layerd\logs\kb-layerd.log
and kb-layerui writes to %LOCALAPPDATA%\kb-layerd\logs\kb-layerui.log.
The Windows UI config file is separate from the daemon config and is created on
first kb-layerui startup. Example:
label_prefix = "L"
label_suffix = ""
popup_enabled = true
[animation]
fade_in_ms = 120
hold_ms = 700
fade_out_ms = 180
slide_offset_px = 18
slide_direction = "up"
Build
cargo build --release
A release build also generates the kb-layerctl man pages and shell
completions in:
target/release/package-assets/man/
target/release/package-assets/completions/
On Windows this also builds kb-layerui.exe.
Linux Installation
Install via RPM with:
sudo dnf install kb-layerd-0.1.2-1.x86_64.rpm
After installing the RPM, the expected setup flow is:
kb-layerctl --human discover
kb-layerctl set-device --serial EXAMPLE0000000001
systemctl --user daemon-reload
systemctl --user enable --now kb-layerd.service
This will create the systemd unit, but it does not create per-user config or start the service automatically.
After installing the RPM, man pages are available with:
man kb-layerctl
Subcommand manuals are also installed, for example:
man kb-layerctl-set-device
Shell completions are also installed for bash, fish, and zsh.
Open a new shell after installing the RPM so your shell can load the new
completion files. Bash users also need the distro bash-completion package
installed and enabled.
Upgrade
Install with dnf:
sudo dnf install ./kb-layerd-0.1.0-1.x86_64.rpm
If kb-layerd is already running as a user service, reload the user systemd
manager and restart the daemon after the package upgrade:
systemctl --user daemon-reload
systemctl --user restart kb-layerd.service
The upgrade replaces package-owned files such as the binaries, user unit, man pages, and license. It does not overwrite the user's own config file.
Uninstall
If the daemon is running as a user service, stop and disable it first:
systemctl --user disable --now kb-layerd.service
Then remove the package:
sudo dnf remove kb-layerd
Removing the RPM deletes only package-owned files. It does not remove
~/.config/kb-layerd/config.toml, runtime sockets under $XDG_RUNTIME_DIR, or
any udev rule that you created manually.
Windows Installation
The repository includes an NSIS installer script at:
packaging/windows/kb-layerd.nsi
To build an installer on Windows:
- Install NSIS so
makensisis onPATH. - From the repo root, run:
powershell -ExecutionPolicy Bypass -File .\packaging\windows\build-installer.ps1
This:
- builds the release binaries
- packages
kb-layerd.exe,kb-layerctl.exe,kb-layerui.exe - builds
docs/windows-help.html - builds
docs/THIRD-PARTY-NOTICES.txt - puts the installer under
target/windows-installer/
The installer will install into:
%LOCALAPPDATA%\Programs\kb-layerd\
by default.
The installer:
- creates a Startup-folder shortcut for
kb-layerui.exe - registers an uninstall entry under the current user
- launches
kb-layerui.exeafter install
The installer does not modify the user PATH. If you want to run
kb-layerctl directly from PowerShell or Command Prompt, either:
- call it by full path:
& "$env:LOCALAPPDATA\Programs\kb-layerd\kb-layerctl.exe" --help
- or add this directory to your user
PATHmanually:
%LOCALAPPDATA%\Programs\kb-layerd\
After editing PATH, close any open terminal windows and start a new one.
Troubleshooting
-
If the daemon cannot find your keyboard, double-check the configured
vid/pidorserial. -
If daemon status shows
reason=hid_open_failed, or the logs show a HID open permission error, your user may not have access to the keyboard'shidrawnode on Linux. In that case, create a udev rule such as:KERNEL=="hidraw*", SUBSYSTEM=="hidraw", SUBSYSTEMS=="usb", ATTRS{idVendor}=="1234", ATTRS{idProduct}=="abcd", TAG+="uaccess"Save it as
/etc/udev/rules.d/70-kb-layerd.rules, then reload udev rules and re-apply them:sudo udevadm control --reload-rules sudo udevadm triggerAfter that, unplug and reconnect the keyboard if needed, then restart the daemon using whatever process manager or launch method you installed it with. If you run it as a Linux user unit, use:
systemctl --user restart kb-layerd -
If startup fails on Linux with an IPC-path error, either set
runtime.ipc_pathexplicitly or make sureXDG_RUNTIME_DIRis set. -
On Windows,
kb-layerctl shutdownasks the daemon to exit cleanly over its per-user named pipe.