1 { config, lib, pkgs, ... }:
2 let cfg = config.services.libinput;
4 xorgBool = v: if v then "on" else "off";
6 mkConfigForDevice = deviceType: {
8 type = lib.types.nullOr lib.types.str;
10 example = "/dev/input/event0";
12 Path for ${deviceType} device. Set to `null` to apply to any
13 auto-detected ${deviceType}.
17 accelProfile = lib.mkOption {
18 type = lib.types.enum [ "flat" "adaptive" "custom" ];
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.
36 accelSpeed = lib.mkOption {
37 type = lib.types.nullOr lib.types.str;
41 Cursor acceleration (how fast speed increases from minSpeed to maxSpeed).
42 This only applies to the flat or adaptive profile.
46 accelPointsFallback = lib.mkOption {
47 type = lib.types.nullOr (lib.types.listOf lib.types.number);
49 example = [ 0.0 1.0 2.4 2.5 ];
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.
56 accelPointsMotion = lib.mkOption {
57 type = lib.types.nullOr (lib.types.listOf lib.types.number);
59 example = [ 0.0 1.0 2.4 2.5 ];
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.
66 accelPointsScroll = lib.mkOption {
67 type = lib.types.nullOr (lib.types.listOf lib.types.number);
69 example = [ 0.0 1.0 2.4 2.5 ];
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.
76 accelStepFallback = lib.mkOption {
77 type = lib.types.nullOr lib.types.number;
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.
87 accelStepMotion = lib.mkOption {
88 type = lib.types.nullOr lib.types.number;
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.
98 accelStepScroll = lib.mkOption {
99 type = lib.types.nullOr lib.types.number;
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.
109 buttonMapping = lib.mkOption {
110 type = lib.types.nullOr lib.types.str;
112 example = "1 6 3 4 5 0 7";
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.
123 calibrationMatrix = lib.mkOption {
124 type = lib.types.nullOr lib.types.str;
126 example = "0.5 0 0 0 0.8 0.1 0 0 1";
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).
133 clickMethod = lib.mkOption {
134 type = lib.types.nullOr (lib.types.enum [ "none" "buttonareas" "clickfinger" ]);
136 example = "buttonareas";
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.
145 leftHanded = lib.mkOption {
146 type = lib.types.bool;
148 description = "Enables left-handed button orientation, i.e. swapping left and right buttons.";
151 middleEmulation = lib.mkOption {
152 type = lib.types.bool;
155 Enables middle button emulation. When enabled, pressing the left and right buttons
156 simultaneously produces a middle mouse button click.
160 naturalScrolling = lib.mkOption {
161 type = lib.types.bool;
163 description = "Enables or disables natural scrolling behavior.";
166 scrollButton = lib.mkOption {
167 type = lib.types.nullOr lib.types.int;
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.
176 scrollMethod = lib.mkOption {
177 type = lib.types.enum [ "twofinger" "edge" "button" "none" ];
178 default = "twofinger";
181 Specify the scrolling method: `twofinger`, `edge`,
186 horizontalScrolling = lib.mkOption {
187 type = lib.types.bool;
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.
196 sendEventsMode = lib.mkOption {
197 type = lib.types.enum [ "disabled" "enabled" "disabled-on-external-mouse" ];
199 example = "disabled";
201 Sets the send events mode to `disabled`, `enabled`,
202 or `disabled-on-external-mouse`
206 tapping = lib.mkOption {
207 type = lib.types.bool;
210 Enables or disables tap-to-click behavior.
214 tappingButtonMap = lib.mkOption {
215 type = lib.types.nullOr (lib.types.enum [ "lrm" "lmr" ]);
218 Set the button mapping for 1/2/3-finger taps to left/right/middle or left/middle/right, respectively.
222 tappingDragLock = lib.mkOption {
223 type = lib.types.bool;
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.
232 transformationMatrix = lib.mkOption {
233 type = lib.types.nullOr lib.types.str;
235 example = "0.5 0 0 0 0.8 0.1 0 0 1";
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).
242 disableWhileTyping = lib.mkOption {
243 type = lib.types.bool;
246 Disable input method while typing.
250 additionalOptions = lib.mkOption {
251 type = lib.types.lines;
255 Option "DragLockButtons" "L1 B1 L2 B2"
258 Additional options for libinput ${deviceType} driver. See
259 {manpage}`libinput(4)`
260 for available options.";
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}
298 (map (option: lib.mkRenamedOptionModule ([ "services" "xserver" "libinput" option ]) [ "services" "libinput" "touchpad" option ]) [
309 "horizontalScrolling"
314 "transformationMatrix"
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" ])
325 services.libinput = {
326 enable = lib.mkEnableOption "libinput" // {
327 default = config.services.xserver.enable;
328 defaultText = lib.literalExpression "config.services.xserver.enable";
330 mouse = mkConfigForDevice "mouse";
331 touchpad = mkConfigForDevice "touchpad";
336 config = lib.mkIf cfg.enable {
338 services.xserver.modules = [ pkgs.xorg.xf86inputlibinput ];
340 environment.systemPackages = [ pkgs.xorg.xf86inputlibinput ];
343 let cfgPath = "X11/xorg.conf.d/40-libinput.conf";
346 source = pkgs.xorg.xf86inputlibinput.out + "/share/" + cfgPath;
350 services.udev.packages = [ pkgs.libinput.out ];
352 services.xserver.inputClassSections = [
353 (mkX11ConfigForDevice "mouse" "Pointer")
354 (mkX11ConfigForDevice "touchpad" "Touchpad")
358 # already present in synaptics.nix
360 assertion = !config.services.xserver.synaptics.enable;
361 message = "Synaptics and libinput are incompatible, you cannot enable both (in services.xserver).";