Repository navigation
Releases
v1.2.0 — Custom Key Actions, Profiles & UX Polish
What's New in v1.2.0
This release is a significant feature expansion. All changes are build-verified via swift build and ready for testing via ./build.sh.
🎛️ Custom Key Remapping
Each F-key can now be remapped to any of four action types:
| Type | What it does |
|---|---|
| System | Original macOS HID/CGEvent function (default, unchanged) |
| App | Launch or activate any app by bundle ID (e.g. com.apple.Safari) |
| URL | Open any URL — https://, file://, or custom schemes |
| Shell | Run an arbitrary command via /bin/sh -c in the background |
Custom actions respect the same 150 ms rate-limit and 200 ms tap-debounce as system keys. Remapped keys show a distinct SF Symbol icon and updated tooltip in the popover.
👤 Profiles
Save and switch between named sets of key mappings:
- Right-click the menu-bar icon to instantly switch profiles (active profile shown with a checkmark)
- Create, duplicate, and delete profiles from the new Profiles tab in Settings
- The built-in Default profile has a stable UUID and cannot be deleted
- Switching profiles takes effect immediately across the entire popover
⚙️ Settings Window
Opens via ⌘, or the gear icon in the popover header.
- Keys tab — per-key segmented type picker, detail input field, per-key reset button, active profile name in the header, and a global "Reset All" button
- Profiles tab — full CRUD for profiles with inline creation
🚀 Launch at Login
A Login checkbox in the popover footer registers the app as a login item via SMAppService.mainApp (macOS 13+, no helper bundle required).
The app must be located in
/Applicationsfor this to take effect at runtime.
🔒 Auto-Dismiss
An Auto-close checkbox in the popover footer closes the popover automatically after any key is pressed. The popover waits for the spring-press animation to finish before dismissing.
📊 Live State Indicators
Brightness and volume levels are now visible directly on the relevant keys:
- F1 / F2 — brightness bar (polls via IOKit
IODisplayGetFloatParameter) - F11 / F12 — volume bar (polls via CoreAudio)
- F10 — bar turns red and empties when muted
State is polled every 1 second in a background Timer; no private APIs are used.
🗂️ New Source Files
| File | Description |
|---|---|
KeyAction.swift |
enum KeyAction with Codable conformance and display helpers |
KeyActionStore.swift |
ObservableObject delegating to ProfileManager |
KeyProfile.swift |
Identifiable + Codable profile model |
ProfileManager.swift |
Profile CRUD + active-profile persistence |
LaunchAtLoginManager.swift |
Thin SMAppService wrapper |
SystemStateMonitor.swift |
IOKit + CoreAudio polling |
SettingsView.swift |
Tabbed settings UI (Keys + Profiles) |
🔧 Modified Files
KeySimulator.swift · FunctionKeyView.swift · KeyboardView.swift · FnKeyboardApp.swift · Info.plist
Full Changelog: 1.1.0...1.2.0
Version 1.1.0
FnKeyboard v1.1.0 — Security Hardening
This release significantly hardens FnKeyboard's security posture — from memory safety in low-level system APIs to build-time integrity checks and runtime protections against event flooding.
What's New
Runtime Security
- Memory-safe event tap lifecycle — replaced raw
Unmanaged<Self>pointer with a weak-referenceTapContextwrapper, eliminating dangling-pointer dereferences if the monitor is deallocated while the CGEvent tap callback is in-flight - Thread-safe monitoring flag —
isMonitoringis now protected byNSLockfor safe access across the main thread and the CGEvent tap callback - CGEvent memory leak fix — switched from
passRetainedtopassUnretainedfor event return values (listenOnly taps ignore the return, so retaining leaked every keyboard event flowing through the system) - Reduced event surface — removed
flagsChangedfrom the event mask; onlykeyDownandkeyUpare intercepted
Rate Limiting & Debouncing
- Per-key rate limiting in
KeySimulator— enforces a 150ms minimum interval between simulated presses, preventing event flooding from rapid automated clicks - UI tap debouncing in
FunctionKeyView— 200ms cooldown as a second layer of defense - Input validation —
KeySimulatornow validates key IDs (1–12) before processing @MainActorannotation onKeySimulatorto guarantee thread-safe access to mutable state
Build & Signing
- Hardened Runtime with zero entitlement exceptions — protects against
DYLD_INSERT_LIBRARIESinjection, unsigned executable memory, and debugger attachment - Code signing integrated into build.sh with support for
CODESIGN_IDENTITY(distribution) and ad-hoc fallback (development) - SHA-256 integrity verification of generate_icon.swift against the committed version before execution (supply-chain protection)
--timestampon distribution signatures for notarization support
Other Improvements
- Added
NSAccessibilityUsageDescriptionto Info.plist for a clear permission prompt - Added comprehensive Security section to README documenting permissions, privilege model, and runtime protections
- Added installation guide with download and build-from-source paths
- Dual-architecture release builds (arm64 + x86_64 DMGs) via
.build.sh --release
Download
| File | Architecture |
|---|---|
FnKeyboard-macos-arm64.dmg |
Apple Silicon (M1/M2/M3/M4) |
FnKeyboard-macos-x86_64.dmg |
Intel |
Upgrading
Drop-in replacement — just replace the app in Applications. Make sure to remove and add permissions in Accesibility and Input Monitoring. Run xattr -cr /path/to/FnKeyboard.app to bypass Gatekeeper due to a lack of a developer certificate at the time of building.
Version 1.0.0
FnKeyboard v1.0
A lightweight macOS menu-bar utility that puts the Mac function keys (F1–F12) at your fingertips.
Highlights
- Menu-bar only — no Dock icon, no windows, just a clean ⌨️ in your status bar
- Tap to trigger — click any keycap to fire the real system action (brightness, media, volume, etc.)
- Physical key detection — highlights keys as you press them on your keyboard
- Native look — SF Symbols, hover animations, and automatic light/dark mode support
- Tiny footprint — ~1 MB, no dependencies, pure Swift + SwiftUI
Requirements
- macOS 13.0 (Ventura) or later
- Input Monitoring permission (prompted on first launch)
Downloads
| File | Architecture |
|---|---|
FnKeyboard-macos-arm64.dmg |
Apple Silicon (M1, M2, M3, M4) |
FnKeyboard-macos-x86_64.dmg |
Intel |
Install
- Download the DMG for your Mac
- Open the DMG and drag FnKeyboard to Applications
- Launch from Applications — grant Input Monitoring when prompted
- Click the ⌨️ icon in your menu bar to use
- Run
xattr -cr /path/to/FnKeyboard.appto bypass Gatekeeper due to a lack of a developer certificate at the time of building.