'===========================================================================
' 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 <CTRL>F-01, <ALT>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 <ALT>,
<CTRL> or <SHIFT> 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 <CTRL> and <ALT> 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 <SHIFT>, <CTRL>, or
           <ALT> 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: <CTRL>J and
           <CTRL>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 <CTRL><ALT><ENTER>,
           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 <SHIFT>, <CTRL>, or <ALT>
    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 <ESC> 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
