diff --git a/README.md b/README.md index 2181344..6d966be 100644 --- a/README.md +++ b/README.md @@ -84,7 +84,36 @@ Default speed stats path: For NixOS notes, see `DEV_SETUP.md`. -## systemd user service +## nixos module + +This flake now exports: + +- `packages..default` (contains `gsf` + `gsfd`) +- `nixosModules.default` (`hardware.gsf`) + +Example: + +```nix +# flake input +inputs.gsf.url = "github:/gotta-scroll-fast"; + +# module import + config +{ + imports = [ inputs.gsf.nixosModules.default ]; + + hardware.gsf = { + enable = true; + device = "/dev/input/by-id/usb-...-event-mouse"; + inputGroupUsers = [ "thomasgl" ]; + # extraArgs = [ "--match-name" "ploopy" ]; + }; +} +``` + +`hardware.gsf` intentionally does **not** provide declarative accel parameters. +Manage those via your dotfiles (`~/.config/gsf/config.json`) and `gsf` CLI/TUI. + +## systemd user service (manual alternative) A starting unit file exists at: diff --git a/flake.nix b/flake.nix index 76b5578..4fb0098 100644 --- a/flake.nix +++ b/flake.nix @@ -10,13 +10,33 @@ let eachSystem = flake-utils.lib.eachDefaultSystem; in - eachSystem (system: + { + nixosModules.default = import ./nix/module.nix; + } + // eachSystem (system: let pkgs = import nixpkgs { inherit system; config.allowUnfree = false; }; + + gsfTools = pkgs.callPackage ./nix/package.nix { + src = self; + }; in { + packages.default = gsfTools; + packages.gsf-tools = gsfTools; + + apps.gsf = flake-utils.lib.mkApp { + drv = gsfTools; + name = "gsf"; + }; + + apps.gsfd = flake-utils.lib.mkApp { + drv = gsfTools; + name = "gsfd"; + }; + devShells.default = pkgs.mkShell { packages = with pkgs; [ rustc diff --git a/nix/module.nix b/nix/module.nix new file mode 100644 index 0000000..1fba052 --- /dev/null +++ b/nix/module.nix @@ -0,0 +1,98 @@ +{ + 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; + }; + }; + }; +} diff --git a/nix/package.nix b/nix/package.nix new file mode 100644 index 0000000..e1b7fa9 --- /dev/null +++ b/nix/package.nix @@ -0,0 +1,33 @@ +{ + lib, + pkgs, + src ? ../., +}: +let + daemonToml = builtins.fromTOML (builtins.readFile (src + "/daemon/Cargo.toml")); +in +pkgs.rustPlatform.buildRustPackage rec { + pname = "gsf-tools"; + version = daemonToml.package.version; + + inherit src; + cargoLock.lockFile = src + "/Cargo.lock"; + + cargoBuildFlags = ["-p" "gsf-cli" "-p" "gsf-daemon"]; + + doCheck = false; + + installPhase = '' + runHook preInstall + mkdir -p $out/bin + cp target/release/gsf $out/bin/ + cp target/release/gsfd $out/bin/ + runHook postInstall + ''; + + meta = with lib; { + description = "gotta-scroll-fast tools (gsf + gsfd)"; + license = licenses.gpl2Plus; + platforms = platforms.linux; + }; +}