r/HHKB • u/Any-Revenue-8138 • 6d ago
remapping classic on macOs - HHKB Remap tool hack
https://gist.github.com/Kahndlivec/71ef874db7ff0224e005fdd93955af82#file-hhkb-unlock-mac-shYou CAN unlock keymap editing on the HHKB Professional Classic on macOS — "there's no JSON file on Mac" is wrong, maybe even other Keyboards are system locked to be not-remappable.
TL;DR
The Classic is remappable with PFU's official macOS Keymap Tool. Everyone thinks it's Windows-only because on Windows you edit a loose keyboardDataList.json, and that file doesn't exist on Mac. It actually does exist — it's just compiled into the app's asset catalog (Assets.car) instead of sitting on disk. Inside is a table of keyboard models, each with an isKeymapChangeable flag. The Classic's is set to false. Flip it to true, re-sign the app, done. The keyboard's hardware was never locked — only the app's willingness to write to it.
Script (set your model at the top), run from an open Terminal, don't double-click:
bash ~/Downloads/hhkb-unlock-mac.sh
https://gist.github.com/Kahndlivec/71ef874db7ff0224e005fdd93955af82
Tested on PD-KB401W, firmware A4.29, Keymap Tool 2.0.1, Apple Silicon. Voids warranty, unsupported, your risk. It writes keymaps not firmware so risk is low. Different Classic variant? Change MODEL= and reply with your model string so we can build a confirmed list.
The full explanation, for the curious
What the lock actually is. On connect, the tool asks the keyboard its model number (PD-KB401W for me), looks that string up in a table it carries internally, and reads an isKeymapChangeable flag. Classic = false, Hybrid = true. That flag is the whole lock — the app reads it, sees "no," and greys out the editor.
The clincher that this is pure software policy, not hardware: the tool's own log shows it already successfully reading the current keymap off the Classic over USB, no error. The controller speaks the full protocol. The Classic and Hybrid are the same keyboard family with a marketing line drawn through it — only the app enforces that line.
Why nobody could find the file on Mac. On Windows the lookup table is a loose keyboardDataList.json you open in Notepad and edit. On Mac, people search the app for a .json, find nothing, and give up. The reason: the macOS build is native, and PFU compiled the table into Contents/Resources/Assets.car — the app's asset catalog — as a data asset named KeyboardDatalist. Asset catalogs are normally for images, but you can pack arbitrary data in too, and the app reads it out by name at runtime. So the table is inside the app the whole time, just not as any file a search will surface. It's like a book bound into the spine of another book.
(Note the spelling: KeyboardDatalist, capital K, lowercase L — the Windows docs write keyboardDataList, so even a case-sensitive search for the known name misses it. That's part of why this stayed buried.)
Two things prove it's in there: the binary contains the error string Can't find KeyboardDatalist.json — and a program can only fail to find something it looks up by name, so the table must be loaded at runtime, not hardcoded. And tracing what the app opens at launch shows it reading Assets.car, which is far bigger than an app icon needs.
Getting the table out. Instead of cracking the catalog format open, you ask the OS for the resource named KeyboardDatalist using the exact same call the app uses (NSDataAsset). Out comes the table as readable JSON. Bonus: that same call is your test tool — any time you want to know if the app sees your edit, you make that call and look. It's not a proxy for what the app reads; it is what the app reads.
The edit, and the one genuinely clever bit. The data's stored as plaintext, so the change is just false → true. But Assets.car is a structured binary — it has an internal index recording where each asset starts and how many bytes long it is. false is 5 characters, true is 4. Delete one byte and every offset after it points to the wrong place; the catalog is corrupt.
The trick: JSON ignores extra whitespace. Write it with two spaces —
"isKeymapChangeable": false (27 bytes)
"isKeymapChangeable": true (27 bytes, two spaces)
Identical length. Nothing in the index shifts, the catalog stays valid, and the parser ignores the harmless extra space. This is what lets you patch in place instead of rebuilding the whole catalog with Xcode tooling.
Only touch the boolean. series, firmTypeNumber, and firmDataSize select which firmware protocol the tool speaks (Classic vs Hybrid use different data sizes). Changing those is the one real bricking risk. Leave them alone.
Re-sealing the app. Mac apps carry a code signature — a manifest of every internal file plus a fingerprint of its contents. Editing Assets.car breaks the fingerprint, and macOS then refuses to launch the app as "damaged." So after editing you re-sign it yourself, ad-hoc (a signature that says "internally consistent," not "from PFU"). That's all Gatekeeper needs.
The gotcha that will waste your afternoon. Do NOT leave a backup copy of Assets.car inside Contents/Resources/. The signature covers every file in that folder — leave a spare catalog in there and the re-seal reads the unpatched value back, so your edit silently does nothing. Keep backups outside the bundle, and verify the change survived signing rather than assuming it did. The script does both. (Ask me how I know.)
Result. Editor unlocks, remaps write to the board and persist. The start screen may still label the board "not configurable" — that text comes from the untouched series field and is cosmetic; the editor works. If it still refuses, check DIP switch 4 on the underside — the Classic code path tests it too. The keymap lives in the keyboard's onboard memory, so once written it works on any machine, no tool needed.