1{
2 config,
3 lib,
4 pkgs,
5 ...
6}:
7let
8
9 cfg = config.services.triggerhappy;
10
11 socket = "/run/thd.socket";
12
13 configFile = pkgs.writeText "triggerhappy.conf" ''
14 ${lib.concatMapStringsSep "\n" (
15 {
16 keys,
17 event,
18 cmd,
19 ...
20 }:
21 ''${lib.concatMapStringsSep "+" (x: "KEY_" + x) keys} ${
22 toString
23 {
24 press = 1;
25 hold = 2;
26 release = 0;
27 }
28 .${event}
29 } ${cmd}''
30 ) cfg.bindings}
31 ${cfg.extraConfig}
32 '';
33
34 bindingCfg =
35 { ... }:
36 {
37 options = {
38
39 keys = lib.mkOption {
40 type = lib.types.listOf lib.types.str;
41 description = "List of keys to match. Key names as defined in linux/input-event-codes.h";
42 };
43
44 event = lib.mkOption {
45 type = lib.types.enum [
46 "press"
47 "hold"
48 "release"
49 ];
50 default = "press";
51 description = "Event to match.";
52 };
53
54 cmd = lib.mkOption {
55 type = lib.types.str;
56 description = "What to run.";
57 };
58
59 };
60 };
61
62in
63
64{
65
66 ###### interface
67
68 options = {
69
70 services.triggerhappy = {
71
72 enable = lib.mkOption {
73 type = lib.types.bool;
74 default = false;
75 description = ''
76 Whether to enable the {command}`triggerhappy` hotkey daemon.
77 '';
78 };
79
80 user = lib.mkOption {
81 type = lib.types.str;
82 default = "nobody";
83 example = "root";
84 description = ''
85 User account under which {command}`triggerhappy` runs.
86 '';
87 };
88
89 bindings = lib.mkOption {
90 type = lib.types.listOf (lib.types.submodule bindingCfg);
91 default = [ ];
92 example = lib.literalExpression ''
93 [ { keys = ["PLAYPAUSE"]; cmd = "''${lib.getExe pkgs.mpc} -q toggle"; } ]
94 '';
95 description = ''
96 Key bindings for {command}`triggerhappy`.
97 '';
98 };
99
100 extraConfig = lib.mkOption {
101 type = lib.types.lines;
102 default = "";
103 description = ''
104 Literal contents to append to the end of {command}`triggerhappy` configuration file.
105 '';
106 };
107
108 };
109
110 };
111
112 ###### implementation
113
114 config = lib.mkIf cfg.enable {
115
116 systemd.sockets.triggerhappy = {
117 description = "Triggerhappy Socket";
118 wantedBy = [ "sockets.target" ];
119 socketConfig.ListenDatagram = socket;
120 };
121
122 systemd.services.triggerhappy = {
123 wantedBy = [ "multi-user.target" ];
124 description = "Global hotkey daemon";
125 documentation = [ "man:thd(1)" ];
126 serviceConfig = {
127 ExecStart = "${pkgs.triggerhappy}/bin/thd ${
128 lib.optionalString (cfg.user != "root") "--user ${cfg.user}"
129 } --socket ${socket} --triggers ${configFile} --deviceglob /dev/input/event*";
130 };
131 };
132
133 services.udev.packages = lib.singleton (
134 pkgs.writeTextFile {
135 name = "triggerhappy-udev-rules";
136 destination = "/etc/udev/rules.d/61-triggerhappy.rules";
137 text = ''
138 ACTION=="add", SUBSYSTEM=="input", KERNEL=="event[0-9]*", ATTRS{name}!="triggerhappy", \
139 RUN+="${pkgs.triggerhappy}/bin/th-cmd --socket ${socket} --passfd --udev"
140 '';
141 }
142 );
143
144 };
145
146}