The pads with a few keys and a knob ship with software that only runs on Windows, a configurator that only runs in Chrome, or nothing at all. Knurl is the Mac side of them. Three wire protocols, one of them reverse engineered here and documented down to the byte.
Knurl reads the key table off the hardware whenever it connects, so the window can never show you something the keypad isn't actually carrying.
Turn left, press and turn right each take a key sequence, a media key or a mouse action. Record a shortcut live, or pick from the list for the keys a Mac keyboard cannot physically send: F13 to F24, Print Screen, Num Lock, the numeric keypad.
Global is the fallback, and every app you add holds its own key set. Bring Final Cut forward and its keys are written to the pad. A set already on the device is skipped, so switching costs nothing.
Written against slots rather than a specific pad, so the same template lands sensibly on three keys or on twelve, and shortcuts resolve against your keyboard layout instead of assuming a US one.
Effect, speed and colour come off the device on connect and go back to it as you make changes. No save step, and nothing cached that could drift out of sync.
Everything is written to the keypad's own flash. It survives unplugging and follows the pad to any machine you carry it to, Windows included.
Every frame sent and received, in the window. It is how the third protocol got decoded, and it is still there so you can watch what the app does to your hardware.
Parts lifted off a neutral ground, dark wells for anything holding data, monospaced labels in small caps, indicator lamps, and readouts plotted as dot fields because macOS ships no pixel face.
Turn on following the front app and the keypad rewrites itself as you move between programs. Apps without their own keys fall back to Global, and a scope already on the device is left alone.
Music, clipboard, design, video editing, screenshots and browser tabs. Each card lists exactly what it will put on every key before you commit, and the lit one is the set the keypad is holding right now.
Off, solid, breathing, blink and tide. Speed goes to four rather than five because the firmware accepts a five and then behaves erratically, and tide always runs the palette, so it is given no colour control.
Every switch the app has sits in one window rather than behind a separate settings shortcut. Underneath, the HID log: 06 08 3A reads a block of the key table, 06 0A reads the backlight.
The device menu picks it up on its own. A green dot means it is connected, and Knurl has already read the key table off the hardware.
Click a key in the pad view, or one of the knob's three segments. Record a shortcut live, or choose a media key from the list.
The mapping goes into the pad's own flash. Unplug it, move it to another machine, and it is still carrying what you set.
Two of the three wire formats are ported from rOzzy1987/MacroPad. This one, used by the pads whose vendor configures them through a WebHID page, was reverse engineered for Knurl and verified against the hardware: reading the key table returned exactly the Ctrl+A those keys type, and a write read back byte for byte. Frames are 64 bytes on report id 0, and byte 0 is always 06.
| Frame | Meaning |
|---|---|
| 06 05 | Read device info. Replies AA 05 <len> with pid, firmware, profile and layer counts |
| 06 08 3A <offLo> <offHi> 00 <layer> | Read 56 bytes of the key table |
| 06 10 07 <off> 00 <layer> 00 <type> <c1> <c2> <c3> | Write one key, at offset 4 × keyIndex |
| 06 09 <len> <off> 00 <layer> 00 | Write a block of entries |
| 06 0A · 06 0B | Read and write the backlight block: effect, speed, direction, hue |
| 06 FB <n> | Select a stored profile |
| 06 0F FF | Factory reset |
Subcommand 0x5A drops the device into its bootloader. Which is why blind command sweeping is a bad way to explore this family, and why the frame format is written down here rather than left for the next person to rediscover.
Anything else is still found automatically. Knurl looks for an interface on a vendor usage page, 0xFF00 or higher, carrying reports of 64 bytes, on a device that also exposes a keyboard interface. Pads with only keyboard interfaces are configured some other way and none of this reaches them.
| VID : PID | Interface | Protocol |
|---|---|---|
| 1189 : 8840 | 1 | Extended |
| 1189 : 8890 | 1 | Legacy |
| 1189 : 8830 to 8833 | 0 | Extended |
| 1189 : 8810 | 0 | Extended |
| 6D7B : DCFA | 2 | WebHub. SDINNOVATION SIDE-KEYBOARD, the pad in these screenshots |
| 6D7C : DCFB · 6D7D : DCFC · 6D7E : DCFD · 6D7F : DCFE · 68BD : DCFC | 2 | WebHub |
It isn't. Knurl isn't signed with an Apple Developer ID, which needs a paid account, and that is the message macOS shows for anything whose signature it cannot check. Right click the app, choose Open, then Open again. Once. If it still refuses, run xattr -dr com.apple.quarantine /Applications/Knurl.app.
Run knurl-probe interfaces from a source checkout; it lists every HID interface on the machine. If yours has one on a vendor usage page carrying reports of 64 bytes, open an issue with that output and it can be added.
The release build is Apple Silicon only. Building from source works on Intel, and the Xcode command line tools are the only requirement.
It writes to the key table and the backlight block, and reads back what it wrote. It never touches firmware. The one command that would is documented above precisely so that nothing sends it by accident.
No. Knurl makes no network calls at all. There is no account, no telemetry and no update check. It talks to the keypad over USB and to nothing else.
A graphic designer, not a developer, with Claude Code. The protocol work is verified against real hardware in both directions, and the source is open so that claim is checkable rather than something you have to take on trust.