The installation depends on whether you are using NixOS or home-manager.
Regardless of the chosen approach, the installation consists of:
- Importing this flake's module
- Configuring xremap
Note that flakes are required. If there is a demand for non-flake-based modules -- please feel free to submit an issue.
There are two main ways of running xremap -- as a system service or as a user service. Not all combinations of mode x desktop environment are supported:
| Scenario | No features | KDE | Gnome | X11 | Wlroots |
|---|---|---|---|---|---|
| System | ✔️ | ✖️ | ✖️ | ✔️ | ✖️ |
| User | ✔️ | ✔️ | ✔️ | ❓ | ✔️ |
For all examples in this section you can copy the code into a random flake.nix on your machine and run it in a VM as nix run <path_to_flake>#nixosConfigurations.nixos.config.system.build.vm.
A very simple configuration that globally maps CapsLock to Escape and Ctrl+U to Page Up can look like this:
# flake.nix
{
inputs.xremap-flake.url = "github:xremap/nix-flake";
outputs = inputs@{ nixpkgs, ... }: {
nixosConfigurations.nixos = nixpkgs.lib.nixosSystem {
system = "x86_64-linux";
modules = [
inputs.xremap-flake.nixosModules.default
/* This is effectively an inline module */
{
users.users.root.password = "hunter2";
system.stateVersion = "24.05";
# Modmap for single key rebinds
services.xremap.config.modmap = [
{
name = "Global";
remap = { "CapsLock" = "Esc"; }; # globally remap CapsLock to Esc
}
];
# Keymap for key combo rebinds
services.xremap.config.keymap = [
{
name = "Example ctrl-u > pageup rebind";
remap = { "C-u" = "PAGEUP"; };
# NOTE: no application-specific remaps work without features (see configuration)
}
];
}
];
};
};
}# flake.nix
{
inputs.xremap-flake.url = "github:xremap/nix-flake";
outputs = inputs@{ nixpkgs, ... }: {
nixosConfigurations.nixos = nixpkgs.lib.nixosSystem {
system = "x86_64-linux";
modules = [
inputs.xremap-flake.nixosModules.default
/* This is effectively an inline module */
{
users.users.root.password = "hunter2";
users.users.alice = {
password = "hunter2";
isNormalUser = true;
};
system.stateVersion = "24.05";
# This configures the service to only run for a specific user
services.xremap = {
/* NOTE: since this sample configuration does not have any DE, xremap needs to be started manually by systemctl --user start xremap */
serviceMode = "user";
userName = "alice";
};
# Modmap for single key rebinds
services.xremap.config.modmap = [
{
name = "Global";
remap = { "CapsLock" = "Esc"; }; # globally remap CapsLock to Esc
}
];
# Keymap for key combo rebinds
services.xremap.config.keymap = [
{
name = "Example ctrl-u > pageup rebind";
remap = { "C-u" = "PAGEUP"; };
}
];
}
];
};
};
}# flake.nix
{
inputs.xremap-flake.url = "github:xremap/nix-flake";
outputs = inputs@{ nixpkgs, ... }: {
nixosConfigurations.nixos = nixpkgs.lib.nixosSystem {
system = "x86_64-linux";
modules = [
inputs.xremap-flake.nixosModules.default
/* This is effectively an inline module */
(
{ pkgs, ... }:
{
users.users.root.password = "hunter2";
users.users.alice = {
password = "hunter2";
isNormalUser = true;
extraGroups = [ "wheel" ];
};
system.stateVersion = "24.05";
services.xserver = {
enable = true;
desktopManager.xfce.enable = true; # xfce is just an example
};
environment.systemPackages = [ pkgs.kitty ];
/* Run a single one-shot service that allows root's services to access user's X session */
systemd.user.services.set-xhost = {
description = "Run a one-shot command upon user login";
path = [ pkgs.xorg.xhost ];
wantedBy = [ "default.target" ];
script = "xhost +SI:localuser:root";
environment.DISPLAY = ":0.0"; # NOTE: This is hardcoded for this flake
};
/* Enable X11 feature support */
services.xremap.withX11 = true;
# Modmap for single key rebinds
services.xremap.config.modmap = [
{
name = "Global";
remap = { "CapsLock" = "Esc"; }; # globally remap CapsLock to Esc
}
];
# Keymap for key combo rebinds
services.xremap.config.keymap = [
{
name = "Example ctrl-u > pageup rebind, only for specific application";
remap = { "C-u" = "PAGEUP"; };
application.only = [ "kitty" ];
}
];
}
)
];
};
};
}Since on non-NixOS configurations, the environment outside the user cannot be controlled (e.g. home-manager cannot add the user to uinput), additional steps may be needed. See upstream for more information.
TODO
TODO
There are three categories of options:
-
enabledoption; true by default for mostly historic reasons. -
Options that enable package features (support for X/Wayland) or service configuration.
Feature flags are:
withWlroots,bool– whether to enable wlroots-based compositor support (Sway, Hyprland, etc.)withGnome,bool– whether to enable Gnome supportwithX11,bool– whether to enable X11 supportwithKDE,bool– whether to enable KDE wayland support
All of them are false by default, which means no application-specific remaps work as xremap does not know which application is being used.
serviceMode,str– whether to run as user ("user") or system ("system", default)userName,str– Name of user logging into graphical session (not set by default)userId,int– user under which IPC socket runs (1000 by default)watch,bool– whether to watch for new devices (false by default)mouse,bool– whether to watch for mice (false by default)deviceNames,list of str, – list of devices to monitor (empty by default)extraArgs,list of str, – list of arguments to provide for xremap (empty by default)package– which package for xremap to use. Useful if you want to somehow override the flake-provided package.debug– enables debug logging for xremap (off by default)
-
Options that define xremap's config. See upstream for more options.
They are defined in either
services.xremap.configas a Nix attrset or inservices.xremap.yamlConfigas raw YAML text.
If there is a binding to launch an application that looks like this:
{
name = "apps";
remap.alt-f.launch = [ "pavucontrol" ];
}But nothing happens, and you see this in the logs:
Jan 01 19:30:46 nix xremap[595413]: [2024-01-01T16:30:46Z DEBUG xremap::action_dispatcher] Running command: ["pavucontrol"]
Jan 01 19:30:46 nix xremap[650912]: [2024-01-01T16:30:46Z ERROR xremap::action_dispatcher] Error running command: Os { code: 2, kind: NotFound, message: "No such file or directory" }
This happens because of a discrepancy in $PATH variable between your environment and xremap service.
Two approaches to solve this:
- Use binds to something like
${lib.getExe pkgs.pavucontrol} - (not applicable to all DEs) use the bind to call DE-specific utility, e.g.
hyprctl exec <binary>. This way whatever UI customizations are present on the DE level will get propagated to launched binary.
If you are using X11 and have enabled withX11, but the application-specific keybinds do not work, check the logs (journalctl -u xremap).
Should the logs contain:
Failed to connect to X11: X11 setup failed: 'Authorization required, but no authorization protocol specified
You would need to run xhost +SI:localuser:root. One approach to do this is described in this example config.
Happens if serviceMode == "user" or when using home-manager module; typically because graphical-session.target is not launched automatically.
If you are using a desktop environment (Gnome, KDE, something wlroots-based, etc.) – make sure that the target is started.
If you intend to use xremap without a DE, change systemd.user.services.xremap.wantedBy to some target that starts after you log in or manually start systemctl --user start xremap
Not (yet?) implemented, see #49.
Feel free to submit an issue or reach out to the main contributor of the repo via any other means.