Dec 232017
 
A simple unit to display function key labels and create corresponding mouse hot spots on the screen. TP 5.5+ source code included.
File PFKEYS.ZIP from The Programmer’s Corner in
Category Pascal Source Code
A simple unit to display function key labels and create corresponding mouse hot spots on the screen. TP 5.5+ source code included.
File Name File Size Zip Size Zip Type
PFDEFINE.INC 948 331 deflated
PFKEYS.DOC 15500 4926 deflated
PFKEYS.PAS 4146 1176 deflated
PFKTEST.EXE 19712 11347 deflated
PFKTEST.PAS 5031 1661 deflated
TPMOUSE.PAS 20245 4901 deflated

Download File PFKEYS.ZIP Here

Contents of the PFKEYS.DOC file


{***************************************************************}
{* PFKEYS.DOC *}
{* *}
{* Gordon M. Cressman *}
{* Research Triangle Institute *}
{* *}
{* CompuServe 75410,2451 *}
{* Internet gmc%[email protected] *}
{* *}
{* 11-02-1989 *}
{* *}
{***************************************************************}


Packing List

PFKEYS.DOC.....This file.
PFKEYS.PAS.....A unit for displaying function key labels with
mouse hot boxes.
PFDEFINE.INC...An include file of compiler defines for
PFKEYS.PAS.
TPMOUSE.PAS....TPMOUSE modified for mouse hot boxes.
PFKTEST.PAS....A test program demonstrating the use of
PFKEYS.PAS


Introduction

The following documentation describes a simple unit to display
function key labels and create corresponding mouse hot spots on
the screen. This allows a user to point to a function key
label with the mouse cursor and press a mouse button to execute
the corresponding function.

PFKEYS.PAS depends on Mike McIntyre's addition of Mouse hot
boxes to the TPMOUSE unit. Mike's modified TPMOUSE.PAS is
included in this package.

PFKEYS.PAS also requires that the mouse cursor be free to move
over the entire screen area. TPPICK, TPHELP, and several other
Turbo Professional units automatically restrict mouse cursor
movement to their own window areas. This file also describes
simple modifications to those units that correct this problem.

This version of PFKEYS displays one row of six function key
labels. This just happens to be the arrangement I needed for
my own program. You can change this to suit your own needs
quite easily by modifying the procedure DispFKeys. For
example, your program design may need two rows of six function
key labels.

Function key information is maintained in a stack structure so
it is possible to "pop" the current function keys from the
stack and restore the previously active set without knowing
what that set is beforehand. I use the same technique in my
program to display a one-line help message for the current
context at the bottom of the screen. A stack is a natural
structure for layered user interfaces and ensures that the
proper set of function keys is always displayed for each
context.

Note that the mouse host spots (implemented by Mike McIntyre)
are also stored in a stack structure. However, since this
entire structure is scanned whenever the specified mouse button
is pressed, the stack must be handled carefully. Care must be
taken to "pop" inactive areas from the stack and to avoid
duplicate areas. PushFKeys pushes a matching hot box onto this
stack for each nonempty function key label, then records the
number of nonempty labels in the function key information
record. PopFKeys uses this number to "pop" *the same number of
hot boxes from the stack*. Calls to PushFKeys and PopFKeys
must be paired to avoid having two sets of function key label
hot boxes active at once.

You can push other mouse hot boxes onto the stack by calling
MouseHotBox directly. However, it is important to remove the
added hot boxes by calling PopMouseHotBox the correct number of
times before calling PopFKeys. The general rule to follow is
that hot boxes must be "popped" in the reverse order from that
in which they were "pushed."

The following sequence is typical:

{Activate a new set of labels}
PushFKeys(@MyFKeys);
....
{Activate a hot box for a Yes/No dialog box that can by}
{toggled by pressing the [Space] bar.}
MouseHotBox(XLow, YLow, XHigh, YHigh, LeftButton, $0020);
...
{Release the dialog box hot box}
PopMouseHotBox;
...
{Release the current set of labels and reactivate the previous}
{set of labels.}
PopFKeys;

