Discussion

Replacing INKEY() with INKEY.BIN

By KENNETH N. GETZ AND KAREN ROBINSON

As you may be aware, in dBASE III PLUS version 1.1, the INKEY() function does
not trap Leftarrow.  For this reason, Inkey.BIN was written to replace INKEY()
in those instances where you want to trap the Leftarrow key.  Inkey.BIN is an
assembly language routine that checks the keyboard buffer to see if a key is
pressed.  If so, it reads the key from the buffer and translates it to a code
you can as you would the code returned by INKEY().  There are, however, some
differences between Inkey.BIN and INKEY().  The following list summarizes the
similarities and the differences.

1. It supports the same keys INKEY() does in addition to the Leftarrow key.

2. Inkey.BIN operates similarly to INKEY() when INKEY() is used with SET
   ESCAPE OFF.  Even if you SET ESCAPE ON, pressing Esc returns CHR(27) and
   does not terminate execution of your program.

3. Inkey.BIN returns the ASCII character corresponding to the correct INKEY()
   value instead of returning the actual numeric value.  This is done since it
   is difficult to pass a numeric value to and from a LOADed module.  When you
   use Inkey.BIN, for example, it returns a CHR(23) when you press Ctrl-W.  In
   contrast, INKEY() returns a value of 23 for the same key press.  To retain
   compatibility with INKEY(), use the ASC() function to convert the character
   value that Inkey.BIN returns to a numeric value.

4. INKEY() returns the values -1 through -9 for F2 through F10.  Since
   Inkey.BIN returns characters instead of values, it adds 256 to the expected
   return value for function keys F2 through F10, as shown in the table
   below: 

     Key		INKEY()	Inkey.BIN
      F1		   28	    28
      F2		   -1	   255
      F3		   -2	   254
      F4		   -3	   253
      F5		   -4	   252
      F6		   -5	   251
      F7		   -6	   250
      F8		   -7	   249
      F9		   -8	   248
      F10	   -9	   247 

   In view of this difference, we suggest that you create memory variables for
   the function keys F2 through F10, using the Inkey.BIN values shown above. 
   Then refer to them by name instead of by their numeric values.  This makes
   them easier to modify should you need to change these values.  For example,
   
     F1 =  28
     F2 = 255
     F3 = 254   
			.
			.
			.

5. Inkey.BIN waits in a long loop (65535 executions) for you to press a key. 
   Without this loop key presses may be missed, requiring you to press the key
   several times before it registers.  With the loop, Inkey.BIN never misses
   any key presses, but this does present a limitation.  If no key is pressed,
   Inkey.BIN waits for one to six seconds (on an IBM XT, shorter on an AT)
   before it returns to dBASE III PLUS.  This means:

   -  Inkey.BIN is fine for applications where the program is to stop and wait
      for a keystroke, process it, and then go on from there.
   
   -  The INKEY() function is better for applications like Cbmenu.PRG on the
      dBASE III PLUS Samples disk, where it is used to test for a pressed key,
      updating the clock if no key is pressed.  With Inkey.BIN, the clock is
      updated only about once every six seconds.


Setup 

Setup

To setup Inkey.BIN create the text file, Inkey.ASM, using MODIFY COMMAND or
any text editor that writes to standard ASCII text files.

Then, assemble Inkey.ASM to a .BIN file.  Before you begin, be sure that the
following files are present, either in the same subdirectory as Inkey.ASM or
through the DOS PATH command: MASM.EXE, LINK.EXE, and EXE2BIN.EXE.  Follow the
steps below to assemble Inkey.ASM as a .BIN file:  

1. From the DOS prompt enter, 

   	MASM Inkey.ASM;    
   
   This creates an object file (INKEY.OBJ).

2. Enter, 
        
   	LINK INKEY;
   
   This creates INKEY.EXE.

3. To create a .BIN file enter,
 
   	EXE2BIN INKEY

4. Last, delete INKEY.EXE,

   	ERASE INKEY.EXE


Usage

Usage

To use Inkey.BIN, first LOAD it into memory.  Then initialize a return
variable to a value never used by Inkey.BIN.  The example below uses CHR(200),
although you may use any number between 128 and 246.  You cannot, however, use
CHR(0) to test if there is a key in the keyboard buffer since dBASE III PLUS
cannot pass this value as the argument of CALL command.  

