Last time we discussed how the app module is born and dies. For the next few installments, we'll tour how the app module performs various functions while a user is using it. For this first part, we'll discuss how time functions work, adjusting alarm values and configuring basic settings.
Time announcement routines: a tale of four brothers
SPL Studio app module for NVDA comes with four time announcement commands. These are elapsed time, remaining time, broadcaster time and complete time including seconds. The first two uses Studio API to obtain needed information, while others use a combination of Python routines and Windows API functions.
Three of these routines are assigned to commands (sometimes termed gestures). These are:
* Control+Alt+T: Remaining time
* Alt+Shift+T: Elapsed time
* NVDA+Shift+F12: Broadcaster time
One can then use Input Gestures dialog (part of NVDA screen reader) to change them or assign a command to complete time routine.
A step sideways with statusAPI function: A central Studio API handler and dispatcher
Before going any further, it is important to mention a function that not only is used by the first two time routines, but also comes in handy in SPL Assistant and other methods. This function, called statusAPI (part of the main app module and defined as a module-level function), sends messages to Studio window and schedules follow-up routines according to arguments passed into it. The signature is:
statusAPI(arg, command, func=None, ret=False, offset=None)
With the arguments being the message to be sent to studio window (arg and command), follow-up function if any, whether it should return the message return value and time offsets if any. In effect, this is a higher order function (a function that takes another function as an argument). The statusAPI function then:
1. Checks if a handle to Studio window is available.
2. Sends a message to Studio window via user32.dll's SendMessage function (see a previous installment for more details and reference) and stores the result. Unlike a typical SendMessage function routine, the Studio handle and message type is automatically filled in, hence only argument (WParem) and command (LParem) are needed.
3. Depending on arguments passed in, studioAPI function:
A. Returns the message result if told to do so (ret=True).
B. Calls a follow-up function if told to do so. As of time of this writing, this function is a time announcer (announceTime, which announces the result of converting milliseconds to human-readable representation via a private function). This time announcer takes the result or SendMessage function and offset if any.
First applications of studioAPI function: Announcing elapsed and remaining times
When you press Control+Alt+T or Alt+Shift+T to hear remaining or elapsed time, the script will first check if you are in the main Playlist Viewer, and if so, will call statusAPI function with correct arguments and commands with announceTime as the follow-up function. In fact, the only differences are argument that is used and the error message.
Broadcaster time: Simulating Studio's broadcaster clock
When you listen to radio shows, you may hear messages such as, "five minutes to two" or "ten minutes past five". This announcement is called broadcaster time.
Studio does display broadcaster clock. However, because it is in the middle of the screen, one has to use object navigation commands to locate it, and this method was used in older Studio add-on releases. This involved locating the foreground window (api.getForegroundObject()) and following a preset direction to arrive at the clock object, and this is still used in some places. However, this was prone to a critical problem: sometimes, the object we're interested in changed positions (a good example was when different builds of Studio 5.10 were released).
Recently, this method was abandoned in favor of using Python's time module to obtain current time and convert it into a format that is familiar to broadcasters, thus removing the need to use object navigation. When you press NVDA+Shift+F12, NVDA first fetches local time (time.localtime), then converts this into a format suitable for output. Along the way NVDA tries to emulate how Studio displays broadcaster clock. When processing is complete, NVDA announces the output text.
Complete time: Windows API to the rescue
Here, complete time refers to time including seconds. Normally, when you press NvDA+F12, NVDA excludes seconds when announcing time. All that is needed to announce seconds is to change the format argument for kernel32.dll's GetTimeFormat function. With this change, NVDA can announce time including seconds, but in order to use it, you need to assign a command to this feature (some app module commands are not assigned by default).
Studio app module comes with three alarms: song outro (ending), intro and microphone active alarm. Because we need to talk about some important things when talking about microphone alarm, we'll just tour the routine used when setting up the intro and outro alarms.
When you press Control+NvDA+2 or Alt+NVDA+2 to open end of track or song intro alarm dialogs, the dialog will display two controls:
* Alarm setting: a spin box (a sping control) is used to adjust alarm values. You can type the alarm value or use up or down arrow to change the value. If an incorrect value is entered, the maximum value (59 for end of track, 9 for song intro) will be used.
* Notification check box: This sets whether alarm will play or not.
In reality, a single dialog (splconfig.SPLAlarmDialog class) presents these two alarm dialogs. The type of dialog to be shown is controled by parameters passed into the dialog class. These include the value to be shown, maximum value and dialog title. The process is outlined below:
1. Just before the dialog opens, checks if another dialog or the add-on settings dialog is opened, and if so, NVDA will ask you to close the previously opened dialog first.
2. Tells NVDA that an alarm dialog is opened. This is meant to prevent the same dialog from being opened repeatedly.
3. After the dialog is dismissed (either a new value is set or you click Cancel), NVDA clears the alarm opened flag, thereby letting other dialogs to be shown.
We'll learn how the alarm values are stored and retrieved in the configuration management article, and you'll get to meet how intro and outro alarms work in the next article.
Studio add-on comes with some toggle settings that affect the operation of the app module. These include status announcements (Control+NVDA+1), library scan announcement (Alt+NVDA+R) and braille timer (Control+Shift+X). For each setting script, NVDA will first check the current value, change the value and announce the new value.
Now you know how the alarm dialogs function, what happenn when you toggle some settings and went through a behind the scenes tour of various time announcement commands. There are other things we need to talk about, and we'll continue our discussion of the Studio app module with how alarms come into play and how status changes are announced.
1. Higher order functions (How do you make a higher order function): http://effbot.org/pyfaq/how-do-you-make-a-higher-order-function-in-python.htm
2. Time (Python documentation, Python Software Foundation): https://docs.python.org/2/library/time.html
3. GetTimeFormat (kernel32.dll) reference (Windows API): https://msdn.microsoft.com/en-us/library/windows/desktop/dd318130(v=vs.85).aspx