DispFKeys is the procedure responsible for displaying the
function key labels and setting up the mouse hot boxes.
DispFKeys is called by PushFKeys and PopFKeys automatically.
In programs that do not have nested user interfaces, you may
want to call DispFKeys directly to avoid the function key
information stack handling.

The function key labels are displayed on FKeyRow, which is a
typed constant initialized to 25. The color used for the
labels is set by the typed constant FKeyAtt, which is
initialized to $70. The typed constant FKeyButton determines
which mouse button must be pressed to activate the function key
labels. It is initialized to LeftButton.

The function key labels are displayed from left to right. This
makes long labels possible provided that one or more labels to
the right are omitted to prevent them from being overwritten.
Note that empty labels do not produce mouse hot spots. Also,
the function key information record allows any key scancode to
be associated with any function key label. Some of these
principles are shown in the DisplayHelp example that follows.


Using PFKEYS

The necessary information records can be setup as typed
constants such as the following:

const
{IBM PC keyboard scan codes for special keys}
F1 = $3B00;
F2 = $3C00;
F3 = $3D00;
F4 = $3E00;
F5 = $3F00;
F6 = $4000;
F7 = $4100;
F8 = $4200;
F9 = $4300;
F10 = $4400;
AF1 = $6800; {Alt+F1}

NormFKeys : FKeyInfoRecd = (
FKNum : 0; {value is not important here}
FKLabel : ('F1-Help','F2-Select','','F4-Clear','F5-Search',
'F10-Quit');
FKey : (F1,F2,F3,F4,F5,F10));

HelpFKeys : FKeyInfoRecd = (
FKNum : 0;
FKLabel : ('F1-Index','Alt+F1-Previous Help Topic','','','',
'F10-Continue');
FKey : (F1,AF1,F3,F4,F5,F10));

NoFKeys : FKeyInfoRecd = (
FKNum : 0;
FKLabel : ('','','','','','');
FKey : (F1,AF1,F3,F4,F5,F10));

Note that HelpFKeys above demonstrates the use of a long
function key label followed by one or more empty labels. It
also shows that any keyboard scancode ([Alt]+[F1] in this case)
can be returned when the specified mouse button is pressed and
the mouse cursor is on the corresponding label.

The following is an example of a DisplayHelp procedure that
uses the PFKEYS procedures:

{$F+}
procedure DisplayHelp(UnitCode : Byte; IdPtr : Pointer;
HelpIndex : Word);
{-Display context sensitive help}
begin
{Disable user-added pick list commands}
if AddPickCommand(0, 1, $20, 0) then; {[Space]}
{...etc.}
if AddPickCommand(PKSSelect, 1, $0D, 0) then; {[Enter]}

case UnitCode of
HelpForPick:{TPPICK}
HelpIndex:=PickHelpIndex; {Adjust help index}
else; {make no adjustment}
end;{case}

{Display matching function key labels}
PushFKeys(@HelpFKeys);

if not ShowHelp(Help,HelpIndex)then
RingBell;

{Restore previous function key labels}
PopFKeys;

{Re-enable user-added pick list commands}
if AddPickCommand(PKSUser1, 1, $20, 0) then; {[Space]}
{...etc.}
if AddPickCommand(PKSUser6, 1, $0D, 0) then; {[Enter]}
end; {DisplayHelp}
{$F-}


Modifying TPPICK and TPHELP

The following are notes showing the minor changes you will need
to make to TPPICK and TPHELP to allow free movement of the
mouse cursor over the entire screen. These notes are based on
Turbo Professional Version 5.06, but should also be useful for
later versions at least up to 5.08. Now for the changes.

{---------------}
TPPICK.PAS (5.06)

