/* * * * * * * * * * * * * * * * * * * * * ANSI-CHK.C (c) 1994, Jim Groeneveld * * * * * * * * * * * * * * * * * * * * * Routine ChkAnsiKKR Version 1.0 Date 30 April 1994 ------------------------------------------------------------------------------ Y. (Jim) Groeneveld, Schoolweg 14, 8071 BC Nunspeet, Nederland, 03412 60413. Email (work): groeneveld@tno.nl, groeneveld@cmi.tno.nl, groeneveld@nipg.tno.nl ------------------------------------------------------------------------------ * ChkAnsiKKR detects the presence of ANSI.SYS by redefining a key to another * one (one is sufficient) using an ANSI escape sequence for KKR (Keyboard Key * Reassignment), entering the original key into the keyboard buffer and check * whether the redefinition or the original one is returned from CON. * This only works all right if there still is space in the keyboard * reassignment buffer in memory. This should always work with reading CON. * * However, that does not appear to work with ANSI.COM vs. 1.3 (C) 1988, * Ziff Communications Co. PC Magazine by Michael J. Mefford, * which reads the original key instead of the definition. If the read is * done from stdin ANSI.COM vs. 1.3 indeed works OK, reading the definition. * For a demonstration of ANSI.COM's incompatibility with other ANSI.SYS's * see and run the program ANSI-COM. * * If the key to check it with already appears to be redefined (checked * initially by feeding it into the keyboard buffer and seeing what is * returned from CON) this may be due to either ANSI.SYS or some other * key redefinition program. Then another key in the range 33-255 is taken * until a key is found that appears not to be redefined and thus is suited * to test a reassignment on, though redefining a key temporarily with ANSI.SYS * that already has been redefined using another program seems to be no problem. * On the other hand using normal keyboard keys it may be expected that these * are only seldomly redefined by users, because they don't want to loose * regular keyboard characters. There may only redefinitions be expected to * switch the functions of specific key pairs, like for national keyboards. * * Care should be taken while initially checking for already redefined keys * because some key may be redefined as one or more commands, each with its * own CR. As the key minimally is any single key it should be read too while * being followed by an explicitly fed CR from the keyboard buffer. So it * would not be known in advance how many "lines" are to be expected and * waiting for user entered keys in the buffer should be prevented. The * solution for this is to feed a very unique character sequence into the * keyboard buffer after the test key to signal the end of the returned input. * * After testing the key has to be reset to its original same key (using * the ANSI escape sequence too, if ANSI.SYS thus indeed has been detected), * but this leaves the definition of itself in the buffer space for * redefinitions. Tests have showed that redefining a key overwrites its * former definition and thus does not add to the buffer space only; it may * even enlarge the remaining buffer space by defining a shorter redefinition. * But at least any definition of a once defined key, even if empty, remains * in the buffer, so this strategy takes up 3 bytes in the buffer permanently. * The bytes consist of a byte indicating a redefinition, the redefined * single key (1 ascii value) and the definition (1 ascii value). (Extended * keys take up two bytes by themselves). * * Input from CON using one of fgets(), getc(), fread() and fscanf() need a * CR before it can be processed, thus at least two keys have to be entered * from the keyboard buffer. * * All these tests generate artificial keypresses to be read from CON and * thus are visible on the screen as some characters and newlines, * whether ANSI.SYS is loaded or not. It is not easily possible to erase * only them. The only possibility to erase all test characters from the * screen is to clear the whole screen after the tests. This may be done * using the ANSI escape code ED ("Esc[2J") or other escape codes, erasing * the concerning scratch output more specific, or a Zortech C function (?) * or by a forced scrolling of the screen for at least 25 lines (see below). * * Return codes: 0 = ANSI.SYS not detected * 1 = ANSI.SYS detected * 5 = unknown, unable to detect ANSI.SYS (out of test keys) * Exit codes: ( 2 = unknown, unable to open SCREEN for write ) * ( 3 = unknown, unable to open KEYBOARD for read ) * ( 4 = unknown, unable to read KEYBOARD ) * Check these with ERRORLEVEL from DOS. Disclaimer ---------- The author is not liable for any negative consequences of the use or misuse of these routines. ----------------------------------------------------------------------- */ /*-----------------------------------DEFINE-----------------------------------*/ /*----------------------------------INCLUDE-----------------------------------*/ #include #include #include "ansi-chk.h" #include "tokeybuf.h" #include "openread.h" /*--------------------------------ChkAnsiKKR----------------------------------*/ int ChkAnsiKKR() { FILE *Screen, *Keyboard; unsigned char TestChar; char *TestStr="#\r"; char *RtnStr="#\n"; int KKRfound; KKRfound=0; /* presence of ANSI.SYS, 0=no, !0=yes */ ClKeyBuf(); /* Keyboard buffer has to be cleared before use */ #if KKR_KEYBOARD == 3 /* Open KKR_KEYBOARD for read to read returned line */ Keyboard=OpenFile(KKR_KEYBD,"r",3); /* "rb" for binary */ #elif KKR_KEYBOARD <= 2 Keyboard = stdin; #endif /* KKR_KEYBOARD */ { char RtnStr[RTNSTRLEN]; /* reserve space to receive returned string */ char *TestStr; /* above: no malloc() for such a few bytes */ char *CompStr; int UndefFound; UndefFound=0; TestStr=TESTSTR; /* reserve space for unique test string */ CompStr=TESTSTR; /* reserve space for unique comp string */ *strchr(CompStr,'\r')='\n'; /* replace CR by NL */ *RtnStr='\0'; /* initialize first char */ /* check key (33-255) for being redefined already */ for (TestChar=33; TestChar!=0 && !UndefFound; TestChar++) { *TestStr=TestChar; /* assign key character to first char of test string */ *CompStr=TestChar; /* assign key character to first char of test string */ ToKeyBuf(TestStr,1); /* feed test string into keyboard buffer */ #if KKR_KEYBOARD >= 2 /* read lines using fgets() from file, CON or stdin */ ReadLine (RtnStr,RTNSTRLEN,Keyboard,4); if (!strcmp(CompStr,RtnStr)) UndefFound=1;/* undefined test char found */ else { /* Process returned string further for end, marked by unique string */ while (!strstr(RtnStr,CompStr+1)) /* end of test string not yet read */ { while (!strchr(RtnStr,'\n')) /* NL not yet read anyway */ /* shift last few characters, the number equal to the number of unique * characters to the beginning of the returned string because * subsequently the rest of a line should be read from there and the * unique characters must be in the same string to be recognized. */ { int RtnStrLen; RtnStrLen=strlen(RtnStr); strcpy(RtnStr,RtnStr+RtnStrLen-MIN(TESTSTRLEN-2,RtnStrLen)); ReadLine(RtnStr+MIN(TESTSTRLEN-2,RtnStrLen), RTNSTRLEN-MIN(TESTSTRLEN-2,RtnStrLen),Keyboard,4); } /* NL now encountered */ } /* end of test string now encountered */ } #else /* KKR_KEYBOARD == 1 */ { int i, UniqueEndFound; i=0; UniqueEndFound=0; while (!UniqueEndFound) { RtnStr[i]=getch(); /* (though index might remain 0 or 1 for RtnStr) */ if (i) /* i>0 */ /* if at least one character before unique end signal already returned */ { if (RtnStr[i]==TestStr[i]) /* partial match unique end signal */ { if (i==TESTSTRLEN-1) /* complete match unique end signal: CR */ { if (RtnStr[0]==TestChar) UndefFound=1; /* match test char. */ UniqueEndFound=1; /* indicate end of input found anyway */ } else i++;/* increment index while test string matches partially */ } else /* no (partial) match with unique end */ { i=1; /* reset index to 1 and search further for unique end */ RtnStr[0]=' '; /* set it to space to indicate no UndefFound */ } } else i++; /* increment index for first character only */ } } #endif /* KKR_KEYBOARD */ } /* proceed trying next character */ if (TestChar==0) KKRfound=5;/* no more keys found to be used for testing */ else TestChar--; /* undo effect of last 'TestChar++;' in for */ } /* Now a test character has been found */ #if KKR_SCREEN == 3 /* Open KKR_SCREEN ("CON") for write */ /* DOS, how about Unix? */ Screen=OpenFile(KKR_CONSOLE,"w",2); #elif KKR_SCREEN == 2 Screen = stderr; #else /* KKR_SCREEN = 1 */ Screen = stdout; #endif /* KKR_SCREEN */ if (KKRfound!=5) { /* Now write a KKR to the screen, redefine everything into an invisible space */ fprintf(Screen,"\x1B[%d;32p",TestChar); /* Now feed the test character and the NL into the keyboard buffer */ *TestStr=TestChar; #if KKR_KEYBOARD == 1 /* Feed only the single key, end string with '\0' */ TestStr[1]='\0'; #endif /* KKR_KEYBOARD == 1 */ ToKeyBuf(TestStr,1); /* Now see whether this is the same or different from the returned string */ #if KKR_KEYBOARD >= 2 /* read lines using fgets() from file, CON or stdin */ ReadLine(RtnStr,2,Keyboard,4);/*only two characters are returned, incl. NL*/ #else /* KKR_KEYBOARD == 1 */ RtnStr[0]=getch(); /* either the original or the redefined character */ #endif /* KKR_KEYBOARD */ /* Now see whether reassignment had effect or not */ if (!(TestChar==*RtnStr)) /* chars are unequal */ { KKRfound=1; fprintf(Screen,"\x1B[%d;%dp",TestChar,TestChar);/* Reset key to itself */ #if KKR_KEYBOARD >= 2 /* Clear the scratch output from fgets() on the screen */ /* fprintf(Screen,ED);*/ /* Clear the screen using ANSI escape sequence(s) */ fprintf(Screen,"%s%s",CUU,EL);/* Wipe line with last redef space and CR */ for (; TestChar>=33; TestChar--) /* For each attempted test character: */ { fprintf(Screen,"%s%s",CUU,EL);/* wipe each line above with test string*/ }/* Due to the last CR the cursor already was in the left most position */ #endif /* KKR_KEYBOARD >= 2 */ } else /* strings are equal, thus reassignment did not work */ { KKRfound=0; /* If no ANSI.SYS detected, while it actually is there, the key may not remain * redefined, because in other cases (not reading from CON) the redefinition * might be active unwantedly. This happens with ANSI.COM vs. 1.3 if input is * read from CON instead of from stdin. So the key has to be reset anyway. * This may reset a key to itself while it originally had been assigned * something else, because, while searching for a not-redefined key to use for * testing, the redefinition was not recognized. This has the drawback that * the original redefinition may be lost anyway. But this only happens using * ANSI.COM vs. 1.3, having this program to read input via CON and then only * affects the exclamation character (!) as the first one to be attempted. * Besides, it is very unlikely that a user has redefined that !-key. */ #if KKR_KEYBOARD == 3 /* Only if CON was used to read input from: */ fprintf(Screen,"\x1B[%d;%dp",TestChar,TestChar); /* Reset key to itself */ #endif /* KKR_KEYBOARD == 3 */ } } if (KKRfound==0) /* not: || KKRfound==5 */ { /* NOT: clear the screen by scrolling; is there a C function for CLS? %%% */ /* Alternatively this may be accomplished with: 'system("cls");' (from * stdlib.h), but that takes longer because COMMAND.COM has to be loaded. */ /* fprintf(Screen,"\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"); */ /* At least erase last KKR escape sequence & go to beginning of current line */ fprintf(Screen,"\r \r"); /* CR, overwrite with 10 spaces and CR */ /* though it is not quite necessary with KKR_KEYBOARD=2: already at begin */ } #if KKR_SCREEN == 3 /* stderr and stdout implicitely closed? */ fclose (Screen); #endif /* KKR_SCREEN == 3 */ #if KKR_KEYBOARD == 3 fclose (Keyboard); #endif /* KKR_KEYBOARD == 3 */ return KKRfound; } /* end of */ /*---------------------------- That's all folks! ----------------------------- ---------------------------------History----------------------------------- Vs. 1.0 Initial working release with side effect of reducing keyboard 30/04-94 assignment buffer by 3 bytes and disrupting the screen in any case. ----------------------------------Future----------------------------------- ---------------------------------Remarks----------------------------------- - works correctly with ANSI.SYS of MSDOS 5.0 and HP's MSDOS 3.1 and 3.3, and with QWIKANSI.SYS ((C) 1986, Michael J. Acker); - does not work quite correctly with ANSI.COM vs. 1.3 ((C) 1988 Ziff Communications Co. PC Magazine by Michael J. Mefford), unless stdin is used to read input from (set KKR_KEYBOARD to 2 in ANSI-CHK.H). */