{ config, lib, pkgs, ... }: let cfg = config.hardware.gsf; defaultPackage = pkgs.callPackage ./package.nix { src = ../.; }; extraArgs = lib.concatMapStringsSep " " lib.escapeShellArg cfg.extraArgs; in { options.hardware.gsf = { enable = lib.mkEnableOption "gotta-scroll-fast daemon"; package = lib.mkOption { type = lib.types.package; default = defaultPackage; description = "Package providing `gsf` and `gsfd` binaries."; }; installTools = lib.mkOption { type = lib.types.bool; default = true; description = "Install gsf/gsfd package in system packages."; }; autoStart = lib.mkOption { type = lib.types.bool; default = true; description = "Start gsfd as a systemd user service."; }; device = lib.mkOption { type = lib.types.nullOr lib.types.str; default = null; example = "/dev/input/by-id/usb-Ploopy_...-event-mouse"; description = "Input event device path passed to `gsfd --device`."; }; extraArgs = lib.mkOption { type = lib.types.listOf lib.types.str; default = []; description = "Extra arguments passed to gsfd."; }; enableUinput = lib.mkOption { type = lib.types.bool; default = true; description = "Enable /dev/uinput support and permissions."; }; inputGroupUsers = lib.mkOption { type = lib.types.listOf lib.types.str; default = []; example = ["thomasgl"]; description = "Users to add to the `input` group for /dev/input and /dev/uinput access."; }; }; config = lib.mkIf cfg.enable { assertions = [ { assertion = !cfg.autoStart || cfg.device != null; message = "hardware.gsf.device must be set when hardware.gsf.autoStart = true"; } ]; environment.systemPackages = lib.mkIf cfg.installTools [cfg.package]; boot.kernelModules = lib.mkIf cfg.enableUinput ["uinput"]; services.udev.extraRules = lib.mkIf cfg.enableUinput '' KERNEL=="uinput", MODE="0660", GROUP="input" ''; users.users = lib.mkIf (cfg.inputGroupUsers != []) ( lib.genAttrs cfg.inputGroupUsers (_: { extraGroups = ["input"]; }) ); systemd.user.services.gsfd = lib.mkIf cfg.autoStart { description = "gotta-scroll-fast daemon"; wantedBy = ["default.target"]; after = ["graphical-session.target"]; serviceConfig = { ExecStart = "${cfg.package}/bin/gsfd --device ${lib.escapeShellArg cfg.device}${lib.optionalString (cfg.extraArgs != []) " ${extraArgs}"}"; Restart = "on-failure"; RestartSec = 1; }; }; }; }