programmable keyboard interceptor and hardware control system

Keyman64 Rev.4

The keyman64 is a programmable keyboard interceptor and hardware control system for computers equipped with a simple 64-key matrix keyboard.

It is installed between the keyboard and the computer, continually scanning the keyboard matrix and relaying the keyboard state to the computer using a crosspoint switch. To the computer, the crosspoint switch matrix looks just like a physical keyboard, while the keyman64 gains the ability to intercept keystrokes and control the matrix seen by the computer.

The keyman64 can be configured to intercept special key combinations and invoke arbitrary sequences of commands to alter the state of sixteen general purpose control lines provided on the board. These lines can be used to control additional hardware instead of using physical buttons or switches.

Additional features include the ability to send predefined keyboard macros or to redefine the keyboard layout. Commands can also be sent from a remote PC via USB, or send on simple serial wire interface, allowing remote control from either a PC or another microcontroller or similar device.

For some concrete examples of what the keyman64 can do, see the configuration examples.


Basic mode of operation

During normal operation, the device simply relays all keyboard events to the computer, except when a special key defined as the meta key is held down. As long as this key is held down, any additional key presses invoke the user-defined command sequences bound to the respective key. When the meta key is released again, the device continues to relay keyboard events to the computer.

If no special key has been pressed while the meta key was down, a press of the meta key itself is simulated on the matrix seen by the computer. This way the meta key is not lost, it can still be pressed as usual in order to type the associated character. The only difference is that the computer will notice the simulated key down and up events only after the physical key has been released.

This scheme works well if the meta key only needs to be pressed once, but not if the meta key is supposed to be held down for a longer period of time. But this can still be accomplished by using a key combination invoking the down command for the meta key itself, for example:


Assuming that the arrow-left key is used as the meta key, this binding can be invoked by holding down arrow-left and pressing m. The virtual arrow-left key now appears held down to the computer as long as the physical meta key is kept down. Once the physical meta key is released, the device beings scanning and relaying the physical keyboard state again, effectivly releasing the virtual meta key seen by the computer.

The meta key defaults to the arrow-left key. To change it to a different key, use the meta command described below.


A simple commandline configuration and control utility is provided. Its main purpose is to convert a plain text configuration file into a binary format. The binary configuration file is flashed to the Atmegas EEPROM Memory. See Configuration for details.

In Addition, the utility allows remote control of the keyman64 via USB. Arbitrary commands can be send via USB and will be immediately executed on the keyman64.

Hardware design

The device is based on an Atmega1284p, a crosspoint switch IC and some discrete 74xx logic ICs. Supported crosspoint switches are the CD74HC22106 or the MT8808 in either DIP or PLCC package. A USB socket is provided to allow easy configuration and firmware updates using a USB bootloader preinstalled on the Atmega. Plese see design documents in the source distribution and the relevant sections in this document for further details.


In theory, the device should work with any computer using a passive 8x8 matrix keyboard. However, the layout of the connectors and the keynames follow those of the C64. Also the type command will use key combinations specific to the C64 to type the ASCII characters given as the argument. If you need software support for a different homecomputer, please feel free to post a feature request on the github issue tracker, preferrably providing the required information.




The source distribution includes the sources for the firmware and the configuration utility as well as schematics and pcb layouts in KiCad format for building the hardware.

Latest stable is keyman64-1.3.tar.gz.

All releases can be found under /download/keyman64

Latest developments are available via github:

git clone




Revision 3

The USB level conversion circuit is not correct in this and all previous revisions. This may result in missing USB functionality. It obviously depends on the specific type of 3.6V zener diodes used. While the diodes I have shipped with revisions 1 and 2 seem to have worked (more by accident than by design), the ones shipped with revision 3 boards have failed to work properly, so I have only discovered this error after shipping revision 3.

In order to fix an already assembled board or when assembling the board, the diodes have to be soldered in like this:

As you can see, the cathodes have to go directly to the D- and D+ lines from the USB socket. You can solder them directly to the leads of the 68Ω resistors, given that you installed them as suggested by the silkscreen.

