A keyboard remapper daemon for Wayland. Intercepts keyboard input at the evdev level and remaps key combinations based on a TOML config, with per-application rules.
Built to bring macOS-style Cmd+C/Cmd+V shortcuts to Linux by remapping Super+key to Ctrl+key, with the ability to exclude specific apps like terminal emulators.
Physical Keyboard (/dev/input/eventX)
│ ← exclusive grab (EVIOCGRAB)
▼
splash-damage daemon
│
├─ TOML config (remap rules + per-app exclusions)
├─ KWin script + D-Bus (active window detection)
│
▼
Virtual Keyboard (/dev/uinput)
│
▼
KDE Plasma / Applications
The daemon grabs your physical keyboard exclusively, processes each key event through remapping rules, and emits the result through a virtual keyboard device. Active window detection is handled via a KWin script that reports focus changes over D-Bus.
# Build release binary
make build
# Build and install to ~/.local/bin
make installDefault config location: ~/.config/splash-damage/config.toml
copilot_as_meta = true
[[remap]]
from = "super+c"
to = "ctrl+c"
exclude = ["kitty"]
[[remap]]
from = "super+v"
to = "ctrl+v"
exclude = ["kitty"]copilot_as_meta- Whentrue, the Copilot key (which sends Super+Shift+F23) is treated as plain Meta/Super by suppressing the Shift and F23 components. This lets you use the Copilot key with your existing Super+key remaps. Note: Shift+Copilot cannot be distinguished from Copilot alone, since the keyboard firmware already includes Shift in the Copilot scancode. Use Shift+Super instead if you need that combination.
Each [[remap]] entry defines:
from- the key combination to interceptto- the key combination to emit insteadinclude- list of window classes where the remap should apply (if empty, applies everywhere)exclude- list of window classes where the remap should not apply
Both include and exclude match against the active window's resourceClass. If both are specified, include is checked first.
Modifiers: ctrl, shift, alt, super (also meta, cmd, control)
Keys: a-z, 0-9, f1-f24, space, enter, tab, escape/esc, backspace, delete, up, down, left, right, home, end, pageup, pagedown, ., ,, /, ;, ', [, ], \, -, =, `
For shifted symbols like >, use the base key with shift: ctrl+shift+.
Run splash-damage and switch between windows - the log output shows the resource_class for each focused window:
INFO splash_damage::window: active window changed resource_class="chromium" caption="..."
INFO splash_damage::window: active window changed resource_class="kitty" caption="..."
The binary uses Linux capabilities (CAP_DAC_OVERRIDE) to access input devices without root. make install sets this up automatically via setcap.
# With explicit config path
splash-damage /path/to/config.toml
# Uses ~/.config/splash-damage/config.toml by default
splash-damageStop with Ctrl+C - the daemon will clean up the virtual keyboard and KWin script.
To have splash-damage start automatically when you log in:
make enableThis will:
- Build and install the binary to
~/.local/bin(withsetcap) - Install a systemd user service
- Enable and start the service
To rebuild and restart after making changes:
make updateTo check the service status:
systemctl --user status splash-damageTo stop and disable:
make disable- Linux with evdev and uinput support
- Rust toolchain for building
- Per-app window detection currently only supports KDE Plasma 6 (Wayland) via KWin scripting + D-Bus. The core remapping works on any Wayland compositor, but exclude lists require window detection.
PRs are welcome - especially for adding active window detection support for other compositors (Hyprland, Sway, GNOME, etc.).