SKHD in Zig Simple Hotkey Daemon for macOS, ported from skhd to Zig. This implementation is fully compatible with the original skhd configuration format - your existing .skhdrc files will work without modification. Additionally, it includes new features like process groups and command definitions ( .define ) for cleaner configs, key forwarding/remapping, and improved error reporting. 📋 View Changelog Installation Homebrew The easiest way to install skhd.zig: brew install jackielii/tap/skhd-zig Pre-built Binaries Download the latest release for your architecture: skhd-arm64-macos.tar.gz - For Apple Silicon Macs - For Apple Silicon Macs skhd-x86_64-macos.tar.gz - For Intel Macs Extract and install: tar -xzf skhd- * .tar.gz sudo cp skhd /usr/local/bin/ Development Builds from GitHub Actions If you need builds with different optimization levels (Debug, ReleaseSafe, ReleaseFast, ReleaseSmall), you can download them directly from GitHub Actions: Go to the CI workflow in Actions tab. Filter by branch main . Click on the latest successful run Scroll down to the "Artifacts" section Download the build artifact for your desired optimization level: skhd-Debug - Debug build with full debugging symbols - Debug build with full debugging symbols skhd-ReleaseSafe - Release build with safety checks and runtime safety - Release build with safety checks and runtime safety skhd-ReleaseFast - Optimized for performance (recommended for daily use) - Optimized for performance (recommended for daily use) skhd-ReleaseSmall - Optimized for binary size Build from Source # Clone the repository git clone https://github.com/jackielii/skhd.zig cd skhd.zig # Build in release mode zig build -Doptimize=ReleaseFast # Install (copy to /usr/local/bin) sudo cp zig-out/bin/skhd /usr/local/bin/ Running as Service After installation, run skhd as a service for automatic startup: # Install and start the service skhd --install-service skhd --start-service # Check if skhd is running properly skhd --status # Restart service (useful for restarting after giving accessibility permissions) skhd --restart-service # Stop service skhd --stop-service # Uninstall service skhd --uninstall-service The service will: Start automatically on login Create logs at /tmp/skhd_$USER.log Use your config from ~/.config/skhd/skhdrc or ~/.skhdrc or Automatically reload on config changes Features Core Functionality Event capturing : Uses macOS Core Graphics Event Tap for system-wide keyboard event interception : Uses macOS Core Graphics Event Tap for system-wide keyboard event interception Hotkey mapping : Maps key combinations to shell commands with full modifier support : Maps key combinations to shell commands with full modifier support Process-specific bindings : Different commands for different applications : Different commands for different applications Key forwarding/remapping : Remap keys to other key combinations : Remap keys to other key combinations Modal system : Multi-level modal hotkey system with capture modes : Multi-level modal hotkey system with capture modes Configuration file : Compatible with original skhd configuration format : Compatible with original skhd configuration format Hot reloading: Automatic config reload on file changes Additional Features (New in skhd.zig!) Process groups : Define named groups of applications for cleaner configs : Define named groups of applications for cleaner configs Command definitions : Define reusable commands with placeholders to reduce repetition : Define reusable commands with placeholders to reduce repetition Key Forwarding : Forward / remap key binding to another key binding : Forward / remap key binding to another key binding Mode activation with command: Execute a command when switching modes (e.g., cmd - w ; window : echo "Window mode" ) Command-Line Interface --version / -v - Display version information / - Display version information --help - Show usage information - Show usage information -c / --config - Specify config file location / - Specify config file location -o / --observe - Observe mode (echo keycodes and modifiers) / - Observe mode (echo keycodes and modifiers) -V / --verbose - Debug output with detailed logging / - Debug output with detailed logging -k / --key - Synthesize keypress for testing / - Synthesize keypress for testing -t / --text - Synthesize text input / - Synthesize text input -r / --reload - Signal reload to running instance / - Signal reload to running instance -h / --no-hotload - Disable hotloading / - Disable hotloading -P / --profile - Profile event handling (Debug and ReleaseSafe builds only) Service Management --install-service - Install launchd service - Install launchd service --uninstall-service - Remove launchd service - Remove launchd service --start-service - Start as service - Start as service --restart-service - Restart service - Restart service --stop-service - Stop service - Stop service PID file management ( /tmp/skhd_$USER.pid ) ) Service logging ( /tmp/skhd_$USER.log ) Advanced Features Blacklisting : Exclude applications from hotkey processing : Exclude applications from hotkey processing Shell customization : Use custom shell for command execution : Use custom shell for command execution Left/right modifier distinction : Support for lcmd, rcmd, lalt, ralt, etc. : Support for lcmd, rcmd, lalt, ralt, etc. Special key support : Function keys, media keys, arrow keys : Function keys, media keys, arrow keys Passthrough mode : Execute command but still send keypress to application : Execute command but still send keypress to application Config includes : Load additional config files with .load directive : Load additional config files with directive Comprehensive error reporting: Detailed error messages with line numbers Build Commands # Build the project (creates executable in zig-out/bin/) zig build # Build in release mode with optimizations zig build -Doptimize=ReleaseFast # Run the application zig build run # Run with arguments zig build run -- -V -c ~ /.config/skhd/skhdrc # Run tests zig build test Configuration & Usage Default Configuration Locations skhd.zig looks for configuration files in the following order: Path specified with -c flag ~/.config/skhd/skhdrc ~/.skhdrc The configuration syntax is fully compatible with the original skhd. See SYNTAX.md for the complete syntax reference and grammar. Configuration Directives # Use custom shell (skips interactive shell overhead) .shell " /bin/dash " # Blacklist applications (skip hotkey processing) .blacklist [ " dota2 " " Microsoft Remote Desktop " " VMware Fusion " ] # Load additional config files .load " ~/.config/skhd/extra.skhdrc " # Define process groups for reuse (New in skhd.zig!) .define terminal_apps [ " kitty " , " wezterm " , " terminal " ] .define native_apps [ " kitty " , " wezterm " , " chrome " , " whatsapp " ] .define browser_apps [ " chrome " , " safari " , " firefox " , " edge " ] # Define reusable commands with placeholders (New in skhd.zig!) .define yabai_focus : yabai -m window --focus {{1}} || yabai -m display --focus {{1}} .define yabai_swap : yabai -m window --swap {{1}} || (yabai -m window --display {{1}} && yabai -m display --focus {{1}}) .define toggle_app : open -a " {{1}} " || osascript -e ' tell app "{{1}}" to quit ' .define resize_window : yabai -m window --resize {{1}}:{{2}}:{{3}} .define toggle_scratchpad : yabai -m window --toggle {{1}} || open -a " {{2}} " Basic Hotkey Syntax # Basic format: modifier - key : command cmd - a : echo " Command+A pressed " # Multiple modifiers cmd + shift - t : open -a Terminal # Different modifier combinations ctrl - h : echo " Control+H " alt - space : echo " Alt+Space " shift - f1 : echo " Shift+F1 " Supported Modifiers # Basic modifiers cmd # Command key ctrl # Control key alt # Alt/Option key shift # Shift key fn # Function key # Left/right specific modifiers lcmd, rcmd # Left/right Command lctrl, rctrl # Left/right Control lalt, ralt # Left/right Alt lshift, rshift # Left/right Shift # Special modifier combinations hyper # cmd + shift + alt + ctrl meh # shift + alt + ctrl Special Keys # Navigation keys cmd - left : echo " Left arrow " cmd - right : echo " Right arrow " cmd - up : echo " Up arrow " cmd - down : echo " Down arrow " # Special keys cmd - space : echo " Space " cmd - return : echo " Return/Enter " cmd - tab : echo " Tab " cmd - escape : echo " Escape " cmd - delete : echo " Delete/Backspace " cmd - home : echo " Home " cmd - end : echo " End " cmd - pageup : echo " Page Up " cmd - pagedown : echo " Page Down " # Function keys cmd - f1 : echo " F1 " cmd - f12 : echo " F12 " # Media keys sound_up : echo " Volume Up " sound_down : echo " Volume Down " mute : echo " Mute " brightness_up : echo " Brightness Up " brightness_down : echo " Brightness Down " Process-Specific Bindings # Different commands for different applications cmd - n [ " terminal " : echo " New terminal window " " safari " : echo " New safari window " " finder " : echo " New finder window " * : echo " New window in other apps " ] Key Forwarding/Remapping # Keyboard layout fixes 0xa | 0x32 # UK keyboard § to ` shift - 0xa | shift - 0x32 # shift - § to ~ # Function key navigation (for laptop keyboards) fn - j | down fn - k | up fn - h | left fn - l | right # When you have cmd - number for yabai spaces, # and you still want the cmd - number to work in applications ctrl - 1 | cmd - 1 ctrl - 2 | cmd - 2 ctrl - 3 | cmd - 3 Passthrough Mode # Execute command but still send keypress to application cmd - p - > : echo " This runs but Cmd+P still goes to app " Modal Workflow with Visual Indicators # Window management mode with anybar visual indicator # Install anybar: brew install --cask anybar # Define window management mode for warp/stack operations # Use anybar to indicate the mode: https://github.com/tonsky/AnyBar :: winmode @ : echo -n " red " | nc -4u -w0 localhost 1738 :: default : echo -n " hollow " | nc -4u -w0 localhost 1738 # Enter window mode with meh + m (shift + alt + ctrl + m) meh - w ; winmode winmode < escape ; default winmode < meh - w ; default # Alternative: Enter window mode AND show notification (New in skhd.zig!) # This executes the command when switching to the mode # It allows for different commands to execute and switch to another mode meh - w ; winmode : osascript -e ' display notification "Window mode active" with title "skhd" ' winmode < escape ; default : osascript -e ' display notification "Normal mode" with title "skhd" ' # Focus operations - basic hjkl for focus winmode < h : yabai -m window --focus west || yabai -m display --focus west winmode < j : yabai -m window --focus south || yabai -m display --focus south winmode < k : yabai -m window --focus north || yabai -m display --focus north winmode < l : yabai -m window --focus east || yabai -m display --focus east # Move operations - shift + hjkl for moving winmode < shift - h : yabai -m window --move rel:-80:0 winmode < shift - j : yabai -m window --move rel:0:80 winmode < shift - k : yabai -m window --move rel:0:-80 winmode < shift - l : yabai -m window --move rel:80:0 # Warp operations - alt + shift + hjkl for warping winmode < alt + shift - h : yabai -m window --warp west winmode < alt + shift - j : yabai -m window --warp south winmode < alt + shift - k : yabai -m window --warp north winmode < alt + shift - l : yabai -m window --warp east # Stack operations - ctrl + shift + hjkl for stacking winmode < ctrl + shift - h : yabai -m window --stack west winmode < ctrl + shift - j : yabai -m window --stack south winmode < ctrl + shift - k : yabai -m window --stack north winmode < ctrl + shift - l : yabai -m window --stack east # Stack management shortcuts winmode < s : yabai -m window --insert stack # Toggle stack mode winmode < u : yabai -m window --toggle float ; yabai -m window --toggle float # Unstack window winmode < n : yabai -m window --focus stack.next # Navigate stack next winmode < p : yabai -m window --focus stack.prev # Navigate stack prev # Resize submode winmode < r ; resize :: resize @ : echo -n " orange " | nc -4u -w0 localhost 1738 resize < h : yabai -m window --resize left:-20:0 resize < j : yabai -m window --resize bottom:0:20 resize < k : yabai -m window --resize top:0:-20 resize < l : yabai -m window --resize right:20:0 resize < escape ; winmode Window Management Example # Focus windows using command definitions (New in skhd.zig!) cmd - h : @yabai_focus( " west " ) cmd - j : @yabai_focus( " south " ) cmd - k : @yabai_focus( " north " ) cmd - l : @yabai_focus( " east " ) # Move/swap windows using command definitions cmd + shift - h : @yabai_swap( " west " ) cmd + shift - j : @yabai_swap( " south " ) cmd + shift - k : @yabai_swap( " north " ) cmd + shift - l : @yabai_swap( " east " ) # Resize windows using command definitions cmd + ctrl - h : @resize_window( " left " , " -20 " , " 0 " ) cmd + ctrl - l : @resize_window( " right " , " 20 " , " 0 " ) # Switch spaces cmd - 1 : yabai -m space --focus 1 cmd - 2 : yabai -m space --focus 2 Application Launching Example # Quick app launching (traditional way) alt - return : open -a Terminal alt - b : open -a Safari # Toggle apps using command definitions (New in skhd.zig!) alt - f : @toggle_app( " Finder " ) alt - c : @toggle_app( " Visual Studio Code " ) # Scratchpad apps with yabai (New in skhd.zig!) # In yabairc: yabai -m rule --add app="^YouTube Music$" scratchpad=music grid=11:11:1:1:9:9 alt - m : @toggle_scratchpad( " music " , " YouTube Music " ) alt - n : @toggle_scratchpad( " notes " , " Notes " ) Text Editing Enhancements Example # Linux-style word navigation and deletion ctrl - backspace [ @native_apps ~ # Terminal apps handle natively * | alt - backspace # Other apps: delete word ] ctrl - left [ @native_apps ~ # Terminal apps handle natively * | alt - left # Other apps: move word left ] ctrl - right [ @native_apps ~ # Terminal apps handle natively * | alt - right # Other apps: move word right ] # Home/End key behavior (with shift for selection) home [ @native_apps ~ # Terminal apps handle natively * | cmd - left # Other apps: line start ] shift - home [ @native_apps ~ # Terminal apps handle natively * | cmd + shift - left # Other apps: select to line start ] # Ctrl+Home/End for document navigation ctrl - home [ @native_apps ~ # Terminal apps handle natively * | cmd - up # Other apps: document start ] ctrl - end [ @native_apps ~ # Terminal apps handle natively * | cmd - down # Other apps: document end ] Testing and Debugging Debug vs Release Builds Important: The logging and profiling behavior differs between build modes: ReleaseFast builds (installed via Homebrew or built with -Doptimize=ReleaseFast ): Only show errors and warnings, even with -V / --verbose flag Profiling ( -P / --profile ) is disabled - all tracing code is compiled out for maximum performance (installed via Homebrew or built with ): ReleaseSafe builds (built with -Doptimize=ReleaseSafe ): Show errors, warnings, and info messages with -V / --verbose flag Profiling ( -P / --profile ) is available for production debugging (built with ): Debug builds (default zig build ): Show all log levels including debug messages with -V / --verbose flag Profiling ( -P / --profile ) is available with full trace details (default ): However, command output will be shown if verbose flag is specified in release builds. This is a trade-off between convenience and performance: Performance mode (default): Command output is discarded for faster execution (default): Command output is discarded for faster execution Verbose mode ( -V ): Command output is preserved, which may add slight overhead but helps with trouble shooting To debug hotkey events and see detailed logging: # Verbose logging for troubleshooting config issues # Note: In release builds, verbose mode only shows errors and warnings. # To see debug/info logs, use a debug build: zig build run -- -V Performance: The event loop is allocation-free in release builds, ensuring consistent low-latency hotkey processing. Testing Commands # Test key combinations and hex code (observe mode) skhd -o # Profile event handling (show after CTRL+C) # Note: Profiling works in Debug and ReleaseSafe builds only zig build && ./zig-out/bin/skhd -P # or for production debugging: zig build -Doptimize=ReleaseSafe && ./zig-out/bin/skhd -P # Test specific keypress skhd -k " cmd + shift - t " # Test text synthesis skhd -t " hello world " # Reload config of running instance skhd -r # Debug memory allocations with real-time tracking zig build alloc -- -V Contributing Fork the repository Create a feature branch Make your changes Run tests: zig build test Submit a pull request License This project maintains compatibility with the original skhd license.