This error will be corrected with the upcoming revision 4. All pending orders will of course include the corrected revision.

Revision 2

The negative voltage generator ICL7660 is not required, although it does not hurt to leave it in. It has been removed in favor of an alternative PLCC socket in Revision 3.

Also, the mounting holes added in this revision are 3mm in diameter, which makes them unsuitable for mounting using common self-adhesive pcb holders, which require at least 4mm holes. The holes have been changed to 4mm in Revsion 3.

Ordering Assembly Kits

I’m offering assembly kits including the keyman64 pcb, the preprogrammed Atmega and all required components (except connection cables) for 30€ each. Worldwide shipping via airmail is free of charge.

You can order kits via email at

To place an order, please include the word “keyman64” in your subject. State your full name, the number of kits you want and your complete international shipping address. You will then receive an email containing payment information (bank transfer only).

Please note that you will have to pay in advance to confirm your order. Since I’m doing all of this in my spare time and on a short budget, I can’t afford to keep complete assembly kits on stock. I need to buy them in multiples of 25 in order to keep the price. This means that it could take quite some time (depending on demand) until you get your kits. However, I will inform you about the status of your order in regular intervals.

Building the hardware

Please refer to the list of parts and the placement on board below below.

Power supply

+5V must be supplied to the center pin of J1. You can either supply +5V from the computers main board directly to this pin, or use a jumper bridge to supply power from pin 4 of P1 (the mainboard keyboard socket) or from the USB socket. To supply power from the mainboard socket, bridge the left and center pin of J1. To supply power from USB, bridge the center and right pin of J1.

Supplying power from the USB socket is only recommended for standalone operation of the keyman64, i.e. when P1 it is not connected to the io ports of a computer and none of the external devices connected to the keyman64 are powered from a different source. In general, all devices involved (the computer, the keyman64 and the devices controlled by it) must be powered from the same source. For example, if the keyman64 was configured to source power over USB and the computer is powered on without the USB cable being connected, the keyman64 might still sink current over the ESD-protection diodes of the Atmels io ports from the io ports of the computer or the external devices, which might cause severe damage to any of the io ports involved.


The pin layouts of P1 and P2 follow the layout of the C64 keyboard connector. The RESTORE line is simply passed through on the board.

List of parts

Reference Type Value Package/RM
C1 Ceramic capacitor 18pF 2.5mm
C2 Ceramic capacitor 18pF 2.5mm
C6 Ceramic/film capacitor 100nF 2.5mm
C7 Ceramic/film capacitor 100nF 2.5mm
C8 Ceramic/film capacitor 100nF 2.5mm
C9 Ceramic/film capacitor 100nF 2.5mm
C10 Ceramic/film capacitor 100nF 2.5mm
C11 Ceramic/film capacitor 100nF 2.5mm
D1 Zener Diode 3.6V DO-204
D2 Zener Diode 3.6V DO-204
R1 Precision Resistor 1k5 6.5mm, ∅ 2.5mm
R2 Precision Resistor 68 6.5mm, ∅ 2.5mm
R3 Precision Resistor 68 6.5mm, ∅ 2.5mm
P3 USB Mini-B Socket - Through-Hole
SW1 Push Button - 6x6mm print
SW2 Push Button - 6x6mm print
X1 Quartz Crystal 16Mhz HC49/U-S
U1 74HC22106 or MT8808 - DIP28
U2 Atmega1284P - DIP40
U3 74HC00 - DIP14
U4 74HC4051 - DIP16
U5 74HC4520 - DIP16
U6 74HC4051 - DIP16
U7 74HC22106 or MT8808 - PLCC28

For the crosspoint switch you can either use U1 for a DIP28 package or U7 for a PLCC28 package version.

Sockets not included.

Placement on board

Installing the firmware

If you bought an assembly kit from me, the Atmega is already programmed with the latest firmware and bootloader versions and is ready to use.

Otherwise, if you have no means of initially programming the Atmega yourself then you can send it to me and I will prepare it for you. Just drop me a line at

Installing the combined firmware image

