Last modified June 12, 1997.

Ideas and specifications for JAWS for Windows Macro Files,
August 22, 1995,
Ted Henter

We will present ideas/guidelines and examples of what and
how we want the JFW macro files to be written.  This is
important information for anyone developing high-quality
macro files on their own.  These are ideas and suggestions,
not cast in concrete, and suggestions for improvements and
extra features are welcome. Generally speaking, your
application macros should have customized logic for
{Insert+F1} screen-sensitive help, {Insert+H} Hot Keys help,
and {FocusChanged} event macros. In addition, {Text} and
{HighlightedText} event macros may need modifying.  Special
macro keys to read information from the screen are always
welcome.  Further discussion and examples follow.

Insert+F1, THE SCREEN SENSITIVE HELP: This is a very
valuable feature for anyone learning Windows or a new
Windows application.  It should tell the user the type of
window the active cursor in currently in.  This helps him or
her to decide what to do next, and what to do now with the
current control.  A "control" is simply another window,
usually a "child window" that has the focus (or has the
active cursor on it), like an edit field or list box.  Below
is an example of the Insert+F1 macro from our Program
Manager macro file.  It has extra comments added for clarity
and education, the current macro in the PROGMAN.JMS file may
differ due to improvements and additions.  The comments are
preceded by a ";".

