by Dr. Peter Wayne
| When A5v4 comes out, it's going to have a number of nifty features.
This article introduces the OnKey event, new to Alpha Five
version 4, and shows how to use it to program a progressive search
field. Warning: This article is based on a beta release of Alpha Five version 4. Although I believe the points discussed here will apply to the final version, there is a small chance that the OnKey event will be modified by Alpha Software before the release. |
Wouldn't you like to start typing in a "Find by Key" dialog, and have Alpha Five update the display as you type the individual keys? That is, as you type "Softquad", the form will first display the words beginning with "s", then those starting "so", then "sof", and so on. Right now, all Alpha Five can do is wait until you have finished typing and pressed {ENTER} or {F9} before beginning a search.
Well, in Alpha Five version 3 you're stuck, because there is no way to intercept individual keystrokes. But in version 4 there is a new event, the OnKey event, that reacts to each keystroke. We can use the OnKey event to program a more dynamic Find by Key form.
This is the form that we will create. Note how as the invisible "user" types in softq the browse scrolls down to softquad, and then as our invisible user types backspaces the browse scrolls up to the top:

Figure 1. Example of scrolling Find
We're going to use the OnKey event, which is a new form-level event. The OnKey event fires under 3 circumstances:
So pressing a key results in 2 or 3 calls to the OnKey event: 2 if the key is briefly touched, 3 if the key is held down for a while. We can determine which activity is triggering the OnKey event by inspecting the value of the special variable, a_user.key.event, which can have the value of "up", "down", or "repeat".
The a_user.key.value variable contains the key that initiated the OnKey event. For example, if the user presses "b", then a_user.key.value contains "b" also. If the user presses a nonprinting key, then a_user.key.value contains the same text that Alpha Five uses in the sys_send_keys() function: "{BACKSPACE}" if the backspace key is pressed, "{F5}" if function key F5 is pressed, "{CONTROL}" and then "c" if the user presses Ctrl-C.
Another special OnKey variable is a_user.key.handled. If your script sets this value to .t., then Alpha Five knows that your script has handled the key, and the key is "swallowed" by your script and never reaches the form. If you set a_user.key.handled to .f., then your script passes the key action on to the form.
| OnKey special variable | Behavior |
|---|---|
| a_user.key.event | can be either "down", "up", or "repeat" |
| a_user.key.value | contains the key that was pressed. For regular keys, contains the value. For control keys, use the same format as in sys_send_keys(), e.g., "{%F5}" is Alt-F5 |
| a_user.key.handled | set to .f. if you want your script to pass the key value on to
Alpha Five set to .t. if you want your script to "swallow" the key |
For this article, we'll use one simple table, keystrokes.dbf, with a single field, name, defined as Character, width 16, and indexed in ascending order on name. I entered a number of names into the keystrokes table - I wasn't particularly choosy about the words I entered, I just had to populate the table with something!
We start to create our form by placing a Session-level variable,
choice, on a blank form. From the Drag-Drop list drag "New
variable" to the form, and call it choice:
Fig. 2. Choose New Variable from the Drag-Drop list.
Place the choice variable on the form:
Fig. 3. Place the choice variable on the blank form.
From the form designer, select Form, Variables, and set the level of the choice variable to Session:

Fig. 4. Make choice into a session-level variable.
Finally, add a browse based on the keystrokes table to the form. Accept the default name of browse1 which Alpha Five assigns to this browse. Save the form - I called mine the keystrokes form.
As letters are entered into the choice field, we want to
resynch browse1 to the current contents of choice. I
thought I would use 2 variables, tempstr and posn, to
record the current search string (= choice) and the length of the
search string as letters are added or subtracted. The OnActivate
script for the form initializes these variables:
Script 1. OnActivate script for the form.
The work of interpreting the key entries is done by the OnKey script for the form:
dim shared tempstr as c
dim shared posn as n
dim shared choice as c
dim up as c
dim repeat as c
table.current().index_primary_put("name")
if this.active()="choice" then
select
case a_user.key.event="down"
if left(a_user.key.value,1)="{" then
' it's a control key or backspace or function key
select
case a_user.key.value="{BACKSPACE}"
if posn>0 then
posn=posn-1
tempstr=iif(posn=0,"",left(tempstr,posn))
a_user.key.handled=.t.
end if
case else
' pass through
a_user.key.handled=.f.
end select
else
posn=posn+1
tempstr=tempstr+a_user.key.value
a_user.key.handled=.t.
end if
case a_user.key.event="up"
up=a_user.key.value
a_user.key.handled=.t.
case a_user.key.event="repeat"
repeat=a_user.key.value
a_user.key.handled=.t.
end select
table.current().fetch_find(tempstr)
browse1.refresh()
choice=tempstr
choice.refresh()
end if
Script 2. OnKey script for the form
Note that in Script 2, our script "swallows" the up and repeat key events. The only nonprinting character that Script 2 understands is the {BACKSPACE} key.
In a real application, you might now want to use the OnRowDblClick method of the browse to launch a form or report based on the selected record found in browse1. If you want to get more sophisticated, you might try to see if you can amend Script 2 to recognize and behave appropriately when handed the {INS}, {DEL}, {LEFT} and {RIGHT} keys. If you succeed, let me know, and I'll post it as an addendum to this article!
9/5/98 - pkw
Don't forget, we need your feedback to make this site better!