(PC Tech Journal September 1986 by Dan Rollins)
The PC keyboard typically takes one-half second to begin repeating
a keystroke. Once the autorepeat process has begun, it repeats
keystrokes at the rate of 11 per second, taking about 7 seconds to move
the cursor across the screen. The typematic action, which can cost the
user valuable time, is not as quick as it could be.
KWIKKEY.ASM uses the computer's timer and interrupt mechanisms to
increase the keyboard's repeat-key rate. This, in turn, decreases the
time the user spends waiting for the keyboard to respond to keystrokes.
The program can be used with a PC, PC/XT, or PC/AT.
KWIKKEY.ASM is able to accelerate the PC keyboard because of the
flexible design of the PC's keystroke handling. The keyboard contains
its own Intel 8048 microprocessor. A control program in the ROM of the
8048 controls the processor's actions. This program is responsible for
identifying individual keystrokes. It maintains communication with the
computer as it serializes data for output to the system.
When a key is pressed (called a make), the keyboard sends the
computer a scan code, ranging from 1 to 83; each represents a different
key on the keyboard. When a key is released (called a break), the
keyboard adds 128 (80h) to the original scan code an sends the
resulting code to the computer. For example, the scan code for the
Esc key is 1. When Esc is pressed, the keyboard sends a 1 (01h) to
the computer; when Esc is released, the keyboard sends a 129 (81h).
When the keyboard senses either a make or a break, it signals the
8259 interrupt controller chip, which is located at the PC end of the
coiled keyboard cable, to interrupt the action of the CPU. The 8259
then forces an INT 9, which passes control to the KB_INT procedure
contained in the ROM BIOS. This routine reads the scan code from the
keyboard and responds appropriately.
The KB_INT procedure is very sophisticated. It must handle the
cases of Shift, Ctrl, and Alt key combinations, as well as the special
commands Shift-PrtSc, Ctrl-Break, Ctrl-NumLock, and Ctrl-Alt-Del. As
soon as the keystroke has been interpreted, the KB_INT procedure places
an ASCII (or special extended ASCII) value in a circular queue. When a
program requests keyboard input, it is passed the first keystroke
contained in this buffer.
Because of this flexible system, nearly every facet of the PC's
keyboard handler can be modified. The most common way to modify
keyboard action is to replace the BIOS KB_INT routine with a custom
driver. Several such keyboard utilities are available, such as
SuperKey and ProKey.
However, simply replacing the BIOS KB_INT routien does not affect
the typematic action of the PC keyboard. KB_INT only processes each
scan code as it comes from the keyboard. The 8048 processor in the
keyboard is responsible for determining how soon to start the
repetitions as well as how fast to send them.
In much the same way that the keyboard interrupts the CPU when a
scan code is ready, the realtime clock also forces hardware interrupts.
It does not wait for an external event, such as a keystroke, but
interrupts the CPU on a regular cycle, every 55 milliseconds or about
18.2 times a second. The interrupt vector called the timer tick (INT
1Ch) can be used to intercept the realtime clock interrupt. Spooler
programs and other background tasks often tie into the timer tick in
order to do a slice of processing in the background while another
program continues running.
KWIKKEY.ASM also uses the timer tick interrupt. The program
intercepts both the keyboard interrupt (KBD_INT) and the timer
interrupt (TIMER_INT) and makes them work together to handle repeat-
The version of KBD_INT defined in KWIKKEY.ASM monitors the
keyboard buffer. When it senses that a keystroke has been recorded,
it saves the keystroke in a memory variable. Simultaneously, the
TIMER_INT included in KWIKKEY checks continuously to see if a repeat
of the keystroke is desired. At the interval specified by the user
at the beginning of the program, TIMER_INT stores the saved keystroke
in the keyboard buffer, effectively repeating the previous key -- long
before the keyboard itself would have been able to repeat the key. The
net result is that keys can be repeated at up to three times the
The KWIKKEY.ASM program is written as three separate procedures:
SET_UP, KBD_INT, and TIMER_INT. When KWIKKEY is executed, it jumps
over the data and the interrupt handlers to get to the SET_UP
procedure, which is the initialization portion of the program. SET_UP
first checks to make sure that a copy of SET_UP has not been installed
Any program that intercepts an interrupt risks the possibility of
interfering with other programs that perform the same task. To avoid
this danger, KWIKKEY does not disable the system interrupt handlers.
It simply borrows the interrupts temporarily, always passing control
down the line to the original interrupt handler. If another timer
interrupt handler has been installed, this technique makes sure that
the original handler is given its expected time share. If KWIKKEY
proves to be incompatible with some already installed program, the
answer might be to install KWIKKEY first.
After storing the original keyboard and timer interrupt vectors
in its data area KWIKKEY loads the new KBD_INT and TIMER_INT addresses.
The program then uses the INT 27h "terminate-but-stay-resident" service
to pass control back to DOS, leaving the interrupt handler code
resident in memory.
After both interrupt handlers have been installed, TIMER_NIT is
executed 18.2 times per second. Thus, its action can be considered
continuous; it is executed regardless of any other processes taking
place. KBD_INT, on the other hand, is executed only when the user
presses or releases a key.
When a key is pressed or released, KBD_INT checks the current
position of the end of the queue in the keyboard buffer (called the
buffer tail). After checking the buffer tail, KBD_INT then invokes
the original keyboard interrupt. Upon returning, it checks the position
of the buffer tail again. If the position has changed, it knows that
a keystroke has been input in the interval. The new keystroke is
saved for handling later by the timer interrupt, and the variable
INIT_DELAY is initialized to start the countdown before the first
repeat. Note that the repeat mechanism is disabled in the special
case of an artificial keystroke, such as Alt combined with a key from
the numeric keypad.
However, if the buffer tail has not moved since KBD_INT first
checked its position, the interrupt must have been caused by a Shift
key combination (which does not produce an ASCII code) or by the
release of a key. In either case, a keystroke repeat is not necessary,
and a flag is set to prevent the timer interrupt from taking any
action. Any autorepeat in progress is stopped. The interrupted
program then is exited via an IRET instruction.
At the same time, the TIMER_INT continues to be executed 18.2
times per second. Its job is to simulate keyboard activity by placing
scan codes in the keyboard buffer at appropriate times. It checks the
value of the INIT_DELAY variable continuously. If the value is not 0,
it decrements it and exits without taking any further action. The
effect is that a new keystroke is not repeated until the fifth time
that TIMER_INT is executed. Because the timer ticks at a rate of
about 55 milliseconds, the keystroke does not begin repeating for about
275 milliseconds (or about one-quarter of a second). A longer delay is
not necessary; this is plenty of time to allow the user to release the
key. A shorter delay might cause spurious repeats. Users can
experiment with this value by changing the REPT_DELAY equate, which is
located at the beginning of the KWIKKEY.ASM program.
After the one-quarter second delay, TIMER_INT begins counting down
to the time specified at the beginning of KWIKKEY.ASM to put a repeat
keystroke in the keyboard buffer. The RATE_DELAY variable is
decremented with each subsequent pass. When it reaches 0, the scan
code in LAST_KEY is placed in the keyboard buffer. If the buffer is
full, no action is taken.
In KWIKKEY.ASM, the REPT_RATE constant is set at 1, which means
that a repeat is forced once every two executions of the TIMER_INT.
The user can change this constant to force the repeat to occur at a
different interval. TIMER_INT is executed 18 times per second; as a
result, 9 repeats are added to the 11 that come from the keyboard, for
a total of 20 repeats per second. This rate can be changed with the
REPT_RATE equate at the beginning of the program.
While KWIKKEY.ASM can be used with an AT, a much simpler method
also exists for accelerating the reaction time of the AT's keyboard.
This is because the AT serial keyboard link is bidirectional. This
allows data to be sent directly to the 8048 keyboard controller. As
a result, repeat-key action can be augmented with a simple BASIC
program called KWIKAT.BAS or a short assembly language program (PC
Tech Journal May 1985 "Rev Up the AT Keyboard").
KWIKAT.BAS can be included in an AUTOEXEC.BAT file. KWIKKEY.ASM
proves the value of assembly language; it could not have been written
in any other language. The program illustrates how to install a
timer-driven interrupt handler using a technique that does not
interfere with other programs of the same nature.
KWIKKEY demonstrates the concepts of background tasking and
coroutines. While the TIMER_INT and the KBD_INT procedures are useless
when examined individually, the dynamic interplay between the routines
provides a unique software solution to a shortcoming of the PC keyboard.