[Next] [Art of Assembly][Randall Hyde]


Art of Assembly Language: Chapter Twenty



Chapter 20 - The PC Keyboard
20.1 - Keyboard Basics
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

rhyde@cs.ucr.edu

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

Notes:

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:
Hello Again Professor Hyde,

Dallas gave me permission to take orders for the Computer Science 13 Manuals. We would need to take charge card orders. The only cards we take are: Master Card, Visa, and Discover. They would need to send the name, numbers, expiration date, type of card, and authorization to charge $95.00 for the manual and shipping, also we should have their phone number in case the company has any trouble delivery. They can use my e-mail address for the orders and I will process them as soon as possible. I would assume that two weeks would be sufficient for printing, packages and delivery time.

I am open to suggestions if you can think of any to make this as easy as possible.

Thank You for your business,

Kathy Chapman, Assistant
Printing and Reprographics
University of California
Riverside
(909) 787-4443/4444
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.


Art of Assembly Bug Report Submissions

Did you find an error in The Art of Assembly Language Programming? You can let me know by using the form below to report the error to me so that I can correct the error for the next beta version. Thank you.


The Submission Form

Please provide your name and e-mail address so I can contact you if I have any questions regarding your submission.

What is your name?
What is your e-mail address?

In the space provided below, please describe the nature of the problem. To help me find the problem quicker, please also provide the chapter and section number containing the problem. If you are reporting a problem with a hardcopy version of the textbook, please provide the page number as well.




Chapter 20 The PC Keyboard


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.


20.1 Keyboard Basics


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:

PC Keyboard Scan Codes (in hex)
KeyDownUpKeyDownUpKeyDownUpKeyDownUp
Esc181[ {1A9A, <33B3center4CCC
1 !282] }1B9B. >34B4right4DCD
2 @383Enter1C9C/ ?35B5+4ECE
3 #484Ctrl1D9DR shift36B6end4FCF
4 $585A1E9E* PrtSc37B7down50D0
5 %686S1F9Falt38B8pgdn51D1
6 ^787D20A0space39B9ins52D2
7 &888F21A1CAPS3ABAdel53D3
8 *989G22A2F13BBB/E0 35B5
9 (0A8AH23A3F23CBCenterE0 1C9C
0 )0B8BJ24A4F33DBDF1157D7
- _0C8CK25A5F43EBEF1258D8
= +0D8DL26A6F53FBFinsE0 52D2
Bksp0E8E; :27A7F640C0delE0 53D3
Tab0F8F' "28A8F741C1homeE0 47C7
Q1090` ~29A9F842C2endE0 4FCF
W1191L shift2AAAF943C3pgupE0 49C9
E1292\ |2BABF1044C4pgdnE0 51D1
R1393Z2CACNUM45C5leftE0 4BCB
T1494X2DADSCRL46C6rightE0 4DCD
Y1595C2EAEhome47C7upE0 48C8
U1696V2FAFup48C8downE0 50D0
I1797B30B0pgup49C9R altE0 38B8
O1898N31B1-4ACAR ctrlE0 1D9D
P1999M32B2left4BCBPauseE1 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.

Keyboard Codes (in hex)
KeyScan CodeASCIIShiftCtrlAltNumCapsShift CapsShift Num
Esc011B1B1B-1B1B1B1B
1 !023121 780031313131
2 @0332400300790032323232
3 #043323-7A0033333333
4 $053424-7B0034343434
5 %063525-7C0035353535
6 ^07365E1E7D0036363636
7 &083726-7E0037373737
8 *09382A-7F0038383838
9 (0A3928-800039393939
0 )0B3029-810030303030
- _0C2D5F1F82002D2D5F5F
= +0D3D2B-83003D3D2B2B
Bksp0E08087F-08080808
Tab0F090F00 -09090F000F00
Q10715111100071517151
W11775717110077577757
E12654505120065456545
R13725212130072527252
T14745414140074547454
Y15795919150079597959
U16755515160075557555
I17694909170069496949
O186F4F0F18006F4F6F4F
P19705010190070507050
[ {1A5B7B1B-5B5B7B7B
] }1B5D7D1D-5D5D7D7D
enter1C0D0D0A-0D0D0A0A
ctrl1D--------
A1E6141011E0061416141
S1F7353131F0073537353
D20644404200064446444
F21664606210066466646
G22674707220067476747
H23684808230068486848
J246A4A0A24006A4A6A4A
K256B4B0B25006B4B6B4B
L266C4C0C26006C4C6C4C
; :273B3A--3B3B3A3A
' "282722--27272222
` ~29607E--60607E7E
Lshift2A--------
\ |2B5C7C1C-5C5C7C7C
Z2C7A5A1A2C007A5A7A5A
X2D7858182D0078587858
C2E6343032E0063436343
V2F7656162F0076567656
B30624202300062426242
N316E4E0E31006E4E6E4E
M326D4D0D32006D4D6D4D
, <332C3C--2C2C3C3C
. >342E3E--2E2E3E3E
/ ?352F3F--2F2F3F3F
Rshift36--------
* PrtSc372AINT 510-2A2AINT 5INT 5
alt38--------
space39202020-20202020
caps3A--------
F13B3B0054005E0068003B003B0054005400
F23C3C0055005F0069003C003C0055005500
F33D3D00560060006A003D003D0056005600
F43E3E00570061006B003E003E0057005700
F53F3F00580062006C003F003F0058005800
F6404000590063006D004000400059005900
F74141005A0064006E00410041005A005A00
F84242005B0065006F00420042005B005B00
F94343005C0066007000430043005C005C00
F104444005D0067007100440044005D005D00
num45--------
scrl46--------
home474700377700-374700374700
up48480038--384800384800
pgup494900398400-394900394900
- (kpd)4A2D2D--2D2D2D2D
left4B4B00347300-344B00344B00
center4C4C0035--354C00354C00
right4D4D00367400-364D00364D00
+ (kpd)4E2B2B--2B2B2B2B
end4F4F00317500-314F00314F00
down50500032--325000325000
pgdn515100337600-335100335100
ins52520030--305200305200
del5353002E--2E53002E5300
Key

 
Scan CodeASCIIShiftCtrlAltNumCapsShift CapsShift 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, the type ahead buffer is empty. If the value in HeadPtr is two greater than the value in TailPtr (or 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 keystrokes, not 16.

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:

Keyboard Related BIOS Variables
NameAddressSizeDescription
KbdFlags1 (modifier flags)40:17ByteThis 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)
KbdFlags2

(Toggle keys down)
40:18ByteSpecifies 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)
AltKpd40:19ByteBIOS uses this to compute the ASCII code for an alt-Keypad sequence.
BufStart40:80WordOffset of start of keyboard buffer (1Eh). Note: this variable is not supported on many systems, be careful if you use it.
BufEnd40:82WordOffset of end of keyboard buffer (3Eh). See the note above.
KbdFlags340:96ByteMiscellaneous 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
KbdFlags440:97ByteMore 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 KbdFlags1 and KbdFlags4. Bits zero through two of the KbdFlags4 variable is BIOS' current settings for the LEDs on the keyboard. periodically, BIOS compares the values for capslock, numlock, 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 KbdFlags4 variable so the system is consistent. Therefore, if you mask in new values for numlock, scroll lock, or caps lock, the BIOS will automatically adjust KbdFlags4 and set the LEDs accordingly.
20.1 - Keyboard Basics
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

Art of Assembly: Chapter Twenty - 29 SEP 1996

[Next] [Art of Assembly][Randall Hyde]