by Michael Smith, via <editor@iso-ezine.com>

Decidedly Pro-Choice
Give your users options with Status(CurrentModifierKeys)
PLATFORM: Mac/Win
Requires FileMaker Pro 4.0

FileMaker 4.0 gave us a new function, Status(CurrentModifierKeys). This function tells us which modifier keys have been pressed. This can be particularly useful in scripts. In our bonus file, Status(CurrentModifierKeys) has been used to allow the user of the database to change the behavior of scripts based on which keys they hold down. This article explains how Status(CurrentModiferKeys) was used in the bonus file and explores some possible uses of the new function.

Let the Customer Choose: Bonus!

The accompanying bonus file shows one possible use for the Status(CurrentModifierKeys) function. The solution is a simple address list database. Our data is shown in a list view with field labels on top of the columns. Those field labels are buttons. Click them and the data sorts according to the label you clicked. But, it doesn't stop there. Hold down the Option key on the Macintosh or the Alt key on Windows and the data sorts according to the label you clicked--in descending order. There's more. Hold down the Shift key or depress the Caps Lock key. Now, the sort dialog appears with the sort information available for change. Note that the sort dialog displays the same sort order that would occur if you had not pressed the Shift or Caps Lock key. There's still more. Hold down the Shift/Caps Lock key and also press the Option/Alt key. Now, we get the sort dialog with the descending sort information.

How'd You Do That?

I'll try to approach this from two angles. I'll explain how the solution works and I'll also try to give you some tools to approach one of these of your own. At first look, checking modifier keys appears to be simple. Wade in a little deaper and you quickly become mired waste deep in muck. I'll see if I can explain why before I show you one way out.

Rather than storing the names of the modifier keys that were pressed, FileMaker stores numbers:

Shift    1
CapsLock    2
Ctrl/control    4
Alt/option    8
Command    16 (note: Mac only)

So, why the cryptic numbering scheme? Its actually quite an elegant way to store the information--particularly when multiple modifier keys have been pressed. The modifier keys are additive. If both the Shift and CapsLock keys are down, the result is 1 and 2 which is 3. Those of you who have worked with file permissions on UNIX systems will be familiar with this system.

Its a beautiful, elegant system. But, the trouble comes when you start trying to unpack the information stored in that number to use it. How do you know that the Caps Lock key has been pressed when the Shift, Control, Option and Command keys have been pressed as well. In that situation, Status(CurrentModifierKeys) yields 31. You can't use a simple calculation:

If(StatusCurrentModifierKeys)=2

One Way Out

    There are many ways to skin a cat. I'm sure there are more elegant approaches to this puzzle than mine. One reason I chose this approach though is that it is fairly easy to follow. Sometimes clarity is worth more than elegance. Examining an excerpt from the script will show you what I mean.

