Not sure if it was worth the time, but it works. A fully native USB-C Apple M0116.
Started the night before trying to adapt the ADB signal with the RP2040-ZERO which ended in shorting out the internal 40-pin DIP microcontroller (NEC 8831HD)
Thought for a day about it if was worth ordering a PCB using the gerbers from elmo project, but ended up deciding against it. All in would have been about 90-180 depening on if the PCB was already assembled or not. Did a bit more research and came across https://git.40percent.club/di0ib/tmk_keyboard/src/commit/75a92ff653735635289a204176e60aa80c33bc7f/keyboard/IIgs_Standard which replaced the 40-pin DIP with a AT90USB Teensy++ 2.0. A little different but i thought it should more or less should work with a RP2040-ZERO. The only catch was the IIgs_Standard controller mod plugged the AT90USB Teensy++ 2.0 directly into the 40-pin DIP socket which made the notes have some weird pin bypasses (because the Teensy had AERF and GND physically hardwired to pins 30 and 31). Spend an ungodly amount of time with a multimeter in continuity mode probing the bare socket and finally figured out how the M0116 actually works.
(With the 40-Pin DIP micro controller sockets reading from the bottom left counter clockwise)
- Sockets 1,7, and 20 all were ground (On an 8048 chip, Pin 20 is VSS (Ground), Pin 7 is EA (External Access, tied to ground on the PCB to run internal ROM), and Pin 1 is T0 (tied to ground)
- Sockets 26 and 40 are the old +5v power rails.
Unlike modern keyboards where modifiers are part of the diode matrix, Apple wired the modifiers directly to Ground:
- Socket 37: Shift (Left and Right Shift are tied together)
- Socket 36: Control
- Socket 35: Top Power/Reset Triangle Key
- Socket 24: Command / GUI
- Socket 23: Option / Alt
- Socket 6: Caps Lock (Locking Alps switch—latches down and holds continuity to Ground until pressed again)
- Socket 34 = Row 0 (Up Arrow)
- Socket 33 = Row 1 (')
- Socket 32 = Row 2 (Numpad -)
- Socket 31 = Row 3 (Esc)
- Socket 30 = Row 4 (Numpad *)
- Socket 29 = Row 5 (Spacebar)
- Socket 28 = Row 6 (Z)
- Socket 27 = Row 7 (A)
- Socket 22: Row 8 (Number row 8 on Col 0 / Socket 12)
- Socket 21: Row 9 (Tab on Col 7 / Socket 19)
- Sockets 12 through 19: Columns 0 through 7 in exact consecutive order.
Total signal count: 10 Rows + 8 Columns + 6 Direct Keys + 1 Ground = 25 wires.
Now it was time to start the fun part, hardware and soldering
The Waveshare RP2040-Zero is tiny enough to tuck inside the case, but it only has 20 outer GPIO through-hole pins (GP0–GP15, GP26–GP29), which isn't quite enough for 24 distinct signal lines. One thing though, it has 10 more flat gold pads on the underside of the board. Pre-tinning those 4 tiny pads and taping down the wires for strain relief gave me the exact extra pins needed for Option, Command, Caps Lock, and Power.
Instead of pushing male Dupont pins into the top of the socket (which stick up too high and can vibrate loose), I flipped the keyboard PCB over and soldered directly to the socket pin tips on the back of the PCB.
Wiring & Color-Code Breakdown:
- Black (Ground): RP2040 GND - Socket 20
- Yellow (10 Matrix Rows):
- GP0 - Socket 34 (Row 0)
- GP1 - Socket 33 (Row 1)
- GP2 - Socket 32 (Row 2)
- GP3 - Socket 31 (Row 3)
- GP4 - Socket 30 (Row 4)
- GP5 - Socket 29 (Row 5)
- GP26 - Socket 28 (Row 6)
- GP27 - Socket 27 (Row 7)
- GP28 - Socket 22 (Row 8)
- GP29 - Socket 21 (Row 9)
- Green (8 Matrix Columns):
- GP8 through GP15 - Sockets 12 through 19 (consecutive order)
- Blue (4 Standard Modifiers):
- GP6 - Socket 36 (Control)
- GP7 - Socket 37 (Shift)
- GP17 (Back Pad 1) - Socket 23 (Option)
- GP18 (Back Pad 2) - Socket 24 (Command)
- White (Special Modifiers):
- GP19 (Back Pad 3) - Socket 6 (Locking Caps Lock)
- GP20 (Back Pad 4) - Socket 35 (Top Power Key)
- Leave Empty: Sockets 1–5, 7–11, 25, 26, 38–40, and the RP2040's 5V / 3V3 pins.
Initially, the plan was to set up a full QMK toolchain, write custom C matrix scanning loops in matrix.c to handle the direct-to-ground modifier row, and compile a .uf2.
Instead, I decided on a different route: CircuitPython.
- Dropped the standard CircuitPython UF2 onto the RP2040-Zero.
- Got Claude to write a quick diagnostic calibration script that configured all connected GPIOs with internal pull-ups and continuously printed which pins shorted together whenever a circuit closed.
- Pressed each key one by one across the keyboard. The script learned every physical switch's exact Row/Col or Direct-to-GND pin combination dynamically.
- Used that auto-generated dictionary to generate the final code.py running the Adafruit HID keyboard library.
Finally got it all to fit in the case and used a USB-C extension to not strain the connecter on the RP2040-Zero. I know the USB-C hole isn't the cleanest right now, I will probably clean it up eventually