Creating a keyboard accelerator table from a resource

by Jon Ripley, August 2007

The normal method of checking for keyboard hot keys is to use INKEY with a negative argument:

          SYS "GetForegroundWindow" TO hWnd%
          IF hWnd% = @hwnd% THEN
            IF INKEY-2 THEN
              IF INKEY-86 THEN PROCnew  :REM Ctrl+N
              IF INKEY-55 THEN PROCopen :REM Ctrl+O
            ENDIF
            REM ...
          ENDIF

However there may be circumstances where you want to use an accelerator table that has already been designed and its template is contained as a resource within a DLL or EXE file. In that case you can create the accelerator table in your program using the resource data. The code example below uses the accelerator table from the resource data for the BB4W IDE (in BBCWIN.EXE or BBCWDEM.EXE):

        REM Acquire handle to BBCWIN.EXE or BBCWDEM.EXE
        SYS "GetModuleHandle", 0 TO hmod%
 
        REM Load the accelerator table
        SYS "LoadAccelerators", hmod%, "BBCWIN" TO hAccel%
        SYS "CopyAcceleratorTable", hAccel%, 0, 0 TO nAccel%
        DIM ACCEL{(nAccel% - 1) fVirt&, _&, key{l&,h&}, cmd{l&,h&}}
        SYS "CopyAcceleratorTableA", hAccel%, ACCEL{(0)}, nAccel%
 
        REM Virtual key to -ve INKEY conversion table
        DIM vTable(255)
        vTable() = 0, -10, -12,   0, -11,   0,   0,   0, -48, -97,   0,   0,   0, -74,   0,   0, \
        \         -1,  -2,  -3,   0, -65,   0,   0,   0,   0,   0,   0,-113,   0,   0,   0,   0, \
        \        -99, -64, -79,-106, -63, -26, -58,-122, -42,   0,   0,   0, -33, -62, -90,   0, \
        \        -40, -49, -50, -18, -19, -20, -53, -37, -22, -39,   0,   0,   0,   0,   0,   0, \
        \          0, -66,-101, -83, -51, -35, -68, -84, -85, -38, -70, -71, -87,-102, -86, -55, \
        \        -56, -17, -52, -82, -36, -54,-100, -34, -67, -69, -98,   0,   0,   0,   0,   0, \
        \       -107,-108,-125,-109,-123,-124, -27, -28, -43, -44, -92, -59, -61, -60, -77, -75, \
        \       -114,-115,-116, -21,-117,-118, -23,-119,-120, -31, -29, -30,   0,   0,   0,   0, \
        \          0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, \
        \        -78, -32,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, \
        \         -4,  -7,  -5,  -8,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, \
        \          0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, \
        \          0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, \
        \          0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, \
        \          0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, \
        \          0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0
 
        ON CLOSE SYS "DestroyAcceleratorTable", hAccel%:QUIT
 
        REPEAT
          click% = 0
          ON SYS click% = @wparam%:RETURN
 
          REPEAT
            REM Scan through accelerator table looking for matches
            SYS "GetForegroundWindow" TO hWnd%
            IF hWnd% = @hwnd% THEN
              FOR i% = 0 TO nAccel% - 1
                IF -(4*INKEY-3 + 2*INKEY-2 + INKEY-1) = (ACCEL{(i%)}.fVirt&>>2) THEN
                  IF INKEYvTable(ACCEL{(i%)}.key.l&) THEN
                    IF ACCEL{(i%)}._& = 0 THEN
                      SYS "SendMessage", @hwnd%, 273, ACCEL{(i%)}.cmd.l&+256*ACCEL{(i%)}.cmd.h&, 0
                      ACCEL{(i%)}._& = 1
                    ENDIF
                  ELSE
                    ACCEL{(i%)}._& = 0
                  ENDIF
                ENDIF
              NEXT i%
            ENDIF
 
            WAIT 1
          UNTIL click%
 
          REM Handle events...
          PRINT "click% = ";click%
        UNTIL FALSE

Naturally this code will only run within the BB4W IDE, because if compiled to an executable file the accelerator table resource data will not be present.

To load an accelerator table from a different file (for example a DLL) then replace the call to “GetModuleHandle” with a call to “LoadLibrary” as follows:

        SYS "LoadLibrary", "EXAMPLE.DLL" TO hmod%

When the program ends all accelerator tables must be destroyed using code similar to the following. Here hAccel% is the handle to the accelerator table:

        SYS "DestroyAcceleratorTable", hAccel%