Lock the keyboard. Clean it. Type the codeword to unlock.
A small macOS utility that swallows every keystroke until you type a short
randomly-chosen codeword — so you can wipe the keys, dust the chassis, or
swap a switch without overwriting your terminal with asdfasdfqwer. The lock
covers every monitor, ignores Mission Control / Space-swipes, and survives
Magic Mouse fingertip-static while staying fully reversible: type the codeword,
or hit ⌘⌥Esc, and your machine is exactly where you left it.
Cleaning a plugged-in keyboard means dragged windows, trashed text fields, accidental Cmd-Q, and the occasional fullscreen toggle from a stray F-key. KeebLock takes the keyboard offline without unplugging it: it installs a global event tap, displays a borderless lock surface on every screen, swallows mouse / scroll / gesture input, and only releases when you type the chosen codeword on a clean key (or when the optional auto-unlock timer expires).
- Random codeword to unlock — re-rollable, visible on screen, drawn from 103 hand-curated single-word entries (mostly geology / minerals) with Wikipedia summaries and "Did you know?" trivia rotated at every 30 keystrokes.
- Multi-display covered, including fullscreen Spaces — uses both
.canJoinAllSpacesand the private CGS API (CGSAddWindowsToSpaces,CGSManagedDisplaySetCurrentSpace) so a display parked on another app's fullscreen Space gets pulled to a regular Desktop for the lock and symmetrically restored on unlock. Resolved viadlsymso a future macOS symbol change degrades to the public flag instead of crashing. - Five accent themes — Day, Sleepy, Sakura, Coffee, Bath. Tints launcher, HUD codeword progress, settings group headers, and ships matching app-icon variants for each theme.
- Five screen effects — sparks, rain, matrix, bubbles, snow — each on a Metal shader path, intensity slider, optional sound.
- App zoom — ⌘+ / ⌘− / ⌘0 scales the window 0.8× → 1.6× without giving up pixel-perfect controls (no dynamic-type scaling fallout).
- Heatmap — per-session and cumulative hit counts per physical keycode, rendered with the active keyboard-layout's actual labels (UCKeyTranslate).
- Cleaning history — every session is recorded with duration, keystroke count, and pixel-wipe stage reached.
- Time-boxed lock (opt-in) — pick a duration in Settings; the lock can auto-release when the timer hits zero. Off by default — codeword is the primary exit.
- Build authenticity — launcher footer surfaces the running binary's Apple Team ID + CDHash, with a one-click "I've verified" toggle that turns the shield green only when the published values match.
- Self-rotating diagnostic log —
~/Library/Logs/KeebLock/keeblock.logrotates once it crosses a configurable size cap (1–100 MB, default 5 MB). - Keyboard-layout aware — translates physical keycodes through the active input source for the heatmap; Greek / Cyrillic / etc. fall back to US-ANSI positions so codeword matching always works by key location.
- No telemetry, no PII, no network — everything stays on your Mac. The event tap reads keystrokes purely to count and swallow them.
The Asset Catalog ships all five tinted variants; the active accent theme also recolours the SwiftUI surfaces (shortcut badges, codeword card, HUD codeword progress, settings group headers).
- macOS 26 or newer (deployment target).
- Apple Silicon or Intel Mac with Metal-capable GPU (any Mac from 2014+).
- Accessibility permission — required to install the global
CGEventTapthat swallows keystrokes. KeebLock asks for it on first run and the launcher banner clears the moment you grant it in System Settings.
-
Grab the latest
KeebLock-x.y.z.zipfrom the Releases page and unzip — you getKeebLock.app. -
Move it into
/Applications. -
The app is signed with a Personal Team certificate (no Apple Developer ID notarisation), so Gatekeeper refuses to launch it on first try. Clear the macOS quarantine flag once:
xattr -dr com.apple.quarantine /Applications/KeebLock.app
Then right-click → Open → Open to confirm. Subsequent launches work normally.
-
Grant Accessibility permission when KeebLock asks (System Settings → Privacy & Security → Accessibility).
Each release publishes the Apple Team ID and CDHash that the build was signed with. The launcher footer shows the same pair from the running binary. To confirm in Terminal:
codesign -dv --verbose=4 /Applications/KeebLock.app 2>&1 \
| grep -E '^(TeamIdentifier|CDHash)='TeamIdentifier is constant across every official KeebLock release —
forging it requires the original signing certificate. CDHash is unique
to each build. Click the orange shield in the launcher, compare with the
release notes, then mark verified to turn it green.
git clone https://github.com/bmmmm/KeebLock.git
cd KeebLock
scripts/build.sh # Debug build, errors / warnings filtered
scripts/install.sh # copies KeebLock.app into /Applications- Open KeebLock from
/Applications. - The launcher shows an orange Accessibility permission required banner. Click Open System Settings.
- In Privacy & Security → Accessibility, enable KeebLock.
- Switch back to KeebLock — the banner clears within a second.
- Press the big button (or hit Return) to start the lock.
| Shortcut | Action |
|---|---|
⌘S / Return |
Start lock |
⌘R |
Roll a new random codeword |
⌘, |
Open Settings tab |
⌘+ / ⌘− |
Zoom the launcher / settings UI |
⌘0 |
Reset zoom to 100 % |
⌘Q |
Quit KeebLock |
| Codeword | …type it on a clean key to unlock |
⌘⌥Esc |
macOS force-quit (always-available exit) |
There is intentionally no Stop Cleaning shortcut: the only way out of an active session is the codeword (or the macOS force-quit panel). A one-click stop would defeat the whole point of the app.
While locked, the HUD shows codeword progress, per-session keystroke breakdown (letters / numbers / symbols / control / function / media keys, mouse buttons, scroll, swipes, pinch, rotate), and a Wikipedia-derived "Did you know?" card for the current codeword.
- No network requests. The codeword data and images ship in the bundle.
- The event tap reads key events to count and swallow them — they are not logged, not stored, not exfiltrated.
- The heatmap stores aggregate hit counts per physical key code, not the characters you typed.
- Logs in
~/Library/Logs/KeebLock/are purely diagnostic; the codeword itself is never written, only its character count. - Per-session counters live in memory; the cumulative heatmap and cleaning history are persisted to UserDefaults under the app's bundle id and scoped to your user account.
scripts/uninstall.shremoves the app, all UserDefaults entries, and~/Library/Logs/KeebLock/. The Accessibility entry in System Settings must be removed manually — macOS does not let apps revoke their own TCC entries.
103 single-word entries grouped by theme (predominantly minerals and geological formations). Each entry carries:
- A canonical title (e.g. "Granite", "Peridotite").
- A 2–3 sentence Wikipedia summary.
- A small set of factoids and a derived "Did you know?" snippet rotation.
- A landscape Wikimedia Commons image, license-checked and resized.
- The original image's licence + author + URL, gathered into
KeebLock/Resources/CodewordImages/CREDITS.md.
To regenerate the dataset (Wikipedia REST → bundle resource):
scripts/fetch_codeword_data.py # incremental; --force rebuilds
scripts/build_dyk.py # offline DYK fallback (or LLM externally)
scripts/build_credits.py # render CREDITS.md from attributionThe shipped codeword_data.json was hand-tuned per word; the scripts are
the regeneration path, not the canonical source.
scripts/build.sh # Debug build (filtered output)
scripts/build.sh full # full xcodebuild log
scripts/build.sh release # Release configuration
scripts/build.sh analyze # Clang static analyzer
scripts/build.sh clean # wipe build/DerivedDataVersions are derived from git: MARKETING_VERSION from the latest tag,
CFBundleVersion from git rev-list --count HEAD. A build phase patches
the generated Info.plist so even a plain Xcode ⌘B picks up the right
version without touching pbxproj.
Code-signing uses Automatic + your Personal Team (free Apple Developer
account). Open the project in Xcode once and pick your team under
Target → Signing & Capabilities if the build complains about signing.
App Sandbox is off — required for CGEventTap global hooks. Hardened
Runtime is on.
scripts/release.sh 0.2.0What it does:
- Tags
v0.2.0, pushes to Forgejo (the GitHub mirror auto-syncs). - Builds Release with the version pinned to that tag.
- Packages
KeebLock.appintoKeebLock-0.2.0.zip(dittopreserves codesign + xattrs). - Captures Team ID + CDHash from
codesign -dvand embeds them in the release notes alongside the SHA-256 of the zip. - Publishes the release on Forgejo via
tea. Forgejo's push-mirror propagates tag + asset to GitHub within minutes.
Pass --notes "..." to override the default install / authenticity block.
scripts/uninstall.shRemoves the app, its UserDefaults blob, and ~/Library/Logs/KeebLock/.
Revoke Accessibility manually in System Settings → Privacy & Security.
- Code — Apache License 2.0.
- Codeword images in
KeebLock/Resources/CodewordImages/retain their original Wikimedia / Wikipedia licences; per-image attribution is documented inCREDITS.md. 63 of the 103 are share-alike — redistribution must include the credits file. - App icon family + banner — © bmmmm, all rights reserved.
- Wikipedia / Wikimedia Commons contributors for every codeword summary and image.
- The reverse-engineered CGS APIs (
CGSAddWindowsToSpaces,CGSManagedDisplaySetCurrentSpace) ride on a decade of work by the yabai / Hammerspoon / Stay communities.
If KeebLock saved you from a bowl of crumbs, you can buy me a coffee: ko-fi.com/bmabma.
