How to revive an Apple IIgs Keyboard

I managed to buy an Apple IIgs Keyboard off the geekhack.org forums. It is an Apple Desktop Bus keyboard, not USB, therefore I can't just plug it into a modern computer and have it working.

The least involved method to get it working

If you're not a DIY sort of person, the easiest way to get it working with a modern computer is to get one of these ADB to USB Converters from eBay. However, you'll be stuck with the funny keyboard layout and no function keys.

Image of Apple IIgs Keyboard

The more fun method

The more fun method involves getting a Teensy microcontroller, hooking it up to the keyboard, and flashing software onto the Teensy to get it working. This way, I could also define the key mapping for the keyboard as I wish, including creating Function layers where holding a particular key while pressing different keys will result in different keys. The most common example of this is the fn + F1/F2 on modern Apple keyboards, which gives you the brightness increase/decrease key.

With that said, let's get started.

Required items

  1. Teensy 2.0 [link 1] [link 2]
  2. A 1k ohm resistor
  3. Some solder & wire
  4. USB Mini cable (not the USB Micro) - The Teensy doesn't come with a cable

First, we look at the ADB protocol to see what connections need to be made. Straightforward information can be found here. In a nutshell, there are four connections we need to make, according to the Pin out diagram, from the keyboard to the Teensy.

ADB (Keyboard) Teensy
Pin 1DataTeensy D1
Pin 2Power onTeensy D2
Pin 3+5 volts powerTeensy VCC
Pin 4GroundTeensy GND