The easiest way to bootstrap the Atmega is to install the combined binary image. The image contains both the bootloader and the application part of the firmware. If you have a programming device capable of programming the complete PROGMEM area from a single binary image (e.g. the TL866), use this method.

Note that you also have to check and eventually program the fuses of the Atmega as well. The required fuse values are:

    Low:      0xd7
    High:     0xd0
    Extended: 0xfc

This corresponds to the following fuses programmed: SUT1, CKSEL3, SPIEN, EESAVE, BOOTSZ0, BOOTSZ1, BOOTRST, BODLEVEL0, BODLEVEL1. All other fuses must remain unprogrammed.

Installing the bootloader manually

The Atmega1284p must contain the USBaspLoader, which must be uploaded to the Atmega via ISP prior to installing it on the board.

There is a preconfigured version of the bootloader in the source tarball.

Change to the bootloader directory and edit the and adjust the PROGRAMMER settings to according to your setup. Then issue

 $ make flash fuse

The Atmega can now be installed on the device. When entering the bootloader, it identifies itself to the host like this:

16c0:05dc Van Ooijen Technische Informatica shared ID for use with libusb

It can be accessed using avrdude -p m1284p -c usbasp <commands...>

Note that you may need to configure the USB devices on your system beforehand.

Entering the bootloader

To manually enter the bootloader, hold down the BOOT Button and press the RESET button, then release the BOOT button again.

Once the device is installed you can configure a key combination using the boot command. For example, by using

b: boot

you can enter the bootloader simply by pressing <meta>-b.

You can also just send the boot command via USB from the PC:

$ keyman64 boot

Note that this will currently produce a non-critical error message. See boot command for further details.

Installing the and updating the application

Once the Atmega is equipped with a USB bootloader the application part of the firmware can be installed with the following command:

$ avrdude -p m1284p -c usbasp -U flash:w:keyman64-firmware-1.3.hex

If you have build the firmware from source you can use the program target of the toplevel Makefile as well.

Configuring USB devices on the PC

The keyman64 implements two separate USB devices, a remote control device and a bootloader device.

During normal operation, the remote control device will be active and accessible from the PC using the configuration and control utility. This device will identify itself to the host using the following properties:

Vendor OpenMoko, Inc.
Manufacturer Henning Bekel
Device Keyman64
Vendor ID 1d50
Product ID 60e9

While in bootloader mode, the bootloader device will be accessible from the PC. This device will identify itself to the host using the following properties:

Vendor Van Ooijen Technische Informatica shared ID for use with libusb
Device USBasp
Vendor ID 16c0
Product ID 05dc


On Linux, the required udev rules are installed alongside the configuration and control utility. After installation, issue

# udevadm control --reload-rules

When in bootloader mode, the bootloader device will be symlinked to /dev/usbasp. During normal operation, the keyman64 control device will be symlinked to /dev/keyman64. These symlinks are created with file permissions 0666, allowing access for any user.


Once you connect one of the usb devices for the first time, Windows will insist on trying to download and install a driver for these devices. Since both devices are general purpose USB devices, this is futile, since there simply are no drivers for windows to install. You must abort the windows driver installation dialog to prevent windows from permanently marking the device as unusable due to its perceived lack of “proper” drivers.

Instead, use the Zadig tool to generate and install minimal drivers that simply associate the devices with the subsystems required for general purpose access.

Run Zadig, connect the usb cable to the keyman64 and power up the device. Zadig should now detect the Keyman64 device. Install the WinUSB driver for this device.

Now enter the bootloader. The Zadig tool should now detect the USBasp device. For use with avrdude, install the libusb-win32 driver for this device. Also make sure that the libusb0.dll is present on your system (it should come with avrdude). If not, follow the link for libusb-win32 shown in the “More information” section of the Zadig window and install libusb-win32 on your system.

Installing the configuration and control utility


For the windows version, use the binary installer package. This will also install the required libusb-1.0.dll. The installation directory will be added to your PATH environment variable.


Linux & MacOSX

libusb-1.0 and corresponding development packages (if any) need to be installed on your system.

Extract the tarball, change to the source directory and type make.

