OVERVIEW OF IBM TYPE F KEYBOARD SCAN CODES
The 3178 sends back scan codes to its control unit, whether a real IBM 3174, some other CU, or the 3174 substitute I am working with. The CU will take such actions as writing a character on the screen that corresponds to the keycap you just pushed. It also tracks the case you are in, such as holding the
Shift Up button or the Upper Case Lock button having been pressed. Finally, it has an ALT key that is a modifier to select an alternate function for a given key.
The scan codes are not ASCII. They are not EBCDIC. They are not even the native character set of the display. They don't have a fixed assignment to a character; instead they represent some internal logic for how the keys are wired.
Since the 3178 terminal can have a variety of keyboards, such as 75 or 87 key, with different arrangements of keycaps. Some are intended for Data Entry, some are considered Typewriter style, others may suit programming better. Thus, the CU has to know the specific keyboard installed on the terminal so that it can interpret a scan code. A given physical key on the keyboard may have the same scan code across all keyboard types, but its keycap and the intended character or function will vary.
I extracted all the scan codes returned by my keyboard, which has 87 keys in a version of the Data Entry Keypunch style. I will make use of this to convert the key that was pressed into the intended character. Further, some keys represent characters that will display on the screen, some represent hardware status, and some represent control functions that must be executed.
As an example of control functions, the TAB key is intended to cause the CU to move the cursor to the first position of the next field on the screen. The ENTER key is used to signal to the mainframe that all desired keystrokes have been entered into the screen and thus the application should read the typed field to begin processing.
SCREEN CHARACTER CODES
The 3270 style terminals use a byte to represent a character that should be displayed in each position of the screen. There are 255 possible characters, plus null, which supports a decent sized character set of upper and lower case letters, numbers, special symbols and quite a few characters for use with foreign (but latin alphabet oriented) languages.
Of the 256 possible codes, 1/4 of them are reserved for special control symbols that are used on the bottom status line (called an Operator Information Area). The remaining 192 characters are used on the main display area, usually some multiple of 12 lines by 80 characters which depends on the terminal model. Mine is a 24 line by 80 character display.
The code used is not ASCII or EBCDIC. It is an internal code that indexes into a character ROM to choose the pixels to illuminate in each character cell. x80 encodes the lower case letter a, while xA0 is the upper case version of A. x22 encodes the numeric digit 2 while x18 represents the question mark.
MAINFRAME USER CHARACTER CODES
Programs on the mainframe who are sending text to place on the screen, and who are receiving the typed input from the operator, don't receive scan codes nor the internal 3270 character set. All data is translated into EBCDIC usually, unless an uncommon feature was installed that provides ASCII instead. The upper case letter A is xC0 in EBCDIC and the digit 2 is xF2.
CONVERSIONS UPON CONVERSIONS ARE REQUIRED
Thus, when I hit the keycap marked A on my keyboard, it sends scan code x182. That is translated to xA0 for display on the screen and to xC0 for transmission from the CU to the mainframe host. This is layer one of the conversion required.
Also, the role of a keycap depends on whether the operator has shifted to upper case. The keycap on my terminal represents an X in lower case and a question mark in upper case. Thus, the CU has to know whether the current state is shifted up or not. Keys such as Shift to Upper, Lock in Upper, and Shift to Lower are used to adjust that current state. These keys are unique in having two scancodes associated with each one.
When pressing Shift to Upper, the code x136 is transmitted, then when the key is released it sends x336. The CU will remember that we are in upper case based on having seen an x136 and drops back to lower when it receives the x336 code. In a similar way, the ALT key sends x13e as it is depressed and x33e when released.
The numeric keypad on my terminal makes use of both of these. In normal mode (not upper case and not ALT), the twelve keys produce program function codes PF1 thru PF12. If ALT is active (key held down), then these produce PF13 thru PF24 instead. If instead the CU is in upper case mode then the pad produces the ten digits, decimal point and TAB. We can be in upper case mode by holding down the Shift to Upper key, or by having pressed the Lock Upper Case keycap.
One fact that may not be obvious is that the keyboard has no way to produce lower case letters. When in lower case mode, a keycap such as B produces the upper case B character. Then shifted to upper case it represents the exclamation point (!)character. Applications can send the code x81 to display a lower case b or xA1 to display an upper case B, but the keyboard only produces capital letter codes.
CENTRALITY OF THE CONTROL UNIT IN HANDLING KEYPRESSES
To the operator, it appears that when the cursor is blinking in a field that is not protected, any key that is pressed produces the associated character on the screen immediately. Further, movement keys such as TAB or down arrow move the cursor immediately. Control keys such as CLEAR cause the entire screen to become blank.
None of those actions are done in the terminal. Instead, scan codes are sent to the CU which in turn makes appropriate changes to the screen in front of the operator. Pressing the keycap for a C will cause the CU to update the screen at the point of the cursor with the code xA2 and we see the C displayed.
Pushing TAB tells the control unit to look through its buffer to find the start position of the next unprotected field and move the cursor to that point. The user sees the cursor jump. Hitting CLEAR sends the code to the CU, when then erases groups of four character positions at a time until the entire screen is cleared.
When the keycap marked B is pressed, the CU decides if it is sending a B or a ! to that screen position. It does so based on what it had last seen done with the shift keys. The keypad on the right is even more complicated. Pressing the keycap labeled PF4/4 will be interpreted as a PF4, a PF16 or a character 4 depending on whether the ALT key or the shift state is active.
When a user has the cursor in a protected field but presses the G keycap, the CU receives that scan code but locks the terminal and displays a status character on the last line that informs the operator that data cannot be typed at the current cursor location. The scan code is still sent, it is just thrown away by the CU.
DEVELOPING A PYTHON OBJECT TO CONVERT SCAN CODES
I built a Python object that, when given a scan code, can tell us if this is a control key, a hardware status such as Power On Reset Complete, or a screen oriented keycap. Further, it can give us the 3270 native code for that scan code, to write to the screen. It can also give us the ASCII equivalent which I can use in the program for diagnostic or logical purposes.
Later we can convert the native 3270 characters to their EBCDIC equivalents for transmission back to a mainframe host, but that is not in the first version of this code.