Redefining Keys in Advanced Revelation
Some applications may require actions to be mapped to keystrokes other than the ones provided by Advanced Revelation. For example, an application may require that TCL be invoked with the [F9] key and records be saved by pressing [F5].
An application may also require the definition of new keystrokes. Your program may have to initiate a global update of a file whenever the user presses [Alt-U], for example.
Techniques for accomplishing these objectives will be explored here.
Keystroke Definition in Advanced Revelation
The ASCII character code (scan code) for each keystroke defined in Advanced Revelation is stored in a field in one of four system variables:
@PRIORITY.INT Priority interrupt keystrokes
@MOVE.KEYS Cursor movement keystrokes
@EDIT.KEYS Editor keystrokes
@INT.CONST Window keystrokes
The meaning of each position of the arrays is documented in the EDIT.KEYS record of the INCLUDE file.
Advanced Revelation processes check each input character against one or more of the arrays, depending on the process. If the character is found, the appropriate subroutine is called. The R/BASIC code is similar to:
(…)
INPUT.CHAR(C)
LOCATE C IN @EDIT.KEYS SETTING POS THEN
ON POS GOSUB ….
END ELSE
(…)
END
(…)
Redefining Keystrokes
Keystrokes for existing Advanced Revelation functionality can be redefined either on the fly or permanently.
Note: Whether the change is permanent or temporary, it is global to Advanced Revelation. That is, if you change the keystroke for Help, that change will be in effect for all processes, not just the one that made the change.
Changing keystrokes on the fly is temporary and affects only the workstation on which you made the changes. Changes are lost when you exit Advanced Revelation or execute a RESET.
Change keystrokes temporarily by changing the appropriate field in the appropriate system variable. For example, to turn off the TCL key ([F5]) you simple null field 2 of @PRIORITY.INT:
@PRIORITY.INT<2> = ""
If, for some reason, you want to exit windows using an exclamation point instead of [Esc], replace the scan code in @INT.CONST<1> with the scan code for an exclamation point:
@INT.CONST<1> = CHAR(33)
A program to determine the scan codes for all keystroke combinations is given in Figure 1.
To change a keystroke permanently, update a record called KEY.DEFINITIONS in the SYSTEM file. These changes affect all users of this copy of Advanced Revelation.
Warning! Before making any changes to KEY.DEFINITIONS, back up the original. That way, if your experiments go awry, you return to a known quantity. For extra security, back up your entire Advanced Revelation system.
KEY.DEFINITIONS is a record mark (@RM) delimited dynamic array. This record is parsed into the system variables as part of the initialization process. Assuming that the record has been read into the variable KEY_REC, the R/BASIC code looks something like:
@PRIORITY.INT = FIELD(KEY_REC, @RM, 1)
@MOVE.KEYS = FIELD(KEY_REC, @RM, 2)
@EDIT.KEYS = FIELD(KEY_REC, @RM, 3)
@INT.CONST = FIELD(KEY_REC, @RM, 4)
Figure 2 is a program that demonstrates a technique that might be used to update KEY.DEFINITIONS.
Adding New Functions
The above techniques allow you to redefine the keystrokes that activate existing Advanced Revelation functions. You can also add new functions to Advanced Revelation. For example, you may have a calendar program that you want to access anytime you press [Alt-7], which is a keystroke not defined by Advanced Revelation.
All keystrokes in Advanced Revelation pass through the system subroutine INPUT.CHAR. Some keystrokes have priority over all other keystrokes, for example, TCL ([F5]) and General Help ([Ctrl-F2]). These are the priority interrupt keys (@PRIORITY.INT).
Among the @PRIORITY.INT keys are the user defined macro keys. If INPUT.CHAR finds a macro keystroke, it goes to @MACRO.KEYS to find the code and command associated with the keystroke. @MACRO.KEYS consists of three fields. Field one is a multivalued list of codes, field two is a multivalued list of commands, and field three contains the name of the macro set.
To add new functions to Advanced Revelation, just add the keystroke scan code to @PRIORITY.INT and the code and command to @MACRO.KEYS. In effect adding another macro to the system. For example, to add the calendar program mentioned above, we need a program that does the following:
(…)
* scan code for [Alt-7]
SCANCODE = CHAR(0):CHAR(126)
@PRIORITY.INT = @PRIORITY.INT : @FM : SCANCODE
@MACRO.KEYS<1,6> = 'S'
@MACRO.KEYS<2,6> = 'CALENDAR'
(…)
Note that the code and command sequence must start at value 6. This is because the first 5 positions are reserved for macros, even if macros are not used.
Note: In order to use this technique, the user must be able to execute macros. That is, @ENVIRON.SET<39> must be true.
Variations
You can redefine Advanced Revelation system keystrokes to execute custom processes. For example, if you wanted to call up the calendar program with a [Ctrl-C] (which cuts a line in the editor), you would put the scan code for [Ctrl-C] in @PRIORITY.INT instead of the code for [Alt-7]. Note, however, that this permanently changes the meaning of [Ctrl-C]. Unless you redefine position 13 of @EDIT.KEYS, you will have no way to break a line while in the editor. This is because the definition of [Ctrl-C] in @PRIORITY.INT takes precedence over the original definition of [Ctrl-C] in @EDIT.KEYS.
To change the definition of @PRIORITY.INT keystrokes, put the scan code at the end of @PRIORITY.INT, as above, and null the normal position. For example, the code to have [F5] call up the calendar would look like this:
@PRIORITY.INT = @PRIORITY.INT : @FM : @PRIORITY.INT<2>
@PRIORITY.INT<2> =
@MACRO.KEYS<1,6> = 'S'
@MACRO.KEYS<2,6> = 'CALENDAR"
Figure 3 shows how to redefine a keystroke for the duration of a single window or process. Used in a window, the ON portion of the code would be called from the Pre-Initialize process, while the OFF portion would be called from the Post-Application process.
Whether the change is permanent or just for the duration of a window, you can add as many new functions or redefine as many keystrokes as you like.
Figure 1
* A program to determine the scan code for any keystroke.
!
DECLARE SUBROUTINE MSG
*
EQU ESC$ TO CHAR(27)
MESSAGE = 'Determine ASCII sequence of a keystroke.'
MESSAGE := '|Press any key ( <Esc> to quit )'
IMAGE =
MSG(MESSAGE,'UB', IMAGE,) ; * message up till DB call
*
ECHO OFF
LOOP
LOOP
INPUT KEY, -1
UNTIL LEN(KEY) = 1 OR LEN(KEY) = 2
REPEAT
UNTIL KEY = ESC$
CHAR1 = SEQ( KEY[1,1] )
CHAR2 = SEQ( KEY[2,1] )
IF CHAR2 THEN STRING = CHAR1:',':CHAR2 ELSE STRING = CHAR1
*
MESSAGE = 'ASCII sequence ='
MESSAGE := '|':STRING
MSG(MESSAGE,
,,
)
REPEAT
*
MSG(,'DB',IMAGE,
)
ECHO ON
STOP
Figure 2
* A program that demonstrates how to redefine keystrokes permanently in
* Advanced Revelation.
*
* This program must be executed from the SYSPROG account.
*
DECLARE SUBROUTINE FSMSG
OPEN SYSTEM TO FILE_SYSTEM ELSE
FSMSG()
STOP
END
READ KEY_REC FROM FILE_SYSTEM, 'KEY.DEFINITIONS' THEN
READ BACKUP FROM FILE_SYSTEM, 'KEY.DEFINITIONS.ORIG' THEN
*
* The original version is on disk, make a backup of the current
* version before any further changes are made.
*
WRITE KEY_REC ON FILE_SYSTEM,'KEY.DEFINITIONS.BAK' ELSE
FSMSG()
END
END ELSE
*
* Make a backup of the original version of KEY.DEFINITIONS.
*
WRITE KEY_REC ON FILE_SYSTEM,'KEY.DEFINITIONS.ORIG' ELSE
FSMSG()
END
END
PRIORITY = FIELD(KEY_REC, @RM, 1)
MOVE = FIELD(KEY_REC, @RM, 2)
EDIT = FIELD(KEY_REC, @RM, 3)
INT = FIELD(KEY_REC, @RM, 4)
*
* Code to redefine the variables would go here.
*
* Write out the changes.
KEY_REC = PRIORITY : @RM : MOVE : @RM : EDIT : @RM : INT
WRITE KEY_REC ON FILE_SYSTEM,'KEY.DEFINITIONS' ELSE
FSMSG()
END
END ELSE
FSMSG()
END
STOP
Figure 3
SUBROUTINE TRAP_KEYS (INBASKET)
$INSERT INCLUDE, EDIT.KEYS
*
* A subroutine to dynamically change @PRIORITY.INT.
*
KEYSTROKE = \003B\ ;* Scan code for [F1].
IF INBASKET = 'ON' THEN
GOSUB ON
END ELSE
GOSUB OFF
END
RETURN
ON:
@PRIORITY.INT = @PRIORITY.INT : @FM : KEYSTROKE
*
* Add the code and command to @MACRO.KEYS. Remember to account for codes
* and commands that are already there.
*
LOCATE KEYSTROKE IN @PRIORITY.INT USING @FM SETTING POS THEN
MACRO_LOCATION = POS - MACROS.START$ + 1
@MACRO.KEYS<1,MACRO_LOCATION> = 'HL' ;* The code goes here.
@MACRO.KEYS<2,MACRO_LOCATION> = 'HELLO' ;* The command goes here.
END
RETURN
OFF:
*
* Remove just our keystroke and our code and command. Don't disturb anything
* else.
*
LOCATE KEYSTROKE IN @PRIORITY.INT USING @FM SETTING POS THEN @PRIORITY.INT = DELETE(@PRIORITY.INT, POS, 0, 0)
MACRO_LOCATION = POS - MACROS.START$ + 1
@MACRO.KEYS = DELETE(@MACRO.KEYS, 1, MACRO_LOCATION, 0)
@MACRO.KEYS = DELETE(@MACRO.KEYS, 2, MACRO_LOCATION, 0)
END
RETURN