From: richard@coos.dartmouth.edu (Richard Brittain)
Newsgroups: comp.os.msdos.programmer
Subject: Keyboard reading via int 16, TurboC bioskey() routine, ctrl-BREAK
Summary: What does bioskey() do in addition to calling int 16.
Date: 6 Nov 92 04:33:13 GMT
Organization: Dartmouth College, Hanover, NH
Originator: richard@coos.dartmouth.edu

Hi,
I'm having a problem with a conflict between reading the keyboard via
the bios int 16 interface and control-C and control-break.  I
originally used bioskey() from the TurboC v2.1 library, but that is
written for old style keyboards and didn't seem to be totally happy
with the command codes for the extended keyboard reads.  I also
discovered that it internally calls dos services to remap the int 1B
vector (ctrl-brk) before making the int 16 call, so you cannot use it
in an interrupt routine - I wanted to use this in a critical error
handler.

I wrote my own bioskey replacement, doing the remapping manually (to a
no-op function declared type interrupt) and surrounded by
disable()/enable(), and it seems to work fine for reading keys, except
for ^C and ^break, which sometimes work and sometimes lock out further
keyboard reads, and sometimes just crash the whole machine.  This seems
to behave slightly differently on the different machines I have access
to , with different dos/4dos combinations.  The original bioskey() does
not have this problem.
I need to be able to use this for keystroke checking in a
running program i.e. non blocking reads.

Any ideas as to what is happening would be appreciated.  Any explanation of why 
it is necessary to remap int 1B would also be welcome.


Thanks,

Richard Brittain,        Dept of Physics and Astronomy, Wilder Laboratory, 
                         Dartmouth College, Hanover NH 03755
INTERNET: richard.brittain@dartmouth.edu
SPAN:     nsfgw::"richard@einstein.dartmouth.edu"


The offending code follows
/*
 *  DISABLE_CBREAK will cause the bioskey() function to temporarily disable the
 *  control-break interrupt .  If using this, compilation/linking should have
 *  use-registers=no and stack-warning=no.  The Borland bioskey() does this but
 *  I don't know why.
 *
 */

#ifdef KEY101
  #define GETKEY        0x10 /* 0x10 extended keyboards, 0x00 old keyboards */
  #define GETKEYTEST    0x11 /* 0x11 extended keyboards, 0x01 old keyboards */
#else
  #define GETKEY        0x00
  #define GETKEYTEST    0x01
#endif
#define	GETSHIFT		0x02


#ifdef DISABLE_CBREAK
void interrupt cbreak_ignore();

void interrupt cbreak_ignore()
{
	return;
}
#endif

int  bioskey(int cmd)
{
/*
 * Replace bioskey() in TurboC library.  Allows for extended keyboard reads
 * Use this for keyboard read functions 00,01,02,10,11,12 (Hex)
 * This routine also saves and restores the ^BREAK interrupt (1B) without
 * using DOS, so is safe to use in interrupt service routines.  The Borland
 * library version of bioskey() seems to do this, but I'm not sure why.
 */
#define FLAG_ZF 0x40
	union REGS regs;

#ifdef DISABLE_CBREAK
	unsigned int cbreak_off, cbreak_seg;
	void far *fp;
	/*
	 * temporarily disable the int 1B (^BREAK) routine by poking the
	 * address of a no-op function into the interrupt table
	 */
	#if defined(__TINY__) || defined(__SMALL__) || defined(__COMPACT__)
	 fp = MK_FP(_CS, cbreak_ignore);
	#else
	 fp = cbreak_ignore;
	#endif
	cbreak_off = peek(0x00,0x6C);
	cbreak_seg = peek(0x00,0x6E);
	disable();
	poke(0x00,0x6C,FP_OFF(fp));
	poke(0x00,0x6E,FP_SEG(fp));
	enable();
#endif
	/* call the keyboard system service with the desired operation */
	regs.h.ah = (unsigned char)cmd;
	int86(0x16,&regs,&regs);

#ifdef DISABLE_CBREAK
	/* replace the original int 1B routine */
	disable();
	poke(0x00,0x6C,cbreak_off);
	poke(0x00,0x6E,cbreak_seg);
	enable();
#endif
	/* return keypress */
	switch(cmd) {
		case GETKEYTEST:
			/* Test zero flag - return 0 if not set, otherwise return ax */
			if ((regs.x.flags & FLAG_ZF) == 0) {
				return(regs.x.ax);
			} else {
				return(0);
			}
		case GETSHIFT:
			/* zero out the high byte */
			regs.h.ah = 0;
			return(regs.x.ax);
		default:
			/* all other functions, return ax */
			return(regs.x.ax);
	}
}
Newsgroups: comp.os.msdos.programmer