grafana-alloy: don't build the frontend twice
[NixPkgs.git] / nixos / modules / services / hardware / libinput.nix
blobe8169af40637f6bd7d3a380b0f4a645ed1647d13
1 { config, lib, pkgs, ... }:
2 let cfg = config.services.libinput;
4     xorgBool = v: if v then "on" else "off";
6     mkConfigForDevice = deviceType: {
7       dev = lib.mkOption {
8         type = lib.types.nullOr lib.types.str;
9         default = null;
10         example = "/dev/input/event0";
11         description = ''
12             Path for ${deviceType} device.  Set to `null` to apply to any
13             auto-detected ${deviceType}.
14           '';
15       };
17       accelProfile = lib.mkOption {
18         type = lib.types.enum [ "flat" "adaptive" "custom" ];
19         default = "adaptive";
20         example = "flat";
21         description = ''
22             Sets the pointer acceleration profile to the given profile.
23             Permitted values are `adaptive`, `flat`, `custom`.
24             Not all devices support this option or all profiles.
25             If a profile is unsupported, the default profile for this is used.
26             `flat`: Pointer motion is accelerated by a constant
27             (device-specific) factor, depending on the current speed.
28             `adaptive`: Pointer acceleration depends on the input speed.
29             This is the default profile for most devices.
30             `custom`: Allows the user to define a custom acceleration function.
31             To define custom functions use the accelPoints<Fallback/Motion/Scroll>
32             and accelStep<Fallback/Motion/Scroll> options.
33           '';
34       };
36       accelSpeed = lib.mkOption {
37         type = lib.types.nullOr lib.types.str;
38         default = null;
39         example = "-0.5";
40         description = ''
41             Cursor acceleration (how fast speed increases from minSpeed to maxSpeed).
42             This only applies to the flat or adaptive profile.
43           '';
44       };
46       accelPointsFallback = lib.mkOption {
47         type = lib.types.nullOr (lib.types.listOf lib.types.number);
48         default = null;
49         example = [ 0.0 1.0 2.4 2.5 ];
50         description = ''
51             Sets the points of the fallback acceleration function. The value must be a list of
52             floating point non-negative numbers. This only applies to the custom profile.
53           '';
54       };
56       accelPointsMotion = lib.mkOption {
57         type = lib.types.nullOr (lib.types.listOf lib.types.number);
58         default = null;
59         example = [ 0.0 1.0 2.4 2.5 ];
60         description = ''
61             Sets the points of the (pointer) motion acceleration function. The value must be a
62             list of floating point non-negative numbers. This only applies to the custom profile.
63           '';
64       };
66       accelPointsScroll = lib.mkOption {
67         type = lib.types.nullOr (lib.types.listOf lib.types.number);
68         default = null;
69         example = [ 0.0 1.0 2.4 2.5 ];
70         description = ''
71             Sets the points of the scroll acceleration function. The value must be a list of
72             floating point non-negative numbers. This only applies to the custom profile.
73           '';
74       };
76       accelStepFallback = lib.mkOption {
77         type = lib.types.nullOr lib.types.number;
78         default = null;
79         example = 0.1;
80         description = ''
81             Sets the step between the points of the fallback acceleration function. When a step of
82             0.0 is provided, libinput's Fallback acceleration function is used. This only applies
83             to the custom profile.
84           '';
85       };
87       accelStepMotion = lib.mkOption {
88         type = lib.types.nullOr lib.types.number;
89         default = null;
90         example = 0.1;
91         description = ''
92             Sets the step between the points of the (pointer) motion acceleration function. When a
93             step of 0.0 is provided, libinput's Fallback acceleration function is used. This only
94             applies to the custom profile.
95           '';
96       };
98       accelStepScroll = lib.mkOption {
99         type = lib.types.nullOr lib.types.number;
100         default = null;
101         example = 0.1;
102         description = ''
103             Sets the step between the points of the scroll acceleration function. When a step of
104             0.0 is provided, libinput's Fallback acceleration function is used. This only applies
105             to the custom profile.
106           '';
107       };
109       buttonMapping = lib.mkOption {
110         type = lib.types.nullOr lib.types.str;
111         default = null;
112         example = "1 6 3 4 5 0 7";
113         description = ''
114             Sets the logical button mapping for this device, see XSetPointerMapping(3). The string  must
115             be  a  space-separated  list  of  button mappings in the order of the logical buttons on the
116             device, starting with button 1.  The default mapping is "1 2 3 ... 32". A mapping of 0 deac‐
117             tivates the button. Multiple buttons can have the same mapping.  Invalid mapping strings are
118             discarded and the default mapping is used for all buttons.  Buttons  not  specified  in  the
119             user's mapping use the default mapping. See section BUTTON MAPPING for more details.
120           '';
121       };
123       calibrationMatrix = lib.mkOption {
124         type = lib.types.nullOr lib.types.str;
125         default = null;
126         example = "0.5 0 0 0 0.8 0.1 0 0 1";
127         description = ''
128             A string of 9 space-separated floating point numbers. Sets the calibration matrix to the
129             3x3 matrix where the first row is (abc), the second row is (def) and the third row is (ghi).
130           '';
131       };
133       clickMethod = lib.mkOption {
134         type = lib.types.nullOr (lib.types.enum [ "none" "buttonareas" "clickfinger" ]);
135         default = null;
136         example = "buttonareas";
137         description = ''
138             Enables a click method. Permitted values are `none`,
139             `buttonareas`, `clickfinger`.
140             Not all devices support all methods, if an option is unsupported,
141             the default click method for this device is used.
142           '';
143       };
145       leftHanded = lib.mkOption {
146         type = lib.types.bool;
147         default = false;
148         description = "Enables left-handed button orientation, i.e. swapping left and right buttons.";
149       };
151       middleEmulation = lib.mkOption {
152         type = lib.types.bool;
153         default = true;
154         description = ''
155             Enables middle button emulation. When enabled, pressing the left and right buttons
156             simultaneously produces a middle mouse button click.
157           '';
158       };
160       naturalScrolling = lib.mkOption {
161         type = lib.types.bool;
162         default = false;
163         description = "Enables or disables natural scrolling behavior.";
164       };
166       scrollButton = lib.mkOption {
167         type = lib.types.nullOr lib.types.int;
168         default = null;
169         example = 1;
170         description = ''
171             Designates a button as scroll button. If the ScrollMethod is button and the button is logically
172             held down, x/y axis movement is converted into scroll events.
173           '';
174       };
176       scrollMethod = lib.mkOption {
177         type = lib.types.enum [ "twofinger" "edge" "button" "none" ];
178         default = "twofinger";
179         example = "edge";
180         description = ''
181             Specify the scrolling method: `twofinger`, `edge`,
182             `button`, or `none`
183           '';
184       };
186       horizontalScrolling = lib.mkOption {
187         type = lib.types.bool;
188         default = true;
189         description = ''
190             Enables or disables horizontal scrolling. When disabled, this driver will discard any
191             horizontal scroll events from libinput. This does not disable horizontal scroll events
192             from libinput; it merely discards the horizontal axis from any scroll events.
193           '';
194       };
196       sendEventsMode = lib.mkOption {
197         type = lib.types.enum [ "disabled" "enabled" "disabled-on-external-mouse" ];
198         default = "enabled";
199         example = "disabled";
200         description = ''
201             Sets the send events mode to `disabled`, `enabled`,
202             or `disabled-on-external-mouse`
203           '';
204       };
206       tapping = lib.mkOption {
207         type = lib.types.bool;
208         default = true;
209         description = ''
210             Enables or disables tap-to-click behavior.
211           '';
212       };
214       tappingButtonMap = lib.mkOption {
215         type = lib.types.nullOr (lib.types.enum [ "lrm" "lmr" ]);
216         default = null;
217         description = ''
218           Set the button mapping for 1/2/3-finger taps to left/right/middle or left/middle/right, respectively.
219         '';
220       };
222       tappingDragLock = lib.mkOption {
223         type = lib.types.bool;
224         default = true;
225         description = ''
226             Enables or disables drag lock during tapping behavior. When enabled, a finger up during tap-
227             and-drag will not immediately release the button. If the finger is set down again within the
228             timeout, the dragging process continues.
229           '';
230       };
232       transformationMatrix = lib.mkOption {
233         type = lib.types.nullOr lib.types.str;
234         default = null;
235         example = "0.5 0 0 0 0.8 0.1 0 0 1";
236         description = ''
237           A string of 9 space-separated floating point numbers. Sets the transformation matrix to
238           the 3x3 matrix where the first row is (abc), the second row is (def) and the third row is (ghi).
239         '';
240       };
242       disableWhileTyping = lib.mkOption {
243         type = lib.types.bool;
244         default = false;
245         description = ''
246             Disable input method while typing.
247           '';
248       };
250       additionalOptions = lib.mkOption {
251         type = lib.types.lines;
252         default = "";
253         example =
254         ''
255           Option "DragLockButtons" "L1 B1 L2 B2"
256         '';
257         description = ''
258           Additional options for libinput ${deviceType} driver. See
259           {manpage}`libinput(4)`
260           for available options.";
261         '';
262       };
263     };
265     mkX11ConfigForDevice = deviceType: matchIs: ''
266       Identifier "libinput ${deviceType} configuration"
267       MatchDriver "libinput"
268       MatchIs${matchIs} "${xorgBool true}"
269       ${lib.optionalString (cfg.${deviceType}.dev != null) ''MatchDevicePath "${cfg.${deviceType}.dev}"''}
270       Option "AccelProfile" "${cfg.${deviceType}.accelProfile}"
271       ${lib.optionalString (cfg.${deviceType}.accelSpeed != null) ''Option "AccelSpeed" "${cfg.${deviceType}.accelSpeed}"''}
272       ${lib.optionalString (cfg.${deviceType}.accelPointsFallback != null) ''Option "AccelPointsFallback" "${toString cfg.${deviceType}.accelPointsFallback}"''}
273       ${lib.optionalString (cfg.${deviceType}.accelPointsMotion != null) ''Option "AccelPointsMotion" "${toString cfg.${deviceType}.accelPointsMotion}"''}
274       ${lib.optionalString (cfg.${deviceType}.accelPointsScroll != null) ''Option "AccelPointsScroll" "${toString cfg.${deviceType}.accelPointsScroll}"''}
275       ${lib.optionalString (cfg.${deviceType}.accelStepFallback != null) ''Option "AccelStepFallback" "${toString cfg.${deviceType}.accelStepFallback}"''}
276       ${lib.optionalString (cfg.${deviceType}.accelStepMotion != null) ''Option "AccelStepMotion" "${toString cfg.${deviceType}.accelStepMotion}"''}
277       ${lib.optionalString (cfg.${deviceType}.accelStepScroll != null) ''Option "AccelStepScroll" "${toString cfg.${deviceType}.accelStepScroll}"''}
278       ${lib.optionalString (cfg.${deviceType}.buttonMapping != null) ''Option "ButtonMapping" "${cfg.${deviceType}.buttonMapping}"''}
279       ${lib.optionalString (cfg.${deviceType}.calibrationMatrix != null) ''Option "CalibrationMatrix" "${cfg.${deviceType}.calibrationMatrix}"''}
280       ${lib.optionalString (cfg.${deviceType}.transformationMatrix != null) ''Option "TransformationMatrix" "${cfg.${deviceType}.transformationMatrix}"''}
281       ${lib.optionalString (cfg.${deviceType}.clickMethod != null) ''Option "ClickMethod" "${cfg.${deviceType}.clickMethod}"''}
282       Option "LeftHanded" "${xorgBool cfg.${deviceType}.leftHanded}"
283       Option "MiddleEmulation" "${xorgBool cfg.${deviceType}.middleEmulation}"
284       Option "NaturalScrolling" "${xorgBool cfg.${deviceType}.naturalScrolling}"
285       ${lib.optionalString (cfg.${deviceType}.scrollButton != null) ''Option "ScrollButton" "${toString cfg.${deviceType}.scrollButton}"''}
286       Option "ScrollMethod" "${cfg.${deviceType}.scrollMethod}"
287       Option "HorizontalScrolling" "${xorgBool cfg.${deviceType}.horizontalScrolling}"
288       Option "SendEventsMode" "${cfg.${deviceType}.sendEventsMode}"
289       Option "Tapping" "${xorgBool cfg.${deviceType}.tapping}"
290       ${lib.optionalString (cfg.${deviceType}.tappingButtonMap != null) ''Option "TappingButtonMap" "${cfg.${deviceType}.tappingButtonMap}"''}
291       Option "TappingDragLock" "${xorgBool cfg.${deviceType}.tappingDragLock}"
292       Option "DisableWhileTyping" "${xorgBool cfg.${deviceType}.disableWhileTyping}"
293       ${cfg.${deviceType}.additionalOptions}
294     '';
295 in {
297   imports =
298     (map (option: lib.mkRenamedOptionModule ([ "services" "xserver" "libinput" option ]) [ "services" "libinput" "touchpad" option ]) [
299       "accelProfile"
300       "accelSpeed"
301       "buttonMapping"
302       "calibrationMatrix"
303       "clickMethod"
304       "leftHanded"
305       "middleEmulation"
306       "naturalScrolling"
307       "scrollButton"
308       "scrollMethod"
309       "horizontalScrolling"
310       "sendEventsMode"
311       "tapping"
312       "tappingButtonMap"
313       "tappingDragLock"
314       "transformationMatrix"
315       "disableWhileTyping"
316       "additionalOptions"
317     ]) ++ [
318       (lib.mkRenamedOptionModule [ "services" "xserver" "libinput" "enable" ]   [ "services" "libinput" "enable" ])
319       (lib.mkRenamedOptionModule [ "services" "xserver" "libinput" "mouse" ]    [ "services" "libinput" "mouse" ])
320       (lib.mkRenamedOptionModule [ "services" "xserver" "libinput" "touchpad" ] [ "services" "libinput" "touchpad" ])
321     ];
323   options = {
325     services.libinput = {
326       enable = lib.mkEnableOption "libinput" // {
327         default = config.services.xserver.enable;
328         defaultText = lib.literalExpression "config.services.xserver.enable";
329       };
330       mouse = mkConfigForDevice "mouse";
331       touchpad = mkConfigForDevice "touchpad";
332     };
333   };
336   config = lib.mkIf cfg.enable {
338     services.xserver.modules = [ pkgs.xorg.xf86inputlibinput ];
340     environment.systemPackages = [ pkgs.xorg.xf86inputlibinput ];
342     environment.etc =
343       let cfgPath = "X11/xorg.conf.d/40-libinput.conf";
344       in {
345         ${cfgPath} = {
346           source = pkgs.xorg.xf86inputlibinput.out + "/share/" + cfgPath;
347         };
348       };
350     services.udev.packages = [ pkgs.libinput.out ];
352     services.xserver.inputClassSections = [
353       (mkX11ConfigForDevice "mouse" "Pointer")
354       (mkX11ConfigForDevice "touchpad" "Touchpad")
355     ];
357     assertions = [
358       # already present in synaptics.nix
359       /* {
360         assertion = !config.services.xserver.synaptics.enable;
361         message = "Synaptics and libinput are incompatible, you cannot enable both (in services.xserver).";
362       } */
363     ];
365   };