Note that Teensy D1 and D2 are arbitrary choices, you just need to reflect which pins you chose in the keyboard firmware code later (we'll come to it). VCC and GND can be either of the two on the Teensy board, it does not matter which.

I basically soldered direct from the keyboard PCB to the Teensy ports above initially, and then soldered the resistor between the +5V (Teensy VCC) and Data (Teensy D1) lines. The connections look like this:

Wiring diagram

Notice that the pin numbers are marked on the PCB as highlighted. Apple IIgs Keyboard - PCB & Pin Outs

At this point, I downloaded all the necessary software to get started with the keyboard firmware. On an OS X computer, I needed to download:

  1. Compiler - to compile firmware before it can be flashed to the Teensy
  2. Teensy Loader - to flash compiled firmware to the Teensy
  3. tmk_keyboard - the actual firmware that becomes the brains of the keyboard. The guy who wrote this, hasu, has done a tremendous amount of work on this that enables this firmware and a Teensy to practically control any sort of keyboard, old and new, and even DIY keyboards made from scratch.

After installing items 1 and 2 above, it's time to dive straight into the firmware code. I opened up /converter/adb_usb/config.h and changed line 51 that says #define ADB_DATA_BIT 0 to #define ADB_DATA_BIT 1, and the line below from 1 to 2 for the ADB_PSW_BIT parameter.

Then, I opened up /converter/adb_usb/keymap.c and started defining my keymap for the IIgs keyboard. (Note that the M0116 keyboard mentioned is indeed the IIgs keyboard; if you're doing this for the also-ADB Apple Extended keyboard the sample function has been written out in this file too. )

At this point I barely knew my way around C, but the code is written in a manner so clear I just followed the breadcrumbs and managed to piece this together:

The IIgs key map has been conveniently defined in a macro that is in the form of a visual representation of the physical keyboard, so you can put the keycode of the key you want whichever key to output in that exact visual spot in the code. Here's the macro in question (which you shouldn't change, just read, to understand what I'm talking about)

    #define KEYMAP_M0116( \  
                               K7F,                                              \  
       K35,K12,K13,K14,K15,K17,K16,K1A,K1C,K19,K1D,K1B,K18,K33, K47,K51,K4B,K43, \  
       K30,K0C,K0D,K0E,K0F,K11,K10,K20,K22,K1F,K23,K21,K1E,     K59,K5B,K5C,K45, \  
       K36,K00,K01,K02,K03,K05,K04,K26,K28,K25,K29,K27,    K24, K56,K57,K58,K4E, \  
       K38,K06,K07,K08,K09,K0B,K2D,K2E,K2B,K2F,K2C,        K7B, K53,K54,K55,     \  
       K39,K3A,K37,K32,        K31,        K2A,K3B,K3C,K3D,K3E, K52,    K41,K4C  \  
    ) { \  
      { KC_##K00, KC_##K01, KC_##K02, KC_##K03, KC_##K04, KC_##K05, KC_##K06, KC_##K07 }, \  
      { KC_##K08, KC_##K09, KC_NO,    KC_##K0B, KC_##K0C, KC_##K0D, KC_##K0E, KC_##K0F }, \  
      { KC_##K10, KC_##K11, KC_##K12, KC_##K13, KC_##K14, KC_##K15, KC_##K16, KC_##K17 }, \  
      { KC_##K18, KC_##K19, KC_##K1A, KC_##K1B, KC_##K1C, KC_##K1D, KC_##K1E, KC_##K1F }, \  
      { KC_##K20, KC_##K21, KC_##K22, KC_##K23, KC_##K24, KC_##K25, KC_##K26, KC_##K27 }, \  
      { KC_##K28, KC_##K29, KC_##K2A, KC_##K2B, KC_##K2C, KC_##K2D, KC_##K2E, KC_##K2F }, \  
      { KC_##K30, KC_##K31, KC_##K32, KC_##K33, KC_NO,    KC_##K35, KC_##K36, KC_##K37 }, \  
      { KC_##K38, KC_##K39, KC_##K3A, KC_##K3B, KC_##K3C, KC_##K3D, KC_##K3E, KC_NO    }, \  
      { KC_NO,    KC_##K41, KC_NO,    KC_##K43, KC_NO,    KC_##K45, KC_NO,    KC_##K47 }, \  
      { KC_NO,    KC_NO,    KC_NO,    KC_##K4B, KC_##K4C, KC_NO,    KC_##K4E, KC_NO    }, \  
      { KC_NO,    KC_##K51, KC_##K52, KC_##K53, KC_##K54, KC_##K55, KC_##K56, KC_##K57 }, \  
      { KC_##K58, KC_##K59, KC_NO,    KC_##K5B, KC_##K5C, KC_NO,    KC_NO,    KC_NO    }, \  
      { KC_NO,    KC_NO,    KC_NO,    KC_NO   , KC_NO,    KC_NO,    KC_NO,    KC_NO    }, \  
      { KC_NO,    KC_NO,    KC_NO,    KC_NO,    KC_NO,    KC_NO,    KC_NO,    KC_NO    }, \  
      { KC_NO,    KC_NO,    KC_NO,    KC_NO,    KC_NO,    KC_NO,    KC_NO,    KC_NO    }, \  
      { KC_NO   , KC_NO,    KC_NO   , KC_##K7B, KC_NO,    KC_NO,    KC_NO,    KC_##K7F }  \  
    }   

So by calling KEYMAP_M0116( ... ) in line 189, you can easily identify each key and map it to your preference. (You replace the KEYMAP_EXTENDED_US( ... ) part, which is a macro also but for the Apple Extended Keyboard, not the IIgs. )

This is how my keymap.c looks at line 189 now:

    static const uint8_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
    KEYMAP_M0116(
                               PWR,                                              
       GRV ,1   ,2   ,3   ,4   ,5   ,6   ,7   ,8   ,9   ,0   ,MINS,EQL ,BSPC, DELETE,PEQL,PSLS,MPLY,
       TAB ,Q   ,W   ,E   ,R   ,T   ,Y   ,U   ,I   ,O   ,P   ,LBRC,RBRC,         P7  ,P8  ,P9  ,VOLU,
       LCTL,A   ,S   ,D   ,F   ,G   ,H   ,J   ,K   ,L   ,SCLN,QUOT,ENT ,         P4  ,P5  ,P6  ,VOLD,
       LSFT,Z   ,X   ,C   ,V   ,B   ,N   ,M   ,COMM,DOT ,SLSH,     RSFT,         P1  ,P2  ,P3  ,
       FN1 ,LALT,LGUI,ESC,        SPC,         BSLS,LEFT,DOWN,UP  ,RGHT,         FN0      ,PDOT,PENT 
    ),
    };

You can find a full list of possible keys to be output in /doc/keycode.txt.

At this point, I've had the compiler (AVR MacPack, see above list of software I downloaded) installed. I fired up the terminal, navigated to this folder (/converter/adb_usb/) and typed make. If all goes well, you will have a new file named adb_usb_lufa.hex. I might have missed out on some intermediate steps or configurations, so if you see any error messages please get in touch.

The final step was to load the .hex file into the Teensy using the Teensy Loader. The keyboard worked after a few seconds, when the Teensy had done booting up.

Putting it all in a nice package

I mentioned a couple of centuries back that I simply soldered four wires from the keyboard's PCB to the appropriate pins on the Teensy. That will not do for daily usage as I have to transport my keyboard between home and work.

I have therefore replaced the soldered wire with a salvaged ribbon cable into a female header. The Teensy pins are soldered to some male pins which correspond to the correct pin positions in the female header. I also built a rough enclosure out of some ice-cream sticks to house the entire thing.

Teensy Enclosure

Special thanks to hasu on geekhack.org for the awesome firmware, which is super simple to get started with and is immensely powerful when you want to define multiple-layered keymaps. More information on the firmware can be found in this forum thread.

I might also write about adding additional keymap layers using this firmware, but chances are you have already figured out how by now. If not, feel free to ask! Please look for hydrospell on the geekhack.org forums or IRC if you have questions. Alternatively, look for @hydrospell on Twitter.

I hope this helps with your old Apple keyboard journey too. These are really so great to type on!

Apple logo on PCB