Apple Extended Keyboard II USB Conversion
This page documents a USB conversion which I performed on an AEK2, by
replacing the controller with a Teensy++
2.0. The software supports multiple layers, in
particular a media layer containing mouse keys, volume controls, and so on. The
controller also acts as an ADB host, so the remaining ADB port works, but only
supports keyboards for the moment (I don't have an ADB mouse to test).
Hardware
There are three ICs on the board: a controller, inverter and decoder (the linked datasheets
came from alldatasheet.com and the datasheet archive). The
following images show their locations (or, in the case of the controller, its
former location--I removed it):
The pin assignments for the controller are documented in this text file. The keyboard matrix has 8 rows
and 16 columns, the latter of which are accessed through the decoder. Setting
the four decoder data pins to the binary value of a column index will make the
corresponding column low. For any switch in this column which is pressed, the
corresponding row pin will then be pulled low, permitting the state of the
switch to be read by the controller. This is not an NKRO keyboard matrix (no
diodes!), so there can be ghosting,
which must be handled in software. The keyboard matrix is given in the
following table:
0 | KP 9 | numlk | | scrlk | prtscr | F12 | F10 | F9 | F7 | F6 | F5 | F4 | F3 | F2 | F1 | esc | 0 |
1 | KP / | KP = | KP 8 | pause | pgup | bksp | F11 | 0) | F8 | 7& | 6^ | 4$ | 3# | 2@ | 1! | `~ | 1 |
2 | KP * | | KP 7 | | pgdn | \| | =+ | O | 9( | 8* | T | 5% | | | | | 2 |
3 | KP - | | KP 6 | | end | home | [{ | -_ | | | Y | G | | | | | 3 |
4 | KP 3 | right | KP 5 | | del | ins | ]} | P | K | I | | R | E | W | Q | tab | 4 |
5 | KP enter | | KP 4 | | up | enter | '" | ;: | L | | U | | D | | | | 5 |
6 | | | KP + | left | | .> | /? | ,< | J | H | B | F | | | S | A | 6 |
7 | | KP . | | down | KP 2 | KP 1 | KP 0 | M | N | | space | V | C | X | Z | | 7 |
Notice that some keys are missing: the modifiers, caps lock key, and the ADB
power (PSW) button. All of these are connected directly to controller pins, and
hence may be treated as simple (active low) pushbuttons (the PSW button is a
bit of an exception, since it's potentially also connected to other peripherals
via the ADB port).
This image outlines the changes I made on the
PCB, with more zoomed-in views in the following images. I'm not a good
solderer, but everything (miraculously) works.
I first replaced the LEDs and the corresponding resistors. The controller
was replaced with a Teensy++ 2.0,
which I wired into the controller location based on the aforementioned text file, with one difference: both command keys
are connected to the same pin, and I wanted my software to be able to
distinguish between them, so I cut the trace for the left command (GUI) key,
and wired it directly to the teensy. Also, as hasu/soarer (I forget which)
suggested on the geekhack forums, I connected a 1kΩ external pull-up
resistor to the ADB pin.
The teensy is located at the edge of the board so that it can fit into a
small "channel" on the bottom of the case. It's snug--I had to tape a little
piece of plastic around the teensy's button to prevent it from being pressed
once the keyboard was assembled, and also dremel the portion of the case
containing the USB port, in order to get it to fit. For such a large keyboard,
there's suprisingly little room.
Software
My software's USB support is based loosely on the PJRC keyboard and mouse examples, but has been
heavily-modified into a more object-oriented style. I wrote the ADB support
myself, but was inspired by, and referred to, hasu's ADB-to-USB
converter, as well as Chapter 6 of the Apple
IIGS Hardware Reference, which hasu refers to in his documentation. All
source code is copyrighted, and licensed under the GPLv3 (PJRC kindly permits
relicensing under certain conditions). Be warned that the code is
overcomplicated and poorly-documented--I hope to improve it in the future.
As is typical in such keyboard-controller projects, my software supports
multiple layers. In particular, it's configured with a media layer (activated
by pressing the right option key) and support for the Matias half-QWERTY layout (activated by
pressing the spacebar in the media layer). This
pdf file documents the current keyboard mapping, although of course it is
configurable (by changing the tables in main.cc).
NKRO-over-USB is supported (although the AEK2's keyboard matrix is not NKRO,
so this is of limited usefulness). You can find the HID descriptors in the
code, but the basic idea is to have two keyboard interfaces, the first of which
is a boot-mode interface. The second interface contains two seven-byte reports
with bit flags for the (in my opinion) 112 most-useful keys, as well as a third
report for consumer controls. Keypresses are sent through the boot-mode
interface unless it is "full", in which case they fall-back to the extended
interface. I've tested this on Linux, OSX and Windows, and it works (although
perhaps it won't on older versions of these OSes). There is also a mouse
interface, which is used by the mouse keys.