at 25.11-pre 3.5 kB view raw
1{ 2 config, 3 lib, 4 pkgs, 5 ... 6}: 7let 8 9 cfg = config.services.actkbd; 10 11 configFile = pkgs.writeText "actkbd.conf" '' 12 ${lib.concatMapStringsSep "\n" ( 13 { 14 keys, 15 events, 16 attributes, 17 command, 18 ... 19 }: 20 ''${ 21 lib.concatMapStringsSep "+" toString keys 22 }:${lib.concatStringsSep "," events}:${lib.concatStringsSep "," attributes}:${command}'' 23 ) cfg.bindings} 24 ${cfg.extraConfig} 25 ''; 26 27 bindingCfg = 28 { ... }: 29 { 30 options = { 31 32 keys = lib.mkOption { 33 type = lib.types.listOf lib.types.int; 34 description = "List of keycodes to match."; 35 }; 36 37 events = lib.mkOption { 38 type = lib.types.listOf ( 39 lib.types.enum [ 40 "key" 41 "rep" 42 "rel" 43 ] 44 ); 45 default = [ "key" ]; 46 description = "List of events to match."; 47 }; 48 49 attributes = lib.mkOption { 50 type = lib.types.listOf lib.types.str; 51 default = [ "exec" ]; 52 description = "List of attributes."; 53 }; 54 55 command = lib.mkOption { 56 type = lib.types.str; 57 default = ""; 58 description = "What to run."; 59 }; 60 61 }; 62 }; 63 64in 65 66{ 67 68 ###### interface 69 70 options = { 71 72 services.actkbd = { 73 74 enable = lib.mkOption { 75 type = lib.types.bool; 76 default = false; 77 description = '' 78 Whether to enable the {command}`actkbd` key mapping daemon. 79 80 Turning this on will start an {command}`actkbd` 81 instance for every evdev input that has at least one key 82 (which is okay even for systems with tiny memory footprint, 83 since actkbd normally uses \<100 bytes of memory per 84 instance). 85 86 This allows binding keys globally without the need for e.g. 87 X11. 88 ''; 89 }; 90 91 bindings = lib.mkOption { 92 type = lib.types.listOf (lib.types.submodule bindingCfg); 93 default = [ ]; 94 example = lib.literalExpression '' 95 [ { keys = [ 113 ]; events = [ "key" ]; command = "''${pkgs.alsa-utils}/bin/amixer -q set Master toggle"; } 96 ] 97 ''; 98 description = '' 99 Key bindings for {command}`actkbd`. 100 101 See {command}`actkbd` {file}`README` for documentation. 102 103 The example shows a piece of what {option}`sound.mediaKeys.enable` does when enabled. 104 ''; 105 }; 106 107 extraConfig = lib.mkOption { 108 type = lib.types.lines; 109 default = ""; 110 description = '' 111 Literal contents to append to the end of actkbd configuration file. 112 ''; 113 }; 114 115 }; 116 117 }; 118 119 ###### implementation 120 121 config = lib.mkIf cfg.enable { 122 123 services.udev.packages = lib.singleton ( 124 pkgs.writeTextFile { 125 name = "actkbd-udev-rules"; 126 destination = "/etc/udev/rules.d/61-actkbd.rules"; 127 text = '' 128 ACTION=="add", SUBSYSTEM=="input", KERNEL=="event[0-9]*", ENV{ID_INPUT_KEY}=="1", TAG+="systemd", ENV{SYSTEMD_WANTS}+="actkbd@$env{DEVNAME}.service" 129 ''; 130 } 131 ); 132 133 systemd.services."actkbd@" = { 134 enable = true; 135 restartIfChanged = true; 136 unitConfig = { 137 Description = "actkbd on %I"; 138 ConditionPathExists = "%I"; 139 }; 140 serviceConfig = { 141 Type = "forking"; 142 ExecStart = "${pkgs.actkbd}/bin/actkbd -D -c ${configFile} -d %I"; 143 }; 144 }; 145 146 # For testing 147 environment.systemPackages = [ pkgs.actkbd ]; 148 149 }; 150 151}