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