Classic Computer Magazine Archive COMPUTE! ISSUE 72 / MAY 1986 / PAGE 93

Upgrading The
Apple ESCape Key

Robert Jacques Beck

With this short routine, you can reprogram the Apple's ESCape key (or any other key) to perform a variety of special functions within Applesoft BASIC. It works with any Apple II-series computer using Applesoft BASIC and DOS 3.2, DOS 3.3, or ProDOS.

Have you ever wished you could detect special escape codes in Applesoft BASIC? For instance, say that you have an Applesoft program that uses INPUT to ask you for a disk filename. In many cases, it would be handy to view the disk catalog before entering the filename. But that's impossible under normal circumstances-you can't type a CATALOG command while the computer's waiting for a response to INPUT.
    "ESCape Key Upgrade," listed below, lets you add a special escape key function to display the catalog automatically whenever you press ESCape. With a little extra programming, you can use the same routine to give special meaning to any other key or keypress sequence on your Apple II computer.

Type in and save Program 1, then run it for a demonstration. The first ten lines install and activate a short machine language routine; line 110 performs an ordinary INPUT command. When the INPUT prompt appears, press ESC. The computer immediately displays a disk catalog, just as if you'd stepped outside program mode for a moment and typed CATALOG in immediate mode. Of course, you're not limited to a catalog display; by substituting different commands after the THEN statement in line 120, you can perform other commands, branch to a subroutine, or do whatever else you like.
    The ESC key is ideally suited for this purpose, since it's located near the upper-left corner of the keyboard and is rarely used except for editing. Program 1 checks ESC after an INPUT statement, but this technique works just as well after any GET statement. If you want a program to respond to ESC more quickly, you needn't wait for an INPUT or GET. Try the technique known as polling (periodically testing) the keyboard. For instance, your program might call the following subroutine at regular intervals:

900 IF PEEK (-16384) < 128 TH
910 POKE -16368,0
920 IF PEEK (-16384) = 27 THE

    The first line of this routine checks whether a key has been pressed since the last keyboard check was made. Only if the answer is yes does the routine go on to test for the ESC key specifically (this prevents the computer from reacting twice to the same keypress). With this routine in place, you can check ESC whenever you like by inserting GOSUB 900 at the appropriate spot in a program.

Checking Other Keys
Testing for keys other than ESC is quite easy. Take a look at line 60 of Program 1. The second value in the DATA statement represents CHR$(27), the ASCII value of the ESC key. To test for a different key, replace the 27 in line 60 with the ASCII code of the desired key, then make the same substitution in line 120 as well. For example, to test for the letter A instead of ESC, substitute a 65 for 27 in lines 60 and 120. If you rerun the program and press A at the INPUT prompt, the computer displays a disk catalog exactly as before.
    What about reprogramming more than one key at a time? Let's check for three special key combinations: The ESC key will display the catalog for drive 1, CTRL-A will catalog drive 2, and CTRL-C will home the cursor. The first step is to add these lines to Program 1 (note that line 120 is replaced with a new line):

58 DATA 201,1,240,10 : REM CO
59 DATA 201,3,240,6 ;REM CONT
   ROL C
120 IF PEEK (-16384) = 27 THE
    D1": GOTO 110
130 IF PEEK (-16384) = 1 THEN
    2": GOTO 110
140 IF PEEK (-16384) = 3 THEN
     HOME: GOTO 110

    The second number in each DATA statement represents the ASCII code for a particular keypress. The last number in each DATA statement must equal the last number in the following line plus 4; since line 59 ends with the value 6, line 58 must end with the value 10 (6+4), and so forth. Lines 130 and 140 add the IF statements needed to test for CTRL-A and CTRL-C. Following this pattern, you can add your own key definitions.
    Reprogrammed keys behave just like the RETURN key, causing INPUT to respond immediately. However, there are some minor restrictions. First, in a multiple INPUT command such as INPUT A$,B$,C$, the computer detects reprogrammed keys only after the last entry (C$ in this case). Second, if the INPUT command expects numeric input, you must always enter some number before typing the special key.
    One disadvantage of checking for ESC is that normal ESC editing functions are disabled. The normal keyscan can be restored by pressing CTRL-RESET, but it's better form for your program to leave the computer in its standard state when it ends. To accomplish this, add the appropriate line below to your program at a point just before the end:

For DOS 3.2 or 3.3:
POKE 56,27:POKE 57,253:CALL 1002

For ProDOS:
PRINT CHR$(4);"IN#0"

