1 { config, lib, pkgs, ... }:
4 cfg = config.services.keyd;
6 keyboardOptions = { ... }: {
9 type = types.listOf types.str;
11 example = [ "*" "-0123:0456" ];
12 description = lib.mdDoc ''
13 Device identifiers, as shown by {manpage}`keyd(1)`.
18 type = (pkgs.formats.ini { }).type;
22 capslock = "overload(control, esc)";
23 rightalt = "layer(rightalt)";
33 description = lib.mdDoc ''
34 Configuration, except `ids` section, that is written to {file}`/etc/keyd/<keyboard>.conf`.
35 Appropriate names can be used to write non-alpha keys, for example "equal" instead of "=" sign (see <https://github.com/NixOS/nixpkgs/issues/236622>).
36 See <https://github.com/rvaiya/keyd> how to configure.
40 extraConfig = mkOption {
47 description = lib.mdDoc ''
48 Extra configuration that is appended to the end of the file.
49 **Do not** write `ids` section here, use a separate option for it.
50 You can use this option to define compound layers that must always be defined after the layer they are comprised.
58 (mkRemovedOptionModule [ "services" "keyd" "ids" ]
59 ''Use keyboards.<filename>.ids instead. If you don't need a multi-file configuration, just add keyboards.default before the ids. See https://github.com/NixOS/nixpkgs/pull/243271.'')
60 (mkRemovedOptionModule [ "services" "keyd" "settings" ]
61 ''Use keyboards.<filename>.settings instead. If you don't need a multi-file configuration, just add keyboards.default before the settings. See https://github.com/NixOS/nixpkgs/pull/243271.'')
64 options.services.keyd = {
65 enable = mkEnableOption (lib.mdDoc "keyd, a key remapping daemon");
67 keyboards = mkOption {
68 type = types.attrsOf (types.submodule keyboardOptions);
70 example = literalExpression ''
76 capslock = "overload(control, esc)";
81 ids = [ "1ea7:0907" ];
90 description = mdDoc ''
91 Configuration for one or more device IDs. Corresponding files in the /etc/keyd/ directory are created according to the name of the keys (like `default` or `externalKeyboard`).
96 config = mkIf cfg.enable {
97 # Creates separate files in the `/etc/keyd/` directory for each key in the dictionary
98 environment.etc = mapAttrs'
100 nameValuePair "keyd/${name}.conf" {
103 ${concatStringsSep "\n" options.ids}
105 ${generators.toINI {} options.settings}
106 ${options.extraConfig}
111 hardware.uinput.enable = lib.mkDefault true;
113 systemd.services.keyd = {
114 description = "Keyd remapping daemon";
115 documentation = [ "man:keyd(1)" ];
117 wantedBy = [ "multi-user.target" ];
119 restartTriggers = mapAttrsToList
121 config.environment.etc."keyd/${name}.conf".source
125 # this is configurable in 2.4.2, later versions seem to remove this option.
126 # post-2.4.2 may need to set makeFlags in the derivation:
128 # makeFlags = [ "SOCKET_PATH/run/keyd/keyd.socket" ];
129 environment.KEYD_SOCKET = "/run/keyd/keyd.sock";
132 ExecStart = "${pkgs.keyd}/bin/keyd";
135 # TODO investigate why it doesn't work propeprly with DynamicUser
136 # See issue: https://github.com/NixOS/nixpkgs/issues/226346
137 # DynamicUser = true;
138 SupplementaryGroups = [
139 config.users.groups.input.name
140 config.users.groups.uinput.name
143 RuntimeDirectory = "keyd";
146 CapabilityBoundingSet = "";
152 PrivateNetwork = true;
154 ProtectHostname = true;
156 PrivateMounts = true;
158 RestrictNamespaces = true;
159 ProtectKernelLogs = true;
160 ProtectKernelModules = true;
161 ProtectKernelTunables = true;
162 ProtectControlGroups = true;
163 MemoryDenyWriteExecute = true;
164 RestrictRealtime = true;
165 LockPersonality = true;
166 ProtectProc = "invisible";
172 RestrictAddressFamilies = [ "AF_UNIX" ];
173 RestrictSUIDSGID = true;
174 IPAddressDeny = [ "any" ];
175 NoNewPrivileges = true;
176 ProtectSystem = "strict";