Use make install to install the keyman64 binary into /usr/local/bin. The PREFIX variable can be used to install with a different prefix, e.g. use make PREFIX=/usr install to install into /usr/bin instead. The DESTDIR variable can be used for a staged install.

On linux, the udev rules required for the USB devices will be installed to /etc/udev/rules.d as well. As root, run

# udevadm control --reload-rules

after installation.


If you’re using cygwin you can build a windows binary in the same way as under Linux or MacOSX. The required pacackes are libusb-1.0 and libusb-1.0-devel. Note that the resulting binary will still need cygwin dlls to be present.

A native win32 binary can be build using mingw32 under Linux or Cygwin. If neccessary, edit the Makefile and adjust the MINGW32 variable to the proper prefix for your toolchain. Then use make win32 to build keyman64.exe.


The configuration file is a plain text file containing configuration commands and keybindings in a human readable format. Using the keyman64 utility this file is converted to a binary format which can be flashed into the EEPROM memory of the Microcontroller. See Transferring the configuration.


Whitespace and comments

Empty lines as well as leading and trailing whitespace characters are ignored. Whitespace is only significant to separate individual tokens and keywords.

Comments begin with a hash character # and continue for the remainder of the current line.


All keywords, like command and key names, as well as user defined symbols are case-insensitive. E.g. CLEAR is equivalent to clear, SPACE is equivalent to space and so on.

Commands and bindings

Each line must contain one command specification, optionally prefixed by a key specification:

[<key>:][<policy>] <command> [<arguments>]

If no key specification is given, the command will be executed on powerup/reset of the microcontroller, and can thus be used to configure the initial state of the device.

If a key specification is given, the command will be bound to the specified key.

If multiple commands are bound to the same key, the commands will be executed in sequence, in the order in which they appear in the configuration file.

Command sequences can also be bound to “slots” by using numeric key specifications between $40 and $FB. These command sequences can not be invoked directly by a key combination, but may be invoked indirectly via the exec command.

The optional policy argument can be set to either 0 or 1, meaning even or odd. If even, the command will only be executed on the second, fourth, sixth etc. time the key is pressed. If odd, the command will only be executed on the first, third, fifth etc. time the key is pressed.


Keys can be specified by using literal key names like DEL, A, RUNSTOP or ONE. To obtain a list of valid key names and their synonyms, run keyman64 --keys.

Keys may also be specified by number, denoting the key position in the C64 keyboard matrix. Keys are numbered from left to right, from row 0, column 0 down to row 7, column 7.

Thus $00 corresponds to the DEL key, $3f denotes the RUNSTOP key.

Key numbers may be given in decimal or hexadecimal notation. Hexadecimal numbers must be prefixed with a dollar sign $ or the literal string 0x.


The sixteen control lines are organized into two 8-bit wide ports. For commands modifying the state of these control lines, the respective port can be specified using the keyword port, followed by the literal string a or b:

port [a|b]


Commands modifying the state of the control lines can be limited to individual bits or ranges of successive bits. Bits are denoted by a decimal number in the range 0-7.

bit <n>

bits <s>-<e>

Where n denotes an individual and s and e denote the start and end bit of a bitrange (inclusive).


Durations can be specified by a series of decimal values and unit specifiers:


Available unit specifiers are d, h, m, s, ms for days, hours, minutes, seconds and milliseconds respectively. If no unit specifier is given, the preceeding value is interpreted as milliseconds.

The maximum possible duration is 232 milliseconds, about 49 days. Specifications that exceed this value will be truncated accordingly.


1m30s = one minute and thirty seconds

1s500 = one second and fivehundred milliseconds

10 = ten milliseconds


Values can be specified in hexadecimal or binary notation. Hexadecimal values need to be prefixed with $. Binary values need to be prefixed with %


Custom symbols can improve the readability of the configuration file. They are defined using simple name/value pairs.

<name> = <value>

Symbol names must consist of alphanumeric characters, digits and underscores only. If a symbol name equals one of the reserved key or command names, a corresponding error message will be issued.

Once a symbol has been defined, any subsequent occurence is replaced by its literal value. If a symbol is used before it is defined, an error message will be generated.

