1 { config, lib, pkgs, ... }:
3 cfg = config.services.keyd;
5 keyboardOptions = { ... }: {
8 type = lib.types.listOf lib.types.str;
10 example = [ "*" "-0123:0456" ];
12 Device identifiers, as shown by {manpage}`keyd(1)`.
16 settings = lib.mkOption {
17 type = (pkgs.formats.ini { }).type;
21 capslock = "overload(control, esc)";
22 rightalt = "layer(rightalt)";
33 Configuration, except `ids` section, that is written to {file}`/etc/keyd/<keyboard>.conf`.
34 Appropriate names can be used to write non-alpha keys, for example "equal" instead of "=" sign (see <https://github.com/NixOS/nixpkgs/issues/236622>).
35 See <https://github.com/rvaiya/keyd> how to configure.
39 extraConfig = lib.mkOption {
40 type = lib.types.lines;
47 Extra configuration that is appended to the end of the file.
48 **Do not** write `ids` section here, use a separate option for it.
49 You can use this option to define compound layers that must always be defined after the layer they are comprised.
57 (lib.mkRemovedOptionModule [ "services" "keyd" "ids" ]
58 ''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.'')
59 (lib.mkRemovedOptionModule [ "services" "keyd" "settings" ]
60 ''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.'')
63 options.services.keyd = {
64 enable = lib.mkEnableOption "keyd, a key remapping daemon";
66 keyboards = lib.mkOption {
67 type = lib.types.attrsOf (lib.types.submodule keyboardOptions);
69 example = lib.literalExpression ''
75 capslock = "overload(control, esc)";
80 ids = [ "1ea7:0907" ];
90 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`).
95 config = lib.mkIf cfg.enable {
96 # Creates separate files in the `/etc/keyd/` directory for each key in the dictionary
97 environment.etc = lib.mapAttrs'
99 lib.nameValuePair "keyd/${name}.conf" {
102 ${lib.concatStringsSep "\n" options.ids}
104 ${lib.generators.toINI {} options.settings}
105 ${options.extraConfig}
110 hardware.uinput.enable = lib.mkDefault true;
112 systemd.services.keyd = {
113 description = "Keyd remapping daemon";
114 documentation = [ "man:keyd(1)" ];
116 wantedBy = [ "multi-user.target" ];
118 restartTriggers = lib.mapAttrsToList
120 config.environment.etc."keyd/${name}.conf".source
124 # this is configurable in 2.4.2, later versions seem to remove this option.
125 # post-2.4.2 may need to set makeFlags in the derivation:
127 # makeFlags = [ "SOCKET_PATH/run/keyd/keyd.socket" ];
128 environment.KEYD_SOCKET = "/run/keyd/keyd.sock";
131 ExecStart = "${pkgs.keyd}/bin/keyd";
134 # TODO investigate why it doesn't work propeprly with DynamicUser
135 # See issue: https://github.com/NixOS/nixpkgs/issues/226346
136 # DynamicUser = true;
137 SupplementaryGroups = [
138 config.users.groups.input.name
139 config.users.groups.uinput.name
142 RuntimeDirectory = "keyd";
145 CapabilityBoundingSet = [ "CAP_SYS_NICE" ];
151 PrivateNetwork = true;
153 ProtectHostname = true;
154 PrivateUsers = false;
155 PrivateMounts = true;
157 RestrictNamespaces = true;
158 ProtectKernelLogs = true;
159 ProtectKernelModules = true;
160 ProtectKernelTunables = true;
161 ProtectControlGroups = true;
162 MemoryDenyWriteExecute = true;
163 RestrictRealtime = true;
164 LockPersonality = true;
165 ProtectProc = "invisible";
171 RestrictAddressFamilies = [ "AF_UNIX" ];
172 RestrictSUIDSGID = true;
173 IPAddressDeny = [ "any" ];
174 NoNewPrivileges = true;
175 ProtectSystem = "strict";