'=========================================================================== ' Subject: RETURN KEY VALUE Date: 09-02-99 (11:32) ' Author: Don Schullian Code: PBCC, PBDLL ' Origin: d83@DASoftVSS.com Packet: PBCC.ABC '=========================================================================== Hi, This text is aimed, primarily, at new, upcoming programmers and those of you that have been around for awhile will find it a rehash of what you already know and will, most likely, wish to skip it. (or not) Windows seems to have lost the abilities to report all the variations of key strokes that were available in DOS. In most cases this doesn't pose much of a problem as there were over 200 distinct codes NOT including the alphabet and standard characters. I'm talking about F-01, Gray5, ect. The code and integer equates found in this file comes as close as I could get to reporting all the variations and there are still over 200 to choose from but they DO NOT, in most cases, equal what was returned by DOS. This, fortunately, is not a problem as the numeric equates, if used religiously, will carry the correct value returned by the fKeyValue function and are named EXACTLY the same as in my DOS code. So, where to start.... The very bottom of the pile are the numeric equates I was speaking of in the previous paragraph. Using them may seem to be a bit of a pain in the posterior but they are common enough throughout the WIN32API.INC file and %ENTER_key makes a whole lot easier reading than &h0D or 13 (and that's an easy one). When you're programming, say, a browser menu for an index you'll want to offer your user a rich set of keys with which to control the list; of which HOME, UP, PgUp, END, DOWN, PgDn, ENTER, and ESC are the most common. A simple SELECT CASE will handle all these quite easily but, what values do you test? Have a look at these two sets of code and see which one YOU would want to see in some six year old code: SELECT CASE fKeyValue(K) SELECT CASE fKeyValue(K) CASE %HOME_key CASE &hF204 CASE %UP_key CASE &h000D CASE %PGUP_key CASE &h001B CASE %END_key CASE &h5100 CASE %DOWN_key CASE &h5000 CASE %PGDN_key CASE &h4F00 CASE %ENTER_key CASE &h4900 CASE %ESC_key CASE &h4800 CASE %CTRL_ENTER CASE &h4700 END SELECT END SELECT Get the picture? Plus, as a bonus to those of you who are coming into PB/cc from DOS, you can use the same code for both PB/DOS and PB/cc by loading a different set of numeric equates. This 'trick' of course, applies to just about any situation where a change is required throughout your program(s) to make them act slightly differently for different users or O/Ss. Ok... that takes care of the equates now lets move onto fGetKey. If you've not read through my notes on that subject I'd strongly suggest you do so as it is, maybe, the most important piece of code I've ever written. It has been in EVERY program I've written in the last decade and has saved MEGs of code and uncountable hours of backtracking. FUNCTON fGetKey () AS INTEGER FUNCTION = CVI(WAITKEY$) END FUNCTION What you see above is the simplest form of fGetKey. You'll find a bit more complicated form below. They both preform the same primary function of awaiting an incoming key press and converting it into an INTEGER value. EVERY incoming key press in my programs comes through this function and that allows me to 'trap' certain keys, change their value before passing them on, block them altogether, branch the program off to, say, help, or even end the program all from the same spot! In the DOS days this function also handled the screen saver function. It removed the requirement for ON KEY which added 2 bytes to each and every command which keep the overall size down and kept the speed up. If I've enticed you then PLEASE read my fGetKey files and adapt the concept to your programs, it works! Finally, we get to the fKeyValue function. As you can see it really is just a few lines of code and pretty fast. I tinkered with other ideas on how to create unique codes for all the various key combinations but this version gave me the uniqueness required and maintained the speed so as not to slow down the whole program. All the incoming key strokes report either 1 byte or 2 bytes. Those, like the function keys, that return two bytes have a low byte value of ZERO so when converting ANY key stroke into an integer, one of the two bytes will be ZERO and working on that fortunate fact I've changed the value of which ever byte is ZERO. The High nibble of that byte is always &hF (15) and the low nibble is either 1, 2, or 4 depending on the status of either the , or key. If none of these keys were employed then the byte retains it's value of ZERO. Notice that fKeyValue reports only ONE of the three modifier keys. That is to say that if both and are depressed then only one of the two keys will be reported. This was done for speed and simplicity and does NOT have to be the case. The system employed to set the unique values can be ORed to report any one, two, or three of the modifier keys if it is required by your program. Well, gang, that about wraps it up and just in time as the wife has decided that I'm not doing anything important and should take her shopping! Thanks, once again, for hanging in there and I sincerely hope I've helped you along. If you've any questions or have spotted (what you erroneously think is) a bug let me know. Have a good one, d83 ----------- ----------- -------------------------< cut here >--------------------------- ----------- ----------- #IF 0 ---------------------------- PowerBASIC/cc v2.0 ---| DASoft |------------------------------------------ ---------------------------- Copyright 1999 DATE: 1999-08-30 | FILE NAME KeyValue.bas | by | DIRECTORY NB1cc | Don Schullian, Jr. ---------------------------- A license is hereby granted to the holder to use this source code in any program, commercial or otherwise, without receiving the express permission of the copyright holder and without paying any royalties, as long as this code is not distributed in any compilable format. IE: source code files, and/or printed listings. ------------------------------------------------------------------------- PURPOSE: Return unique key-press values based on , , or status. PARMAS: KeyIn An INTEGER representation of the latest key input NOTE: fGetKey (shown in the test code) creates these INTEGER values. RETURNS: adjusted INTEGER value of KeyIn USE: As the values returned by fKeyValue% are contrived and NOT of any known standard you would be well advised to use the INTEGER constants (included in this file) that represent the values. This will also make correcting any errors that may exist easier. NOTE: There is one double among the 200+ values below: J and ENTER. As this condition has existed since the beginning of time I have elected not to make a unique distinction. NOTE: If you require combination key values, such as , The code in fKeyValue can be modified to OR the values of each "shift" key instead of selecting only one. Insert the following lines of code in place of the SELECT CASE and create the new integer constants. eg: %CTRL_ALT_F01 = &h3BF3 DIM V AS LOCAL INTEGER V = (INSHIFT AND &b011111) IF V = 0 THEN GOTO ExitFunction IF V = 16 AND K > 31 AND K < 256 THEN GOTO ExitFunction IF (V AND &b000011) THEN I = &h00F1 ' ALT IF (V AND &b001100) THEN I = (I OR &h00F2) ' CTRL IF (V AND &b010000) THEN I = (I OR &h00F4) ' SHIFT -------------------------------------------------------------------------------- #ENDIF #IF 0 Windows' default keys %ALT_ENTER = &hF10D %ALT_ESC = &hF11B %ALT_TAB = &hF109 %CTRL_ESC = &hF21B #ENDIF 'START HERE =============== Used by LoadData %HOME_key = &h4700 : %ALT_HOME = &h47F1 : %CTRL_HOME = &h47F2 : %SHIFT_HOME = &h47F4 %UP_key = &h4800 : %ALT_UP = &h48F1 : %CTRL_UP = &h48F2 : %SHIFT_UP = &h48F4 %PGUP_key = &h4900 : %ALT_PGUP = &h49F1 : %CTRL_PGUP = &h49F2 : %SHIFT_PGUP = &h49F4 %LEFT_key = &h4B00 : %ALT_LEFT = &h4BF1 : %CTRL_LEFT = &h4BF2 : %SHIFT_LEFT = &h4BF4 %RIGHT_key = &h4D00 : %ALT_RIGHT = &h4DF1 : %CTRL_RIGHT = &h4DF2 : %SHIFT_RIGHT = &h4DF4 %END_key = &h4F00 : %ALT_END = &h4FF1 : %CTRL_END = &h4FF2 : %SHIFT_END = &h4FF4 %DOWN_key = &h5000 : %ALT_DOWN = &h50F1 : %CTRL_DOWN = &h50F2 : %SHIFT_DOWN = &h50F4 %PGDN_key = &h5100 : %ALT_PGDN = &h51F1 : %CTRL_PGDN = &h51F2 : %SHIFT_PGDN = &h51F4 %INS_key = &h5200 : %ALT_INS = &h52F1 : %CTRL_INS = &h52F2 : %SHIFT_INS = &h52F4 %DEL_key = &h5300 : %ALT_DEL = &h53F1 : %CTRL_DEL = &h53F2 : %SHIFT_DEL = &h53F4 %ENTER_key = &h000D : %CTRL_ENTER = &hF20A : %SHIFT_ENTER = &hF40D %ESC_key = &h001B : %SHIFT_ESC = &hF41B %BKSPC_key = &h0008 : %ALT_BKSPC = &hF108 : %CTRL_BKSPC = &hF27F : %SHIFT_BKSPC = &hF408 %TAB_key = &h0009 : %CTRL_TAB = &h0FF2 : %SHIFT_TAB = &hF409 %F01_key = &h3B00 : %ALT_F01 = &h3BF1 : %CTRL_F01 = &h3BF2 : %SHIFT_F01 = &h3BF4 %F02_key = &h3C00 : %ALT_F02 = &h3CF1 : %CTRL_F02 = &h3CF2 : %SHIFT_F02 = &h3CF4 %F03_key = &h3D00 : %ALT_F03 = &h3DF1 : %CTRL_F03 = &h3DF2 : %SHIFT_F03 = &h3DF4 %F04_key = &h3E00 : %ALT_F04 = &h3EF1 : %CTRL_F04 = &h3EF2 : %SHIFT_F04 = &h3EF4 %F05_key = &h3F00 : %ALT_F05 = &h3FF1 : %CTRL_F05 = &h3FF2 : %SHIFT_F05 = &h3FF4 %F06_key = &h4000 : %ALT_F06 = &h40F1 : %CTRL_F06 = &h40F2 : %SHIFT_F06 = &h40F4 %F07_key = &h4100 : %ALT_F07 = &h41F1 : %CTRL_F07 = &h41F2 : %SHIFT_F07 = &h41F4 %F08_key = &h4200 : %ALT_F08 = &h42F1 : %CTRL_F08 = &h42F2 : %SHIFT_F08 = &h42F4 %F09_key = &h4300 : %ALT_F09 = &h43F1 : %CTRL_F09 = &h43F2 : %SHIFT_F09 = &h43F4 %F10_key = &h4400 : %ALT_F10 = &h44F1 : %CTRL_F10 = &h44F2 : %SHIFT_F10 = &h44F4 %F11_key = &h5700 : %ALT_F11 = &h57F1 : %CTRL_F11 = &h57F2 : %SHIFT_F11 = &h57F4 %F12_key = &h5800 : %ALT_F12 = &h58F1 : %CTRL_F12 = &h58F2 : %SHIFT_F12 = &h58F4 %ALT_0 = &hF130 : %CTRL_0 = &h0BF2 %ALT_1 = &hF131 : %CTRL_1 = &h02F2 %ALT_2 = &hF132 : %CTRL_2 = &h03F2 %ALT_3 = &hF133 : %CTRL_3 = &h04F2 %ALT_4 = &hF134 : %CTRL_4 = &h05F2 %ALT_5 = &hF135 : %CTRL_5 = &h06F2 %ALT_6 = &hF136 : %CTRL_6 = &h07F2 %ALT_7 = &hF137 : %CTRL_7 = &h08F2 %ALT_8 = &hF138 : %CTRL_8 = &h09F2 %ALT_9 = &hF139 : %CTRL_9 = &h0AF2 %ALT_A = &h1EF1 : %CTRL_A = &hF201 %ALT_B = &h30F1 : %CTRL_B = &hF202 %ALT_C = &h2EF1 : %CTRL_C = &hF203 %ALT_D = &h20F1 : %CTRL_D = &hF204 %ALT_E = &h12F1 : %CTRL_E = &hF205 %ALT_F = &h21F1 : %CTRL_F = &hF206 %ALT_G = &h22F1 : %CTRL_G = &hF207 %ALT_H = &h23F1 : %CTRL_H = &hF208 %ALT_I = &h17F1 : %CTRL_I = &hF209 %ALT_J = &h24F1 : %CTRL_J = &hF20A %ALT_K = &h25F1 : %CTRL_K = &hF20B %ALT_L = &h26F1 : %CTRL_L = &hF20C %ALT_M = &h32F1 : %CTRL_M = &hF20D %ALT_N = &h31F1 : %CTRL_N = &hF20E %ALT_O = &h18F1 : %CTRL_O = &hF20F %ALT_P = &h19F1 : %CTRL_P = &hF210 %ALT_Q = &h10F1 : %CTRL_Q = &hF211 %ALT_R = &h13F1 : %CTRL_R = &hF212 %ALT_S = &h1FF1 : %CTRL_S = &hF213 %ALT_T = &h14F1 : %CTRL_T = &hF214 %ALT_U = &h16F1 : %CTRL_U = &hF215 %ALT_V = &h2FF1 : %CTRL_V = &hF216 %ALT_W = &h11F1 : %CTRL_W = &hF217 %ALT_X = &h2DF1 : %CTRL_X = &hF218 %ALT_Y = &h15F1 : %CTRL_Y = &hF219 %ALT_Z = &h2CF1 : %CTRL_Z = &hF21A %ALT_MINUS = &hF12D : %CTRL_MINUS = &h0CF2 %ALT_F_SLASH = &hF12F : %CTRL_F_SLASH = &h35F2 %ALT_B_SLASH = &hF15C : %CTRL_B_SLASH = &hF21C %ALT_EQUAL = &hF13D : %CTRL_EQUAL = &h0DF2 %ALT_TILDE = &hF160 : %CTRL_TILDE = &h29F2 %ALT_QUOTE = &hF127 : %CTRL_QUOTE = &h28F2 %ALT_COLON = &hF13B : %CTRL_COLON = &h27F2 %ALT_COMMA = &hF12C : %CTRL_COMMA = &h33F2 %ALT_PERIOD = &hF12E : %CTRL_PERIOD = &h34F2 %ALT_L_BRACKET = &hF15B : %CTRL_L_BRACKET = &hF21B %ALT_R_BRACKET = &hF15D : %CTRL_R_BRACKET = &hF21D %ALT_GRAY_PLUS = &hF12B : %CTRL_GRAY_PLUS = &h4EF2 %CTRL_GRAY_MINUS= &h4AF2 %CTRL_GRAY_STAR = &h37F2 %GRAY5_key = &h4C00 : %ALT_GRAY5 = &h4CF1 : %CTRL_GRAY5 = &H4CF2 'QUIT ============ Used by LoadData DECLARE FUNCTION fKeyValue (BYVAL K AS INTEGER) AS INTEGER ' '------------------------------------------------------------------------------- ' FUNCTION fKeyValue (BYVAL K AS INTEGER) EXPORT AS INTEGER DIM I AS LOCAL INTEGER SELECT CASE (INSHIFT AND &b011111) ' check for , , or CASE = 0 : GOTO ExitFunction ' CASE = 16 : IF (K>31) AND (K<256) THEN _ ' SHIFT GOTO ExitFunction ' I = &h00F4 ' CASE < 04 : I = &h00F1 ' ALT CASE < 16 : I = &h00F2 ' CTRL END SELECT ' ' IF (K < 256) THEN SHIFT LEFT I, 8 ' move flag into most significant nibble K = ( K OR I ) ' insert the flag into the return value ExitFunction: FUNCTION = K END FUNCTION #IF 1 '------------------------------------------------------------------------------- '----------- TEST CODE --------------------------------------------------------- '------------------------------------------------------------------------------- $FileSpec = "KeyValue.bas" ' file name of this file DECLARE FUNCTION fGetKey () AS INTEGER DECLARE SUB LoadData (V() AS INTEGER,D() AS STRING,SEG Last AS LONG) FUNCTION PBMAIN () DIM D(202) AS LOCAL STRING DIM H AS LOCAL LONG DIM K AS LOCAL INTEGER DIM Last AS LOCAL LONG DIM T(202) AS LOCAL LONG DIM Tested AS LOCAL LONG DIM V(202) AS LOCAL INTEGER DIM X AS LOCAL LONG COLOR 0, 15 : CLS LoadData V(), D(), Last IF Last = 0 THEN PRINT "Can't find "; $FileSpec; " in $FileSpec" WAITKEY$ EXIT FUNCTION END IF PRINT "Following is a list of 'doubles' (if any)" PRINT STRING$(41,45) FOR H = 2 TO Last INCR X IF V(X) = V(H) THEN PRINT D(H); " returns the same as "; D(X) NEXT PRINT STRING$(41,45) PRINT "Press keys to se the return value. Those values that are" PRINT "not represented by integer constants will be shown in hex." PRINT FORMAT$(Last,"There are a total of ### keys to be tested.") PRINT "Press to quit." PRINT COLOR 1, 15 DO K = fGetKey ARRAY SCAN V(1) FOR Last, = K, TO H IF H = 0 THEN PRINT "&h"; HEX$(K,4); IF (K > 0) AND (K < 256) THEN PRINT CHR$(32,34,K,34); ELSE PRINT D(H); IF T(H) = 0 THEN T(H) = 1 INCR Tested X = Last - Tested PRINT TAB(20); FORMAT$(X,"There are ### keys left to be tested."); END IF END IF PRINT LOOP UNTIL K = &h001B COLOR 0, 15 PRINT PRINT "DONE....." WAITKEY$ END FUNCTION ' '------------------------------------------------------------------------------ ' FUNCTION fGetKey () AS INTEGER DIM K AS LOCAL INTEGER WHILE NOT INSTAT : WEND ' wait for something to happen ' IF MOUSESTAT THEN EXIT FUNCTION ' if a mouse event then RETRUN ZERO ' K = CVI(INKEY$) ' read/covert the incoming key press ' FUNCTION = fKeyValue(K) ' convert to DOS key value END FUNCTION ' '------------------------------------------------------------------------------- ' SUB LoadData (V() AS INTEGER, D() AS STRING, SEG Last AS LONG) DIM L AS LOCAL STRING DIM P AS LOCAL STRING DIM X AS LOCAL LONG DIM Y AS LOCAL LONG DIM Z AS LOCAL LONG Z = UBOUND(V(1)) Last = 0 IF LEN(DIR$($FileSpec)) = 0 THEN EXIT SUB OPEN $FileSpec FOR INPUT AS #1 DO LINE INPUT #1, L LOOP UNTIL LEFT$(L,6) = "'START" DO LINE INPUT #1, L IF LEFT$(L,5) = "'QUIT" THEN EXIT LOOP L = TRIM$(L) FOR X = 1 TO PARSECOUNT(L,":") P = TRIM$(PARSE$(L,":",X)) IF ASC(P) <> 37 THEN ITERATE INCR Last D(Last) = TRIM$(PARSE$(P,"=",1)) V(Last) = VAL(TRIM$(PARSE$(P,"=",2))) IF Last = Z THEN Z = Z + 10 REDIM PRESERVE V(Z) REDIM PRESERVE D(Z) END IF NEXT LOOP CLOSE #1 ARRAY SORT V(1) FOR Last, TAGARRAY D() END SUB #ENDIF