A fast, reliable command-line tool to toggle the behavior of function keys on your Mac.
- Fast: Optimized timing (~3-4 seconds)
- Reliable: Automatic retry logic handles intermittent timing issues
- Smart Cleanup: Only waits for process cleanup if System Settings was actually running
- Detailed Logging: Console output with emojis shows exactly what's happening at each step
- Audio Feedback: Subtle sound effects confirm success or alert failures
- Clean Code: Well-structured and easy to maintain
- Keyboard Shortcut: Optional global hotkey setup with Hammerspoon
- Configurable: Easy-to-tune delay settings
This tool toggles between:
- Standard function keys (F1-F12): Function keys act as F1, F2, F3, etc.
- Special multimedia keys: Function keys control brightness, volume, etc.
- macOS (tested on MacBook Pro M4 with macOS Sequoia)
- Accessibility permissions for your Terminal app (Terminal.app, iTerm2, Warp, etc.)
- Open System Settings > Privacy & Security > Accessibility
- Click the lock icon and authenticate
- Add your terminal application to the list
- Toggle it ON
Simply run:
./fn-toggle.shThe script will:
- Open System Settings
- Navigate to Function Keys settings
- Toggle the checkbox
- Close System Settings
- Play a Tink sound on success (keyboard click sound)
- Changes take effect immediately!
On Success:
- Displays:
✓ Done! Fn key behavior toggled. - Plays subtle "Tink" sound (like a keyboard click)
- Settings close automatically
On Timing Issues:
- Automatically retries up to 3 times
- Shows progress:
⚠ Attempt N failed (timing issue). Retrying... - Usually succeeds on retry
On Failure:
- Displays:
✗ Failed after 3 attempts. - Plays "Basso" error sound
- Suggests increasing delay in configuration
To test:
- Press F1, F2, F3, etc. on your Mac's built-in keyboard (without holding Fn)
- The behavior should have changed
Optional - Add to PATH:
Create an alias in your ~/.zshrc:
alias fn-toggle='/Users/shayshimonov/Projects/fn-toggle/fn-toggle.sh'Then you can run fn-toggle from anywhere!
Optional - Global Keyboard Shortcut:
For instant toggling with a keyboard shortcut, use Hammerspoon:
- Install Hammerspoon:
brew install --cask hammerspoon - Add to
~/.hammerspoon/init.lua:
hs.hotkey.bind({"ctrl", "shift"}, "A", function()
hs.execute("/Users/shayshimonov/Projects/fn-toggle/fn-toggle.sh")
end)- Now press
⌃⇧A(Control+Shift+A) from anywhere to toggle!
All timing delays and settings are at the top of fn-toggle.sh:
# Timing delays (optimized for speed and reliability)
DELAY_PROCESS_CLEANUP=0.5 # Wait after killing System Settings
DELAY_SETTINGS_ACTIVATION=0.5 # Wait for System Settings to activate
DELAY_SEARCH_RESULTS=0.5 # Wait for search results to populate
DELAY_NAVIGATION=0.2 # Wait after navigation
DELAY_DIALOG_OPEN=0.6 # Wait for dialog to fully load (critical)
# Retry settings
MAX_RETRIES=3 # Maximum retry attempts
RETRY_DELAY=0.2 # Wait between retries
# Sound feedback
SOUND_SUCCESS="/System/Library/Sounds/Tink.aiff"
SOUND_FAILURE="/System/Library/Sounds/Basso.aiff"Delays are optimized for speed while maintaining reliability. Adjust if needed for your system.
The script uses AppleScript with UI automation to:
- Check if System Settings is running (only cleans up if needed)
- Search for "Function Keys" in System Settings
- Navigate to the Function Keys dialog
- Click the checkbox at path:
sheet 1 → group 1 → splitter group 1 → group 2 → scroll area 1 → group 1 → checkbox 1 - Close System Settings
- The toggle happens instantly without needing to restart or log out
Console output shows detailed progress with emoji indicators (🚀 ⏳ ✅ ❌) at each step for easy troubleshooting.
- Runtime: ~3-4 seconds
- Smart Cleanup: Skips 0.5s delay if System Settings wasn't running (faster subsequent runs)
- Reliability: Automatic retry logic handles intermittent timing failures
- Success Rate: >95% with retry mechanism
- Detailed Logging: Console output with emojis for easy troubleshooting
1= Standard function keys (F1-F12)0= Multimedia keys by default
- Attempts to toggle the Fn key setting
- Logs every step with emoji indicators for easy tracking
- If AppleScript fails, automatically retries (up to 3 attempts)
- Waits 0.2s between retries
- Success detected by checking for "Current state:" in output
- Permission errors exit immediately (no point retrying)
- Plays appropriate sound feedback (Tink for success, Basso for failure)
The script modifies:
com.apple.keyboard.fnState(global preferences)AppleFnUsageTypeincom.apple.HIToolbox
This script only affects the Mac's built-in keyboard. External keyboards may behave differently depending on their own settings.
/Users/shayshimonov/Projects/fn-toggle/
├── fn-toggle.sh # Main script ⭐
├── README.md # Documentation
├── package.json # npm scripts (npm start)
└── .vscode/ # Editor configuration
├── tasks.json # Build tasks
└── launch.json # Run configurations
# Command line
./fn-toggle.sh
# Or with npm
npm start