For example, this configuration

    r: clear port a bit 0
    r: sleep 10
    r: tristate port a bit 0

can be made easier to read and change:

    RESETLINE = port a bit 0
    RESET = r
    RESET: sleep 10
    RESET: tristate RESETLINE

Commands for configuration and maintenance


using <8808|22106>

Specify which crosspoint switch IC is installed in the device. Either a CD74HC22106 or an MT8808 may be used. Default is 8808.


meta <key>

The meta command defines the meta key to be used. Default is ARROWLEFT.



Enter the bootloader and expect configuration or firmware updates via USB. The device will remain bootloader mode until a new configuration or firmware has been programmed or the reset button has been pressed.

When sending the boot command via the remote USB interface, e.g. by executing keyman64 boot on the PC, the firmware will immediately jump into the bootloader without properly terminating the current USB communication properly, which will result in the following non-critical error message:

error: could send usb control message: Pipe error

This message can be ignored as long as the AVR has successfully entered the bootloader.



Permanently saves the current state of the control lines to eeprom. This state can be restored later using the restore command.

See the --preserve option of the configuration utility on how to automatically preserve a saved state during reconfiguration.



Restore the state of the control lines that were stored in eeprom by a preceeding save command. If no state has been saved before, all lines are set to tristate.

Commands for modifying control lines


set <port> [<bits>] [to <value>]

Sets the specified bits of the specified port to the specified value. If value is omitted, it defaults to setting all bits to 1 (high). If bits are ommitted, sets all bits of the specified port.


set port a bit 3 to 1 – sets bit 3 of port a to high

set port b bits 3-4 to 2 – sets bit 3 to low and bit 4 to high on port b

set port a – sets bits 0-7 to high


clear <port> [<bits>]

Clears the specified bits of the specified ports, i.e. sets them to 0 (low). If bits are ommitted, clears all bits of the specified port.


tristate <port> [<bits>]

Tristates the specified bits on the specified port. If bits are ommitted, tristates all bits on the specified port.

Tristating a line means setting it to a high-impendance state which is neither high nor low. This is equivalent to physically disconnecting the line.


invert <port> [<bits>]

Inverts the state of the specified bits on the specified ports. If bits are ommitted, inverts all bits of the specified port. If a bit has been set to tristate beforehand, it will be set to output high.


increment <port> [<bits>]

Increment the state of the specified bits on the specified port by one. If bits are ommitted, increments the state of all bits on the specified port.

This can be used to implement a binary counter on a port or a specific bit range on a port. If all bits are already set (e.g. the counter has reached its maximum) then all bits are cleared again.

Example of a four-bit binary up-counter in the lower part of port a:

increment port a bits 0-3


decrement <port> [<bits>]

Decrements the state of the specified bits. Works similar to the increment command.

Commands for controlling the keyboard matrix


down <key>

Holds down the key on the matrix seen by the computer. The key will remain held down until an up command for the key is executed or the meta key is released.


up <key>

Releases the specified key on the matrix seen by the computer. The key will remain released until a down command for the key is executed or the meta key is released.


press <key>

Presses the specified key on the matrix seen by the computer, i.e. the key is held down for 20 milliseconds and then released again. This is a shortcut for

down <key>
sleep 20
up <key>


type <string>

Types the specified string on the matrix seen by the computer. The tilde character ~ is interpreted as RETURN.

Lower case ASCII characters will cause the corresponding key to be pressed without modifiers. Upper case and special characters will be pressed in conjunction with shift if necessary to type the correct character. To type PETSCII characters that are not present in the ASCII character set, simply use the ASCII character at the respective position in the ASCII table. For example, the pound symbol, which is at position 92 in the PETSCII table, can be specified by using the corresponding ASCII backslash character.

Note that the lower case ASCII characters might appear as upper case characters on the C64 depending on which of its build-in character sets (upper or mixed case) is currently selected.

In any case, only the lower 127 ASCII characters will be interpreted. Results for ASCII characters above 127 are undefined.

Example (on the C64):

type load"*",8,1~ – types LOAD"*",8,1 and presses RETURN


swap <key> <key>