Set Field [MODKEYS, "Status(CurrentModifierKeys)"]
Sort [Restore, No dialog]
Set Field ["Command", """"]
...
Set Field ["Shift", """"]
If ["MODKEYS=0"]
Exit Script
End If
Set Field ["Command","If(Int(MODKEYS/16) = 1, "true", "false")"]
Set Field ["MODKEYS","If(Int(MODKEYS/16) = 1, MODKEYS-16, MODKEYS)"]
Set Field ["OptionAlt","If(Int(MODKEYS/8) = 1, "true", "false")"]
Set Field ["MODKEYS","If(Int(MODKEYS/8) = 1, MODKEYS-8, MODKEYS)"]
Set Field ["Control","If(Int(MODKEYS/4) = 1, "true", "false")"]
Set Field ["MODKEYS","If(Int(MODKEYS/4) = 1, MODKEYS-4, MODKEYS)"]
Set Field ["CapsLock","If(Int(MODKEYS/2) = 1, "true", "false")"]
Set Field ["MODKEYS","If(Int(MODKEYS/2) = 1, MODKEYS-2, MODKEYS)"]
Set Field ["Shift","If(MODKEYS = 1, "true", "false")"]

We begin by grabbing the value from Status(CurrentModifierKeys) and stuffing it in a Global field for later access and manipulation. Next, we sort the database. This is what we want to happen if no modifier keys are pressed; this is the default action. The next group of Set Field steps initializes the script, emptying needed fields.

We begin the evaluation of modifier keys by checking to see if MODKEYS is 0. If so, we simply exit the script. The sort action we just performed is all that happens. Putting this first in the script and allowing for a quick exit is kind. Only users who are playing with the modifier keys are burdened with the time it takes the script to evaluate them.

Next, we begin to unpack the number in MODKEYS. We first check to see if the number is once divisible by 16. If so, we know that the number "contains" 16 and that the Command key was pressed. The script sets the field Command to true. We also know that we want to remove 16 from that number so that we can evaluate whether the smaller numbers are "contained" in MODKEYS without the later number masking it. For example, if MODKEYS was 20, we know that it contains 16 but its tough to build a test to see if it contains 2. So, the way I have chosen to deal with this is to simply remove the larger numbers from the picture as we determine they are part of MODKEYS.

As we move through the script, we pull out one number after another and set Global fields to true or false based on whether MODKEYS contains the number representing that modifier key. Once this section of the script is complete, we have a short list of modifiers keys paired with true/false results. Now its much easier to build the If statements to control the behavior of the script.

Sign Post Up Ahead

From this point on, the script is a pretty straightforward application of If statements.

If ["If(OptionAlt="true", 1, 0)"]
Perform Script [Sub-scripts, "Sort by Name Descending']
Exit Script
End If
If[If(Shift="true", 1, 0) or If(CapsLock="true", 1, 0)]
Sort [Restore]
End If

Whenever the Option or Alt key has been pressed, we want to go to another script which handles that scenario. In that script, we deal with the case where the Shift or CapsLock key has been pressed as well. I've chosen Option/Alt as the fork in the road because only one Restore value can be stored in a single script. In this script, we've got Sort with the Restore option used twice. This works because its the same sort both times--the dialog is just shown once and not the other. The script which handles the Option/Alt scenario is the same except that Sort has descending order stored with it.

How Do I Know When I'm There?

Perhaps the most difficult things about this solution is deciding what you want it to do when and then making sure it does it. One thing that helped me was to make lists. First, I made a list of all the things I wanted to happen and which option keys were associated with that.

A. No keys: Sort by Name, ascending
B. Shift/CapsLock: Sort by Name, with dialog
C. Option/Alt: Sort by Name, descending
D. Shift/CapsLock, Option/Alt: Sort by Name, descending, with dialog

Next, I worked up the If logic described in the section just above. Basically, you've got four things that could happen and you need to figure out how to arrange the If statements to get there. This is always an iterative process for me. The most frustrating thing about building this solution file was the checking to make sure the Ifs were handling all the cases as I expected. After several frustrating attempts, I finally made myself a list--in FileMaker no less. It is the accompanying bonus file EXTRA.FP3. Basically, it provides a list of all the possible modifier key combinations along with the expected action and a checkbox to mark whether or not it worked.

Y/N    0
Y/N    1    1    Shift
Y/N    2    2    Caps Lock
Y/N    3    2,1    Shift,Caps Lock

Every time I would make a change to the script, I would run through my list again. Whenever I would get to a key combination that wouldn't work, I'd go back and take a look at those If statements again. It was a happy day when I checked every checkbox. I thought the little tool might prove useful to someone else out there so I included it along with the bonus file MODIFY.FP3 which shows the results in action.

We're Just Getting Started

Know that you've seen an example and approach to handling modifier keys, you are probably thinking of ways to use them. There are several that come to mind right away:

* Allow a user to show the Print dialog... or not
* Allow a user to show the Page Setup dialog... or not
* Administration: Opt out of a repeating loop at a known location
* Administration: Set Allow User Abort to On
* Toggle Windows to non-default settings

There are many more. One out-there idea that I've found particularly intriguing is to use this technique on a machine hosting databases using the Web Companion. Press the Caps Lock key to temporarily change the behavior of your web site in instances where -Script, -Script.PreFind, and -Script.PreSort are used. Perhaps you want to occasionally offer something special to people that request a catalog but you want to be able to turn this special offer on and off when you feel like it. You want the offer on, you depress the Caps Lock key. When its pressed, the script that runs using -Script sets flag that this person should get something special. The CDML page that tells them their request for a catalog has been received also tests for that flag and informs them of the valuable prize they just won. Ok, its a silly example but it might just be enough to plant a seed that will sprout a masterpiece. Enjoy!


## END ##