Defining Functions Keys with PC-DOS 2.0 (PC Magazine Vol 2 No 1 June 1983 by Kenneth W. Wood) PC-DOS 2.0 is packed full of new features. One is its ability to redefine the function of any key on the keyboard. Most often, users will want to redefine the ten function keys. An item in PC-DOS 2.0 that is rarely looked at is the ANSI terminal handler contained in the file called ANSI.SYS. When in memory, the ANSI terminal handler interprets special character sequences written to the console. Since each of these special sequences begins with the Escape character, these are called "escape sequences." The Escape character (ASCII 27) is referred to as Esc. Basically, the ANSI terminal handler defines a way of positioning the cursor and setting certain terminal attributes. For example, if a program were to write the sequence "Esc[12;43f", the cursor would be positioned at line 12 column 43. Other sequences control blinking, underlining, erasing to end of line, clearing the screen, etc. Thus, from any language (Pascal, BASIC, C, assembler, etc.) you can precisely control the appearance of the screen. In addition, the ANSI terminal handler provides programmers with a tool for developing easily transportable software for compatible computers, regardless of the specific terminal characteristics of each computer. The Keyboard Key Reassignment (KKR) escape sequence is of special interest. The KKR sequence establishes a new set of ASCII characters that are to be issued whenever the designated key is depressed. For example, one could define the F1 key to be "DIR A:". According to the PC-DOS manual, any key on the keyboard can be reassigned, even the QWERTY keys. The manual, however, provides very little documentation on the KKR sequence. Worse, there are undocumented limitations! Without getting too technical, PC-DOS 2.0 sets up a special area of memory as a lookup table for each key that you redefine. This lookup table is limited to 128 bytes. Thus, if you attempt to define too many keys, or use long character sequences on too many keys, the table size is exceeded. If care is not taken, it will be exceeded to the extent that PC-DOS meets its maker and you must reboot! How do you use this new PC-DOS capability? First of all, you must have a file on your boot disk called CONFIG.SYS. This file is read automatically by PC-DOS at boot time to determine the system configuration. In order to define the function keys, you must have a "DEVICE = ANSI.SYS" statement in the CONFIG.SYS file. This statement loads the ANSI terminal handler into memory. Next, you must print a KKR sequence to the screen for each key to be defined. Since this can be tedious, I developed a special C language program for this purpose. This program, FUNKEY, is designed specifically for defining the function keys F1 to F10, as well as Shift, Ctrl, and Alt in combination with the ten function keys. FUNKEY accepts a list of function key definitions as input and issues the appropriate KKR sequences as output. The program does not provide for the arbitrary redefinition of any or all keys on the keyboard. Sample function key definition files are discussed in the next section. I created FUNKEY using the Computer Innovations, Inc. C language compiler, CI-C86. This is one of the few C compilers for the IBM PC that includes all standard C language features. FUNKEY, however, only involves simple input and output commands, so any adequate C compiler should be able to run this program. Similar programs could also be written in Pascal, BASIC or other languages. Use of the program is straightforward. When you type FUNKEY, the program is loaded into memory and begins execution. To define F3 as "CHKDSK B:" you simply type F3=CHKDSK B: then hit Return. After defining the desired keys, type a Ctrl-Z and hit Return. For a large number of keys, this method is inconvenient. Instead, you can type FUNKEY FILE.KEY to have the list of function key definitions taken from the file. For example, the file STAR.KEY could contain a list of function key definitions for WordStar. This article will not concentrate on programming techniques involved in FUNKEY. Instead, my emphasis is upon various ways of using the function key definition capability. The program provided here should be viewed as a foundation on which to build a more user-friendly key definition program. To increase the flexibility of the program somewhat, each function key definition is normally terminated with a space. However, if you need a command to end with a carriage return, simple use the "!" as the last character of that function key definition. Applications of function key definitions fall into two broad categories: defining keys to issue commands, and defining keys with specific strings for use in an application. As an example for the first category, I find that DIR, TYPE, COPY, and CHKDSK are among the most common PC-DOS commands that I use. The file shown in Figure 1 illustrates the set of function keys for use at the PC-DOS command level. By including "FUNKEY DOS.KEY" in my AUTOEXEC.BAT file, each time I use PC-DOS all of the commands are just a function key away. There are many ways that you can use the function keys at the PC- DOS level. For example, one key could be set up as "CHKDSK A:", and another as "CHKDSK B:". However, this approach is inefficient, since the same command appears on more than one key. I chose to set up F1 and F2 as "A:" and "B:". Then, by combining another command key with either F1 of F2 I can specify either disk. For example, typing F4 ("CHKDSK") then F2 ("B:") issues the "CHKDSK B:" command. A few potential problems should be considered. First of all, many popular programs already make special use of the function keys. The program I principally use is The FinalWord. All of the function keys are already defined by this software and they can be customized with a FinalWord utility. The PC-DOS function key definitions, discussed above, would override the FinalWord definitions since they are intercepted by the operating system and passed to the program. However, there is no documented way to clear the definitions you use. The only method to restore the default set of key definitions is to reboot the system. On the other hand, the fact that your definitions override existing definitions can be a blessing as well. Some of the choices made by MicroPro for the PC-DOS function keys defy logic. The key arrangements in many other programs are equally illogical. In some cases, you can use the capabilities described here. However, if a program bypasses the normal operating system calls in order to perform keyboard input, then the key definitions you created are also bypassed. Such is apparently the case with WordStar, since an attempt to redefine function keys for WordStar failed to override the existing definitions. Finally, each key definition sequence must end with "white space" -- that is, a blank or a carriage return. The ANSI driver seems to use these characters as separators between new definitions. I tried terminating the definitions with other characters, such as the null, with the result that all of the key definitions ran together into one giant sequence. There is no problem in using this capability to define strings. However, some programs do not like a space or carriage return after a sequence of control characters. Using this capability to reset the function keys can create another minor problem. Suppose that you set the keys up for WordStar, then switched to VisiCalc. The key definitions are no longer appropriate. I find it annoying to constantly remind myself to switch to the proper function key set. The best way to painlessly use the function keys is to write a batch file for each program. The batch file takes the generic form: FUNKEY APPL.KEY Application FUNKEY DOS.KEY This file loads the definitions for an application, calls the application, and resets the keys for PC-DOS after you exit the application. For example, if STAR.KEY was a file of the key definitions for WordStar, create a batch file called WORD.BAT. Its contents would be: FUNKEY STAR.KEY WS FUNKEY DOS.KEY Then call up the batch file by typing WORD rather than WS. Another way to use the function keys is with commonly used strings. For example, suppose that your company name is "Federated Software Arts and Science, Inc." You could assign a string with the company name to a function key. Then, as you use your word processor, whenever the company name is needed, you just press that function key. Or, in writing an article for a specific subject, frequently used lengthy terms such as "operational transconductance amplifier" can be assigned to function keys and used as needed. If you do this, remember that PC-DOS restricts you to 128 characters as the total for all keys that you define. I am aware of at least two programs, written for use with PC-DOS 1.0 and 1.1, that provide function key capabilities: ProKey and Keynote. Both ProKey and Keynote provide many more key definition capabilities than PC-DOS 2.0. First of all, there is no 128-byte restriction. ProKey provides over 125 definable keys, and each key can be up to 1,000 characters long. Furthermore, key definitions can include "fill-in-the-blank" fields and references to other defined keys. ProKey is memory resident, which means that you can change the key definitions anytime while in a program. Thus, ProKey can provide macro-like capability. The possibilities provided by ProKey and Keynote are endless. Function key redefinition is one of the new capabilities provided by PC-DOS 2.0. Although useful, this capability is still limited compared to commercial programs designed specifically for the purpose. However, the examples in this article should illustrate that the time you spend exploring PC-DOS can be well worthwhile. Figure 1: After running FUNKEY, the following PC-DOS 2.0 commands are assigned to the ten function keys. F1 to F10 are the input file names of the function keys in their normal state; C1 to C10 are the names for the keys in combination with the Control Key. F1 = A: C1 = MORE F2 = B: C2 = FIND F3 = DIR C3 = SORT F4 = CHKDSK C4 = MODE F5 = COPY C5 = PATH F6 = ERASE C6 = TREE F7 = TYPE C7 = MKDIR F8 = PRINT C8 = RMDIR F9 = RENAME C9 = RECOVER F10 = CLS C10 = FORMAT - - - - - /* FUNKEY.C - A program for defining function keys */ #define SEQ "\033[0;" /* initial sequence to ANSI driver */ #include "stdio.h" /* copy in the standard I/O routines */ main(argc,argv) int argc; char *argv[]; { FILE *fp, *fopen(); if (argc ==1) { printf("\nEnter new key definitions\n\n"); fkey(stdin); /* get input from keyboard */ } else { fp = fopen(*++argv,"r"); fkey(fp); /* get input from file */ } } int count = 0; /* counter for tracking size of table */ fkey(fp) FILE *fp; { int c,offset; /* input character and function key identifier */ while((c=getch(fp)) != EOF) { switch (c) { case 'F': /* F1 through F10 */ offset = 58; func(getch(fp),offset,fp); break; case 'S': /* Shift F1 through F10 */ offset = 83; func(getch(fp),offset,fp); break; case 'C': /* Control F1 through F10 */ offset = 93; func(getch(fp),offset,fp); break; case 'A': /* Atl F1 through F10 */ offset = 103; func(getch(fp),offset,fp); break; default: print("Unknown function key\n"); break; } } } getch(fp) /* throw away white space until a character */ FILE *fp; { int x; while(x=getc(fp)) ==' '||x=='\n'||x=='\t') ; /* ignore while space */ return(x); } func(c,offset,fp) /* send out the required definition sequence */ int c,offset; FILE *fp; { int x,save; save = ' '; while ((x=getch(fp)) != '=') if (x=='0') c=':'; /* read until get = sign */ /* if character is 0 then F10 was chosen rather */ /* rather than F1. Change c so that offset is */ /* calculated correctly */ printf9SEQ); printf("%d",offset+(c-'0')); putchar(';'); putchar('"'); while ((x=getc(fp)) != '\n') { if (x != '!') { putchar(x); if ((count = count+1) ==128) { printf("\nTable size exceeded. Program terminated...\n"); exit(); } } else save = x; } putchar('"'); if (save == '!') printf(";13p"); else printf(";32p"); save = ' '; if ((count=count+1) == 128) { printf("\nTable size exceeded. Program terminated...\n"); exit(); } } /* End of listing */ ----------------------------------------------------------------- Further to "Defining Functions Keys with PC-DOS 2.0" (PC Magazine Vol 2 No 4 Sept 1983 User-to-User) The article, "Defining Functions Keys with PC-DOS 2.0," mentioned that the Keyboard Key Reassignment (KKR) escape sequence had an undocumented limit of 128 bytes in its lookup table. The actual table limit is 190 bytes. The table, used to store the key redefinitions, contains a 1-byte length code followed by the string between the Esc [ and the p delimiters for each key redefinition. For example, the sequence: Esc [0;68;"dir";13p would be stored as the hex string, 07 00 44 64 69 72 13. The DEBUG procedure shown below creates a copy of ANSI.SYS with a larger lookup table. For ease in calculating the required numbers, I would recommend enlarging the table by a multiple of 80H bytes. The expressions given in parentheses should be calculated and placed in the command without parentheses. The length the table is extended is shown as xxxH. The numbers I used for enlarging my KKR lookup table by 200H bytes are shown near the right margin. My comments are in brackets. First make a copy of ANSI.SYS. Do not modify your original copy. COPY ANSI.SYS ANSIX.SYS Then enter DEBUG ANSIX.SYS and follow the rest of the procedure shown below. The entry in CONFIG.SYS should now be changed to DEVICE=ANSIX.SYS and the system rebooted. A command file ANSIX.CMD to be used as redirected input to DEBUG is shown here. The lines changing the CS and DS registers must, of course, be changed to match your system. My CS on entry to DEBUG was A8A and I made ANSIX.SYS 200H bytes longer. Execute as: DEBUG ANSIX.SYS < ANSIX.CMD. r r cs a9a f ds a9a rcs 880 a cs:12 dw 809 a cs:4ff mov cs,809 a cs:530 cmp bx,2c8 f cs:680 87f 0 m cs:600 67f 800 f cs:600 67f 0 a cs:842 mov word ptr [bx+0e],809 a cs:84a jmp 0de r cs a8a r ds a8a w q This change allows a more reasonable KKR sequence to be defined. The DEBUG procedure that creates a copy of ANSI.SYS with a larger lookup table: DEBUG ANSIX.SYS {The program will be loaded at CS:100} R {Determine current CS, DS and CX} R CS (old CS + 10H) {Compensates for the load A9A offset} R DS (old CS + 10H) {Compensates for the load A9A offset} R CX (old CX + xxxH) {Sets file length to be 880 A CS:12 written} Dw(609H + xxxH) {Fix pointer to initializa- 809 tion}{Return to end assembly} A CS:4FF MOV CX,(609H + xxxH) {Pointer to initialization} 809 {Return to end assembly} A CS:530 CMP BX,(OC8H + xxxH) {Table length} 2C8 {Return to end assembly} F CS:680 (67FH + xxxH) 0 {Fill extended table with 87F zeros} M CS:600 67F (600H + xxxH) {Move initialization code} 800 F CS:600 67F 0 {Zero old unit code location} A CS:(642H + xxxH) {Fix pointer to initializa- 842 MOV WORD PTR [BX + 0E],(609H + xxxH) tion} 809 {Return to end assembly} A CS:(64AH + xxxH} {Fix jump to main code} 84A JMP 0DE {Return to end assembly} RCS {Restore original CS} (CS: as it was on entry to debug) A8A RDS {Restore original DS} (DS: as it was on entry to debug) A8A W {Write the new file} Q {Quit debug} ----------------------------------------------------------------- Changing Keys (PC World Vol 2 No 3 March 1984 by Brian Mann) One reason the PC is so versatile is that you can define not only its function keys but also its standard keys. The definition process is somewhat complicated, particularly when the escape code (ASCII 27) is required. This character is interpreted as an "erase line" command, and care must be taken when including it not to inadvertently destroy code or text. Another problem is reassigning keys back to their original DOS definitions. It is often necessary to reassign key values so that other programs, such as the IBM Personal Editor, can define keys for their own purposes. By studying Chapter 13 in the DOS 2.0 manual, "Using Extended Screen and Keyboard Control," and using the DOS batch file in this article, problems with assigning and reassigning keys can be avoided. Before the assigned key definitions, including those for the function keys, can be changed the ANSI driver must be resident in the PC. First, a CONFIG.SYS file containing the statement DEVICE = ANSI.SYS must be created on the boot disk. The CONFIG.SYS file will, among other things, install a program that is not "native" to DOS -- in this case, the ANSI driver. The ANSI.SYS file, which is included on the DOS 2.0 disk, must also be on the boot disk. To create this file, first place the boot disk in drive A. At the DOS A> prompt, type COPY.CON:CONFIG.SYS and then press . Type DEVICE = ANSI.SYS and press . Finally, press (or . The CONFIG.SYS file is automatically read only when the PC is turned on or restarted with the -- sequence. A disk containing CONFIG.SYS must be in drive A before any keyboard reassignment program can be run. Using an editor such as EDLIN, enter the batch program KEYS.BAT (see Listing 1) onto a disk in drive A. If you have an emulated disk drive, operation will be faster if you copy KEYS.BAT there. If you enter KEYS ON from DOS, the program will execute and define the keys you specify. If you enter KEYS OFF, the keys will return to their original DOS definitions. The first line in KEYS.BAT illustrates the undocumented fact that DOS treats a statement beginning with a period as a comment. The second line turns ECHO off so DOS won't display the KEYS.BAT statements as they execute. The "%1" used in the next four statements is equal to the parameter entered after the file name. In other words, when KEYS ON is entered, KEYS.BAT is loaded and "%1" is set equal to "on". The statements determine what "%1" is equal to ("ON", "on", "OFF', or "off") and jump to the proper label, either ":ON" or ":OFF", or to ":END" if no value is set equal to "%1". Next, ECHO is turned back on. ECHO must be on so that the following key assignments accomplished via the DOS command PROMPT will work. The PROMPT command is often used to change the standard DOS prompt. For example, PROMPT = WHAT NEXT? would cause DOS to display WHAT NEXT? as a DOS prompt instead of A>. In KEYS.BAT the PROMPT command issues an escape code (ASCII 27) with the symbol "$e"; this code is necessary when ANSI.SYS is used to define the keys. Keys are defined in the first section of the batch file following the ":ON" label. If an automatic return is desired, the definition should be followed by ";13p"; if no return is desired, a "p" should be used. Almost any key's value may be redefined. In order to change a key, the ASCII code representing that key must be sent to the ANSI driver via a special escape sequence. The ASCII codes of standard keys such as the A or backslash keys are only one character long, and a sequence would look like: prompt=$e[50;"definition "p The PC has an extended set of ASCII codes to represent the special keys on the keyboard. The special keys (mostly function keys and keys shifted using Alt or Ctrl) are two characters long and are prefaced by a zero and a comma. A sequence would look like: prompt=$e[0;59;"DIR "p But how are original DOS definitions restored? To understand the process, the role of the ANSI driver must be considered. The letter A is not sent to the computer when you press the A key. Neither is the ASCII code of the letter sent, but rather a scan code determined by the location of the key. The ANSI driver, which can be imagined as a box between the keyboard and the PC, intercepts the scan code sent by the keyboard and compares it against a reassignment list. If the key has not been reassigned, the ANSI driver converts the scan code to the proper ASCII value and sends it to the PC. If the key has been reassigned, the ANSI driver sends out the character string that was given to the key. Restoring a key to its original DOS value involves writing over the last key definition. For example, the first prompt statement in Listing 1 following the ":ON" label (prompt=$e[0;59; "DIR "p) tells the ANSI driver to send out DIR when it intercepts the ASCII code. The first prompt line after the ":OFF" label (prompt=$e[0;59;0;59p) tells the ANSI driver to send out 0;59 when it intercepts the ASCII code. The computer is not aware that the ASCII code was ever intercepted and applies the original DOS definition (0;59) to the key. In reassigning the original definitions, it is not necessary to include an automatic return. In Listing 1 the Alt-1 combination (ASCII code 0;120) issues the command A:KEYS ON, and the Alt-0 combination (ASCII code 0;129) issues the command A:KEYS OFF. These definitions are not changed by the KEYS OFF command, since the above ASCII codes do not appear below the ":OFF" label. Once KEYS ON is executed, pressing Alt-0 returns the keyboard to the original DOS definitions; Alt-1 reassigns the keyboard. After the reassignments or original assignments are made, KEYS.BAT jumps to the ":END" label, which sets the prompt back to A>. If execution is aborted by Ctrl-Break, the prompt will not appear, and "prompt=$n$g" must be entered to return the prompt to the screen. Keys may be defined as desired, but there is a catch. If you exceed 190 characters of ANSI driver definitions, the COMMAND.COM file next to the ANSI driver on the disk is likely to be overwritten. The computer will freeze up, and you will be forced to turn it off and start all over. Using the PROMPT command will sometimes produce an "Out of environment space" error message. This will not freeze up the computer, but it will prevent key redefinition. The environment, as defined by DOS 2.0, is a place where the operating system puts information so other programs can access it. (This is not the same as the ANSI definition space discussed above.) Issuing the command SET from DOS will display the environment, for example: COMSPEC = A:\COMMAND.COM PATH = A:B:C: PROMPT = $n$g When the PC is started, 128 bytes are allocated to the environment. If more space is needed, DOS will attempt to acquire more space. If a resident program, such as MODE, PRINT, or GRAPHICS has been executed, space is not available and the "Out of environment space" error message will show up. In the case of KEYS.BAT, the error message occurs when a large PROMPT statement is put into the environment after a resident program has been run. There are two solutions to the problem. You can include key definitions in an AUTOEXEC.BAT file before any resident programs are run (see Listing 2). The second method is more complicated but may be superior. If you have an editor that permits use of the escape code (ASCII 27), read the KEYS.BAT file into the editor, remove the "prompt=$n$g" statement after the ":END" label, and replace all occurrences of "prompt=$e" to ECHO followed by your editor's code for Escape. The ECHO statement prints the key definition text; this circumvents the prompt statement and the alteration of the environment altogether. - - - - - Listing 1: KEYS.BAT echo off if %1 == ON goto ON if %1 == on goto ON if %1 == OFF goto OFF if %1 == off goto OFF goto END :ON echo on prompt=$e[0;59;"DIR "p prompt=$3[0;60;"TYPE "p prompt=$e[0;61;"COPY "p prompt=$e[0;62;"ERASE "p prompt=$e[0;63;"A: "p prompt=$e[0;64;0;64p prompt=$e[0;65;"B: "p prompt=$e[0;66;"C: "p prompt=$e[0;67;"D: "p prompt=$e[0;68;"A:BASICA ";13p prompt=$e[0;120;"A:KEYS ON";13p prompt=$e[0;129;"A:KEYS OFF";13p .The Function Keys have been defined goto END :OFF echo on prompt=$e[0;59;0;59p prompt=$e[0;60;0;60p prompt=$e[0;61;0;61p prompt=$e[0;62;0;62p prompt=$e[0;63;0;63p prompt=$e[0;64;0;64p prompt=$e[0;65;0;65p prompt=$e[0;66;0;66p prompt=$e[0;67;0;67p prompt=$e[0;68;0;68p .The Function Keys have been disabled :END prompt $n$g (End of KEYS.BAT) - - - - - Listing 2: Example AUTOEXEC.BAT file echo off date time echo on prompt=$e[0;59;"DIR "p prompt=$e[0;60;"TYPE "p prompt=$e[0;61;"COPY "p prompt=$e[0;62;"ERASE "p prompt=$e[0;63;"A: "p prompt=$e[0;64;0;64p prompt=$e[0;65;"B: "p prompt=$e[0;66;"C: "p prompt=$e[0;67;"D: "p prompt=$e[0;68;"A:BASICA ";13p prompt=$e[0;120;"A:KEYS ON";13p prompt=$e[0;129;"A:KEYS OFF";13p (The Function Keys have been defined) prompt $n$g echo off mode 80 veify on graphics cls ver vol a: (End of AUTOEXEC.BAT) ----------------------------------------------------------------- Assigning Strings to Keys with PC-DOS 2.0 (PC Magazine Vol 2 No 6 Nov 1983 by Gregg Weissman) The manual for PC-DOS 2.0 mentions that you can assign any character string to any of the keys on the IBM PC's keyboard. You could create command lines and text that can be called up with single keystrokes from DOS, just as can be done from BASIC. However, the manual is sketchy. There is a limit to the total number of characters that can be assigned to the keyboard in this way -- the computer will crash if you try to exceed this quota. If you're adventurous and somewhat familiar with DEBUG, you might follow my additional instructions to increase the maximum number of characters allowed while implementing a key-assignment scheme. The portion of an operating system that controls input from the keyboard and output to the screen is called the device driver because it controls those devices. DOS has been designed to allow you to easily replace those drivers with others. In the following case, the normal keyboard/screen input/output program (the Console device driver) will be replaced with the ANSI.SYS device driver. This extended program contains the logic for detecting and acting upon the special sequences of characters known as escape sequences, so-called because they all begin with ASCII 27 decimal, which stands for Escape. The escape sequences translate into the key assignments you wish to make. The first step is to get the ANSI.SYS program loaded into the computer by creating a configuration file called "CONFIG.SYS" which will tell the operating system what to do with itself. If the statement "DEVICE=ANSI.SYS" appears in the CONFIG.SYS file, DOS will load ANSI.SYS in place of the standard keyboard/screen console device driver. If you'd like to see this information in action, type in the following two lines to copy a CONFIG.SYS file to your disk: COPY CON: C:\CONFIG.SYS DEVICE=ANSI.SYS (In the first line, "C:" is the label for the fixed hard disk. If you want to use a different disk drive, substitute the appropriate label.) After entering the second line, press F6 and then the Return key. Now the extended console driver will be loaded from disk when the operating system starts. If this is the first time you have included the CONFIG.SYS file and the "DEVICE=ANSI.SYS" command, first reset the computer so that DOS can load up the ANSI program; otherwise the examples in the article won't work. The next thing that happens after the ANSI.SYS is loaded is that DOS "calls" an initialization routine within the driver; DOS asks the driver to set itself up (as it were) and return an address that is the last memory location the ANSI.SYS driver will occupy. DOS needs to know how big the driver is, so it can utilize the memory above it for other functions. In its present, unmodified state, the ANSI driver returns an address that allows space for 200 of your defined character strings in addition to the program itself. Once this initialization is complete, DOS goes about its business, which normally has nothing to do with getting special things to happen when keys are pressed. The way that you assign a string to a key on the keyboard is simpler than it may appear in the DOS manual. All you need to do is send a sequence of characters to CON, which is the driver for the keyboard/screen console driver. Ultimately, this can be done either by sending the appropriate data to the CON device with the COPY command or by TYPEing the appropriate file. Either way, as long as the file contains the proper sequence of characters, the driver will interpret the file as key assignments (the file can also provide screen controls, but that should be the subject of another article). Instead of having any text appear on the screen, as would normally happen when you TYPE a file to the console, the keys you specify in the file will be set up to return the string you assigned to them. The form of the escape sequence that will cause the ANSI.SYS driver to assign text to a key is also simple. The first character must be the Escape character (ASCII 27). (This would be CHR$(27) in BASIC; in hexadecimal, the value is 1B.) When the ANSI driver sees you trying to print the character with a value of 27 decimal, it prepares itself to respond to subsequent characters not as characters to be printed to the screen, but as codes that you wish to be interpreted for you. The next character must be a left bracket, ([) (ASCII 91 or 5B hex). Once the driver has detected the Escape character, nothing will happen until it next detects the left bracket. Up to this point, the driver has seen the Escape character and the left bracket, and is prepared to interpret the remainder of the command sequence either as numeric values (represented by ASCII text digits) of as literal characters. In the first case, the driver interprets ASCII digits "0" thru "9", and calculates a binary value for the represented digits. If the driver is sent the ASCII value for 9, the program calculates 19 decimal. If ASCII codes for 1, 2, and then 0 are sent, the resulting ASCII value is 120 decimal, and so on. The program continues to receive and calculate until it detects a semicolon character (ASCII value 3B hex), which serves to tell where one number leaves off and another one begins. In the "1,2,0" example above, the command would mean that you are telling the program to reassign the key that sends out the ASCII code 120 decimal when it is pressed. What is going on is that you are using ASCII codes for digits to represent the decimal value of another ASCII code that the keyboard sends out. If you were to look at the hexadecimal representation of the sequence so far, just as the ANSI driver receives them, it would look like this: 1B 5B 31 32 30 3B [ 1 2 0 ; Now, if you send a single or double quote mark to the driver, it will store the next sequence of characters into memory as is, to be sent out later as a string of text whenever it detects key 120 decimal (which is lowercase "x"). Say you wish to have the computer spell out "EXAMINE" whenever you press lowercase "x". Your next command sequence would then be: EXAMINE , followed by another semicolon, then a lowercase p (p is the "Yes, I really meant that; now do it!" command to the driver program). The following procedure demonstrates how you could assign a string to a key by using the DEBUG program. Assume the same conditions as before; that is, you wish to have the computer type the word "EXAMINE" when you press the lowercase x key. You must use the DEBUG program at this point because you can't enter the Escape character from the keyboard. Under DOS, the Escape key is interpreted as "cancel the input line." A little later I will show a BASIC program that will automate all this, but for now, from DOS, start the DEBUG program by typing "DEBUG". When you see the dash prompt (-), DEBUG is ready to use. Type this line as it appears, quotes and all. (The 22 that you type on either side of "EXAMINE" is the ASCII hex value of a double quote mark.) E 100 1B "[120;"22"EXAMINE"22"p" Then press the Return key. What you did was to give the Enter command (e), then the required sequence was entered directly into memory. Now type D100 and press return. Look at the hexadecimal values on the first line at the left of the screen; they should look familiar: 1B 5B 31 32 30 3B Now look to the right of the screen; you should see: .[120;"EXAMINE"; Perhaps the result is a little clearer in this form. Pressing the lowercase x key will return the ASCII value 120; that value is looked up by the console driver, and the associated string "EXAMINE" is printed out. Before this will work, however, you must write the little file you created onto the disk. To do so, type R CX and press Return. When you see the prompt, key in 10 and press Return; then type N KEYX.ANS and press Return to give the file the name KEYX.ANS. If you want to save the file on a different disk, type a drive designation before the file name; for example, you could key in N B: KEYX.ANS to assign the file to the B drive. After naming the file, press the W key and then Return. The computer will respond with the message "Writing 10 bytes." When that process is over, press the Q key and then Return to exit from DEBUG. Check the disk directory to verify that the new file called KEYX.ANS is actually saved on the disk. Then type: COPY KEYX.ANS CON: and press Return. (If you had put KEYX.ANS on another drive, make sure to include the drive's name here.) When you do this, nothing should happen except that the message "1 File(s) copied" and the DOS prompt will appear. Now type a lowercase x, and see what happens. If "EXAMINE" didn't appear on the screen, either the ANSI.SYS console driver hadn't been installed (see the beginning of this article) or you keyed in something incorrectly. Try again after making sure the device driver is installed. Another more effective and rapid solution is that the entire keyboard can be defined by running a BASIC program that writes the control codes to a sequential disk file, which you can then TYPE or COPY to the console driver. First another word on the ASCII values. It would be nice if we could leave the standard key definitions as they are, and assign special character strings only to the functions keys of Alt keys. The way to do this is to define the first number sent after the Escape and left bracket characters as ASCII value zero; this is followed by the semicolon, the actual "extended ASCII code" for the key desired, and finally the string assignment itself. You can use all the function keys in the standard, Shift, Ctrl, or Alt modes; actually 40 different codes can be assigned to the function keys. In addition, all the alphanumeric keys can be used in the Alt mode, including such keys as Home and End. However, this vast versatility is limited by the 200-character limit imposed by the unmodified ANSI driver. Figure 1 is a simple BASIC program that could be used to let you go through the ten function keys, one at a time, and assign a different string to each one. When the BASIC program finishes and saves the KEYS.ANS file to disk, you can enter DOS, they type the file in order to effect the key assignments. If you avoided the 200-character limit by being conservative with the length of strings you assigned to the function keys, you should now be able to return to DOS from BASIC by typing SYSTEM, then COPY the KEYS.ANS file to CON by entering: COPY KEYS.ANS CON: If the computer hangs up, just reboot to start from scratch with DOS and trim down your string assignments. Figure 2 shows the key assignment program in use. If you succeed in assigning strings to your function keys, but get tired of that set of tricks, you can eliminate the key assignments by rebooting the system. You can also run the BASIC program again to input blank "null strings" that eliminate the key assignments. - - - - - Figure 1: A BASIC program that prompts a user to assign strings to the ten function keys. 10 DEFINT I-Z:DEFSTR A-H 20 DIM ANSI.KEY(10) 30 FOR I=1 TO 10 40 ?"KEY NUMBER";I;"STRING";:INPUT ANSI.KEY(I) 50 NEXT 60 REM This is an admittedly oversimplified input routine. 70 OPEN "0",#1,"KEYS.ANS" 80 FOR I=1 TO 10 90 ASKEY.CODE=MID$(STR$(58+I),2) 100 REM Line 90 strips off the leading blank from the string. 110 PRINT #1,CHR$(27)"["0;"ASKEY.CODE";"CHR$(34);ANSI.KEY(I); CHR$(34)"p"; 120 REM Note the trailing semicolon at the end of line 110 130 NEXT 140 CLOSE 150 END - - - - - Figure 2: A demonstration of using the program in Figure 1. I wanted to be able to press any of the ten function keys and have the French word for its number appear on the screen. I ran the BASIC program in Figure 1 and keyed in the lowercase words in response to the prompt on each line. KEY NUMBER 1 STRING? un KEY NUMBER 2 STRING? deux KEY NUMBER 3 STRING? trois KEY NUMBER 4 STRING? quatre KEY NUMBER 5 STRING? cinq KEY NUMBER 6 STRING? six KEY NUMBER 7 STRING? sept KEY NUMBER 8 STRING? huit KEY NUMBER 9 STRING? neuf KEY NUMBER 10 STRING? dix After entering the string for F10, I was returned to DOS. I then saved the file of key assignments by entering the following after the prompt: C> COPY KEYS.ANS CON: The computer responded with "1 File(s) copied" and another prompt. Following this prompt, I pressed each of the function keys and the French names of the numbers appeared. C> un deux trois quatre cinq six sept huit neuf dix When I pressed Return again, the screen read "Bad command or file name". ----------------------------------------------------------------------- Modifying the ANSI.SYS Console Driver (PC Magazine Vol 2 No 6 November 1983 by G. Weissman) If you now understand how to assign strings to key, and if you are familiar with the DEBUG program, you may want to take this next step -- modifying the ANSI.SYS file to allow longer strings and more keys to be assigned. But beware: this can get tricky. If you're not comfortable with messing around in machine-language files, go very slowly. And, although this procedure seems to work okay on my version of DOS 2.0, I can give you no guarantees. The first thing to do if you undertake this project is to make a backup copy of the file called ANSI.SYS. To be on the safe side, you may want to modify this file on a separate disk before modifying the hard disk's system files. It would be a funny feeling to have 2.5 megabytes of valuable data refuse to boot. Have the CONFIG.SYS file set up to load the ANSI.SYS file, as explained in the earlier procedure, by keying in these two lines: COPY CON: C:\CONFIG.SYS DEVICE=ANSI.SYS After entering these two lines, press F6 and then Return. You should find it helpful to obtain a disassembly of the ANSI.SYS file from the debugger. To obtain the listing, press Ctrl-PrtSc, then call up DEBUG along with the name of the file by entering DEBUG ANSI.SYS. Then type U 1A2 750, press Return, and take a break until the disassembly prints out. It would be a good time to read the rest of the procedure. I assume you have the DOS 2.0 DEBUG program that allows you to assemble simple commands directly into memory. If you don't have 2.0, I doubt you can do any of this. Four changes have to be made to the program: 1) the initialization procedure has to return a higher ending address to DOS upon completion of initialization; 2) the maximum value test for the total number of characters assigned to keys must be increased; 3) the initialization procedure must be actually moved to make the necessary room and pointed to within the device driver itself; and, 4) a new end-of-buffer-value loaded into the CX register must be altered to conform with our changes. The first step is to move the initialization code up by 300 hex bytes, using the "M" command. It might be a good idea to keep the Ctrl-PrtSc printing turnd on to maintain a log of what you do here in case there are problems. You can refer to the printout later and check your work. Look at the listing from 0709 to 074D. This is the initialization code that we will move. Type M 709 750 A09 and press Return. You have just moved the code up 768 bytes, enough for many more keys to be assigned. But now we must compensate. Look on the screen to find the disassembly at 0A42. It reads: MOV WORD PTR [BX+0E],0609" This is the code that tells DOS that it can have back everything from 0609 hex on, relative to offset 0 in the segment where the device driver is loaded. The code you are seeing now has an offset of 100 hex added to it by the debugger. In DOS now, the code you moved from 0709 is actually located at offset 0609; this is precisely where the driver released its claim on memory. We have to add 300 hex to the value passed to DOS as well. You may use either the "A" command or the "E" command to change the value "0909" (not 0A09 -- remember the 100 byte offset from the debugger?) To use the "A" command to assemble a new instruction, enter these two lines: A 0A42 MOV WORD PTR [BX+0E],0909 To use the "E" command, enter this line: E 0A46 09 Either method has the same result. Next, look at the code on the screen at location 0A4A. It reads "JMP 04DE". Use the "A" command and change that by entering these two lines: A 0A4A JMP 01DE This compensates for the jump forward of 300 hex bytes, as JMP instructions are calculated as an offset from the current instruction (more or less). That's why you effectively subtracted 300 from the JMP offset using the "A" command. (A good exercise would be to try using the "E" command to directly input the recalculated offset that must be added to the location counter so that you land in the right spot.) Does everything seem all right so far? Double check! One slipped bit is all it takes. Next, just for cosmetics, fill the locations once used by the initialization routine (and any other garbage that was lying around in the computer in between the old and new initialization routines) with zeros, so that the keystring buffer loads up empty. Use the "F" command by entering: F 0709 0A00 00 Now use the "D" command to look at the "device driver header" up at offset 100. Start by keying in D100. (Look on the screen, as you didn't print out this portion.) Specifically, look at offset 0112. Two consecutive memory locations should read: "09 06". This was the offset from 0 of the initialization routine. Change the byte at 0113 to 09 by entering: E 113 09 The offset is now that of the relocated initialization code. Remember that the offset will be 100 hex less than the offset you see in DEBUG. You can increase the limit on the number of stored characters, now that there's room for them. Look at the code at 0630. It reads: "CMP BX,00C8". By using the "A" command again, you can enter a nice round figure like, say 02C0; this would raise the maximum number of allowed characters to 704. (I like to leave a lot of leeway here until the crash problem is solved, but theoretically you should be able to use all the memory from 541 to 0909 -- a total of 3C8 hex bytes, or 968 decimal.) To do this, enter these two lines: A 630 CMP BX,02C0 We're almost finished now. Look at the code at address 05FF. It reads "MOV CX,0609". That number seems familiar, as it is the offset to the old initialization routine, and it appears at the end of the keystring buffer. You have to preserve the same offset relations with the other changes made, so change the code at 05FF to read "MOV CX,0909" by entering these two lines: A 05FF MOV CX,0909 The changes to code are now complete! One final step. We have to write the debugged file to disk, but the size of the file must be increased to take into account the expanded buffer and relocated initialization code. Type R CX. The computer should respond with "CX 0680". You should now enter 980. Your ANSI.SYS file will not be 768 bytes larger. Enter W and the computer will respond with "writing 0980 bytes". When this is finished, you will have vastly more potential to assign strings to the keyboard. The ANSI.SYS file will load when you reset the computer, and you can then test your work. If anything weird happens that didn't happen before you made these changes, double and triple check your modifications. Start from the beginning if necessary. Though the effort may seem great now, afterwards you can let the computer do some of your typing once you've assigned strings to keys to your heart's content. Theoretically, there should be no limit to the storage space you can add to the key buffer using this technique. ----------------------------------------------------------------- Creating Keyboard Assignments (PC Magazine Vol 3 No 9 May 15, 1984 by Tom Sheldon) Creating keyboard assignments for DOS 2.x involes the following process: 1. Create a file of the control sequences for changing key assignments. 2. Create a CONFIG.SYS file containing the ANSI.SYS keyboard driver. 3. Reboot the system to load the new driver. 4. Display the assignment file on the screen to assign the keys. The first step is the most complex. Section 13 of the DOS manual describes the kayboard assignment feature, and page 13-10 gives an example of assigning the DIR command to the F10 key: ESC {0;68;"dir";13p. The 0;68 indicates the location of the F10 key on the keyboard, the 0 indicates that the key is an extended key (see page G-6 of the BASIC manual) and the 13p is a carriage return. The tricky part is getting the escape code into the file without actually escaping while doing it. You can't use the escape key on the keyboard. The process described below uses a dummy character in place of the escape code, and then uses DEBUG to replace the dummy code with the escape code. After you've captured the elusive code using this method, you can use EDLIN to make multiple copies of the original line for other keyboard assignments. Create a file called ASSIGN.CDS. The dummy character will be the asterisk. You need only the first part of the string at this point. Enter: COPY CON;ASSIGN.CDS *[0; Now use DEBUG to fix the file. Type: DEBUG ASSIGN.CDS Type D, and the first line should look like: 0952:0100 2a 5b 30 3b 00 00 00 00 00 00 00 00 00 00 00 00 *[0; The asterisk (hex 2a) must be replaced with hex 1b (escape). Type E and the address: E0952:0100 The asterisk character appears first. Type 1b, press Return, type W to write the changes to disk, and then type Q to exit. The next step is to get into EDLIN and finish. Type: EDLIN ASSIGN.CDS For 10 copies of the first line, enter: 1, 1, 2, 10c If you list the file, there are 11 lines of escape codes. The escape code in each line is now ^[. Now you only have to add the rest of the string to each line. You can use the right arrow key to copy from the template, which is the line above the one being edited. The first four lines should look like: ^[[0;104;"HELP';13p ^[[0;105;"MENU";13p ^[[0;105;"MM";13p ^[[0;107;"PM";13p You may use the remaining lines for your own strings. The codes for the function keys are on page G-6 of the BASIC manual. Enter 13p at the end of each string only if you want a carriage return to be executed when you press the assigned function key. When finished, hit E to exit and save the file. Create the CONFIG.SYS file by typing: COPY CON:CONFIG.SYS DEVICE=ANSI.SYS Press F6 and Return. Reboot to load the new driver. If you created the AUTOEXEC.BAT file shown in the main text, the ASSIGN. CDS file will be displayed on the screen and the keys will be assigned. (The main text is "Building An Orderly Hard Disk" and appears on p. 269-276; it includes the files referenced in the last couple of paragraphs of this article.)