Swaps the specified keys against each other before relaying them to the computer. This can be used to redefine the keyboard layout, e.g. to switch to a QWERTZ layout on the C64:

swap Z Y

Note that this applies only to the keys relayed to the computer, not to the keys interpreted as a part of a key binding. Commands bound to the physical key Z can still be invoked by pressing <meta>-Z in this example.

Commands for controlling execution


exec <key>|<slot>

Executes the command sequence bound to the specified key or slot number. Execution of the current command sequence will resume after the specified sequence has been executed.


sleep <duration>

Suspend execution of the current command sequence for the specified duration. No keyboard processing will occur during sleep, e.g. key presses will neither be relayed nor interpreted as bindings.

Configuation and control utility

$ keyman64 --help

keyman64 version 1.3
Copyright (C) 2015 Henning Bekel.
License GPLv2: GNU GPL version 2 <>.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

      keyman64 <options>
      keyman64 convert [<infile>|-] [<outfile>|-]
      keyman64 [<options>] <command>
      keyman64 [<options>] [<file>]

           -v, --version  : print version information
           -h, --help     : print this help text
           -d, --device   : specify usb device (default: /dev/keyman64)
           -D, --delay    : delay in ms between commands
           -k, --keys     : list key names and synonyms
	   -p, --preserve : preserve saved state during convert 

  Conversion arguments:
           <infile>  : input file, format is autodetected
           <outfile> : output file, format determined by extension:

           *.conf : plain text config file format
           *.bin  : binary file format (default)

           Missing arguments default to stdin or stdout

            (any valid keyman64 command)

Transferring the Configuration

The convert command of the configuration and control utility is used to convert the configuration file to a binary format which can then be written to the Atmega1284p’s EEPROM memory over USB.

Assuming you have written a configuration file named keyman64.conf, you can convert it using

$ keyman64 convert keyman64.conf keyman64.bin

If no errors are encountered this results in the file keyman64.bin.

Make the keyman64 enter the bootloader.

Then use avrdude to write the configuration to the EEPROM memory:

$ avrdude -p m1284p -c usbasp -U eeprom:w:keyman64.bin:r

After the configuration has been transfered, the keyman64 will reset and the new configuration should be in effect.

Please note that the bootloader will reset the AVR immediately after the update operation has completed, even before the current USB communication between the bootloader and avrdude has been completed. This results in the following non-critical error message from avrdude:

error: usbasp_transmit: usb_control_msg: sending control message failed

This message can be ignored as long as avrdude reports that it has successfully written and verified eeprom contents.

Preserving saved state when updating the configuration

If the current eeprom contains a saved control state, this state will be lost if a new binary configuration is created using the convert command, since the eeprom will be flashed with new values.

In order to preserve a saved state, the --preserve option may be used in conjunction with the convert command. The utility will then try to obtain the currently saved state of the control lines via USB and insert this state into the newly created binary configuration. Thus the device has to powered up and connected via USB.

Remote control

Any command can be send from the PC via USB to the keyman64, where it will be executed immediately.

A single command can be executed by passing it directly on the commandline, e.g.

$ keyman64 press F5

If no arguments are specified on the commandline, the keyman64 utility will read commands from STDIN, where one command can be given on each line. Note that the commands will get parsed and executed after STDIN has been closed, e.g. all commands have been entered/piped in:

$ keyman64
reading commands from stdin...
> type load"$",8~
> sleep 5s
> type list~
> ^D

If the first argument to the keyman64 utility is a file, commands will be read from this file and subsequently sent to the keyman64.

Thus you can create a file containing a script like the following:

exec rightshift
press f5
press cursordown
press cursordown
press cursordown
press return

and run this script via

$ keyman64 --delay 250 script.txt

The --delay option will add an additional delay of 250ms after each command. This avoids having to add explicit sleep commands in the script.

On Linux and MacOSX, the she-bang mechanism can be used to create an executable script. Just make the script executable and add an appropriate she-bang line at the top, e.g.

#!/usr/bin/keyman64 --delay 250
press f5
press cursordown
press return

then chmod +x the script and you can execute it like any other command.

