Creating the Accessibility Class
Each area in the Accessibility class (AccessTimeOut, FilterKeys, and so on) uses a particular user-defined type to retrieve and set its information. To retrieve the information, you call SystemParametersInfo with a flag indicating you want to retrieve the information and a data structure in which to place the information. To send the information back to Windows, you repeat the operation, using a flag indicating you want to send information back.
Each group of properties has its own module-level variable and its own procedure (named xxReset) that retrieves a data structure full of information. For example, Listing 9.6 shows the fkReset subroutine, which fills in the module-level fk variable with all the current FilterKeys settings.
Listing 9.6: Use fkReset to Retrieve Current FilterKeys Settings
Private Sub fkReset() ' Retrieve current values. fk.lngSize = Len(fk) Call SystemParametersInfo(SPI_GETFILTERKEYS, _ fk.lngSize, fk, 0) End Sub
The Accessibility class uses a similar technique to save changed values back to Windows, the xxApply set of procedures. Each function in this series returns a Boolean value indicating the success or failure of the procedure. Although the properties in Accessibility do not use the return value, you could easily modify the class so that it handles errors when you set the various parameters. Listing 9.7 shows the fkApply function, similar to the functions used by all the Accessibility class groups.
Listing 9.7: Use fkApply to Set the New FilterKeys Settings
Private Function fkApply() As Boolean fkApply = CBool(SystemParametersInfo(SPI_SETFILTERKEYS, _ fk.lngSize, fk, SPIF_TELLALL)) End Function
What's in those user-defined structures? In general, you'll find two kinds of information there: quantitative values (such as the number of milliseconds to wait before repeating a key) and long integer flag values, containing a series of bits indicating Boolean values. In addition, each structure begins with a long integer containing the size of the structure. For example, the simplest structure, ACCESSTIMEOUT, looks like this:
Private Type ACCESSTIMEOUT lngSize As Long lngFlags As Long lngTimeOutSecs As Long End Type
In this case, code must supply the lngSize value before calling SystemParametersInfo so the function knows how many bytes it has to work with. The lngTimeOutSecs member indicates how many milliseconds to wait before turning off Access-ibility functions. (See the atTimeOutMillisecs Let and Get Property procedures in ACCESSIBILITY.CLS.) The lngFlags member groups a number of Boolean values (up to 32) into the single long integer value. In the case of the ACCESSTIMEOUT structure, there are only three possible values: ATF_AVAILABLE, ATF_TIMEOUTON, and ATF_ONOFFFEEDBACK, all defined in ACCESSIBILITY.CLS. Other structures use a different set of flags, and it's up to the programmer to know which flag coincides with which property of the feature. (This is why the class module makes this so much easier than working with SystemParametersInfo directly—you don't need to dig into each flag individually.)
To work with these Boolean flags, the Accessibility class includes two private procedures, IsBitSet and SetBit, shown in Listing 9.8, that handle the bits for you. To check whether a particular bit flag is set, property procedures can call IsBitSet, providing the flag value and particular bit to check. For example, the following procedure checks whether the FilterKeys click is enabled:
Property Get fkClickOn() As Boolean Call fkReset fkClickOn = IsBitSet(fk.lngFlags, FKF_CLICKON) End Property
To use this property, you might include code like this in your own application:
Dim oAccess As New Accessibility If oAccess.fkClickOn Then ' You know the click is on. End If
To set or clear a particular feature, property procedures can call SetBit, indicating the current flag's value, the particular feature to work with, and the new value. For example, the following procedure controls whether the FilterKeys click is enabled:
Property Let fkClickOn(Value As Boolean) Call SetBit(fk.lngFlags, FKF_CLICKON, Value) Call fkApply End Property
To set this property, you might use code like this:
Dim oAccess As New Accessibility ' Force the sound to be on when FilterKeys is active. oAccess.fkClickOn = True
Listing 9.8: Retrieve, Set and Clear Bits Using These Procedures
Private Function IsBitSet(lngFlags As Long, lngValue As Long) _ As Boolean ' Use logical AND to see if a particular bit within ' a long integer is set. IsBitSet = CBool((lngFlags And lngValue) = lngValue) End Function Private Sub SetBit(lngFlags As Long, lngValue As Long, _ fSet As Boolean) ' Use logical OR to set a particular bit. ' Use logical AND NOT to turn off a particular bit. If fSet Then lngFlags = lngFlags Or lngValue Else lngFlags = lngFlags And Not lngValue End If End Sub
As you can see from Tables 9.3 through 9.8, which list information about the various properties, some of the numeric properties (especially those related to FilterKeys) allow only specific numeric values. These values aren't documented, nor is the behavior when you supply a value that's out of range. Test your application carefully, if you attempt to set these values, and make sure you understand the ramifications of changing these numeric values. For example, setting the fkDelayMSec property to 15 may seem like a good idea, but when you next retrieve the setting, the value will certainly not be the value you think you set—Windows will have set it to 0 instead.