THE PC KEYBOARD (Part 1)
20.2 - The Keyboard Hardware Interface
20.3 - The Keyboard DOS Interface
20.4 - The Keyboard BIOS Interface
20.5 - The Keyboard Interrupt Service Routine
20.6 - Patching into the INT 9 Interrupt Service Routine
20.7 - Simulating Keystrokes
20.7.1 - Stuffing Characters in the Type Ahead Buffer
20.7.2 - Using the 80x86 Trace Flag to Simulate IN AL 60H Instructions
20.7.3 - Using the 8042 Microcontroller to Simulate Keystrokes
|Copyright 1996 by Randall Hyde
All rights reserved.
Duplication other than for immediate display through a browser is prohibited by U.S. Copyright Law.
This material is provided on-line as a beta-test of this text. It is for the personal use of the reader only. If you are interested in using this material as part of a course please contact email@example.com
Supporting software and other materials are available via anonymous ftp from ftp.cs.ucr.edu. See the "/pub/pc/ibmpcdir" directory for details. You may also download the material from "Randall Hyde's Assembly Language Page" at URL: http://webster.ucr.edu
This document does not contain the laboratory exercises programming assignments exercises or chapter summary. These portions were omitted for several reasons: either they wouldn't format properly they contained hyperlinks that were too much work to resolve they were under constant revision or they were not included for security reasons. Such omission should have very little impact on the reader interested in learning this material or evaluating this document.
This document was prepared using Harlequin's Web Maker 2.2 and Quadralay's Webworks Publisher. Since HTML does not support the rich formatting options available in Framemaker this document is only an approximation of the actual chapter from the textbook.
If you are absolutely dying to get your hands on a version other than HTML you might consider having the UCR Printing a Reprographics Department run you off a copy on their Xerox machines. For details please read the following EMAIL message I received from the Printing and Reprographics Department:
We are currently working on ways to publish this text in a form other than HTML (e.g. Postscript PDF Frameviewer hard copy etc.). This however is a low-priority project. Please do not contact Randall Hyde concerning this effort. When something happens an announcement will appear on "Randall Hyde's Assembly Language Page." Please visit this WEB site at http://webster.ucr.edu for the latest scoop.
Redesigned 10/2000 with "MS FrontPage 98" using
17" monitor 1024x768
The PC's keyboard is the primary human input device on the system. Although it seems rather mundane the keyboard is the primary input device for most software so learning how to program the keyboard properly is very important to application developers.
IBM and countless keyboard manufacturers have produced numerous keyboards for PCs and compatibles. Most modern keyboards provide at least 101 different keys and are reasonably compatible with the IBM PC/AT 101 Key Enhanced Keyboard. Those that do provide extra keys generally program those keys to emit a sequence of other keystrokes or allow the user to program a sequence of keystrokes on the extra keys. Since the 101 key keyboard is ubiquitous we will assume its use in this chapter.
When IBM first developed the PC they used a very simple interface between the keyboard and the computer. When IBM introduced the PC/AT they completely redesigned the keyboard interface. Since the introduction of the PC/AT almost every keyboard has conformed to the PC/AT standard. Even when IBM introduced the PS/2 systems the changes to the keyboard interface were minor and upwards compatible with the PC/AT design. Therefore this chapter will also limit its attention to PC/AT compatible devices since so few PC/XT keyboards and systems are still in use.
There are five main components to the keyboard we will consider in this chapter - basic keyboard information the DOS interface the BIOS interface the int 9 keyboard interrupt service routine and the hardware interface to the keyboard. The last section of this chapter will discuss how to fake keyboard input into an application.
The PC's keyboard is a computer system in its own right. Buried inside the keyboards case is an 8042 microcontroller chip that constantly scans the switches on the keyboard to see if any keys are down. This processing goes on in parallel with the normal activities of the PC hence the keyboard never misses a keystroke because the 80x86 in the PC is busy.
A typical keystroke starts with the user pressing a key on the keyboard. This closes an electrical contact in the switch so the microcontroller and sense that you've pressed the switch. Alas switches (being the mechanical things that they are) do not always close (make contact) so cleanly. Often the contacts bounce off one another several times before coming to rest making a solid contact. If the microcontroller chip reads the switch constantly these bouncing contacts will look like a very quick series of key presses and releases. This could generate multiple keystrokes to the main computers a phenomenon known as keybounce common to many cheap and old keyboards. But even on the most expensive and newest keyboards keybounce is a problem if you look at the switch a million times a second; mechanical switches simply cannot settle down that quickly. Most keyboard scanning algorithms therefore control how often they scan the keyboard. A typical inexpensive key will settle down within five milliseconds so if the keyboard scanning software only looks at the key every ten milliseconds or so the controller will effectively miss the keybounce.
Simply noting that a key is pressed is not sufficient reason to generate a key code. A user may hold a key down for many tens of milliseconds before releasing it. The keyboard controller must not generate a new key sequence every time it scans the keyboard and finds a key held down. Instead it should generate a single key code value when the key goes from an up position to the down position (a down key operation). Upon detecting a down key stroke the microcontroller sends a keyboard scan code to the PC. The scan code is not related to the ASCII code for that key it is an arbitrary value IBM chose when they first developed the PC's keyboard.
The PC keyboard actually generates two scan codes for every key you press. It generates a down code when you press a key and an up code when you release the key. The 8042 microcontroller chip transmits these scan codes to the PC where they are processed by the keyboard's interrupt service routine. Having separate up and down codes is important because certain keys (like shift control and alt) are only meaningful when held down. By generating up codes for all the keys the keyboard ensures that the keyboard interrupt service routine knows which keys are pressed while the user is holding down one of these modifier keys. The following table lists the scan codes that the keyboard microcontroller transmits to the PC:
|1 !||2||82||] }||1B||9B||. >||34||B4||right||4D||CD|
|2 @||3||83||Enter||1C||9C||/ ?||35||B5||+||4E||CE|
|3 #||4||84||Ctrl||1D||9D||R shift||36||B6||end||4F||CF|
|4 $||5||85||A||1E||9E||* PrtSc||37||B7||down||50||D0|
|8 *||9||89||G||22||A2||F1||3B||BB||/||E0 35||B5|
|9 (||0A||8A||H||23||A3||F2||3C||BC||enter||E0 1C||9C|
|= +||0D||8D||L||26||A6||F5||3F||BF||ins||E0 52||D2|
|Bksp||0E||8E||; :||27||A7||F6||40||C0||del||E0 53||D3|
|Tab||0F||8F||' "||28||A8||F7||41||C1||home||E0 47||C7|
|Q||10||90||` ~||29||A9||F8||42||C2||end||E0 4F||CF|
|W||11||91||L shift||2A||AA||F9||43||C3||pgup||E0 49||C9|
|E||12||92||\ |||2B||AB||F10||44||C4||pgdn||E0 51||D1|
|I||17||97||B||30||B0||pgup||49||C9||R alt||E0 38||B8|
|O||18||98||N||31||B1||-||4A||CA||R ctrl||E0 1D||9D|
|P||19||99||M||32||B2||left||4B||CB||Pause||E1 1D 45 E1 9D C5||-|
The keys in italics are found on the numeric keypad. Note that certain keys transmit two or more scan codes to the system. The keys that transmit more than one scan code were new keys added to the keyboard when IBM designed the 101 key enhanced keyboard.
When the scan code arrives at the PC a second microcontroller chip receives the scan code does a conversion on the scan code makes the scan code available at I/O port 60h and then interrupts the processor and leaves it up to the keyboard ISR to fetch the scan code from the I/O port.
The keyboard (int 9) interrupt service routine reads the scan code from the keyboard input port and processes the scan code as appropriate. Note that the scan code the system receives from the keyboard microcontroller is a single value even though some keys on the keyboard represent up to four different values. For example the "A" key on the keyboard can produce A a ctrl-A or alt-A. The actual code the system yields depends upon the current state of the modifier keys (shift ctrl alt capslock and numlock). For example if an A key scan code comes along (1Eh) and the shift key is down the system produces the ASCII code for an uppercase A. If the user is pressing multiple modifier keys the system prioritizes them from low to high as follows:
Numlock and capslock affect different sets of keys so there is no ambiguity resulting from their equal precedence in the above chart. If the user is pressing two modifier keys at the same time the system only recognizes the modifier key with the highest priority above. For example if the user is pressing the ctrl and alt keys at the same time the system only recognizes the alt key. The numlock capslock and shift keys are a special case. If numlock or capslock is active pressing the shift key makes it inactive. Likewise if numlock or capslock is inactive pressing the shift key effectively "activates" these modifiers.
Not all modifiers are legal for every key. For example ctrl-8 is not a legal combination. The keyboard interrupt service routine ignores all keypresses combined with illegal modifier keys. For some unknown reason IBM decided to make certain key combinations legal and others illegal. For example ctrl-left and ctrl-right are legal but ctrl-up and ctrl-down are not. You'll see how to fix this problem a little later.
The shift ctrl and alt keys are active modifiers. That is modification to a keypress occurs only while the user holds down one of these modifier keys. The keyboard ISR keeps track of whether these keys are down or up by setting an associated bit upon receiving the down code and clearing that bit upon receiving the up code for shift ctrl or alt. In contrast the numlock scroll lock and capslock keys are toggle modifiers. The keyboard ISR inverts an associated bit every time it sees a down code followed by an up code for these keys.
Most of the keys on the PC's keyboard correspond to ASCII characters. When the keyboard ISR encounters such a character it translates it to a 16 bit value whose L.O. byte is the ASCII code and the H.O. byte is the key's scan code. For example pressing the "A" key with no modifier with shift and with control produces 1E61h 1E41h and 1E01h respectively ("a" "A" and ctrl-A). Many key sequences do not have corresponding ASCII codes. For example the function keys the cursor control keys and the alt key sequences do not have corresponding ASCII codes. For these special extended code the keyboard ISR stores a zero in the L.O. byte (where the ASCII code typically goes) and the extended code goes in the H.O. byte. The extended code is usually though certainly not always the scan code for that key.
The only problem with this extended code approach is that the value zero is a legal ASCII character (the NUL character). Therefore you cannot directly enter NUL characters into an application. If an application must input NUL characters IBM has set aside the extended code 0300h (ctrl-3) for this purpose. You application must explicitly convert this extended code to the NUL character (actually it need only recognize the H.O. value 03 since the L.O. byte already is the NUL character). Fortunately very few programs need to allow the input of the NUL character from the keyboard so this problem is rarely an issue.
The following table lists the scan and extended key codes the keyboard ISR generates for applications in response to a keypress with various modifiers. Extended codes are in italics. All other values (except the scan code column) represent the L.O. eight bits of the 16 bit code. The H.O. byte comes from the scan code column.
|Key||Scan Code||ASCII||Shift||Ctrl||Alt||Num||Caps||Shift Caps||Shift Num|
|* PrtSc||37||2A||INT 5||10||-||2A||2A||INT 5||INT 5|
|Key||Scan Code||ASCII||Shift||Ctrl||Alt||Num||Caps||Shift Caps||Shift Num|
The 101-key keyboards generally provide an enter key and a "/" key on the numeric keypad. Unless you write your own int 9 keyboard ISR you will not be able to differentiate these keys from the ones on the main keyboard. The separate cursor control pad also generates the same extended codes as the numeric keypad except it never generates numeric ASCII codes. Otherwise you cannot differentiate these keys from the equivalent keys on the numeric keypad (assuming numlock is off of course).
The keyboard ISR provides a special facility that lets you enter the ASCII code for a keystroke directly from the keyboard. To do this hold down the alt key and typing out the decimal ASCII code (0..255) for a character on the numeric keypad. The keyboard ISR will convert these keystrokes to an eight-bit value attach at H.O. byte of zero to the character and use that as the character code.
The keyboard ISR inserts the 16 bit value into the PC's type ahead buffer. The system type ahead buffer is a circular queue that uses the following variables
40:1A - HeadPtr word ? 40:1C - TailPtr word ? 40:1E - Buffer word 16 dup (?)
The keyboard ISR inserts data at the location pointed at by
TailPtr. The BIOS keyboard function removes characters from the location
pointed at by the
HeadPtr variable. These two pointers almost always contain
an offset into the
Buffer array. If these two pointers are equal
ahead buffer is empty. If the value in
HeadPtr is two greater than the value
HeadPtr is 1Eh and
TailPtr is 3Ch)
then the buffer is full and the keyboard ISR will reject any additional keystrokes.
Note that the
TailPtr variable always points
at the next available location in the type ahead buffer. Since there is no
"count" variable providing the number of entries in the buffer
we must always
leave one entry free in the buffer area; this means the type ahead buffer can only hold 15
In addition to the type ahead buffer the BIOS maintains several other keyboard-related variables in segment 40h. The following table lists these variables and their contents:
|KbdFlags1 (modifier flags)||40:17||Byte||This byte maintains the current status of the modifier
keys on the keyboard. The bits have the following meanings:
bit 7: Insert mode toggle
bit 6: Capslock toggle (1=capslock on)
bit 5: Numlock toggle (1=numlock on)
bit 4: Scroll lock toggle (1=scroll lock on)
bit 3: Alt key (1=alt is down)
bit 2: Ctrl key (1=ctrl is down)
bit 1: Left shift key (1=left shift is down)
bit 0: Right shift key (1=right shift is down)
(Toggle keys down)
|40:18||Byte||Specifies if a toggle key is currently down.
bit 7: Insert key (currently down if 1)
bit 6: Capslock key (currently down if 1)
bit 5: Numlock key (currently down if 1)
bit 4: Scroll lock key (currently down if 1)
bit 3: Pause state locked (ctrl-Numlock) if one
bit 2: SysReq key (currently down if 1)
bit 1: Left alt key (currently down if 1)
bit 0: Left ctrl key (currently down if 1)
|AltKpd||40:19||Byte||BIOS uses this to compute the ASCII code for an alt-Keypad sequence.|
|BufStart||40:80||Word||Offset of start of keyboard buffer (1Eh). Note: this variable is not supported on many systems be careful if you use it.|
|BufEnd||40:82||Word||Offset of end of keyboard buffer (3Eh). See the note above.|
|KbdFlags3||40:96||Byte||Miscellaneous keyboard flags.
bit 7: Read of keyboard ID in progress
bit 6: Last char is first kbd ID character
bit 5: Force numlock on reset
bit 4: 1 if 101-key kbd 0 if 83/84 key kbd.
bit 3: Right alt key pressed if 1
bit 2: Right ctrl key pressed if 1
bit 1: Last scan code was E0h
bit 0: Last scan code was E1h
|KbdFlags4||40:97||Byte||More miscellaneous keyboard flags.
bit 7: Keyboard transmit error
bit 6: Mode indicator update
bit 5: Resend receive flag
bit 4: Acknowledge received
bit 3: Must always be zero
bit 2: Capslock LED (1=on)
bit 1: Numlock LED (1=on)
bit 0: Scroll lock LED (1=on)
One comment is in order about
KbdFlags4. Bits zero through two of the
is BIOS' current settings for the LEDs on the keyboard. periodically
BIOS compares the
values for capslock
and scroll lock in
KbdFlags1 against these
three bits in
KbdFlags4. If they do not agree
BIOS will send an appropriate
command to the keyboard to update the LEDs and it will change the values in the
variable so the system is consistent. Therefore
if you mask in new values for numlock
or caps lock
the BIOS will automatically adjust
set the LEDs accordingly.
Chapter Twenty: The PC Keyboard (Part
29 SEP 1996