Configuration examples

Switching the kernal and performing a reset

Let’s assume you have a dual-kernal adapter installed in your C64. These adapters usually come with a switch that controls the highest address line of the eprom und thus chooses the kernal that is seen by the C64. You are expected to drill a hole in your C64 case to install the switch.

Using keyman64 you can avoid drilling a hole in your precious case.

Simply remove the switch and connect the highest address line of the eprom to one of the 16 control lines of the keyman64. For this example, we’ll assume that we’re using the highest line of the first control port (port a bit 7).

Create a configuration file with the following contents:

clear port a
clear port b

k: invert port a bit 7

Convert it using the keyman64 command line tool:

keyman64 convert example.conf example.bin

And write the resulting binary file to the avr’s eprom:

avrdude -p m1284p -c usbasp -U eeprom:w:example.bin:r

After the configuration is written, the keyman64 will reset. First it executes any command not bound to a key. This allows us to set the initial state of the control lines. In this case, all lines are initially pulled low using the clear command).

Now the key combination <meta>-k will invert the state of the eprom address line, effectively switching back and forth between the two kernal images on each invocation.

While this does the job on the hardware level, it might still cause the C64 to crash, since you might swap the kernal contents while kernal code is being executed. So it would be nice to also reset the C64 after switching the kernal rom.

We’ll connect the C64 reset line to the first line of the first control port and change the configuration to:

tristate port a bit 0
clear port a bits 1-7
clear port b

r: clear port a bit 0
r: sleep 10
r: tristate port a bit 0

k: invert port a bit 7
k: exec r

Now if we press <meta>-r, the reset line will be driven from tristate to low for 10 milliseconds and is then tristated again, effectively causing the C64 to reset.

And if we press <meta>-k, the kernal will be switched just like before, but then the reset sequence bound to <meta>-r will be executed in addition.

Thus we can switch the kernal and immediately reset the C64 simply by pressing <meta>-k instead of having to turn off the C64, flip a switch and turn the C64 back on every time we want to change the kernal.

Holding down a key during reset

Some expansion port modules execute special functions when a key is held down during reset. Things like this can be simulated as well. The following binding performs a reset while holding down the RUNSTOP key:

u: down runstop
u: clear port a bit 0    
u: sleep 10
u: tristate port a bit 0
u: sleep 1s
u: up runstop

Defining keyboard macros

The type command can be bound to a key as well:

d: type load"$",8~

Now pressing <meta>-d will type load"$",8<return>. The ~ symbol denotes a newline in this context.

Remapping the keyboard

The swap command can be used to virtually swap two keys on the keyboard. For example, to change the keyboard layout to QWERTZ, just add

swap z y

to your configuration.

If you want to switch between both layouts on the fly, you can simply bind the swap command to a key:

y: swap z y

Serial interface

The P4 connector offers a simple serial interface allowing remote control of the keyman64 by external hardware. The left pin provides the input for an active-low clock signal (denoted as /CLK on the board). The right pin provides the data input (denoted DATA). On the falling edge of the clock signal the value present on the data input is transferred to the keyman64.

Each command consists of a command-nibble, followed by an argument byte. Both parts are transferred individualy in litte-endian order, i.e. the least significant bit is send first. For example, to press RUNSTOP, the actual command looks like this:

0100 00111111 => 0x4 (command) 0x3f (argument)

but must be transferred like this:

0010 11111100 => command, then argument, both lsb first.

The following commands are available:

  • 0001 <key>: execute command sequence bound to key or slot number
  • 0010 <key>: hold the specified key down
  • 0011 <key>: release the specified key
  • 0100 <key>: press the specified key (hold down for 20ms, then release again)

Note that if a key is held down via the serial interface it will remain in this state until explicitly released via the serial interface again. The state of the physical key will be ignored during this time.

Connecting the Serial interface to the C64

One possible way of using the serial interface is to connect it to the C64 via the bit 3 and 4 of the 6510 IO port. These are available as “Cassette Sense” and “Cassette Data” at the tapeport (assuming you don’t use the tapeport for anything else). “Cassette Sense” will be used as the /CLK signal and “Cassette Data” as the DATA signal.

