1{ config, lib, pkgs, ... }:
2
3with lib;
4
5let cfg = config.services.xserver.libinput;
6 xorgBool = v: if v then "on" else "off";
7in {
8
9 options = {
10
11 services.xserver.libinput = {
12
13 enable = mkEnableOption "libinput";
14
15 dev = mkOption {
16 type = types.nullOr types.str;
17 default = null;
18 example = "/dev/input/event0";
19 description =
20 ''
21 Path for touchpad device. Set to null to apply to any
22 auto-detected touchpad.
23 '';
24 };
25
26 accelProfile = mkOption {
27 type = types.enum [ "flat" "adaptive" ];
28 default = "adaptive";
29 example = "flat";
30 description =
31 ''
32 Sets the pointer acceleration profile to the given profile.
33 Permitted values are adaptive, flat.
34 Not all devices support this option or all profiles.
35 If a profile is unsupported, the default profile for this is used.
36 <literal>flat</literal>: Pointer motion is accelerated by a constant
37 (device-specific) factor, depending on the current speed.
38 <literal>adaptive</literal>: Pointer acceleration depends on the input speed.
39 This is the default profile for most devices.
40 '';
41 };
42
43 accelSpeed = mkOption {
44 type = types.nullOr types.string;
45 default = null;
46 description = "Cursor acceleration (how fast speed increases from minSpeed to maxSpeed).";
47 };
48
49 buttonMapping = mkOption {
50 type = types.nullOr types.string;
51 default = null;
52 description =
53 ''
54 Sets the logical button mapping for this device, see XSetPointerMapping(3). The string must
55 be a space-separated list of button mappings in the order of the logical buttons on the
56 device, starting with button 1. The default mapping is "1 2 3 ... 32". A mapping of 0 deac‐
57 tivates the button. Multiple buttons can have the same mapping. Invalid mapping strings are
58 discarded and the default mapping is used for all buttons. Buttons not specified in the
59 user's mapping use the default mapping. See section BUTTON MAPPING for more details.
60 '';
61 };
62
63 calibrationMatrix = mkOption {
64 type = types.nullOr types.string;
65 default = null;
66 description =
67 ''
68 A string of 9 space-separated floating point numbers. Sets the calibration matrix to the
69 3x3 matrix where the first row is (abc), the second row is (def) and the third row is (ghi).
70 '';
71 };
72
73 clickMethod = mkOption {
74 type = types.nullOr (types.enum [ "none" "buttonareas" "clickfinger" ]);
75 default = null;
76 example = "none";
77 description =
78 ''
79 Enables a click method. Permitted values are none, buttonareas, clickfinger.
80 Not all devices support all methods, if an option is unsupported,
81 the default click method for this device is used.
82 '';
83 };
84
85 leftHanded = mkOption {
86 type = types.bool;
87 default = false;
88 example = true;
89 description = "Enables left-handed button orientation, i.e. swapping left and right buttons.";
90 };
91
92 middleEmulation = mkOption {
93 type = types.bool;
94 default = true;
95 example = false;
96 description =
97 ''
98 Enables middle button emulation. When enabled, pressing the left and right buttons
99 simultaneously produces a middle mouse button click.
100 '';
101 };
102
103 naturalScrolling = mkOption {
104 type = types.bool;
105 default = false;
106 example = true;
107 description = "Enables or disables natural scrolling behavior.";
108 };
109
110 scrollButton = mkOption {
111 type = types.nullOr types.int;
112 default = null;
113 example = 1;
114 description =
115 ''
116 Designates a button as scroll button. If the ScrollMethod is button and the button is logically
117 held down, x/y axis movement is converted into scroll events.
118 '';
119 };
120
121 scrollMethod = mkOption {
122 type = types.enum [ "twofinger" "edge" "none" ];
123 default = "twofinger";
124 example = "edge";
125 description =
126 ''
127 Specify the scrolling method.
128 '';
129 };
130
131 horizontalScrolling = mkOption {
132 type = types.bool;
133 default = true;
134 example = false;
135 description =
136 ''
137 Disables horizontal scrolling. When disabled, this driver will discard any horizontal scroll
138 events from libinput. Note that this does not disable horizontal scrolling, it merely
139 discards the horizontal axis from any scroll events.
140 '';
141 };
142
143 sendEventsMode = mkOption {
144 type = types.enum [ "disabled" "enabled" "disabled-on-external-mouse" ];
145 default = "enabled";
146 example = "disabled";
147 description =
148 ''
149 Sets the send events mode to disabled, enabled, or "disable when an external mouse is connected".
150 '';
151 };
152
153 tapping = mkOption {
154 type = types.bool;
155 default = true;
156 example = false;
157 description =
158 ''
159 Enables or disables tap-to-click behavior.
160 '';
161 };
162
163 tappingDragLock = mkOption {
164 type = types.bool;
165 default = true;
166 example = false;
167 description =
168 ''
169 Enables or disables drag lock during tapping behavior. When enabled, a finger up during tap-
170 and-drag will not immediately release the button. If the finger is set down again within the
171 timeout, the draging process continues.
172 '';
173 };
174
175 disableWhileTyping = mkOption {
176 type = types.bool;
177 default = true;
178 example = false;
179 description =
180 ''
181 Disable input method while typing.
182 '';
183 };
184
185 additionalOptions = mkOption {
186 type = types.str;
187 default = "";
188 example =
189 ''
190 Option "DragLockButtons" "L1 B1 L2 B2"
191 '';
192 description = "Additional options for libinput touchpad driver.";
193 };
194
195 };
196
197 };
198
199
200 config = mkIf cfg.enable {
201
202 services.xserver.modules = [ pkgs.xorg.xf86inputlibinput ];
203
204 environment.systemPackages = [ pkgs.xorg.xf86inputlibinput ];
205
206 services.udev.packages = [ pkgs.libinput ];
207
208 services.xserver.config =
209 ''
210 # Automatically enable the libinput driver for all touchpads.
211 Section "InputClass"
212 Identifier "libinputConfiguration"
213 MatchIsTouchpad "on"
214 ${optionalString (cfg.dev != null) ''MatchDevicePath "${cfg.dev}"''}
215 Driver "libinput"
216 Option "AccelProfile" "${cfg.accelProfile}"
217 ${optionalString (cfg.accelSpeed != null) ''Option "AccelSpeed" "${cfg.accelSpeed}"''}
218 ${optionalString (cfg.buttonMapping != null) ''Option "ButtonMapping" "${cfg.buttonMapping}"''}
219 ${optionalString (cfg.calibrationMatrix != null) ''Option "CalibrationMatrix" "${cfg.calibrationMatrix}"''}
220 ${optionalString (cfg.clickMethod != null) ''Option "ClickMethod" "${cfg.clickMethod}"''}
221 Option "LeftHanded" "${xorgBool cfg.leftHanded}"
222 Option "MiddleEmulation" "${xorgBool cfg.middleEmulation}"
223 Option "NaturalScrolling" "${xorgBool cfg.naturalScrolling}"
224 ${optionalString (cfg.scrollButton != null) ''Option "ScrollButton" "${toString cfg.scrollButton}"''}
225 Option "ScrollMethod" "${cfg.scrollMethod}"
226 Option "HorizontalScrolling" "${xorgBool cfg.horizontalScrolling}"
227 Option "SendEventsMode" "${cfg.sendEventsMode}"
228 Option "Tapping" "${xorgBool cfg.tapping}"
229 Option "TappingDragLock" "${xorgBool cfg.tappingDragLock}"
230 Option "DisableWhileTyping" "${xorgBool cfg.disableWhileTyping}"
231 ${cfg.additionalOptions}
232 EndSection
233 '';
234
235 assertions = [
236 # already present in synaptics.nix
237 /* {
238 assertion = !config.services.xserver.synaptics.enable;
239 message = "Synaptics and libinput are incompatible, you cannot enable both (in services.xserver).";
240 } */
241 ];
242
243 };
244
245}