kanata.nix 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. { config
  2. , lib
  3. , pkgs
  4. , ...
  5. }:
  6. let
  7. cfg = config.services.kanata;
  8. driverPkg = pkgs.fetchurl {
  9. url = "https://github.com/pqrs-org/Karabiner-DriverKit-VirtualHIDDevice/releases/download/v6.0.0/Karabiner-DriverKit-VirtualHIDDevice-6.0.0.pkg";
  10. sha256 = "sha256-S14c06v/L/PraLekzIroG6FQnV5dpx0cyJNb9ylB458=";
  11. };
  12. configFile = lib.mkIf (cfg.config != "")
  13. "${pkgs.writeScript "kanata.kbd" ("\n" + cfg.config + "\n")}";
  14. in
  15. {
  16. options.services.kanata = {
  17. enable = lib.mkEnableOption "kanata, a tool to improve keyboard comfort and usability with advanced customization";
  18. package = lib.mkPackageOption pkgs "kanata" {
  19. example = [ "kanata-with-cmd" ];
  20. extraDescription = ''
  21. ::: {.note}
  22. If {option}`danger-enable-cmd` is enabled in any of the keyboards, the
  23. `kanata-with-cmd` package should be used.
  24. :::
  25. '';
  26. };
  27. errorLogFile = lib.mkOption {
  28. type = lib.types.path;
  29. default = "/Library/Logs/Kanata/kanata.err.log";
  30. example = "/Users/jsmith/Library/Logs/kanata.err.log";
  31. description = "Path to the Kanata error log file";
  32. };
  33. outLogFile = lib.mkOption {
  34. type = lib.types.path;
  35. default = "/Library/Logs/Kanata/kanata.out.log";
  36. example = "/Users/jsmith/Library/Logs/kanata.out.log";
  37. description = "Path to the Kanata stdout log file";
  38. };
  39. config = lib.mkOption {
  40. type = lib.types.str;
  41. default = "";
  42. description = "";
  43. };
  44. };
  45. config = lib.mkIf cfg.enable {
  46. environment.systemPackages = [ cfg.package ];
  47. # Install the driver during activation
  48. system.activationScripts.preActivation.text = ''
  49. echo "Installing Karabiner DriverKit VirtualHIDDevice..." >&2
  50. # Check if already installed by looking for the system extension
  51. if ! systemextensionsctl list 2>/dev/null | grep -q "org.pqrs.Karabiner-DriverKit-VirtualHIDDevice"; then
  52. echo "Installing driver package..." >&2
  53. installer -pkg ${driverPkg} -target /
  54. # Give it a moment to install
  55. sleep 2
  56. # Try to activate the system extension
  57. if [ -f "/Applications/.Karabiner-VirtualHIDDevice-Manager.app/Contents/MacOS/Karabiner-VirtualHIDDevice-Manager" ]; then
  58. echo "Activating system extension..." >&2
  59. /Applications/.Karabiner-VirtualHIDDevice-Manager.app/Contents/MacOS/Karabiner-VirtualHIDDevice-Manager activate || {
  60. echo "System extension activation requires user approval in System Settings > Privacy & Security" >&2
  61. }
  62. fi
  63. else
  64. echo "Karabiner DriverKit already installed" >&2
  65. fi
  66. '';
  67. # Cleanup when disabled
  68. system.activationScripts.postActivation.text = lib.mkIf (!cfg.enable) ''
  69. echo "Cleaning up Karabiner DriverKit..." >&2
  70. # Stop and remove launchd services
  71. for service in org.nixos.karabiner-vhiddaemon org.nixos.karabiner-vhidmanager; do
  72. launchctl unload "/Library/LaunchDaemons/$service.plist" 2>/dev/null || true
  73. rm -f "/Library/LaunchDaemons/$service.plist" 2>/dev/null || true
  74. done
  75. # Remove the manager app copy
  76. rm -rf /Applications/.Nix-Karabiner-DriverKit/ 2>/dev/null || true
  77. # Note: We don't uninstall the system extension as that requires manual user action
  78. # and the extension can be shared with other apps
  79. echo "Note: Karabiner system extension remains installed (can be removed manually in System Settings)" >&2
  80. '';
  81. launchd.daemons.karabiner-vhiddaemon.serviceConfig = {
  82. Label = "org.nixos.karabiner-vhiddaemon";
  83. ProgramArguments = [
  84. "/Library/Application Support/org.pqrs/Karabiner-DriverKit-VirtualHIDDevice/Applications/Karabiner-VirtualHIDDevice-Daemon.app/Contents/MacOS/Karabiner-VirtualHIDDevice-Daemon"
  85. ];
  86. RunAtLoad = true;
  87. KeepAlive = true;
  88. };
  89. launchd.daemons.karabiner-vhidmanager.serviceConfig = {
  90. Label = "org.nixos.karabiner-vhidmanager";
  91. ProgramArguments = [
  92. "/Applications/.Karabiner-VirtualHIDDevice-Manager.app/Contents/MacOS/Karabiner-VirtualHIDDevice-Manager"
  93. "activate"
  94. ];
  95. RunAtLoad = true;
  96. };
  97. launchd.daemons.kanata.serviceConfig = {
  98. Label = "org.nixos.kanata";
  99. ProgramArguments = [
  100. "${lib.getExe cfg.package}"
  101. "--port"
  102. "10000"
  103. # "--debug"
  104. ] ++ lib.optionals (cfg.config != "") [ "-c" configFile ];
  105. RunAtLoad = true;
  106. KeepAlive = true;
  107. StandardOutPath = cfg.outLogFile;
  108. StandardErrorPath = cfg.errorLogFile;
  109. };
  110. };
  111. meta.maintainers = [ ];
  112. }