In my projects, I often use modifier keys (SHIFT, CTRL, …) to offer the user additional features. For example, I use buttons to go to the previous or next record. This behavior changes, when the CTRL key is pressed. Now, the buttons redirect to the first or last record.
A function from my Custom Function Vault makes it easy to work with modifier keys. It creates variables, representing the state of the modifier keys:
get.modifierKeys()
FileMaker’s Contribution
The built-in function Get( ActiveModifierKeys ) will return a number, representing the active modifier keys. It is actual a calculated sum of the values representing each modifier key being pressed.
- Shift = 1
- Caps Lock = 2
- Ctrl (Windows) / Control (Mac OS) = 4
- Alt (Windows) / Option (Mac OS) = 8
- Command (Mac OS) = 16
If all modifier keys are being pressed (on a Mac), the function will return 31 (1+2+4+8+16).
The Problem
For my project, I often need to know, whether a specific modifier key is being pressed. I have to extract this information from the value that represents a combination of the state of all modifier keys. To extract the current state for the SHIFT key is easy. If the value is odd, the SHIFT key is being pressed.
Extracting the other information is not so easy. The values for the modifier keys correspond with binary values, from SHIFT = 20 to Command = 24. I have to check, whether a specific bit is set or not. Unfortunately, FileMaker does not offer binary functions like bit testing or bit shifting.
The Solution
Of course, there is a solution to the problem. Using a custom function, I will create global variables, representing the current state of the modifier keys.
I already mentioned a way to extract the value for the SHIFT key. There is no function Odd( ) in FileMaker, but that is easily composed. A value is odd, when it is not evenly divisible by 2. And FileMaker has a function to check exactly that:
Odd( value ) = Mod( value; 2 )
The result will either be 0 or 1, the remainder of the division by 2. Accidentally, these are the numeric representation of FALSE and TRUE in FileMaker. I can use the result to create a global variable. Applied to the function Get( ActiveModifierKeys ), it informs about the state of the SHIFT key.
To retrieve the other values, I have to shift the bits in the modifier keys value one position to the right. This is done with an integer division by 2. Again, FileMaker has a function for that:
ShiftRight( value ) = DIV( value; 2 )
Now, the former second bit is in the first (far right) position. I can check this bit using the odd function, right shift again, and repeat the procedure until all bits are tested.
CF get.modifierKeys
Now, putting it all together.
Let( [ _modKeys = Get( ActiveModifierKeys ); _returnValue = _modKeys; $$SHIFT = Mod( _modKeys; 2 ); _modKeys = Div( _modKeys; 2 ); $$CAPS = Mod( _modKeys; 2 ); _modKeys = Div( _modKeys; 2 ); $$CTRL = Mod( _modKeys; 2 ); _modKeys = Div( _modKeys; 2 ); $$ALT = Mod( _modKeys; 2 ); _modKeys = Div( _modKeys; 2 ); $$CMD = Mod( _modKeys; 2 ) ]; _returnValue )
The custom function expects no function parameter. It gets its value from the FileMaker function Get( ActiveModifierKeys ). The five far most right bits are tested, representing the five possible modifier keys. The function returns the same numeric value as the FileMaker function, but in the process, it creates five global variables $$SHIFT, $$CAPS, $$CTRL, $$ALT, and $$CMD. These variables are logical representation of the state of the modifier keys.
In the Field
Now it is easy to check the state of a specific key. First, call the custom function, then check the different variables:
Set Variable [$modifierKeys; Value: get.modifierKeys] If [$$CTRL;] … do something … ElseIf [$$SHIFT]; … do something else … End If
Now go and key-control your database.
chivalry
Here’s how I solve the same issue, which you might be interested in.
First of all, I use a custom function written by Mikhail Edoshin, BitIsSet( Number, Bit ).
// Returns whether or not the binary bit in the given number is turned on. i.e., ~BitIsSet( 16; 5 ) would return True as 16 is 10000 in
// binary. Similarly, ~BitIsSet( 18; 2 ) would also return True as 18 is 10010 in binary. This calculation is thanks to Mikhail Edoshin
// and is found at http://edoshin.skeletonkey.com/2005/11/custom_function.html.
//
// Written by Mikhail Edoshin
Mod( Div( Number; 2 ^ ( Bit – 1 ) ); 2 )
Next I have a set of custom functions that are simply constants, such as kModifierShift:
// Used as a named constant. Should have a value such that ModifierKeyIsActive( kModifierShift ) = True when the shift key is held down.
1
kModifierCapsLock is 2, kModifierControl is 3, etc, each value corresponding to the bit tha
t’s true from GetActiveModifierKeys.
Finally, I have ModifierKeyIsActive( ModifierKey ), which accepts one of those constant custom functions:
// The ModifierKey parameter should be an integer between 1 and 5. These can be accessed via the kModifier* custom function
// constants. Returns whether or not the given modifier key, as specified by it’s power of two equivalent, is held down at the time
// the function is evaluated.
//
// EXTERNAL REQUIREMENTS: The BitIsSet custom function. Easiest to use with the presence of the kModifier* custom function
// constants.
//
// Written by Charles Ross
BitIsSet( Get( ActiveModifierKeys ); ModifierKey )
With the above, I get code that looks quite nice: If[ ModifierKeyIsActive( kModifierShift )]