procedure PickBar
...
{about line 853 of the file}
{$IFDEF UseMouse}
if MouseInstalled then
SaveMouseOn := MouseCursorOn;
if PickMouseEnabled then begin
{Save mouse position and window}
{$IFNDEF UseFullMouseWindow}
SaveMX := MouseWhereX+MouseXLo; {Absolute}
SaveMY := MouseWhereY+MouseYLo;
SaveMXL := MouseXLo+1;
SaveMXH := MouseXHi;
SaveMYL := MouseYLo+1;
SaveMYH := MouseYHi;
{$ENDIF}
SaveWaitFor := WaitForButtonRelease;
WaitForButtonRelease := True;
{PrevSlid := 0;}
HideMouse;
{Set mouse window around the pick list}
if MouseScroll then begin
{Let mouse move into frame}
{$IFNDEF UseFullMouseWindow}
MouseWindow(XL, YL1, XH1, YH1);
{$ENDIF}
{Draw scroll marks}
DrawMouseMarks(W);
{$IFNDEF UseFullMouseWindow}
MouseDefaultXY(MouseXLo+1, MouseYLo+2, SaveMX, SaveMY);
{$ENDIF}
end else begin
{Don't let mouse move into frame}
{$IFNDEF UseFullMouseWindow}
MouseWindow(XL, YL, XH, YH);
MouseDefaultXY(MouseXLo+1, MouseYLo+1, SaveMX, SaveMY);
{$ENDIF}
end;
end;
{$ENDIF}
...
{about line 1088 of the file}
{$IFDEF UseMouse}
if PickMouseEnabled then begin
{Restore mouse state}
{$IFNDEF UseFullMouseWindow}
SaveMX := MouseWhereX+MouseXLo; {Absolute}
SaveMY := MouseWhereY+MouseYLo;
MouseWindow(SaveMXL, SaveMYL, SaveMXH, SaveMYH);
MouseDefaultXY((MouseXLo+MouseXHi) shr 1,
(MouseYLo+MouseYHi) shr 1,
SaveMX, SaveMY);
{$ENDIF}
WaitForButtonRelease := SaveWaitFor;
end;
if SaveMouseOn then
ShowMouse;
{$ENDIF}
...
end {PickBar}


{-------------}
TPHELP.PAS 5.06

...
{about line 1040 of the file}
procedure UpdateMouseFrame(Help : HelpPtr;
var HelpState : HelpStateRec);
{-Set mouse window coordinates and scroll bar}
begin
with Help^, HelpState, WindowP(W)^, Draw do begin
MouseScrollNow := MouseScroll and (Pcnt > 1);
if MouseScrollNow then begin
{Let mouse move into frame}
{$IFNDEF UseFullMouseWindow}
MouseWindow(XL1, YL1, XH1, YH1);
{$ENDIF}
{Draw scroll marks}
FastWrite(MouseUpMark, YL1, XH1, FAttr);
FastWrite(MouseDnMark, YH1, XH1, FAttr);
ShowMoreNow := False;
Lslid := 0;
end else
begin
{Don't let mouse move into frame}
{$IFNDEF UseFullMouseWindow}
MouseWindow(XL1, YL1, XH, YH);
{$ENDIF}
end;
{Draw previous help mark}
FastWrite(MousePrevMark, YL1, XL1, FAttr);
end;
end;
{$ENDIF}
...
function ShowHelpPrim(Help : HelpPtr;
...
{about line 1377 of the file}
{$IFDEF UseMouse}
if HelpMouseEnabled then
with WindowP(W)^, Draw do begin
{Save current mouse parameters}
SaveMX := MouseWhereX;
SaveMY := MouseWhereY;
SaveMXL := MouseXLo+1;
SaveMXH := MouseXHi;
SaveMYL := MouseYLo+1;
SaveMYH := MouseYHi;
SaveWaitFor := WaitForButtonRelease;
{Set new mouse parameters}
WaitForButtonRelease := True;
UpdateMouseFrame(Help, HelpState);
{Position to top left corner of window}
{$IFNDEF UseFullMouseWindow}
MouseGoToXY(1, 1);
{$ENDIF}
end;
{$ENDIF}
...

{about line 1672 of the file}
{$IFDEF UseMouse}
if HelpMouseEnabled then begin
{Restore mouse position and window}
{$IFNDEF UseFullMouseWindow}
MouseWindow(SaveMXL, SaveMYL, SaveMXH, SaveMYH);
MouseGoToXY(SaveMX, SaveMY);
{$ENDIF}
WaitForButtonRelease := SaveWaitFor;
end;
if SaveMouseOn then
ShowMouse;
{$ENDIF}

{--------------}


Conditional Compilation

Note that the new conditional compilation symbol
"UseFullMouseWindow" must be defined when you recompile your
modified TPPICK and TPHELP units. This is easily done by
adding the following statement to the TPDEFINE.INC file that
comes with Turbo Professional:

{$DEFINE UseFullMouseWindow}

Make sure that you recompile TPPICK and TPHELP after defining
this symbol. To drop out the new sections of code, just add a
period (".") before the dollar sign in the above statement and
recompile the units. This will restore TPPICK and TPHELP to
their previous mouse cursor handling habits.

Mike McIntyre's changes to TPMOUSE follow the same pattern.
All of his code changes depend on the conditional compilation
symbol "EnableMouseHotBoxes". You can define this symbol by
adding the following statement to the TPDEFINE.INC file:

{$DEFINE EnableMouseHotBoxes}

Make sure to recompile the modified TPMOUSE unit after defining
this symbol. As with my changes to TPPICK and TPHELP, you can
disable mouse hot boxes by adding a period before the dollar
sign in the above statement and then recompiling TPMOUSE.

The unit PFKEYS also checks for the symbol
"EnableMouseHotBoxes" as well as the "UseMouse" symbol already
included in TPDEFINE.INC. As distributed, PFKEYS.PAS includes
its own PFDEFINE.INC file that includes the necessary
definitions. You may prefer to change PFKEYS.PAS so that it
includes TPDEFINE.INC instead. This will centralize your
control over these features and will eliminate the need for
PFDEFINE.INC.


PFKTEST.PAS

I have included a short example program, PFKTEST,PAS, that
demonstrates PFKEYS.PAS. This example depends on the included
modified version of TPMOUSE.PAS, but it does not use TPPICK or
TPHELP.

PFKTEST displays a simple query window in the middle of the
screen. It asks a silly question and demands a Yes or No
answer. You can press [Y] for Yes, [N] for No, or [Space] to
toggle the answer. You can also toggle the answer by moving
the mouse cursor into the Query box and pressing the left mouse
button. Pressing the right mouse button registers your
response and clears the screen, just as if you had pressed
[Enter], [Esc], or [F10].

The Query procedure is an ugly variation of one I've use in
my programs. I've modified it for this example so that you can
also answer "Yes" by pressing [F2] and "No" by pressing [F3].
[F2], [F3] and [F10] appear on the function key line at the
bottom of the screen. Test the mouse handling by moving the
mouse cursor to any of the function key labels and pressing the
left mouse button. Move the mouse to empty regions of the
display and press mouse buttons at random, just to make sure
that only the desired areas are "hot." You never know.

Note that PFKTEST is highly simplified to avoid obscuring the
main points. For example, it assumes the display is in
80x[25,43,50] text mode and it uses only monochrome display
attributes.

One other note. If you're using Version 5.0 of Turbo Pascal
you'll need to change line 161 of PFKTEST.PAS so that it reads:

Integer(MouseRt),

This type cast is necessary because the value of MouseRt
exceeds the maximum value for an integer. Turbo Pascal
5.0 does not a case selector to be of type Word.

-Gordon


 December 23, 2017  Add comments

Leave a Reply