MacroBegin {Insert+F1}
var ;start of variable definition area
string TheType,
String TheClass
If (GetCurrentWindow ()) then ;window handle is not 0
; first handle the unknown window types
let TheType = GetWindowType(GetCurrentWindow())
if  (TheType == "Unknown") then
Let TheClass = GetWindowClass (GetCurrentWindow ())
;start of custom or special window recognizing,
; check the class name for special names that you know
; get the special names with the Insert+F1 or Insert+F2 macros
if (TheClass == "PmGroup") then
SayString ("this is a group window in program manager")
SayString ("it contains icons for launching applications")
SayString ("use reeding keys to reed the icons")
SayString ("or the first letter of the name to select it")
SayString ("if the pc cursor is on then press enter to launch")
SayString ("or click the mouse once to select or twice to 
launch")
return ; exit this macro, your work is finished
EndIf

if ((TheClass == "pmhotkey")
|| (TheClass == "Ppmhotkey")) then
SayString ("This is the Short cut key window ")
SayString ("be careful, you will define a short cut key by 
pressing any letter key")
SayString ("or most combinations of letter key and alt control 
or shift.")
SayString ("for more information press F1 for help on Program 
Properties")
SayString ("then tab to Short Cut Keys and press enter")
return ; exit this macro, your are done
EndIf
; add any additional checks here,
; use same syntax and logic as the examples above
; then you will arrive here if the current window was not 
handled above.
; if you have no special code for the current window, 
; use the generic Insert+F2 macro performed below
PerformMacroKey ({Insert+F2}) ; handle other unknown 
window types and classes
else ;the window type was not unknown
PerformMacroKey ({Insert+Control+f1}) ; known types, like 
edit or listbox
endif ; end if type unknown
else ; handle of current window was 0
PerformMacroKey ({Insert+F2}) ;handle = 0
EndIf
MacroEnd

You can see that the above macro uses two other pre-defined 
macros to take care of generic functions that will not change, i.e. 
the known window types like edit, combo box, scroll bar, etc., 
and the totally unknown window types.  The Insert+F2 macro 
simply says the window type name, and then says and spells the 
window class.  This is how you get to know the exact class names
and spellings so you can write the special code that handles it, lie 
the "pmhotkey" window above.  These techniques can be used for 
any window:  instead of just saying and spelling the window
name (big deal) it should recognize it and give the user some 
useful information.

FOCUS CHANGED EVENT MACRO:
The FocusChanged macro is probably the single most important 
macro in the JFW arsenal.  It has the responsibility of speaking 
something appropriate each and every time the focus changes.  
What is a "focus change"?  Every time a new application program 
is launched, every time a new dialog box appears or disappears, 
everytime a menu appears or disappears, or any time you tab from 
one control to another (from the edit field to a list box) that is a 
"focus change" and this macro gets "called" or "performed".
If you look at {FocusChanged} in the DEF_INCL.JMS file you 
will see the default or generic logic for handling this focus 
change.  It first tries to decide if there is a new application, if so 
then speak its name/title.  If there is a new "real window" (one 
that has a title, like a dialog box) then speak it, as long as it is not 
the same as the application window, and it is not the same as the 
window that has the current focus.  Then, no matter what, speak 
the window that does have the current focus.
When you launch a new application, or just alt+tab to bring it into 
focus, you are likely to hear the application name, the "real" 
window name (perhaps the document name or name of the dialog 
box that is active), then the name of the "current window", the 
one that has the focus.  It say all three things since that are "new".
If you bring up the "file open" dialog box in Notepad you will 
only hear the name of the dialog box and the current control/child 
window, "file name edit".  If you then tab to the list box you will 
only hear it say "list box", because neither the application nor the 
dialog box change.  Then if you choose a file name it will say the 
name of the document (the new real window) and the name of the 
current control "edit".
That is just a sample of how the default generic focus changed 
macro works.  What about a special one to handle a special 
situation in your favorite application?  Look towards the bottom 
of the focus changed macro in DEF_INCL.JMS.  It performs the 
Insert+; macro to handle the last step, speaking the current 
control, the one with the focus.  You can easily replace this macro 
in your own macro file designed for your application: any macros 
found in the default macro set are ignored if the same macro is 
found in the application-specific macro set.  That is, to replace the 
default macro simply copy it into your application macro file and
modify it. When you exit that application the default macro is still 
there and gains control again.
Look at the c file for an example of a special Insert+; macro
designed to handle the "short cut key" window in the Program 
Properties dialog (activate it through the File menu or Alt+Enter).  
An example of this macro with extra comments appears below.
MacroBegin {Insert+;}
;this macro is performed by the Default focus Change macro
;no matter what, say the window currently with focus
; below handles all the known window types
SayWindowTypeAndText (GlobalFocusWindow)
; now handle any special window types or classes
; special check for the hot-key section of the Properties dialog 
box,
; a nonstandard window type, it is not spoken by any of the 
above.
if ((GetWindowClass (GlobalFocusWindow) == "pmhotkey")
|| (GetWindowClass (GlobalFocusWindow) == "Ppmhotkey")) 
then
; we are definitely on the hot key or short cut key window,
; first speak the "previous window" that contains the 
label/prompt
SayWindow (GetPriorWindow (GlobalFocusWindow), 0)
; now say the window that contains the short cut key 
definition, if any
SayWindow (GlobalFocusWindow, 0)
; now throw in a special warning for beginners
If (GetVerbosity () == 0) Then
SayString ("be careful or you will define a short cut key by 
pressing any letter key")
SayString ("or most combinations of letter key and alt control 
or shift")
endif ; end if verbosity set to beginner
EndIf ; end if window class = hot key
MacroEnd ; end of Insert+; macro


Some applications will require extensive modifications to the 
focus changed macro, more than can be handled by the Insert+; 
macro.  It can handle only the last step, a special control or 
window that is asking for a special action.  Some applications use 
special, non-standard child windows or dialog boxes, we usually 
call them "real" windows because they have a name or title.  In 
these cases more extensive changes are required, although similar 
logic can be used to provide similar, familiar performance.
The Word for Window macro file, WINWORD.JMS, contains a 
FocusChanged macro with extensive modifications.  First you 
will notice that is checks for a "SDM" real window or dialog box.  
This is a special, non-standard type of dialog box developed by 
Microsoft, bless their hearts.  The SDM window also contains 
special controls, like edit fields and list boxes, that require special 
handling.  Notice the macro functions that start with "SDM" that 
we developed for this situation.
If you read further into this complex macro you will see a special
check for the Spell Checker dialog, so it acts differently when an 
unrecognized word pops up.   In Fact, this macro does nothing at 
all in this case, purposely keeping silent, allowing the {Text} 
event macro and the {Insert+W} macros to do all the talking.  
There is a good reason for this:  This macro only gets performed 
whenever the focus changes, which happens only when you first 
start the spell checker.  After the first word, the focus stays on this 
dialog box, it does not change, so the macro does not get called 
again until spell checking is over.  Obviously this would not do, 
unless you have only one misspelled word in each of your 
documents.  This type of behavior is quite common and must be 
taken into account when developing user friendly behavior 
through the JFW macro system.
Notice that the Insert+W macro actually is designed to read the 
appropriate information from the spell checker dialog box:  It 
reads "Not in Dictionary" followed by the word being spoken and 
spelled.  Then it reads "Change to:" followed by the suggested 
word both spoken and spelled.  If this is too much verbiage then 
you can set Verbosity to Intermediate or Advanced and hear just 
the pertinent data.  This macro works fine after the words have 
appeared on the screen and you muster the energy to press the 
right keys.  But us lazy computer users want it to speak/spell 
automatically, as soon as the words pop up.  We must find a 
"event" that can be used to trigger the Insert+W macro at the 
appropriate time, and only at that time, once per unrecognized 
word.
There are three event macros that might meet our needs.  The 
FocusChanged macro gets called only once, so there would be no 
unwanted repeating of the data.  Unfortunately it gets called only 
for the first word, not subsequent words, so it will not work in 
this case.  The highlighted text event gets called at least once for 
each and every word that is unrecognized by the spell checker.  
But it usually gets called more than once per word with 
unpredictable data being written to the screen.  If we called our 
Insert+W macro each time the Highlighted Text macro got called 
it would cause unwanted repeating of the information.
The {Text} event macro also gets called several times each time a 
new word pops up in the spell checker:  All the un-highlighted 
text that appears on the screen is written through this macro, so it 
must re-write and refresh the text in the document and the text in 
the dialog box many times.  However, the text being written is 
predictable to some extent:  Each time a new unrecognized word 
appears in the spell checker dialog box the phrase "Not in 
Dictionary:" is written to the screen through the Text event 
macro.  Here is the "trigger" we need to perform our macro at
least once and only once for each new unrecognized word.  The 
key phrase may be written to the screen as part of the documents 
text, so we must be careful to trigger only when in the spell 
checker and only when that phrase is being written into the 
appropriate "control" or child window.  The macro logic below, 
copied from the WINWORD.JMS macro file, {Text} event 
macro, handles the situation beautifully:
; first check to see if right spot in dialog box,
if ((GlobalCurrentControl == 29) ; first control in dialog
&& (GlobalPrevRealName == "Spelling:") ; definitely spell 
checker
&& StringContains (buffer, "Not in Dictionary")) then ; proper 
event
PerformMacroKey ({Insert+W}) ; read the desired text
EndIf


This specific logic does not handle the case when the string 
"Capitalization:" is displayed instead of "Not in Dictionary:".  A 
simple addition to this logic would fix it.  The variables named 
GlobalCurrentControl and GlobalPrevRealName are defined or 
set by the FocusChanged macro as part of its special logic to 
handle SDM dialog boxes.  Since they are "Global" they can be 
used by any macro.  You must be sure they are being set properly 
and currently/recently by a reliable macro if you intend to use 
these or other global variables.  For example, if you are not in an 
SDM dialog, and not using our macro logic that sets the 
GlobalCurrentControl value, then you better not use it, it would 
contain old and probably unreliable data.
 
 INSERT+H HOT KEYS HELP
The Insert+H macro should be customized for each application.  
The macro can determine which dialog box it is in, or other child 
window or situation, and give the user the appropriate 
information to help them out.  Here we mainly want to resent the 
"Hot keys" that can be used, i.e. Alt+D for the Directories list box
in the file open dialog.  Determining these hot keys may need 
some sighted assistance, the letter to be used is underlined and 
appears in the prompt/title of the control or child window.  
In the future we will have a JFW macro function to find and read 
that underlined letter, but you will still have to write the hot key 
information to be used in this macro.  Below is an excerpt from 
the Program Manager macros, PROGMAN.JMS.  Refer to the 
other application macro files for more examples, like 
WINWORD.JMS.
MacroBegin {Insert+H}
; hot keys for Program Manager
; Insert h text for Program Item Properties Dialog box.
if (GetWindowName (GetRealWindow (GetFocus())) == 
"Program Item Properties") then
SayString("Tab through the controls or use the following 
Windows keys")
SayString("To get to description edit use Alt D")
SayString("Description is the text label associated with 
program icons")
SayString("To get to the program command line use Alt C")
SayString("This is the execute command for the application")
SayString("To select the working directory use Alt W")
SayString("This is the default directory where files will be 
saved")
SayString("To set up a Windows short cut key use Alt S")
SayString("This will allow you to launch the program with a 
key combination")
SayString("Use Alt H for Windows help and further 
explanation or escape to Cancel")
Return
EndIf
; Insert h text for Program Group Properties Dialog box.
if (GetWindowName (GetRealWindow (GetFocus())) == 
"Program Group Properties") then
SayString("Tab through the controls or use the following 
Windows keys")
SayString("To get to description edit use Alt D")
SayString("Description is the text label which appears on title 
line of the new group")
SayString("To get to Group file use Alt G")
SayString("Use Alt H for Windows help or escape to Cancel")
Return
EndIf
; Insert h text for Run dialog box.
if (GetWindowName (GetRealWindow (GetFocus())) == "Run")
then
; End of sample Insert+H macro code.
INSERT+W WINDOWS HELP
The Insert+W macro key is designed to give the user Windows 
related help as opposed to JAWS related help.  An example from 
the default macros follows, you can also look for examples in 
other application macro files.

MacroBegin {Insert+W}
SayString("The Following windows keyboard commands can 
be useful")
SayString("To jump between running programs, Press Control 
plus Escape")
SayString("This will put you in the Task List of all running 
applications")
SayString("Use the arrow keys or Type the first letter and 
Enter to Choose")
SayString("To close a selected application, use Alt plus F4")
SayString("To close a selected Group, use Control plus F4")
SayString("You also close selected documents with Control 
plus F4")
MacroEnd



OTHER MACRO IDEAS:

Some dialog boxes may need special help, like quick access to the 
"file type" being saved in the Save As dialog box, or the directory 
path that will be used if you type in only the file name.  Look for 
examples of these macros on Insert+F3 or Insert+F4 (just because 
they are close to F1 and F2).  Our current WINWORD.JMS file 
has an example of this.
The tab key in a data base or other formatted screen usually 
moves to the next field.  You probably want to hear the name of 
the field and the data in the edit area.  Refer to the tab and 
Insert+tab macros in the ACTWIN2.JMS file (for Act for 
Windows).  This technique will not always work.  Act uses a 
separate window for the field name and the edit area, but not all 
programs do.  We are working on other solutions for those 
programs.
Refer to ACTWIN2.JMS for examples of the FindString macro.  
It is used to find a particular piece of information, like phone 
number or company name, and read it.

FOR MORE INFORMATION:
You may ask us questions about macros in several ways.  The 
best way currently is the "GO JAWS" forum on Compuserv.  
Soon we will have an Internet site.  Our BBS is 813-803-8002.
Any of these are preferable to voice phone, it is too difficult to 
provide acurate technical information, and most of not all of this 
information should be shared.
 

