diff --git a/projectDocs/dev/developerGuide/developerGuide.md b/projectDocs/dev/developerGuide/developerGuide.md index 2ad9d6d6f2f..ccd6b315b05 100644 --- a/projectDocs/dev/developerGuide/developerGuide.md +++ b/projectDocs/dev/developerGuide/developerGuide.md @@ -12,7 +12,7 @@ This guide provides information concerning NVDA development, including translati The NVDA Add-on API includes all NVDA internals, except symbols that are prefixed with an underscore. -The NVDA Add-on API changes over time, such as removals, deprecations and new features. +The NVDA Add-on API changes over time, for example because of the addition of new features, removal or replacement of outdated libraries, deprecation of unused or replaced code and methodologies, and changes to Python. Important changes to the API are announced on the [NVDA API mailing list](https://groups.google.com/a/nvaccess.org/g/nvda-api/about). Changes relevant to developers are also announced via the [NVDA changes file](https://www.nvaccess.org/files/nvda/documentation/changes.html). Any changes to the API policy outlined in this section will be conveyed via these two channels. @@ -41,7 +41,7 @@ For an overview of nvdaHelper, including how to configure Visual Studio to enabl ## Translation {#translation} -In order to support multiple languages/locales, NVDA must be translated and data specific to the locale must be provided. +In order to support multiple languages/locales, NVDA must be translated, and data specific to the locale must be provided. This section only includes information on custom NVDA file formats required for translation. Other items need to be translated, such as the NVDA user interface and documentation, but these use standard file formats. For complete documentation about translating NVDA, please see the [Translating page](https://github.com/nvaccess/nvda/blob/master/projectDocs/translating/readme.md) @@ -52,9 +52,9 @@ Sometimes it can be very difficult or even impossible to distinguish one charact For example, two characters might be pronounced the same way, even though they are actually different characters. To help users when this occurs, character descriptions can be provided which describe the character in a unique way. -Character descriptions can be provided for a locale in a file named characterDescriptions.dic in the directory for the locale. +Character descriptions can be provided for a locale in a file named `characterDescriptions.dic` in the directory for the locale. This is a UTF-8 encoded text file. -Blank lines and lines beginning with a "#" character are ignored. +Blank lines and lines beginning with a "`#`" character are ignored. All other lines should contain a character, followed by a tab, then one or more descriptions separated by tabs. Multiple descriptions for a character will be read with natural pauses between them when reading a single character, e.g. when using `leftArrow` or `rightArrow`. When reading character descriptions of multiple subsequent characters using spelling commands, the first description is used for each character, e.g. spelling the current line with triple press on `NVDA+upArrow`. @@ -73,7 +73,8 @@ In most cases, the characters in this file should be a single lower case charact It is assumed that characters will have the same description regardless of their case, so upper case characters are converted to lower case before looking up their character descriptions. #### Translating this file {#TranslatingCharacterDescriptionsFile} -Translations for characterDescriptions.dic happen on SVN following [this process](https://github.com/nvaccess/nvda/wiki/TranslatingUsingAutomaticProcess). + +Translations for `characterDescriptions.dic` happen on SVN following [this process](https://github.com/nvaccess/nvda/wiki/TranslatingUsingAutomaticProcess). For a full example and reference, please look at the English [characterDescriptions.dic file](https://github.com/nvaccess/nvda/blob/master/source/locale/en/characterDescriptions.dic). @@ -83,15 +84,16 @@ It is often useful to hear punctuation and other symbols pronounced as words whe Unfortunately, the pronunciation of symbols is inconsistent between speech synthesisers and many synthesisers do not speak many symbols and/or do not allow control over what symbols are spoken. Therefore, NVDA allows information about symbol pronunciation to be provided. -This is done for a locale by providing a file named symbols.dic in the directory for the locale. +This is done for a locale by providing a file named `symbols.dic` in the directory for the locale. This is a UTF-8 encoded text file. -Blank lines and lines beginning with a "#" character are ignored. +Blank lines and lines beginning with a "`#`" character are ignored. All locales implicitly inherit the symbol information for English, though any of this information can be overridden. The file contains two sections, [complex symbols](#complexSymbols) and [symbols](#symbolInformation). #### Translating this file {#TranslatingSymbolsFile} -Translations for symbols.dic happen on SVN following [this process](https://github.com/nvaccess/nvda/wiki/TranslatingUsingAutomaticProcess). + +Translations for `symbols.dic` happen on SVN following [this process](https://github.com/nvaccess/nvda/wiki/TranslatingUsingAutomaticProcess). See the file [locale\en\symbols.dic](https://github.com/nvaccess/nvda/blob/master/source/locale/en/symbols.dic) for the English definitions which are inherited for all locales. #### Defining Complex Symbols {#complexSymbols} @@ -207,31 +209,31 @@ thousands separator comma all norep ### Gestures {#TranslatingGestures} -The gestures defined originally in NVDA are adapted with English softwares and keyboard layout. +The gestures defined originally in NVDA are configured to expect English software and keyboard layout. In most cases, these gestures can also be executed on other keyboard layouts without any problem. However, sometimes a gesture originally defined by NVDA is not adapted for a specific locale (keyboard layout or software). The need to modify an original gesture may be due to the following reasons: * The original gesture is defined with a character that is not a key name on the locale keyboard layout. Generally, the key names are the characters that can be input without the help of a modifier key (`shift`, `control`, etc.) -* The original gesture takes advantage of the keys physical location on the English keyboard layout, but this advantage does not appear anymore with the locale keyboard layout. +* The original gesture takes advantage of the keys physical location on the English keyboard layout, but this advantage does not exist with the locale keyboard layout. * The original gesture is defined to match a native shortcut in Windows or in an application, but the shortcut in the local version of Windows or of this application is not the same as the English one. -In all of this case, NVDA allows to remap this gesture for this specific locale. +In all of these cases, NVDA allows remapping of this gesture for this specific locale. #### Examples {#TranslatingGesturesExamples} -Below are three detailed examples of gestures.ini files corresponding to the three listed situations where a gesture remapping could be required. +Below are three detailed examples of `gestures.ini` files corresponding to the three listed situations where a gesture remapping could be required. ##### Example 1: The original gesture is defined with a character that is not a key name on the locale keyboard layout {#TranslatingGesturesEx1} -In English original version, the scripts for left and right mouse click (laptop layout) are executed respectively with `NVDA+[` and `NVDA+]`. +In the original English version, the scripts for left and right mouse click (laptop layout) are executed with `NVDA+[` and `NVDA+]`, respectively. -* On English keyboard layout, the `[` and `]` keys are the two keys at the right of the `p` key. -* On Italian keyboard layout, `[` and `]` characters can only be input with the help of `AltGr` modifier: `AltGr+è` and `AltGr+Plus` respectively. +* On an English keyboard layout, the `[` and `]` keys are the two keys at the right of the `p` key. +* On an Italian keyboard layout, `[` and `]` characters can only be input with the help of `AltGr` modifier: `AltGr+è` and `AltGr+Plus`, respectively. -Thus Italian translators decided to remap these scripts with the two keys at the right of the `p` key on Italian keyboard layout, i.e. `è` and `+`. -To do this they have added the following lines in the `gestures.ini` file: +Thus, the Italian translators decided to remap these scripts using the two keys at the right of the `p` key on the Italian keyboard layout, i.e. `è` and `+`. +To do this, they have added the following lines in the `gestures.ini` file: ``` [globalCommands.GlobalCommands] @@ -245,7 +247,7 @@ Looking again at the scripts for left and right mouse click (laptop layout) we c This corresponds to the left and right buttons of the mouse. As seen in example 1, many translators have had to modify these keys. Most of them (if not all) have chosen two neighboring keys. -For example, in French `gestures.ini` the following lines have been added: +For example, in the French `gestures.ini`, the following lines have been added: ``` [globalCommands.GlobalCommands] @@ -254,13 +256,13 @@ For example, in French `gestures.ini` the following lines have been added: rightMouseClick = kb(laptop):nvda+* ``` -The `ù` and `*` on French layout are not at the same location as `[` and `]` of English layout, but these are still two neighboring keys. -Moreover we can see here that `NVDA+[` and `NVDA+]` has been among other mapped to None in order to unbind these gestures. -For French (France) layout, this was not mandatory since there is no possibility to input `NVDA+[` or `NVDA+]` without any other modifier key. +The `ù` and `*` on the French layout are not at the same location as `[` and `]` of the English layout, but these are still two neighboring keys. +Moreover we can see here that `NVDA+[` and `NVDA+]`, among others, have been mapped to `None`, in order to unbind these gestures. +For the French (France) layout, this was not mandatory since there is no possibility to input `NVDA+[` or `NVDA+]` without any other modifier key. ##### Example 3: The original gesture is defined to match a native shortcut {#TranslatingGesturesEx3} -NVDA provides a script for Word document object named `toggleBold`. +NVDA provides a script for the Word document object named `toggleBold`. This script is mapped to the same gesture as the Word native shortcut to set text bold, i.e. `control+b` in English version of Word. However on French version of Word, the shortcut to turn text bold is `control+g`. The G stands for "gras" meaning "bold" in French. @@ -273,14 +275,14 @@ The following lines have been added in the French `gestures.ini` file to remap t ``` We can see that `control+b` has been unbound. -This was necessary because it is the shortcut of another command in French version of Word. -No remapping has been done for `toggleItalic` script since the shortcut is the same for French and English versions of Word. +This was necessary because it is the shortcut of another command in the French version of Word. +No remapping has been done for the `toggleItalic` script, since the shortcut is the same for French and English versions of Word. #### How to remap a shortcut key {#TranslatingGesturesSteps} ##### Identify the class, the script and the original gesture to be remapped {#TranslatingGesturesStepIdentify} -To edit the gesture.ini file, you will have to identify the class, the script and the original shortcut you want to remap. +To edit the `gesture.ini` file, you will have to identify the class, the script and the original shortcut you want to remap. ##### Case of a global command script {#TranslatingGesturesStepCaseGlobal} @@ -290,7 +292,8 @@ If the gesture to be remapped is a global command, you may execute the following * press the gesture you want to remap, e.g. `NVDA+]` (laptop layout) * de-activate input help (`NVDA+1`) * open the log (`NVDA+F1`) -* find out the line corresponding to the moment you have executed the gesture, e.g.: +* find out the line corresponding to the moment you executed the gesture, e.g.: + ``` Input help: gesture kb(laptop):NVDA+], bound to script rightMouseClick on globalCommands.GlobalCommands ``` @@ -298,7 +301,7 @@ If the gesture to be remapped is a global command, you may execute the following The information you are searching is on this line: * script name: `rightMouseClick` -* class name: `globalCommands.GlobalCommands` (Note that this is always this class for global commands) +* class name: `globalCommands.GlobalCommands` (Note that this is always the class for global commands) * original gesture: `kb(laptop):NVDA+]` ##### Case of an application specific script {#TranslatingGesturesStepCaseApplication} @@ -308,19 +311,19 @@ You just need to ensure before proceeding that you are in the targeted applicati ##### Case of an object specific script {#TranslatingGesturesStepCaseObject} -For object specific scripts such as the ones linked to `NVDAObjects.window.winword.WordDocument`, you may follow the same steps as those for application specific script, paying attention to the two following points: +For object specific scripts such as the ones linked to `NVDAObjects.window.winword.WordDocument`, you may follow the same steps as those for application specific scripts, paying attention to the two following points: * You need to ensure before proceeding that the object to which the script is bound is focused. * Some of these scripts have no help message, so you may not hear anything when executing them in input help mode; but the script's name and the class of the object will still appear in the log. -Though, the class of the object appearing in the log may be a subclass of the one where the original gesture is actually bound. +Note, that the class of the object appearing in the log may be a subclass of the one where the original gesture is actually bound. In this case, you will have to explore NVDA's source code to find this parent class. #### Translating this file {#TranslatingGesturesFile} -Translations for gestures.ini happen on SVN following [this process](https://github.com/nvaccess/nvda/wiki/TranslatingUsingAutomaticProcess). +Translations for `gestures.ini` happen on SVN following [this process](https://github.com/nvaccess/nvda/wiki/TranslatingUsingAutomaticProcess). -1. In your local copy of the screenReaderTranslations repository, check if the gestures.ini file exists, e.g. `d:\SVN\SRT\fr\gestures.ini` +1. In your local copy of the screenReaderTranslations repository, check if the `gestures.ini` file exists, e.g. `d:\SVN\SRT\fr\gestures.ini` * If this file does not exist, create it by copying it from the last version of NVDA. * If it already exists, all is fine. 2. In this file the sections correspond to the class to which the script belongs. @@ -331,7 +334,7 @@ If the class your looking for does not exist, create this section. toggleBold = kb:control+g, kb:control+shift+b ``` - If a line already exists for the script name you want to modify the shortcut, add the new shortcut on the same line, separating each shortcut from another with a comma (,) + If a line already exists for the script name, but you want to modify the shortcut: add the new shortcut on the same line, separating each shortcut from others with a comma ("`,`") 4. If you want to unmap the original shortcut, just map it to `None`, e.g.: @@ -342,8 +345,7 @@ If the class your looking for does not exist, create this section. Unmapping the original shortcut is only required if this shortcut does not match any other remapped locale shortcut. 5. Save your file in UTF-8 format. -6. Commit your changes to screenReaderTranslations repo. - +6. Commit your changes to the screenReaderTranslations repo. ## Plugins {#plugins} ### Overview {#pluginsOverview} @@ -834,8 +836,8 @@ This is done by providing an App Module for that application which simply sets s ### Example 5: A Sleep Mode App Module {#example5} -The following code can be copied and pasted in to a text file, then saved in the appModules directory with the name of the application you wish to enable sleep mode for. -As always, the file must have a .py extension. +The following code can be copied and pasted in to a text file, then saved in the `appModules` directory with the name of the application you wish to enable sleep mode for. +As always, the file must have a `.py` extension. ```py import appModuleHandler @@ -853,22 +855,22 @@ This method allows you to place all the needed logic for a particular control al There are two steps to providing a custom NVDA Object class: * Define the NVDA Object class and its events, scripts, gesture bindings and overridden properties. -* Tell NVDA to use this NVDA Object class in specific situations by handling it in the plugin's chooseNVDAObjectOverlayClasses method. +* Tell NVDA to use this NVDA Object class in specific situations by handling it in the plugin's `chooseNVDAObjectOverlayClasses` method. When defining a custom NVDAObject class, you have many NVDAObject base classes to choose from. These base classes contain the base support for the particular accessibility or OS API underlying the control, such as win32, MSAA or Java access Bridge. You should usually inherit your custom NVDAObject class from the highest base class you need in order to choose your class in the first place. -For example, if you choose to use your custom NVDAObject class when the window class name is "Edit" and the window control ID is 15, you should probably inherit from NVDAObjects.window.Window, as clearly you are aware that this is a Window object. -Similarly, if you match on MSAA's accRole property, you would probably need to inherit from NVDAObjects.IAccessible.IAccessible. +For example, if you choose to use your custom NVDAObject class when the window class name is "Edit" and the window control ID is 15, you should probably inherit from `NVDAObjects.window.Window`, as clearly you are aware that this is a Window object. +Similarly, if you match on MSAA's `accRole` property, you would probably need to inherit from `NVDAObjects.IAccessible.IAccessible`. You should also consider what properties you are going to override on the custom NVDA Object. -For instance, if you are going to override an IAccessible specific property, such as shouldAllowIAccessibleFocusEvent, then you need to inherit from NVDAObjects.IAccessible.IAccessible. +For instance, if you are going to override an IAccessible specific property, such as `shouldAllowIAccessibleFocusEvent`, then you need to inherit from `NVDAObjects.IAccessible.IAccessible`. -The chooseNVDAObjectOverlayClasses method can be implemented on app modules or global plugin classes. +The `chooseNVDAObjectOverlayClasses` method can be implemented on app modules or global plugin classes. It takes 3 arguments: -1. self: the app module or global plugin instance. -1. obj: the NVDAObject for which classes are being chosen. -1. clsList: a Python list of NVDAObject classes that will be used for obj. +1. `self`: the app module or global plugin instance. +1. `obj`: the `NVDAObject` for which classes are being chosen. +1. `clsList`: a Python list of `NVDAObject` classes that will be used for `obj`. Inside this method, you should decide which custom NVDA Object class(es) (if any) this NVDA Object should use by checking its properties, etc. If a custom class should be used, it must be inserted into the class list, usually at the beginning. @@ -877,10 +879,10 @@ You can also remove classes chosen by NVDA from the class list, although this is ### Example 6: Command to Retrieve the Length of Text in an Edit Field Using a Custom NVDA Object {#example6} This app module for notepad provides a command to report the number of characters in edit fields. -You can activate it using NVDA+l. +You can activate it using `NVDA+l`. Notice that the command is specific to edit fields; i.e. it only works while you are focused in an edit field, rather than anywhere in the application. -The following code can be copied and pasted in to a text file, then saved in the appModules directory with the name of notepad.py. +The following code can be copied and pasted in to a text file, then saved in the `appModules` directory with the name of `notepad.py`. ```py import appModuleHandler @@ -906,12 +908,12 @@ class EnhancedEditField(IAccessible): Sometimes, you may wish to make only small changes to an NVDA Object in an application, such as overriding its name or role. In these cases, you don't need the full power of a custom NVDA Object class. -To do this, you can use the NVDAObject_init event available only on App Modules. +To do this, you can use the `NVDAObject_init` event available only on App Modules. -The event_NVDAObject_init method takes two arguments: +The `event_NVDAObject_init` method takes two arguments: -1. self: the AppModule instance. -1. obj: the NVDAObject being initialized. +1. `self`: the AppModule instance. +1. `obj`: the `NVDAObject` being initialized. Inside this method, you can check whether this object is relevant and then override properties accordingly. @@ -920,7 +922,7 @@ Inside this method, you can check whether this object is relevant and then overr This app module for notepad makes NVDA report Notepad's main edit field as having a name of "content". That is, when it receives focus, NVDA will say "Content edit". -The following code can be copied and pasted in to a text file, then saved in the appModules directory with the name of notepad.py. +The following code can be copied and pasted in to a text file, then saved in the `appModules` directory with the name of `notepad.py`. ```py import appModuleHandler @@ -935,27 +937,35 @@ class AppModule(appModuleHandler.AppModule): ### Parsing additional command line arguments in your plugin {#PluginCLIArgs} -By default NVDA accepts limited set of command line arguments and shows an error for an unknown ones. -However if you want to use any additional arguments, this is possible by adding a handler to the extension point `addonHandler.isCLIParamKnown`. -Note that since command line arguments are processed just after NVDA starts, your add-on needs to process them in the global plugin, since app modules or other drivers may not be loaded at this stage. +By default NVDA accepts a limited set of command line arguments and shows an error for unknown ones. +However if you want to use any additional arguments, this is possible by adding a handler to the [extension point](#ExtensionPoints) `addonHandler.isCLIParamKnown`. +Note that since command line arguments are processed just after NVDA starts, your add-on needs to process them in a global plugin, since app modules or other drivers may not be loaded at this stage. A sample handler can be written as follows: ```py def processArgs(cliArgument: str) -> bool: if cliArgument == "--enable-addon-feature": - ... + # Code to process your argument... return True # Argument is known to the add-on and should not be flagged by NVDA return False # unknown argument - NVDA should warn user ``` -Then the handler needs to be registered - preferably in the constructor of your global plugin: +Then the handler needs to be registered, preferably in the constructor of your global plugin: + +```py +import addonHandler + +class GlobalPlugin(globalPluginHandler.GlobalPlugin): + + def __init__(self) -> None: + super().__init__() + addonHandler.isCLIParamKnown.register(processArgs) +``` - addonHandler.isCLIParamKnown.register(processArgs) ## Packaging Code as NVDA Add-ons {#Addons} Add-ons make it easy for users to share and install plugins, drivers, speech symbol dictionaries and braille translation tables. They can be packaged in to a single NVDA add-on package, which the user can then install into a copy of NVDA via the Add-on Store found under Tools in the NVDA menu. -Add-on packages are only supported in NVDA 2012.2 and later. An add-on package is simply a standard zip archive with the file extension of "`nvda-addon`". It can contain a manifest file, install/uninstall code and directories containing plugins, drivers, speech symbol dictionaries and braille translation tables. @@ -1019,7 +1029,7 @@ The lastTestedNVDAVersion field in particular is used to ensure that users can b It allows the add-on author to make an assurance that the add-on will not cause instability, or break the users system. When this is not provided, or is less than the current version of NVDA (ignoring minor point updates e.g. 2018.3.1) then the user will be warned not to install the add-on. -The manifest can also specify information regarding the additional speech symbol dictionaries and braille translation tables provided by the add-on. +The manifest can also specify information regarding any additional speech symbol dictionaries or braille translation tables provided by the add-on. Please refer to the [speech symbol dictionaries](#AddonSymbolDictionaries) and [braille translation tables](#BrailleTables) sections. #### An Example Manifest File {#manifestExample} @@ -1040,29 +1050,29 @@ lastTestedNVDAVersion = "2022.3.3" The following plugins and drivers can be included in an add-on: -* App modules: Place them in an appModules directory in the archive. -* Braille display drivers: Place them in a brailleDisplayDrivers directory in the archive. -* Global plugins: Place them in a globalPlugins directory in the archive. -* Synthesizer drivers: Place them in a synthDrivers directory in the archive. +* App modules: Place them in an `appModules` directory in the archive. +* Braille display drivers: Place them in a `brailleDisplayDrivers` directory in the archive. +* Global plugins: Place them in a `globalPlugins` directory in the archive. +* Synthesizer drivers: Place them in a `synthDrivers` directory in the archive. * [Speech symbol dictionaries](#AddonSymbolDictionaries): Place them in the directory for one or more [locales](#localizingAddons) with a file name of `symbols-.dic`, e.g. `locale\en\symbols-greek.dic`. -* [Braille translation tables](#BrailleTables): Place them in a brailleTables directory in the archive. +* [Braille translation tables](#BrailleTables): Place them in a `brailleTables` directory in the archive. ### Optional install / Uninstall code {#installUninstallCode} -If you need to execute code as your add-on is being installed or uninstalled from NVDA (e.g. to validate license information or to copy files to a custom location), you can provide a Python file called installTasks.py in the archive which contains special functions that NVDA will call while installing or uninstalling your add-on. +If you need to execute code as your add-on is being installed or uninstalled from NVDA (e.g. to validate license information or to copy files to a custom location), you can provide a Python file called `installTasks.py` in the archive which contains special functions that NVDA will call while installing or uninstalling your add-on. This file should avoid loading any modules that are not absolutely necessary, especially Python C extensions or dlls from your own add-on, as this could cause later removal of the add-on to fail. However, if this does happen, the add-on directory will be renamed and then deleted after the next restart of NVDA. -Finally, it should not depend on the existence or state of other add-ons, as they may not be installed, have already been removed or not yet be initialized. +Finally, it should not depend on the existence or state of other add-ons, as they may not be installed, may have already been removed or may not yet be initialized. #### the onInstall function {#onInstall} -NVDA will look for and execute an onInstall function in installTasks.py after it has finished extracting the add-on into NVDA. -Note that although the add-on will have been extracted at this time, its directory will have a .pendingInstall suffix until NVDA is restarted, the directory is renamed and the add-on is really loaded for the first time. +NVDA will look for and execute an `onInstall` function in `installTasks.py` after it has finished extracting the add-on into NVDA. +Note that although the add-on will have been extracted at this point, its directory will have a `.pendingInstall` suffix until NVDA is restarted, the directory is renamed and the add-on is really loaded for the first time. If this function raises an exception, the installation of the add-on will fail and its directory will be cleaned up. #### The onUninstall Function {#onUninstall} -NVDA will look for and execute an onUninstall function in installTasks.py when NVDA is restarted after the user has chosen to remove the add-on. +NVDA will look for and execute an `onUninstall` function in `installTasks.py` when NVDA is restarted after the user has chosen to remove the add-on. After this function completes, the add-on's directory will automatically be removed. As this happens on NVDA startup before other components are initialized, this function cannot request input from the user. @@ -1075,7 +1085,7 @@ This directory should contain directories for each language it supports, using t #### Locale-specific Manifest Files {#localeManifest} Each of these language directories can contain a locale-specific manifest file called manifest.ini, which can contain a small subset of the manifest fields for translation. -These fields are summary and description. +These fields are `summary` and `description`. You can also override the `displayName` field for speech symbol dictionaries and braille translation tables. All other fields will be ignored. @@ -1243,7 +1253,7 @@ These variables are: ### Tab completion {#pythonConsoleTab} -The input control supports tab-completion of variables and member attributes names. +The input control supports tab-completion of variables and member attribute names. Hit the tab key once to complete the current input if there is one single candidate. If there is more than one, hit the tab key a second time to open a menu listing all matching possibilities. By default, only "public" member attributes are listed. @@ -1277,7 +1287,7 @@ There are some special functions: NVDA's `extensionPoints` module, allows code in different parts of NVDA, or in add-ons, to perform tasks such as: -* Be notified when an action occurs or a state is changed. +* Being notified when an action occurs or a state is changed. * Receive, as part of being notified, variables related to the action or changed state. * Cancel or alter an action NVDA was going to take, based upon certain conditions. * Modify data that NVDA is using (such as changing speech sequences or braille, before they are spoken or brailled).