Extending JAWS ® Using Python
JAWS ® features a powerful scripting language that allows developers to tailor the way any Windows application is presented by the screen reader. While the language has a number of functions that make interface inspection and speech generation easy, it lacks some of the features of full programming languages (e.g. object orientation, diverse standard library). Thankfully, JAWS ® can interact with Component Object Model (COM) objects, making it possible for developers to extend JAWS ® scripts with components built in other programming languages.
In this tutorial, I describe how JAWS ® may be extended with a very simple COM object built using the Python programming language. I assume that the reader has some experience with JAWS ® scripting and programming in some modern object oriented language (Python, C++, Java, etc.). The reader need not have an understanding of COM, although some background might illuminate the details that I skip.
Prerequisites
- JAWS 4.51 or higher
- Python 2.3 or higher
- Mark Hammond's Python win32all extensions
- Internet Explorer 5.0 or higher (for the purposes of this tutorial only)
The Goal: A Timer for Internet Explorer
In this tutorial, we will create a COM object that times how long the user has been browsing the current web page. When the user presses a key combination, JAWS ® speaks how long it has been since the current web page loaded. This is not the most useful JAWS ® extention, but it is quite simple to code and serves as a good educational example.
Creating the Python Timer
We will start by creating the timer COM object in Python.
- Create a new text file in your text editor.
- Save this file to some folder with the filename JAWSTimer.py.
- Enter the code given below into the blank text file. Be certain to preserve the indentation as Python is whitespace sensitive.
import datetime
class JAWSTimer:
# this is the globally unique identifier for this COM class
_reg_clsid_ = '{6CB6257E-CCEF-4AA4-B82D-ACC5CC433F80}'
# this is the human readable name of this COM class
_reg_progid_ = 'UNC.Assist.Tutorial.JAWSTimer'
# these are the methods that are callable from JAWS
_public_methods_ = ['StartTimer', 'ReportTime']
def __init__(self):
# constructor; this function is called when the COM object is created
self.timer = datetime.datetime.now()
def StartTimer(self):
# record the start time for this timer
self.timer = datetime.datetime.now()
def ReportTime(self):
# compute the time difference
td = datetime.datetime.now() - self.timer
# the time difference is given in seconds, days, and microseconds
# compute the difference in seconds
seconds = td.seconds + td.days*24*60*60
# return a string to JAWS to be spoken
return 'The web page has been loaded for ' + str(seconds) + ' seconds.'
if __name__ == '__main__':
# this code will only run if this file is executed directly using Python
# the code registers the COM object in the Windows registry
import win32com.server.register
win32com.server.register.UseCommandLine(JAWSTimer)
Some explanation is in order. Most of the meaning of this code is described in the embedded Python comments (i.e. lines that begin with a pound sign). The value of the _reg_clsid_ variable is a unique identifier I generated using a separate utility. For this project, you may use this identifier, but you must make a new one for each unique COM class you make. (I will discuss this topic more later.) The value of the _reg_progid_ variable will be used to create this COM object from JAWS ®. You may set it to any value not already reserved by another COM class. The __init__ method is the standard constructor for a Python class, while StartTimer and ReportTime are two public methods that will be called in our JAWS ® script. Finally, the section of code at the bottom registers the COM class on the local machine for later use.
We must still register this COM class on the local machine. You may do this in one of two ways.
COM Registration: Method 1
- Open a command prompt and change directories to the folder in which you saved the JAWSTimer.py file.
- Run the script in Python with a command like c:\python23\python.exe JAWSTimer.py. (Your Python executable might be in a different folder depending on where you installed it.)
- If everything goes well, a message will print saying the class is registered. An error traceback will print if your code has any bugs that need to be fixed.
COM Registration: Method 2
- Double click the JAWSTimer.py file.
- If your code has no bugs, the COM class will be registered. You will not be able to see if the registration was successful using this method since the command window disappears too quickly to see the result.
Once the COM class has been registered, you cannot move the JAWSTimer.py file to a new location without re-registering it.
The JAWS ® Script
Now that the COM object is registered, we can use it in a JAWS ® script. We want to time how long we have been looking at a web page in Internet Explorer, so we need to edit the JAWS ® script source file for Internet Explorer. In JAWS ® 4.51 this file is named browseui.jss. In JAWS 5.0, the script is named Internet Explorer 5-6.jss. In both versions, the script is located in the SETTINGS/enu subfolder of your JAWS ® folder.
- Open the Internet Explorer script source file in your text editor or the JAWS ® Script Manager.
- Near the top of the file add a new global variable that will store our COM object. This global can be declared as follows:
globals object pyTimer
- Locate the AutoStartEvent function. At the bottom of this function, add the following code to create the COM object when the first instance of the browser starts.
If ! pyTimer Then Let pyTimer = CreateObject("UNC.Assist.Tutorial.JAWSTimer") EndIf - Locate the DocumentLoadedEvent function. Near the bottom of this function, but above the last function call to DocumentLoadedEvent, add the following code to start the timer each time a new web page is loaded.
pyTimer.StartTime()
- Add a new script to the file called SpeakTime with the code given below. This script will get the elapsed time from our COM object and speak it to the user. We will map this script to a key combination later.
Script SpeakTime() SayString(pyTimer.ReportTime()) EndScript
- Finally, we need to recompile the script. If you're using the Script Manager, press Control-S to save your script and recompile it. If you're not using the script manager, then open a command prompt and change to the SETTINGS/enu subfolder of your JAWS ® folder. Then type the following command, substituting the name of your script in double quotes where it says your_script_name:
../../scompile.exe your_script_name
The Doc File
We now have to document our new script so that we can assign a hotkey to it. The documentation file for Internet Explorer is called browseui.jsd in JAWS ® 4.51 and Internet Explorer 5-6.jsd in JAWS ® 5.0.
Open the appropriate documentation file in your text editor or the JAWS ® Script Manager.
At the top of the file, add the following lines:
:Script SpeakTime :Synopsis Speak the time elapsed since the current page was loadedescription Speak the time elapsed since the current page was loaded
The Hotkey
Finally, we can hook our new SpeakTime script to a key combination in JAWS ®.
- In the main JAWS ® window, select the Keyboard Manager menu item from the Utilities menu.
- In the left scroll pane, select the name of your Internet Explorer script source file. Again, that's Internet Explorer 5-6 for JAWS ® 5.0 and browseui for JAWS ® 4.51.
- In the right scroll pane, select the SpeakTime list item.
- Press Control-A to assign a new keystroke to this script.
- Press Control-Shift-T to map it to our script.
- Testing the Script
You can now run Internet Explorer to test our new COM object and script. When you press Control-Shift-T, JAWS ® should speak a string stating how long the current web page has been open in the browser.
The Next Step
That's it. You've completed this tutorial and your first Python COM object for JAWS ®. Now you can apply the steps in this tutorial to the creation of your very own, useful extension to JAWS ®. However, there are a few exceptions to keep in mind when developing your own COM object:
- You need to generate a new class ID number for each COM object you make. To generate a new unique ID, start an interactive Python shell by running Python from the command line. With the shell open, type import pythoncom and press Enter. Then type print pythoncom.CreateGuid(). A new, unique identifier will be printed on the next line. Use this identifier as the value for the _reg_clsid_ variable in your COM class.
- Your COM object must have a unique human-readable name. Be sure you set the _reg_progid_ variable in your COM class to a unique name.
- You may use your COM object in any JAWS ® script source file, not just the file for Internet Explorer. Do not limit your ideas for extensions to just the web.
References
For more information about JAWS ®, Python, and accessibility, please visit the following websites: