The big challenge with a keyboard is handling various different keyboard layouts in a flexible manner. To understand the challenge, here's a quick run down of how a keyboard operates.
When a key is pressed or released, the keyboard transmits a sequence of bytes. The format of this is:
- (Optional) $E0 if the key is an enhanced/extended key.
- (Optional) $F0 if the key is being released (not sent if pressed).
- The scancode itself.
For some of the complex keys (such as the duplicate navigation keys on a 102 key keyboard), the keyboard sends a lengthy sequence of presses and released. We'll ignore these for the moment.
The old Emerson code was pretty much hard-coded to a UK layout. It would look on one of two tables (depending on whether the scancode was enhanced or not) to work out what the value of the key was, and then convert that to an ASCII-ish value after handling modifiers. You could load different tables, but the behaviour depended on modifiers being in the same place and having the same effect on all devices.
The new system is geared towards being much more flexible. The way I intend on structuring the layout files is a bit like this...
First up, you have a list of available scancodes. One scancode represents one key. This table is an index onto further data for each key.
A key can be one of two types - a "modifier" (Shift, Num Lock, AltGr, Ctrl) or a "valued" (A, B, 6, Home) key. A modifier key won't actually return a value, but will be used to modify the current state of the keyboard.
Modifier keys map onto a bit index for the status byte. This byte holds the current modifier state of the keyboard. Multiple modifier keys can share the same bit - for example, both Shift keys could share bit 0, both Ctrl keys could share bit 1 - but as there's only one AltGr key, that would have bit 2 all to itself. Which bit you pick doesn't matter. The keys would also have an "LED" bit index - this could be used to set/reset the LED status on the keyboard.
Modifier keys can be either temporary (Shift, AltGr, Ctrl) or a toggle (Num Lock). A temporary key would only set the status bit it is tied to when it is held down, a toggle would switch the status of the bit when pressed.
For each value key, you would have a bitmask which contains the bits of the status byte that can affect it. For example, for the space key you would have a bitmask of 0 - it produces a space whatever the state of the modifier keys. For something like 5 you would have a bitmask of whatever the bitmask for shift is - it can either be 5 or %. Something like E would have to have a bitmask of Ctrl OR Shift OR Caps Lock OR AltGr. And so on.
There's a rough editor for all this:
When the code working out what value the key is, based on modifiers, it would take the current status and AND it with the bitmask of which modifiers affect it. It could then use the resulting value as an index into the different values associated with that key and return it.
The return values can be one of two types - a character or control code that corresponds to the key ('A', '1', BS), or a "non-displayable" key (Page Up, Left). Users will have to handle values < 32 (or 127) themselves (for example, it is expected that the Del key returns character 127, DEL, or that Enter returns 13, CR).
Hopefully this system is flexible enough for most layouts!