Finally, CALL it from within a DO WHILE keytrap loop.  As stated before, if
you want to evaluate the returned value using the values returned by INKEY(),
use the ASC() function to convert the character to its numeric equivalent.

The following programs show the programming differences between INKEY() and
Inkey.BIN:

With INKEY() 						With Inkey.BIN
------------						--------------	

SET ESCAPE OFF						LOAD Inkey
SET TALK OFF						SET TALK OFF
x = 0									x = CHR(200)
DO WHILE x = 0						DO WHILE x = CHR(200)
  x = INKEY()					  		CALL Inkey WITH x
ENDDO									ENDDO
? "INKEY(): " + STR(x,3,0)	   ? "Inkey.BIN: " + STR(ASC(x),3,0)


Program

; Program ...: Inkey.ASM
; Author ....: Kenneth N. Getz
; Date ......: April 1, 1987
; 
; .BIN file to be loaded from within dBASE III PLUS to replace the
; INKEY() function, since Version 1.1 doesn't trap left arrow correctly.
; The only differences are in the calling sequence (x = CHR(200),
; DO WHILE x = CHR(200)), in the return values (INKEY() returns an
; integer, Inkey.BIN returns a character), and in the use of function keys:
;
; 		KEY	INKEY()		INKEY.BIN
; 		---     -------		---------
; 		F1	28		28
; 		F2	-1		255
; 		F3	-2		254
; 		F4	-3		253
; 		F5 	-4		252
; 		F6	-5		251
; 		F7 	-6		250
; 		F8	-7		249
; 		F9	-8		248
; 		F10 	-9		247
; 
;
CODE	SEGMENT	BYTE PUBLIC	'CODE'	

INKEY	PROC	FAR
	ASSUME	CS:code

START:	JMP	ENTRY

DELAY	DW	0FFFFH
TABLE	DB	  0,  0,  0,  0,  0,  0,  0,  0,  0,  0
	DB  	  0,  0,  0,  0, 15, 16, 17, 18, 19, 20
	DB 	 21, 22, 23, 24, 25,  0,  0,  0,  0, 30
	DB 	 31, 32, 33, 34, 35, 36, 37, 38,  0,  0
	DB  	  0,  0,  0, 44, 45, 46, 47, 48, 49, 50
	DB  	  0,  0,  0,  0,  0,  0,  0,  0, 28,255
	DB	254,253,252,251,250,249,248,247,  0,  0
	DB	  1,  5, 18,  0, 19,  0,  4,  0,  6, 24
	DB	  3, 22,  7, 84, 85, 86, 87, 88, 89, 90
	DB	 91, 92, 93, 94, 95, 96, 97, 98, 99,100
	DB	101,102,103,104,105,106,107,108,109,110
	DB	111,112,113,114, 26,  2, 23, 30, 29, 31
	DB	 31, 31, 31, 31, 31, 31, 31, 31, 31, 31
	DB	 31, 31

ENTRY:	PUSH	AX			; Save the registers used.
	PUSH	CX
	MOV	CX,DELAY		; Set up for wait loop.
TOP:	MOV	AH,1			; Set for buffer poll.
	INT	16H			; See if key in buffer.
	JNZ	FOUND			; If so, jump out.
	LOOP	TOP			; Otherwise, try again DELAY times.
FOUND:	JZ	EXIT			; Quit if all the way through the
loop.
	AND	AH,0			; Otherwise, set for buffer read.
	INT	16H			; Read the key from the buffer.
	CMP	AL,0			; See if we got an extended character.
	JNE	ENDIT			; If not, we're OK.
	PUSH	BX			; Otherwise, save BX for later.
	PUSH	DS			; Save DS for dBASE III PLUS.
	PUSH	CS			; Make CS and DS same for translation.
	POP	DS
	MOV	AL,AH			; Move extended value into AL.
	LEA	BX,TABLE		; Get the address of the table.
	DEC	AL			; Subtract 1 to offset at 0.
	XLAT				; Do the lookup. Answer in AL.
	POP	DS			; Reset DS.
	POP	BX			; Reset BX.
					; Send back character to dBASE III
PLUS.
ENDIT:	MOV	BYTE PTR [BX],AL	
								
EXIT:	POP	CX			; Restore used registers.
	POP	AX
	RET
INKEY	ENDP
CODE	ENDS
	END	START 
