kanata.nix 4.5 KB

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