The source distribution contains the file serial.h and serial.asm in KickAssembler format. These files can be used to issue serial commands from the C64 using the 6510 IO port.

For example, the following code will execute the command sequence bound to <meta>-RUNSTOP:

.import source "serial.h"

jsr    // configure the tapeport lines for output

ldy #$04           // Y: number of bits to send
lda #Command.exec  // A: the actual bits to send
jsr serial.write   // right shift the bits out (i.e. lsb first)

ldy #$08           // The same for the argument, but 8 bits this time
lda #$3f           // This is the "RUNSTOP" key
jsr serial.write

jsr serial.close   // Reset tapeport lines to default state (input)


.import source "serial.asm"


             keyman64 Hardware, Firmware, and Software
     Copyright (c) 2015, Henning Bekel <>

                    GNU GENERAL PUBLIC LICENSE
                       Version 2, June 1991

 Copyright (C) 1989, 1991 Free Software Foundation, Inc.
               59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 Everyone is permitted to copy and distribute verbatim copies
 of this license document, but changing it is not allowed.


  The licenses for most software are designed to take away your
freedom to share and change it.  By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users.  This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it.  (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.)  You can apply it to
your programs, too.

  When we speak of free software, we are referring to freedom, not
price.  Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.

  To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.

  For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have.  You must make sure that they, too, receive or can get the
source code.  And you must show them these terms so they know their

  We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.

  Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software.  If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.

  Finally, any free program is threatened constantly by software
patents.  We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary.  To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.

  The precise terms and conditions for copying, distribution and
modification follow.

                    GNU GENERAL PUBLIC LICENSE

  0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License.  The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language.  (Hereinafter, translation is included without limitation in
the term "modification".)  Each licensee is addressed as "you".

Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope.  The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.

  1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.

You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.

  2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:

    a) You must cause the modified files to carry prominent notices
    stating that you changed the files and the date of any change.

    b) You must cause any work that you distribute or publish, that in
    whole or in part contains or is derived from the Program or any
    part thereof, to be licensed as a whole at no charge to all third
    parties under the terms of this License.

    c) If the modified program normally reads commands interactively
    when run, you must cause it, when started running for such
    interactive use in the most ordinary way, to print or display an
    announcement including an appropriate copyright notice and a
    notice that there is no warranty (or else, saying that you provide
    a warranty) and that users may redistribute the program under
    these conditions, and telling the user how to view a copy of this
    License.  (Exception: if the Program itself is interactive but
    does not normally print such an announcement, your work based on
    the Program is not required to print an announcement.)

These requirements apply to the modified work as a whole.  If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works.  But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.

Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.

In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.

  3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:

    a) Accompany it with the complete corresponding machine-readable
    source code, which must be distributed under the terms of Sections
    1 and 2 above on a medium customarily used for software interchange; or,

    b) Accompany it with a written offer, valid for at least three
    years, to give any third party, for a charge no more than your
    cost of physically performing source distribution, a complete
    machine-readable copy of the corresponding source code, to be
    distributed under the terms of Sections 1 and 2 above on a medium
    customarily used for software interchange; or,

    c) Accompany it with the information you received as to the offer
    to distribute corresponding source code.  (This alternative is
    allowed only for noncommercial distribution and only if you
    received the program in object code or executable form with such
    an offer, in accord with Subsection b above.)

The source code for a work means the preferred form of the work for
making modifications to it.  For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable.  However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.

If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.

  4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License.  Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.

  5. You are not required to accept this License, since you have not
signed it.  However, nothing else grants you permission to modify or
distribute the Program or its derivative works.  These actions are
prohibited by law if you do not accept this License.  Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.

  6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions.  You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.

  7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License.  If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all.  For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.

If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other

It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices.  Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.

This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
  8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded.  In such case, this License incorporates
the limitation as if written in the body of this License.

  9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time.  Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.

Each version is given a distinguishing version number.  If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation.  If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software

  10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission.  For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this.  Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.

                            NO WARRANTY



                     END OF TERMS AND CONDITIONS