W$KEYBUF: Theory and Practice
Appendix I of the ACUCOBOL-85 and ACUCOBOL-GT® manuals describes the
library routines that are built into the runtime system. These routines are special
functions that are activated via the "CALL" verb. Since they perform functions outside
of standard COBOL, these routines have not been introduced as extensions to the
language.
With each new version of the compiler, Acucobol has increased the number of library
routines that it maintains. With the release of ACUCOBOL-GT Version 3.1, there are
now 40 routines in all (see Table 1).
In this article, we describe the use of one particular library routine: W$KEYBUF.
This routine manages the keyboard input buffer and allows you to record character
sequences that can be reproduced to simulate data input from the user. The character
sequences can be stored in temporary variables or files. By storing characters in
the keyboard input buffer, you can alleviate repetitive work for end users and,
at the same time, increase their productivity. Some Acucorp tools, such as AcuEdit--the
new editor written totally in ACUCOBOL-85--employ a CALL to W$KEYBUF to manage macro
commands.
The W$KEYBUF routine can be useful in real business situations. For example, accounting
programs can often be repetitive for operators, because they commonly require long
series of similar data to be entered. Registration or invoicing applications also
require operators to enter sequences of similar or identical data. With W$KEYBUF,
operators can simply press a single key to enter information, saving them from a
repetitive job.
In this article, we examine the call's syntax and functions, and we illustrate a
practical application, which we hope will be useful to you. But first, it is important
that you understand the keyboard buffer and how it is managed.
The Keyboard Buffer
The keyboard buffer is a memory area containing a representation of the keys the
user has pressed. It can be updated with new data when the program is not executing
an ACCEPT.
Let's try to compile and execute the source code in Table 2. After clearing the
screen, the program waits for three seconds (C$SLEEP) and then executes the ACCEPT.
If you press any key in the meantime, its content is returned in the acknowledgment
field.
When executing an ACCEPT instruction, the Acucobol runtime checks to see if the
keyboard's buffer contains any characters. If so, the runtime transfers the characters
from the buffer to the variable specified in the acknowledgment field. Since W$KEYBUF
lets you add or eliminate characters in this buffer, you need to know the format
of the character sequences in the buffer.
Buffer Format
The memory area of the keyboard buffer contains alphanumeric information. It can
be assimilated to a COBOL variable, defined as PIC X( ), where the parentheses contain
the keys' codes. These codes can be either alphanumeric characters or function keys.
Alphanumeric codes, normally used to write text, are represented in their natural
format. Function key codes are represented according to this convention:
{Function-key}
where Function-key is the code used in the UNIX a_termcap file to represent
the key. For example, <F1> and <F2> are represented by the "k1" and
"k2" codes between curly braces ({k1}, {k2}).
During reproduction, when W$KEYBUF encounters curly braces, it emulates the typing
of the corresponding function key. This allows you to pick out special keys that
return control sequences. For example, if you want to input a company's full address,
and you want confirmation with the <F1> key, you can type the following. (Note:
the <Enter> key is written as {^M}.)
Acucorp, Inc. {^M} 7950 Silverton Avenue {^M}
San Diego {^M} {k1}
You can also emulate the calls to "W$MENU," the library routine managing the pop-up
menus, with {M#}, where # corresponds to the menu choice desired. To represent the
curly brace character itself, type "{{".
W$KEYBUF Syntax
The W$KEYBUF routine is activated via the CALL verb, according to the following
syntax:
CALL "W$KEYBUF" USING OP-CODE, parameters.
where OP-CODE indicates the kind of operation to execute, and the parameters
depend on the selected op-code.
OP-CODE "1"
Op-code "1" allows you to add characters to the keyboard input buffer, simulating
data input. All the characters inserted in the buffer are then attributed to the
variables in subsequent ACCEPT commands. For example:
CALL "W$KEYBUF" USING "1", "TEST {^M}".
attributes the content of "TEST" to the subsequent ACCEPT variable and stops the
ACCEPT execution. (Remember that {^M} means <Enter>.) The character sequence
to add to the keyboard input buffer can be specified either as a constant, such
as in the above example, or an alphanumeric variable. The above example would have
worked in the same way if the call had been done like this:
CALL "W$KEYBUF" USING "1", BUFF.
where BUFF is an alphanumeric variable (PIC X), which has been assigned the "TEST
{^M}" value. Moreover, you can include a third optional parameter that specifies
the number of characters you really want to add to the buffer. For example, the
call:
CALL "W$KEYBUF" USING "1", "TEST {^M}", "3".
adds "TES" to the keyboard buffer--that is, the first three characters of the "TEST"
string. Please note that characters added this way are placed before any character
typed by the user. Now try to execute the program shown in Table 3. While the program
executes the "C$SLEEP", type the "A" key three times. The result of the "X" variable,
when passed to the ACCEPT, is "TESTAAA" and not "AAATEST", as you might have expected.
This behavior keeps the user from interfering with the pre-programmed input sequence.
OP-CODE "2"
Op-code "2" is the same as op-code "1", except that the characters are added at
the beginning of the input buffer--before any others that already exist--instead
of at the end. If you execute the program shown in Table 4, you can see that the
"X" variable content assumes the "VATES" value, since the second string of "VA"
characters has been inserted in the buffer using operation code "2".
OP-CODE "3"
Op-code "3" is used to clear the keyboard buffer, and it doesn't need any parameters.
Note that op-code "3" empties the buffer used by W$KEYBUF, not the one used by the
operating system. (In other words, the regular keyboard characters are unaffected
by this operation.) Try to execute the program shown in Table 5. While the program
executes C$SLEEP, type any character sequence. The "W$KEYBUF USING 3" call excludes
the effects of the former call; so this time, no content is assigned to the "X"
variable.
OP-CODE "4"
As mentioned earlier, one of W$KEYBUF's functions is to record work sessions. To
activate recording, use operation code "4". Immediately following this call, every
keystroke is memorized in a variable specified as a second (mandatory) call parameter.
The recording remains in effect until deactivated with op-code "5". An optional
third parameter, numerical, can set a limit to the number of characters that can
be recorded. If this parameter is missing, the limit is defined by the width of
the alphanumeric variable.
This code turns off the recording mechanism put in action with op-code "4". When
you make this call, the RETURN-CODE implicit variable contains the number of characters
typed in, and therefore, the number contained in the memory variable or file set
that contains them (see op-code "7").
OP-CODE "6"
This code lets you know if the recording mode is active or not. The result is put
in the implicit variable RETURN-CODE. If the value is "1", the recording mechanism
is turned on. If it's "0", the mechanism is turned off.
OP-CODE "7"
Sometimes it is not sufficient to record keystrokes in one variable--for instance,
if the recording is exceedingly long, or if the maximum length is not known. In
these situations, operation code "7" can be used. Op-code "7" lets you specify a
sequential file as a recording buffer. The sequential filename must be specified
as the second call parameter. If the file can be created and the pathname is valid,
the RETURN-CODE implicit variable is set to value "0" (zero). If the file cannot
be created, then it is set to "1". If the specified file already exists, it is deleted.
This way, the recording duration can be virtually unlimited.
OP-CODE "8"
Operation code "8" is identical to op-code "7", except that the file is appended
to if it already exists.
OP-CODE "9"
Op-code "9" is used to play back a session previously recorded in a file. The pathname
of the file to be played back is passed as the second parameter. RETURN-CODE is
set to "0" if the file is opened successfully; otherwise it is set to "1".
Alternatively, you can initiate playback from the command line by passing the "k"
parameter to the runtime, followed by the file pathname. The command syntax is as
follows:
runcblprogram-name -k file-recording
New OP-CODES with Release 2.4.2
Prior to Version 2.4.2 of ACUCOBOL-85, the options run by the W$KEYBUF routine occurred
without any speed control, so simulated keystrokes were not very realistic. The
screen became full at the maximum speed allowed by the hardware, without letting
the user understand what was happening. Moreover, the user could not interrupt the
reproduction, temporarily or definitively. Version 2.4.2 answers such concerns;
the new op-codes that it introduced are described below.
OP-CODE "10"
This new op-code lets you define a delay between the reproduction of one character
and the next. The delay, in hundredths of a second, is passed as the second parameter.
For example, to set a delay of a quarter of a second, execute the following call:
CALL "W$KEYBUF" USING 10, 25.
This then becomes your default delay. By inserting additional commands in the reproduced
memory buffer, you can then introduce pauses of different durations. Following is
a list of possible options:
- {p#} the reproduction pauses for # hundredths of a second (lower case p, followed
by pound sign)
- {P#} the reproduction pauses for # seconds (capital P, followed
by pound sign)
- {P} the reproduction pauses for one second (capital P)
For example, the following character string inserted in a file or play-back variable
will cause a delay of 1-1/2 seconds after reproducing the "Acucobol" string and
before ending the ACCEPT input with the <Enter> key:
"Acucobol {p150}{^M}"
OP-CODE "11"
As mentioned before, some calls specify keys that can be interpreted only by reproductions
with pauses. Op-code "11" allows you to define a key that stops buffer playback
for an indefinite period of time. Playback resumes when the user presses any other
key. For example, if you want thekey to stop playback, you should make the call:
CALL "W$KEYBUF" USING 11, 27.
where "27" is the ASCII code of the <Esc> key. Please note that this function
can be linked only with keys that return a simple ASCII code and not with complex
functions keys.
OP-CODE "12"
Op-code "12" is defined in the same way as op-code "11". It allows you to define
a key that stops buffer playback, and returns the program to interactive mode.
OP-CODE "13"
Op-code "13" works the same as op-code "12", except that the specified key turns
off the procedure running the runtime, in addition to interrupting the recording
reproduction. Please note the following:
- Upon encountering an op-code "13", the runtime displays a "Killed by user" message.
If you don't want to read this message, then standard output should be assigned
with the "-e" option on the line of command that initiated the runtime.
- This
mode should not be used when the program is executed with the "-s" option (safe
mode). In this case, the key pressed to interrupt the program accomplishes two things:
it ends execution and then re-starts the ACCEPT command that turned it on. This
causes a de-synchronization between the playback buffer and the requests of the
reproduced program, with unforseeable results. Therefore, it is not safe to use
this mode in presence of the "-s" option.
Deleting Extra Characters from the Buffer
When you record key sequences in a variable or sequential file, the function key
chosen to deactivate the recording mechanism is also recorded in the destination
buffer. This happens unless you record a program from the beginning to the end,
or interrupt the recording after a certain time. Since the deactivation keystroke
is of no interest to you, you may want to eliminate it from the buffer. To do this,
we suggest two simple methods.
Let's suppose that, in both cases, function key <F1> is used to deactivate
the recording. Since is represented as "{K1}" in UNIX a_termcap, you need to eliminate
the last four characters of the variable or file.
If your buffer is stored in a variable, you should set the recording end by calling
the W$KEYBUF function with op-code "5". Since RETURN-CODE contains the number of
inserted characters, it is very simple to eliminate the last four by executing the
command:
move spaces to record_buf (return-code - 3 : )
If you use a file to store the recording, the problem becomes a bit more complex.
The memorized file is in binary sequential format and the re-writing operation cannot
be used for this kind of file. You should read the entire file, write it to another
one, and eliminate the last four characters there. This, of course, can be quite
long and complex. It would be much easier to open the sequential file as a relative
file with a record length of one byte. This way, it is easy to move to the end of
the file and delete the last four characters with READ PREVIOUS. (See Table 6.)
Another way to handle the problem is to synchronize the keyboard buffer reproduced
with W$KEYBUF and the program. You need to make the keys' sequences coincide with
the ACCEPT instructions, since the W$KEYBUF cannot produce any control. It is not
safe to execute a reproduction starting from an ACCEPT different from the one at
which you started the recording, because this can produce unforseeable results.
Example
A practical example showing W$KEYBUF calls and parameters may be very useful. We
created a tool that allows you to use self-running demos. With this tool you can
interactively record sessions of your programs, interrupt them, display information
on the screen, or visualize message boxes, etc.
This program is available to you on the Acucobol BBS. Please, download it and try
it! Together with the program, you will find some useful instructions and the Version
2.4.2 MS-DOS runtime, since this Acucobol release takes advantage of new calls,
illustrated in a section of this article.
Please note that this program has just been completed: so, your comments, suggestions,
or notes on possible problems are welcome. Feel free to contact an Acucobol representative
at 800-COBOL85 or 619-689-4500, or send e-mail to info@acucorp.com.
Table 1: Acucobol Library Routines
|
Call Name
|
Function
|
|
C$CALLERR
|
It gives back the reason why a CALL didn't work
|
|
C$CHAIN
|
It ends the program execution and calls any other program available on the computer.
|
|
C$CHDIR
|
It changes the actual work directory.
|
|
C$COPY
|
It copies a file.
|
|
C$FILEINFO
|
It gives back system information about a file.
|
|
C$FILESYS
|
It gives back information about the file system.
|
|
C$JUSTIFY
|
It justifies a string of characters on the right, on the left, or in the center.
|
|
C$KEYMAP
|
It saves and restores the keyboard configuration.
|
|
C$LOCALPRINT
|
It addresses the printing output on a local printer.
|
|
C$MEMCPY
|
It copies bytes between two memory locations.
|
|
C$NARG
|
It gives back the parameters passed to the actual program.
|
|
C$OPENSAVEBOX
|
It creates an OPEN or SAVE AS dialog box.
|
|
C$PARAMSIZE
|
It returns the number of bytes passed by the caller for a particular parameter.
|
|
C$RECOVER
|
It recovers a file from the transaction log file.
|
|
C$RERR
|
It gives back an extended error code.
|
|
C$RERRNAME
|
It returns the name of the last file used for I/O.
|
|
C$RUN
|
It gives back the actual length of a parameter passed to a program.
|
|
C$SLEEP
|
It executes a program pause without seizing the CPU.
|
|
C$TOUPPER/C$TOLOWER
|
It changes a character string into upper/lower characters.
|
|
LIB$GET_SYMBOL
|
Specific routine for VMS.
|
|
LIB$SET_SYMBOL
|
Specific routine for VMS.
|
|
M$ALLOC
|
It allocates an area of dynamic memory.
|
|
M$FREE
|
It releases a block of memory previously allocated.
|
|
M$GET
|
It reads data from a memory block.
|
|
M$PUT
|
It memorizes data in a memory block.
|
|
RENAME
|
It recalls a file.
|
|
SYSTEM
|
It executes calls to the operating system.
|
|
W$BITMAP
|
It visualizes images in bitmap format.
|
|
W$FONT
|
It provides support for font selection.
|
|
W$FORGET
|
It restarts the Acucobol terminal manager.
|
|
W$GETC
|
It gives back the pressed key code.
|
|
$WINHELP
|
It calls Windows help.
|
|
W$KEYBUF
|
See this article.
|
|
W$MENU
|
It manages a pop-up menu.
|
|
W$MOUSE
|
It manages the mouse.
|
|
W$PALETTE
|
It defines the color palette used.
|
|
W$TEXTSIZE
|
It measures the height and width of a string of text.
|
|
WIN$PRINTER
|
It configures the Windows print spooler.
|
|
WIN$VERSION
|
It returns information for Windows and Windows NT.
|
Table 2
identification division.
program-id. wkbuf1.
******************************
environment division.
configuration section.
data division.
******************************
working-storage section.
******************************
01 x
pic x(20).
******************************
procedure division.
******************************
ini.
display window erase.
call "c$sleep" using "3".
accept x at 1010 prompt.
stop run.
Table 3
identification division.
program-id. wkbuf2.
******************************
*
environment division.
configuration section.
data division.
******************************
working-storage section.
******************************
01 x
pic x(20).
******************************
procedure division.
******************************
ini.
display window erase.
call "c$sleep" using "3".
call "w$keybuf" using "1" "PRO".
call "w$keybuf" using "1" "VA".
accept x at 1010 prompt.
stop run.
Table 4
identification division.
program-id. wkbuf3.
******************************
*
environment division.
configuration section.
data division.
******************************
working-storage section.
******************************
01 x
pic x(20).
******************************
procedure division.
******************************
ini.
display window erase.
call "c$sleep" using "3".
call "w$keybuf" using "1" "PRO".
call "w$keybuf" using "2" "VA".
accept x at 1010 prompt.
stop run.
Table 5
identification division.
program-id. wkbuf4.
******************************
*
environment division.configuration section.data division.
******************************
working-storage section.
******************************
01 x
pic x(20).
******************************
procedure division.
******************************
ini.
display window erase.
call "c$sleep" using "3".
call "w$keybuf" using "1" "PROVA".
call "w$keybuf" using "3".
accept x at 1010 prompt.
stop run.
Table 6
identification division.
program-id. wkbuf5.
Installation. Acucorp, Inc.
******************************
environment division.
configuration section.
special-names.
decimal-point is comma.
input-output section.
file-control.
select temp_work_file
assign to random file_name
organization relative
access dynamic
relative key work_key.
******************************
data division.
file section.
fd temp_work_file.
01 work_record pic x.
******************************
working-storage section.
******************************
01 work_key pic 9(5).
01 file_name pic x(80).
******************************
procedure division using file_name.
******************************
swapmrc.
open i-o temp_work_file.
move 99999 to work_key.
start temp_work_file key is not > work_key.
perform 4 times
read temp_work_file previous record
delete temp_work_file record
end-perform
close temp_work_file.
stop run.