NVDA, Variability for Usability
In the previous three articles, we presented various insightful analyses of NVDA by exploring the codebase. In the last article of this series, we will focus on the variability of the great screenreader software NVDA, which aims to make the computer freely accessible for blind and visually impaired individuals.
In the software architecture lecture, the variability is explained as the following1:
the ability of a software system to be efficiently extended, changed, customized or configured for use in a particular context.
Since NVDA is a user-initiative open source software, it contains a bunch of features which can be further configured, customized, or even extended and changed by its users as well as developers. Thus, an analysis of NVDA’s variability is helpful for us to understand how NVDA deals with configurations of different features and meets requirements for every individual.
Variability Modeling
As mentioned in our previous article, NVDA’s vision, the most important stakeholders of NVDA are the end users. NVDA implements various features which can be configured and fulfill the preferences for different individuals2. Meanwhile, developers are also important stakeholders. We introduce 10 significant features of NVDA and discuss the possible beneficiaries of these features in the following part:
-
Support for third-party applications: NVDA supports various popular applications, for example, web browsers and office suites. This variability allows end users to use NVDA in different scenarios, for example, entertainment and work.
-
Support for add-ons: NVDA makes it possible for end users to install additional add-ons to fulfill their personal requirements3. The add-ons support a wide range of functionalities. Developers are also welcome to make contributions to add-ons and improve NVDA’s performance.
-
Support for different braille displays: NVDA supports different refreshable braille displays, for example, the ability to detect many of them automatically. The variability in braille displays makes NVDA more convenient for end users; they don’t need to worry about buying an additional braille display for NVDA.
-
Support for different accessibility interfaces: NVDA supports common accessibility interfaces such as Java Access Bridge and UI Automation. The variability of accessibility interfaces makes it convenient for developers to implement other features. For example, developers can exploit Java Access Bridge to enable the accessibility of Java applications on Windows systems4.
-
Ability to run entirely from a portable media like a USB without the need for installation: Since the targeted end users of NVDA are blind and visually impaired individuals, it might be hard for them to download the NVDA when they are not using their own computers. The portable copy makes NVDA able to accompany end users everywhere.
-
Support for local and remote Python console: NVDA not only supports local python consoles for emulating the interactive Python interpreter from within NVDA, it also supports a remote Python console which is accessed via TCP. The remote Python console makes it possible for developers to debug NVDA remotely.
-
Support for different interaction methods: The interaction methods of NVDA include mouse, keyboard, and touch. This variability allows users to interact with NVDA using their preferred methods.
-
Support for different speech synthesizers: NVDA supports both free and commercial speech synthesizers. Advanced users with demand for different speech synthesizers are able to choose their preferable one.
-
Translated into 54 languages5: The variability in languages ensures that people anywhere in the world have equal access to NVDA.
-
Support for Windows OS 32 and 64 bit variants: Users with 32 bit and 64 bit Operating Systems can use NVDA without worries.
There are also several incompatibilities between those features. For the NVDA’s add-ons, they are unable to work when they have not been updated with NVDA’s significant changes. For speech synthesizers, NVDA has different default synthesizers on different Windows operating systems. The default one on Windows 7, 8 and 8.1 is eSpeak NG, and the default one on Windows 10 is Windows One Core. For NVDA running entirely from a portable media, it doesn’t support input from a touch screen.
In order to obtain a clear view of the variability of NVDA, we illustrate the relationship between the aforementioned features with a feature modeling tool, FeatureIDE. The above image presents the feature model6. The model shows whether a feature is mandatory. It also shows possible configurations of a feature, for example, keyboard is one of the possible configurations of the feature of interaction methods. The constraints between different configurations and features are also presented, for example, the constraint between the braille output and speech output is “or”.
We hope that we have given you a general view of the variability of NVDA by showing its main features. In the following sections, we will dive into two specific features, add-ons and output. We will introduce how users can configure these features and how developers manage them during their development processes.
Add-on variability
Add-ons are one of the biggest ways in which NVDA provides extensibility. These are installable packages which provide application-specific or global functionality, as well as support for new braille displays or speech synthesizers. We will use this essay to go into more detail about add-ons, beginning with the user’s perspective.
Users can find valuable information on installing and configuring add-ons in the user guide. To manage add-ons, NVDA contains an add-on manager, which we show below:
Here, users can install and enable add-on packages or see if there is any incompatibility between add-ons and the NVDA version. From here, users can obtain community-approved add-ons from the official NVDA add-on website. Let us now move on to the developer’s perspective.
For the development of add-ons, developers can consult the general developer guide and the add-on specific developer guide, which extensively covers the different functionalities, implementation details and system and software prerequisites for building add-ons.
Essentially, an add-on is simply a Python file (e.g. teamviewer.py
would contain an add-on for the TeamViewer application).
These files are put in an AppModules
folder and define a class which inherits from the AppModuleHandler.AppModule
class.
These modules can then handle UI events by implementing event-handling methods, which often follow the event_eventName(obj)
pattern.
Thus, the add-on system makes use of the observer implementation pattern, as we show below:
As we mentioned in our second essay, NVDA encapsulates every single control into an NVDAObject
.
This gives the ability to retrieve information from or manipulate UI elements uniformly, regardless of the application or operating system.
The application-specific AppModules
(i.e. the observers) can receive and then handle UI events regarding these objects.
These events are sent to the observers through an EventHandler
(i.e. the controller) system.
When an NVDAObject
event occurs, the system finds the appropriate observer AppModule
by using the AppModuleHandler.fetchAppModule
method.
This method uses the name of the currently active Windows process to retrieve the correct AppModule
for the current application.
Once the right AppModule
is found, the EventHandler
will notify the observer that the event has occurred.
Next to regular events, these AppModules
can also use the chooseOverlayClasses
and event_NVDAObject_init
methods to add application-specific functionality for NVDAObjects
or modify their values.
These events are raised by the NVDAObject
itself, instead of going through the EventHandler
.
Now that we have looked at implementation, let us look at when these add-ons are loaded.
The add-on system works primarily with load time binding.
When an add-on is installed or enabled, this status is managed via the AddonHandler
, which saves it in a configuration file.
When NVDA starts, it looks through every available add-on in the user-specified default add-on directory, and prepares the modules of the enabled add-ons so that they can be used.
This only happens once, when the application is initially loaded.
Thus, whenever the user enables or disables an add-on, he needs to restart NVDA for changes to take effect.
However, there is also some runtime binding.
During runtime, whenever a new process starts, the relevant modules are dynamically loaded with importlib.import_module
via the AppModuleHandler
class.
This class also saves a list of (processID, AppModule
) pairs in its cache, so that the relevant AppModule
can easily be found in the future.
The EventHandler
can then use this to raise events for the appropriate AppModule
.
When a process dies, the event handler makes sure the relevant app module is properly terminated and cleared from the cache.
Add-on management
There is an open proposal to add an add-on store to NVDA7. The main intention of this store would be to improve the end-to-end process and underlying infrastructure for hosting and installing add-ons. It is mostly aimed at users, to ease the process of browse, search, install and update add-ons for NVDA. To provide some guarantee of safety, ensuring that all versions are reviewed, and that users are running the add-on they think they are, is important. Many such checks could also be automated to reduce the burden on add-on reviewers. This store would improve add-on management, however, at the moment this is still just a proposal.
Output variability
We have spoken about changing and extending the functionality of NVDA, but there are also many options with regards to how NVDA communicates with you. NVDA allows for different types of outputs, each having different settings. The two main outputs that NVDA supports are audio, through speech synthesisers and sounds; and braille, through braille displays.
The developers built this variability so that every user can use the synthesiser and voice that they like and which supports their language. Braille support is there for those that prefer to read instead of listen; the variability here is necessary to support all the different refreshable braille displays that end users own. Users can set their preferred output methods in the NVDA settings8. Here you can also set different behaviours for the speech or braille output, such as pitch, automatic language switching and braille output table (which braille alphabet to use). Users can find information about these settings and the different options in the user guide.
This brings us to the code side of things, as these settings are saved in a configuration file. In terms of binding time, the configuration is used at load time to select the right output, but a new configuration can be applied without restarting NVDA, so it also binds at runtime. NVDA comes with all the code necessary to link to each of the supported synthesisers and braille displays. These synthesisers and displays are all external, though NVDA does install its default synthesiser, eSpeak. The only thing that the developers need to maintain is the connection to each system. These connections take the form of drivers following the template-method pattern, where each driver implements the same abstract class defining the interface.
Developers add variants when a user requests them9. Unfortunately, there are currently no automated tests for checking the different variants. Additional variants are mostly tested manually10.
Variability in the future
In this section, we will discuss some design choices made regarding the handling of variability in NVDA, with a focus on potential future developments and extensions.
Add-ons
Regarding add-ons, the NVDA team is currently considering potential future developments, as is evident from the aforementioned add-on store proposal. One potential concern is that add-ons in this store should be ready to go when installed, as many add-ons currently require build steps. If this is solved, it would also convert some compile-time bindings to load-time bindings, which increases variability. Additionally, the plan is to have several automated review approaches to streamline the process of adding add-ons to the store, increasing scalability.
Output
Output variability is somewhat less scalable at the moment. As mentioned before, essentially all steps are done manually. However, this is not necessarily a huge problem, as the variance in output is probably going to be fairly limited, with a limited number of output methods. Additionally, output methods of the same type (e.g. two different speech synthesizers), cannot reasonably be combined or active at the same time, which severely limits the number of possible combinations.
Conclusions
In conclusion, we have modeled NVDA’s variability with its 10 most significant variability features. We also dove deeper into two of these features and discussed their future expansion. We hope that we have managed to show you how NVDA provides variability to serve its most important stakeholder, the end user, thereby providing variability for usability!
-
https://se.ewi.tudelft.nl/delftswa/2021/slides/tudelft-architecture-spl2021.pdf ↩︎
-
https://www.nvaccess.org/files/nvda/documentation/userGuide.html ↩︎
-
https://docs.oracle.com/javase/accessbridge/2.0.2/introduction.htm ↩︎
-
https://www.nvaccess.org/files/nvda/documentation/userGuide.html#GeneralFeatures ↩︎
-
For a clear view of the feature model, you can checkout this link. ↩︎
-
https://github.com/nvaccess/addon-store-submission/blob/master/README.md ↩︎
-
https://www.nvaccess.org/files/nvda/documentation/userGuide.html?#NVDASettings ↩︎