A tiny native macOS menu-bar app that keeps a Logitech K380 (including K380 for Mac) in function-keys-primary mode.
Out of the box the top row is media / “smart” keys; F1–F12 need Fn. Logitech Options can invert that. This app sends the same short HID++ output report to the keyboard and keeps sending it, because the firmware does not remember the setting. It reverts after power-off, Easy-Switch, sleep/wake, or Bluetooth glitches.
There is no Dock icon. Control it from the Fn item in the menu bar. Finder and System Settings show a cream Fn app icon.
No Logitech software, no hidapi, no Karabiner, no hidutil, no network.
Works with:
| Keyboard | USB/Bluetooth ID |
|---|---|
| K380 | 046D:B342 |
| K380 for Mac | 046D:B362 |
Any Logitech HID device whose product name contains K380 is also matched.
Languages: English (default) and Português (Brasil). Follows the Mac’s first preferred language, or pick one in Settings.
Requires macOS 13+ (Apple silicon or Intel).
This app was written with AI assistance (vibe coded 🦾🤖). It is provided as-is, with no warranty — review the source and the HID report bytes yourself before trusting it with your keyboard.
You need Xcode Command Line Tools:
xcode-select --installThen, in the project folder:
./scripts/build.sh
open dist/K380Fn.appbuild.sh will:
- Run tests (
./scripts/test.sh; skip withSKIP_TESTS=1) - Compile with
swiftc(not SwiftPM — some Command Line Tools installs cannot loadPackage.swift) - Wrap
dist/K380Fn.appand ad-hoc codesign it (com.github.cobalto.k380fn) - Quit any running K380 Fn and reset Input Monitoring for this bundle (
tccutil reset ListenEvent com.github.cobalto.k380fn)
Skip the quit/reset with SKIP_RESET=1 ./scripts/build.sh if the current build is already authorized and you only changed UI.
Package.swift is only for opening the folder in Xcode. Day-to-day builds are ./scripts/build.sh.
macOS will not let the app talk to the keyboard until Input Monitoring is granted to this exact .app.
- Connect the K380 over Bluetooth and select this Mac’s Easy-Switch slot.
open dist/K380Fn.app— look at the right of the menu bar for Fn.- Click Allow on the Input Monitoring prompt. (If you click Don’t Allow, HID will fail until you reset — see below.)
- System Settings → Privacy & Security → Input Monitoring
- Turn on K380 Fn.
- If you see two K380 Fn rows, enable the one whose path is
…/K380-FunKit/dist/K380Fn.app
A copy in Applications is a different app. Toggling that one does nothing fordist/.
- Optional: allow notifications (failures only, never success).
- Menu: Enable F-keys primary if it is not already on, or Re-apply now.
F1–F12 should work without Fn; media keys should need Fn.
Ad-hoc signing is a new Input Monitoring client each time the binary changes. ./scripts/build.sh resets TCC for you. Then:
open dist/K380Fn.appClick Allow, and enable the dist row again if macOS lists more than one K380 Fn.
Reset without rebuilding (quits the app):
./scripts/reset-permissions.sh
open dist/K380Fn.appIn Settings: Forget Input Monitoring permission… runs the same tccutil reset (it removes the app from the list). Use Re-apply now on the menu if the keyboard is merely stuck.
Menu bar: Fn plus a status mark (filled = F-keys on, hollow = off, × = no keyboard, lock/warning = permission or write error). Settings can switch the mark to short text (On / Off). Hover for a longer explanation.
Click Fn:
- One status line
- Enable / Disable F-keys primary
- Settings…
- Quit K380 Fn
- Re-apply now (always): send the HID report again, no System Settings changes
- When permission is missing: Open Input Monitoring…
Settings
- F-keys primary, Launch at Login, glyph vs text, language
- Copy a diagnostics report (for GitHub issues)
- Input Monitoring / re-apply / permission reset
- About tab
Launch at Login uses SMAppService (no Apple Developer account). You can also add dist/K380Fn.app under System Settings → General → Login Items — use the same copy you authorized.
- F-keys primary: F1–F12 without Fn; media needs Fn.
- Turn the keyboard off and on, or Easy-Switch away and back: the mode should return by itself.
- Sleep/wake the Mac: same.
- Disable F-keys primary: factory-like media row; enable again.
Logs:
log stream --predicate 'eventMessage CONTAINS "K380Fn"' --style compactA good write looks like SetReport ... -> 0x00000000.
| What you see | What it usually means | What to do |
|---|---|---|
| Input Monitoring required | macOS blocked IOHIDManagerOpen (0xe00002e2). The switch in Settings is for a different signature or path. |
Quit the app. ./scripts/reset-permissions.sh then open dist/K380Fn.app. Click Allow. Enable the dist row, not Applications. |
| Waiting for K380 | No matching HID device (Bluetooth off, wrong Easy-Switch slot, or keyboard asleep). | Pair the K380; press this Mac’s Easy-Switch key; power-cycle the keyboard. |
| Write failed / retrying | Device seen but the report was rejected (often right after connect). | Wait a few seconds; Re-apply now. |
| Two K380 Fn in Input Monitoring | dist/ vs /Applications/ (or an old rebuild). |
Authorize the path you actually open. |
| Top row still media after “applied” | Wrong Easy-Switch device, or Options+ fighting the same report. | Confirm this Mac is the active slot. Quit Options+ if it is installed. |
Copy report for GitHub in Settings pastes version, status, and recent HID lines.
HID++ 1.0 output report, report ID 0x10:
| Mode | Bytes |
|---|---|
| F-keys primary | 10 FF 0B 1E 00 00 00 |
| Media primary | 10 FF 0B 1E 01 00 00 |
Tried as 7 bytes (including report ID) then 6 bytes (without), on every matching K380 collection until one write succeeds. Retries with backoff after attach; re-applies about every 15 seconds and on wake.
Use and share freely. Not affiliated with Logitech.