Building a Telegraphic Keyboard

For a while, I've been thinking about building a special keyboard for my PC. It should only have one key! That key would be used to telegraph the characters to write to the computer. I don't know if I ever will build it, but thought that I would summarise the solutions I've been thinking of in case anybody else is interested in this.

Using a software driver

Using a Software driver and a normal telegraphy key connected to the serial or parallel port of the computer. Back in high school I wrote a Pascal program to decode telegraphy into normal characters and print them on the screen.. That program required that you tapped the Morse code in by pressing one of the keys on the keyboard. It used a special library to be able to know both when a key was pressed and when it was released

In the DOS days, it would have been easy to write a TSR (Terminate Stay Resident) program that would run in the background and poll either the serial or the parallel port to read a telegraphy key attached to that port. If I remember correctly, it wouldn't have been hard either to stuff characters into the keyboard buffer, such that you could emulate the keyboard.

Today, as I have most experience with Linux, it would be fairly simple to write a new device driver for Morse code input, again by poling the serial or the parallel port. I don't know what to do with XP, but there probably are some viable solutions for that as well, searching MSDN for API functions related to keyboard input might give something.

Using hardware

The other way of using telegraphy instead of a keyboard would include building hardware that emulates a keyboard and plugs into a PS2 (or USB) connector. The hardware would be simple, and the firmware would require a little bit more effort. The simplest part (for me) would actually be the decoding of the Morse code, as I already have implemented that in Pascal once.

The hard part is emulating the keyboard. In the 8086 days, the emulation would have been trivial. Those keyboard only sent data in one direction, and the codes sent when pressing and releasing keys would be the only thing we had to care about. Today, the keyboards are much more complex. The keyboard not only sends data to the computer, the computer also sends data back to the keyboard. Besides that, the computer can change the keyboards behaviour in a number of ways, the most basic is "scancode mode 1", where the keys only sends a key code to the computer when the key is depressed (for alphanumeric keys, and the keyboard repeats the keypress scancode if the key is held down). Then there are two additional modes, "scancode mode 2 and 3", where all keys sends both press and release codes. The code size to handle all these variants in a microcontroller has made me postpone this project.

It might actually be just as hard to implement a USB keyboard interface emulating a HID keyboard instead. I currently have no USB-enabled microcontrollers, so an USB implementation would probably depend on any of the emulated USB projects similar to the AVR-USB, IgorPlug-USB (mirror), or USBtiny projects.

Some notes on decoding Morse code:

The most important insight is that any Morse character can be seen as part of a binary tree. Each node containing a character, and the nodes can have a dot and a dash as subnodes. Decoding is performed by starting in the root of the tree, jumping to the next dot-node when dots are received, or to the next dash-node when dashes are received. The only two problems with decoding is to be able to distinguish long and short dots, and to be able to know when there are spaces between words.

The table below shows half of the tree used for decoding Morse code, it's the half containing all digits and characters beginning with a dot (.). If one would like to decode the code ". - - .", one would pass the first dot in the table (landing on the letter E), then go down two dashes (landing on W), and then right one dot to end up on the letter P, which is the correct decoding of ". - - .".

==> . E   .   I  .   S  .  H  .  5
      |       |      |     |
      A.R.L   U.F    V     4
      |       |      |                     
      W.P  invalid   3                     
      |       |                          
      J       2                         
      |                         
      1                          

If I remember correctly[I should try and find that code], the program I wrote in secondary school used three vectors to decode Morse code, arranged as below. Note that I still only use half of the Morse code alphabet to keep the size of the illustration down.

/*    position       =    0    1    2    3    4    5    6    7    8    9   10   11   12   13   14   15   16   17   18   19 */
char  character[]    = { ' ', 'E', 'I', 'S', 'H', '5', 'A', 'R', 'L', 'U', 'F', 'V', '4', 'W', 'P', '~', '3', 'J', '2', '1' };
char  next_if_dot[]  = {  1,   2,   3,   4,   5,  -1,   7,   8,  -1,  10,  -1,  -1,  -1,  14,  -1,  -1,  -1,  -1,  -1,  -1  };
char  next_if_dash[] = { -1,   6,   9,  11,  12,  -1,  13,  -1,  -1,  15,  -1,  16,  -1,  17,  -1,  18,  -1   19,  -1,  -1  };

If one would decode the code ". - - ." through this table, one would begin at position 0 (zero) in the tables. Since one received a dot first, one would jump to position next_if_dot[0], which is 1 (one). That means that the current position for all references in the table should be 1. We also see that position one corresponds to the character E. The next sign is a dash, and next_if_dash[1] is 6, which corresponds to the letter A. Now we have a new current position, 6, to keep track of. The next dash gives the character W, since next_if_dash[6] is 13 and character[13] is W. The final sign to decode was a dot, and next_if_dot[13] gives us position 14 which is the character P, just as in the previous tree-like structure.