| The Farber Consulting Group, Inc. |
Tel:
(516) 796-6545 / Fax: (516) 796-1273
E-Mail Me: doron@dfarber.com
Our Web Site: http://www.dfarber.com
This following article was published in FoxTalk on June 1994
Uncontrolled ON KEY LABEL (OKL)
handler recursion is one of the most common problems with using
OKLs assignments. This is
caused by the user holding down a key so that it repeats
continuously, resulting in the dreaded error 103, "Do
Nesting Too Deep."
This error is actually more prevalent on slower hardware
but can happen on faster equipment as well depending ran the
users habits,
I have found a way to prevent such recursions.dependably
Here's an example. I have a
general procedure called GoRecNo that handles all record movement
in my applications. I use OKLs to
define the shortcut keys for the record movement
buttonsprevious, next, last and first - because I use
control keys such as Ctrl-N
and Ctrl-P as shortcuts for those buttons. This rules out using
hot key definitions in the button prompt strings.
Some of my users want to be able
to hold these shortcut keys down continuously , then release the
key when they reach the record.
When they tried this, they were getting the recursion problem.
The first keystroke called my GoRecNo procedure, and sometime
before GoRecNo was finished executing the second keystroke woke
up another call to GoRecNo, and so on. The way FoxPro handles
this internally, two DO levels are actually used up for each
keystroke, and you quickly reach FoxPro's limit for nested
program calls.
Interestingly, this was happening
even though I had performed a PUSH KEY CLEAR at the start of
GoRecNo (which in theory should
disable all ON KEY LABEL assignments), and then did a POP KEY at
the end of the routine to restore the OKL assignments. The reason
is that OKL events can and do occur between the time of the
initial keypress and the moment PUSH KEY CLEAR is executed, even
if it's
the first statement in your handler.
The solution proved to be simple
and fairly clean. When you start FoxPro, SET TYPEAHEAD defaults
to 20, meaning that the user can type
up to 20 characters ahead. Many developers have this set at the
maximum setting of 128. However, if you SET TYPEAHEAD TO 0 as the
first order of business in your OKL handler, you prevent further
typeahead and therefore prevent OKL recursion. I found that
although this
prevents recursion, I would still get one unwanted repeat when I
released the key I was holding down. I found that CLEAR TYPEAHEAD
solved this problem.
Here is a model for a recursion-proof OKL handler
PROCEDURE OKhRandler
PARAMETER cAction
SET TYPEAHEAD TO 0
PUSH KEY CLEAR
* Call the appropriate service routine.
&cAction
CLEAR TYPEAHEAD
SET TYPEAHEAD TO 128
POP KEY
RETURN
Page 2
If an defined OKLs go through this
handler, you avoid having to add this "recursion proofing
code in every OKL handler you write.
Here's a sample OKL setup usurp this routine:
ON KEY LABEL CTRL+P DO OKLHandler WITH [DO GoRecNo WITH 'Previous']
OKL Handler is very generic and
simplistic, but it can be adapted or optimized in many ways. For
instance, if none of your
OKLs need to have arguments passed to them, you could change the
macro expansion, &cAction, to DO (cAction) and
modify the ON KEY LABEL calls accordingly.
You could replace &cAction
with a CASE statement that processes the action specified in
cAction; this would allow more
flexibility in how the handler is called. Or, if your application
uses a central event handler attached to your Foundation READ,
you can make just the "Recursion proofing" code part of
the CASE in your event handler that processes key events.
Here is a model for an event handler for a recusrion-proof OKL
DO WHILE m.Terminate
DO CASE
CASE m.MenuEvnt
Your Code .........
CASE m.HotKeyEvnt
SET TYPEAHEAD TO 0
PUSH KEY CLEAR
IF m.NowKeyEvnt==""
DO (m.NowProc)
ELSE
DO (m.NowProc) WITH m.NowKeyEvnt
ENDIF
CLEAR TYPEAHEAD
SET TYPEAHEAD TO 20
POP KEY
CASE m.ButtEvnt
Your Code .........
OTHERWISE
READ VALID RetVal()
ENDCASE
ENDDO
That’s how I implemented it in my own work.
Actually, I find that PUSH/POP KEY
statements don't even seem necessary with this scheme, but I
leave them in "Just in Case"
FoxPro (and users) can be unpredictable at time. The placement of
CLEAR TYPEAHEAD after performing your OKL actions is
important; it eats any keystrokes the user may input during the
execution of the routine and which would then be released by
resetting the TYPEAHEAD buffer to a non-zero value.
Also, you should adjust the SET TYPEAHEAD TO 128 statement to whatever TYPEAHEAD setting you use in your applications.