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