A Short Diversion
Though you can use this routine without knowing how it works, machine language programmers may appreciate a closer examination. In simple terms, it diverts the computer from its normal keyscan routine to a new one that we install in RAM. To understand the details of this process, you'll need to know something about how the Apple's keyboard is normally scanned.
    The Apple reads its keyboard with a routine known as RDCHAR (located at $FD35). RDCHAR in turn calls another routine known as RDKEY which retrieves an ASCII code from the keyboard and stores it in the microprocessor's accumulator. Then the computer adds 128 to the key code and stores the resulting value in the keyboard data byte (location $C000, which is expressed in decimal integer form as -16384). You can subtract 128 from the keyboard data byte with a GET, an INPUT, or by PEEKs or POKES to the keyboard status byte; Apple calls this location ($C010 or decimal -16386) the keyboard strobe. After RDKEY is finished, RDCHAR checks to see if the key pressed was the ESC key. If so, it branches to a special routine. The ESC keypress itself is always ignored except as a signal indicating that the next keypress should be processed specially-as an escape code rather than a normal keypress.
    Instead of obtaining the keycode on its own, RDKEY jumps to yet another routine, KEYIN, which actually does the work. KEYIN ordinarily begins at location $FD1B. This final bit of code is not called as a subroutine; instead, the computer performs an indirect jump instruction, passing control to the address stored in zero page locations 56-57 ($38-$39). Apple documentation refers to this pair of locations as the keyboard input switch. The important points to remember are that the keyboard data byte (-16384) can be PEEKed from BASIC, and that you can divert the computer to a different keyscan routine by changing two bytes in zero page.
    Replacing the ROM version of KEYIN with a customized version is straightforward. Lines 10-70 of Program 1 POKE the new routine into memory beginning at address 768. Line 80 checks a memory location in the ProDOS global page, which begins at address 48640. If this location contains the value 76, ProDOS is active, so the standard input routine is changed using the command IN#A768, which tells ProDOS to get its input from the routine beginning at address 768. (That routine begins with a byte of 216, the CLD opcode, to let ProDOS know that this is a valid machine language routine.)
    Lines 90 and 100 perform the input redirection for DOS 3.2 and 3.3. First, the high and low bytes of the routine's starting address ($300, or decimal 768) are POKEd into locations 56 and 57. (Since this routine is relocatable, you could put it any other place that isn't used by your main program.) Then the CALL 1002 in line 100 tells DOS to use the new KEYIN routine in place of the usual code. If you're interested, Program 2 contains the source code for this routine.
    The first instruction in Program 2 is necessary for ProDOS. The next eight lines simply mimic the normal KEYIN routine. These instructions continuously generate a random number by incrementing locations $4E-$4F until a key is pressed. When you press a key, the computer moves the keycode found in the keyboard data byte into the accumulator, then clears the keyboard status byte. At that point, the normal version of KEYIN would return to RDCHAR, which would check the keycode to see if it is ESC. The custom KEYIN routine does the check right away. If ESC was pressed, we replace the accumulator's contents with the ASCII code for a carriage return (with the high bit set).

Program 1: ESCape Key

For instructions on entering this listing, please
refer to "COMPUTE!'s Guide to Typing In
Programs" in this issue of COMPUTE!.

AC 10 J = 768
2F 20 READ A: IF A < > 256 THEN
      POKE J,A:J = J + 1: GOTO 2
31 30 DATA 216,230,78,208,2,230,
lE 40 DATA 192,16,245,145,40,173
8E 50 DATA 44,16,192,72,41,127
A7 60 DATA 201,27,240,2 : REM ES
      CAPE KEY
66 70 DATA 104,96,104,169,141,96
EA 80 IF PEEK (190 * 256) = 76 T
      HEN PRINT CHR$ (4);"IN#A76
      8": GOTO 110
3D 90 POKE 56,0: POKE 57,3
92 100 CALL 1002
CC 120 IF PEEK ( - 16384) = 27 T
       G": GOTO 110

Program 2: New KEYIN

This source code listing is for illus-
trative purposes only. It requires an
assembler to be typed in.

       CLD         ; Valid ML routine.
       BNE NEXT
       INC $4F
NEXT   BIT $C000
       BPL START
       STA ($28),Y
       LDA $C000
       BIT $C010
       PHA        ; Save key code
       AND #$7F   ; Set high bit to zero
       CMP #$1B   ; Is it ESC?
       BEQ RETURN ; If yes, branch.
       PLA        ; Not ESC, so replace
       RTS        ; original code, exit.
RETURN PLA        ; Tidy up stack.
       LDA #$8D   ; Carriage return.