Windows Program Structure
What is a Window?
Most people who use the Windows environment never really understand what the word "window" actually means. Most users realize the rectangular box that appears on the screen when a new application is opened is a window. They probably think of the text area of their word processor as a window as well.
In most applications, every dialog box, menu, button, edit field, list box, etc. is actually a separate window with one or more identifiers that can be used to refer to it. However, a programmer may choose to create controls, such as entry fields, without making them actual windows. Programs like this are the most difficult to make accessible because there's no simple way to identify and speak the various controls.
Windows Hierarchy
The operating system does not randomly place the various windows that may be present on your screen at any one time. They are interrelated with a special hierarchy that allows the Windows operating system and the programmers who work within it to keep track of each window.
You can think of these inter-relationships as one of parents and children. The desktop is the parent of all application windows. Thus, the JAWS window, your word processor's window and the Internet browser's window are all children of the desktop. These windows are all one level down from the desktop, which makes them all children of the desktop at the same logical level. It also means that all of them are peers of each other. When you later encounter terms such as PriorWindow() and NextWindow(), the reference is to moving among peer windows at the same logical level.
The word processor window has several child windows, the text area, the menu bar, the toolbar and the status line. These are all children of the word processor window and are all children at the same logical level. When you press the keystroke to open a file in your word processor, the word processor displays a child window that prompts you for the file to open. This window is often referred to as a dialog box, but it is a child window to the word processor, its parent.
If you think of the Open File dialog box as a parent then you will find that the File Name edit box and all other controls are children of the open file dialog box. These are all children of the parent dialog and are at the same logical level. Each window is a child to the window one level up that spawned or generated it, and each window is a parent to the windows one level down from it.
You can find a good analogy of the parent-child relationship by using the directory structure of your PC. On your disk drive, the C:\ drive is the parent of all other directories on your drive. All of the subdirectories one level down from C:\ are children of that parent and are at the same logical level.
Thus, if you have sub-folders named Program Files, Users, and Windows on your system, they are all one level down from C:\. They are all children of C:\ and are all one logical level down. For the purposes of folder structure and window hierarchy, you can assume that being at the same logical level means that all windows were spawned or generated by the same parent.
When you open the Program Files subdirectory, you should find subdirectories such as Common Files, Freedom Scientific and Internet Explorer. These three sub-folders are all one level down from Program Files, are children of Program Files, and are at the same logical level as each other, two levels down from C:\. This can continue until the lowest logical level of a particular branch is reached.
The parent/child structure of Windows works much the same way as a folder structure. Each application is a branch of the tree, and child windows are spawned from it. All windows one level down from the parent application are children at the same logical level. Each of these children can spawn children of their own, and these children are three levels down from the parent application.
Diagram of Windows Window Hierarchy and File/Directory Analogy
graph TD
subgraph WIN["🪟 Windows Window Hierarchy"]
D["Desktop<br/>(window parent)"]
A["Applications"]
J["JAWS"]
W["Word"]
C["Chrome"]
TA["Text Area"]
MB["Menu Bar"]
TB["Toolbar"]
SL["Status Line"]
OFD["Open File<br/>Dialog"]
FNE["File Name<br/>edit box"]
OC["Other controls"]
D --> A
A --> J
A --> W
A --> C
W --> TA
W --> MB
W --> TB
W --> SL
W --> OFD
OFD --> FNE
OFD --> OC
end
subgraph FILE["📁 File/Directory Hierarchy"]
DR["C:<br/>(drive root)"]
PF["Program<br/>Files"]
CF["Common<br/>Files"]
FS["Freedom<br/>Scientific"]
BR["Browser"]
U["Users"]
WD["Windows"]
DR --> PF
DR --> U
DR --> WD
PF --> CF
PF --> FS
PF --> BR
end
ANALOGY["🔗 Analogy<br/>Desktop ↔ Drive<br/>Window spawn ↔ Subfolder<br/>Dialog ↔ Folder"]
style WIN fill:#ADD8E6,stroke:#4169E1,stroke-width:2px
style FILE fill:#90EE90,stroke:#228B22,stroke-width:2px
style ANALOGY fill:#FFE4B5,stroke:#FF8C00,stroke-width:2px
style D fill:#ADD8E6,stroke:#000
style A fill:#90EE90,stroke:#000
style J fill:#FFFFE0,stroke:#000
style W fill:#FFFFE0,stroke:#000
style C fill:#FFFFE0,stroke:#000
style DR fill:#ADD8E6,stroke:#000
style PF fill:#90EE90,stroke:#000
style U fill:#FFFFE0,stroke:#000
style WD fill:#FFFFE0,stroke:#000
Identifying Windows
An application programmer assigns a number of identifiers to each window. These identifiers allow the window in question to be referred to unambiguously. Each window has a class, type, type code, window subtype code, and control ID. These window categories are important because JAWS behaves differently, depending on what category of window is active.
For example, if an edit field is active, JAWS tracks the insertion point. When you press DOWN ARROW, JAWS speaks the line of text to which the insertion point moves. When a list box or menu is active, JAWS tracks the highlight or lightbar as the arrow keys are used to move it up and down the list. JAWS knows to do these things because of the scripts that are associated with the up and down arrow keys in the Default.jss script file. These scripts contain logic that decides what to do based on the type of the window that has the focus when one of these keys is used.
::: {#the-window-handle}
The Window Handle
:::
The window handle is a unique number assigned by the operating system to each window when it is created during a given session. Window handles change each time the window is created. However, the handle value remains constant as long as the window exists.
As long as a window exists, you can use the handle to refer to and identify that window. But when a window is closed, it relinquishes its handle. If the window is created later, the operating system assigns a different handle.
You can retrieve the window handle using the built-in functions, GetCurrentWindow() and GetFocus(). There is a distinct difference between these two functions. The GetFocus() function retrieves the handle of the window that contains the insertion point or system focus. The GetCurrentWindow() function retrieves the handle of the window containing the active cursor.
An example of how the GetFocus() function is used follows:
Script GetWindowFocus ()
Var
Handle hFocusWindow
Let hFocusWindow = GetFocus ()
; the GetFocus statement could be replaced by the following line:
; Let hFocusWindow = GetCurrentWindow ()
SayInteger (hFocusWindow); speak the value of the window Handle
EndScript
::: {#window-class}
Window Class
:::
The window class is a string of text that denotes some information about a window and what it does. A window class can be edit, list box, or a button. It provides valuable information about the window. However, the window class does not always provide specific information. Checking the window class will return the same information for a button, radio button, and checkbox all of which have a Window Class of button. JAWS recognizes 28 different classes.
Many times, programmers use custom window classes that JAWS cannot recognize. In these cases, you must tell JAWS how to treat the unrecognized class. After you tell JAWS how to treat a custom window class, JAWS reacts to the window class just as if it were a recognized window class.
You can retrieve the Window Class with the function, GetWindowClass().
An example of how the window class is retrieved follows:
Script RetrieveWindowClass ()
Var
String sTheClass
Let sTheClass = GetWindowClass (GetFocus ())
If sTheClass == "Edit" Then ; the window class is an edit box
SayFormattedMessage (OT_MESSAGE, "Focus is in an edit box.")
Else
SayFormattedMessage (OT_MESSAGE, "The focus is Not in an edit box.")
EndIf
EndScript
::: {#window-type}
Window Type
:::
The window type is a string of text that describes the window. Occasionally, the window type reveals more specific information about certain windows. The window type and window class are the same if no more specific information is available. For example, the window class and window type of an edit box are exactly the same.
You can use the window type to differentiate between a checkbox and a radio button. You use the function GetWindowType() to retrieve the Window Type. The GetWindowType() function returns the string of "unknown window type" when the application programmer used a custom window class to define the window. The Window Type is always in English and is not very useful for those using JAWS in other languages.
An example of how the GetWindowType() function is used follows:
Script RetrieveWindowType ()
Var
String sTheType
Let sTheType = GetWindowType (GetFocus ())
If sTheType == "Edit" Then
SayFormattedMessage (OT_MESSAGE, "The focus is in an edit box")
Else
SayFormattedMessage ("OT_MESSAGE, The focus is Not in an edit box.") ; a window type other than edit was found
EndIf
EndScript
::: {#window-type-code}
Window Type Code
:::
The window type code is a numeric value instead of a string. This number is translated into a recognizable string by constant definitions found in the file, HJConst.jsh. For example, in this file you can find lines such as WT_BUTTON=1, WT_COMBOBOX=2, WT_EDIT=3, WT_LISTBOX=4, and WT_SCROLLBAR=5. The WT prefix of the constant indicates that this is a constant that refers to a window type code.
While the window type code does not provide any more information than the window type, it does have the advantage of being language independent. You retrieve the window type code with the function, GetWindowTypeCode().
An example of how the GetWindowTypeCode() function is used follows:
Script RetrieveWindowTypeCode ()
Var
Int iTheTypeCode
Let iTheTypeCode = GetWindowTypeCode (GetFocus ())
If iTheTypeCode == WT_Edit Then
SayFormattedMessage (OT_MESSAGE, "The focus is in an edit box.")
Else
SayFormattedMessage (OT_MESSAGE, "The focus is Not in an edit box.")
EndIf
EndScript
::: {#window-subtype-code}
Window Subtype Code
:::
Like the window type code, the window subtype code is also a numeric value. However, the window subtype code may provide more detailed information about a window. If no subtype code is available for the window, then the window type code and window subtype code are identical. You should use the window sub type code as it generally provides more specific information about a window than does the window type code. You can use the same constant definitions to refer to window subtype codes as you can for window type codes in your scripts and functions. For example, a radio button has a window type code of 1 (WT_Button) but a subtype code of 19 (WT_RadioButton).
Window subtype codes are also language independent. You use the function, GetWindowSubTypeCode(), to retrieve the window subtype code for a given window.
An example of the use of the GetWindowSubTypeCode() function follows:
Script RetrieveWindowSubTypeCode ()
Var
Handle hWnd,
Int iTheSubTypeCode,
Int iTheTypeCode
Let hWnd = GetFocus ()
Let iTheTypeCode = GetWindowTypeCode (hWnd)
Let iTheSubTypeCode = GetWindowSubTypeCode (hWnd)
If iTheTypeCode == WT_Button Then
If iTheSubTypeCode == WT_RadioButton Then
SayFormattedMessage (OT_MESSAGE, "The active window is a radio button.")
Else
SayFormattedMessage (OT_MESSAGE, "The active window is Not a radio button.")
EndIf
Else
SayFormattedMessage (OT_MESSAGE, "The active window is Not a button.")
EndIf
EndScript
::: {#window-control-id}
Window Control ID
:::
The control ID is a number that is assigned by the programmer to each window during application development. The control ID, unlike the window class, has no special meaning, but you can use it to refer to a particular window. Ideally, no two windows in a program have the same control ID, but they sometimes do. If you know how to access the control ID, and, if it is unique within the application, you can tell JAWS to do certain things if you are focused on the window with the control ID you have identified.
One example where the use of control ID's are extremely useful is in applications where the buttons are labeled with bit map drawings instead of text labels. Normally, JAWS speaks the text label of a button when you move to it. If the label is a drawing, there is no name to be spoken. By determining the control ID numbers of the various bit map buttons, you can write a script that speaks the name of a button when the focus moves to a button with a particular control ID.
In most cases, the control ID is defined during application development and can be relied upon to uniquely identify a specific window. However, you may find cases where control ID's have not been assigned by the application developer. In these cases, you will find that each window in a given application have control ID values of 0. You must then rely on other window identifiers along with the window's hierarchical position to uniquely identify it.
You may also find that the control ID's in a given application are dynamically assigned. This means that each time an application window or any of it's child windows are created, the control ID's are assigned and do not remain constant. In these cases, you will find that you need to use the other windows identifiers and the window hierarchical position to uniquely identify the window.
You can determine if control ID's are dynamically assigned by running the application, noting the control ID values of some of it's child windows, then restarting the application and looking at those same control ID values. If they have changed, then you will know that the ID's are dynamically assigned. You use the function, GetControlID(), to retrieve the control ID for a given window.
An example of how the GetControlID function is used follows:
Script IdentifyWindow ()
Var
iControlID
Let iControlID = GetControlID (GetFocus ())
If iControlID == 1100 Then
SayFormattedMessage (OT_MESSAGE, "This is the file name edit box")
Else
SayFormattedMessage (OT_MESSAGE, "This is Not the file name edit box.")
EndIf
EndScript
Reassigning Window Classes
There is a standard list of window classes used by most programmers during the development of windows applications. The scripts and user-defined functions found in the default script file contain the necessary logic to allow proper speaking of these standard classes. However, application programmers do not always use standard window classes during application development. Many times, a programmer creates custom window classes that are non-standard. JAWS is unable to recognize the custom class and speak the window correctly.
You use the Configuration Manager to equate the unknown class to a standard class to allow JAWS to process the window correctly. This process is called reassigning the window class. Once you have reassigned a custom window class, JAWS is able to identify the window and speak it correctly. During window reassignment, you may need to try more than one class to determine what standard class works best.
To reassign a window class, you can use the JAWS Cursor, Invisible Cursor or PC Cursor to locate the window. To reassign a window class, do the following:
-
Move the JAWS Cursor, Invisible Cursor or PC Cursor to the window with the non-standard class.
-
Press JAWSKEY + F2 to activate the Run JAWS Manager dialog.
-
Press JAWS Cursor, Invisible Cursor or W to move to the JAWS Cursor, Invisible Cursor or Window Class Reassign item.
-
Press ENTER to start the Configuration Manager and display the Window Classes dialog. The New Class edit box is the active control. The non-standard window class is shown in this edit box.
-
Press TAB to move to the Assign To list box. This list box contains all of the standard window classes JAWS recognizes.
-
Use your ARROW KEYS to move through the list. Select the window class you think best suits the non-standard window class.
-
Press TAB to move to the Add Class button. Press SPACEBAR to activate this button. You can also press ENTER from the Assign To list box to activate the add Class button.
-
Press the SPACEBAR to activate the OK button to close the Window Classes dialog. The Configuration Manager will also close.