Core Modules
appModuleHandler
Handles application-specific modules.
Base class for app modules Properties:
processID (int): Process ID
appName (str): Application name
processHandle (int): Process handle
sleepMode (bool): Whether NVDA sleeps in this app
productName (str): Product name from executable
productVersion (str): Product version
is64BitProcess (bool): Whether process is 64-bit
isWindowsStoreApp (bool): Whether this is a Store app
Methods:
chooseNVDAObjectOverlayClasses(obj, clsList): Choose overlay classes
event_appModule_gainFocus(): Called when app gains focus
event_appModule_loseFocus(): Called when app loses focus
getAppModuleFromProcessID
Get app module for a process mod = appModuleHandler.getAppModuleFromProcessID(processID)
registerExecutableWithAppModule
Register custom executable-to-module mapping appModuleHandler.registerExecutableWithAppModule(
"myapp" ,
"myAppModule"
)
globalPluginHandler
Handles global plugins.
Base class for global plugins Methods:
terminate(): Called when plugin is unloaded
chooseNVDAObjectOverlayClasses(obj, clsList): Choose overlay classes
Set of currently running global plugins
api
Core API functions for accessing NVDA state.
Focus
Navigator
Mouse
Review
import api
# Get focused object
obj = api.getFocusObject()
# Get focus ancestors (parent chain)
ancestors = api.getFocusAncestors()
# Set focus
api.setFocusObject(obj)
# Get foreground object
fg = api.getForegroundObject()
User interface feedback.
import ui
# Simple message
ui.message( "Hello" )
# Browse mode message (interruptible)
ui.browseableMessage( "Long text..." , title = "Title" )
# Report status
ui.reportTextCopied(text)
ui.reportTextNotCopied()
controlTypes
Control roles and states.
import controlTypes
# Common roles
controlTypes.Role. BUTTON
controlTypes.Role. EDITABLETEXT
controlTypes.Role. CHECKBOX
controlTypes.Role. RADIOBUTTON
controlTypes.Role. COMBOBOX
controlTypes.Role. LIST
controlTypes.Role. LISTITEM
controlTypes.Role. LINK
controlTypes.Role. TREEVIEW
controlTypes.Role. TREEVIEWITEM
controlTypes.Role. TABLE
controlTypes.Role. TABLECELL
controlTypes.Role. MENU
controlTypes.Role. MENUITEM
controlTypes.Role. DIALOG
controlTypes.Role. WINDOW
scriptHandler
Script decorator and utilities.
Decorator for defining scripts from scriptHandler import script
@script (
description = "My script" ,
category = "My Category" ,
gesture = "kb:NVDA+shift+m"
)
def script_myScript ( self , gesture ):
pass
Parameters:
description (str): User-visible description
category (str): Category for Input Gestures
gesture (str): Single gesture string
gestures (list[str]): Multiple gestures
canPropagate (bool): Allow on ancestors
bypassInputHelp (bool): Run in input help
allowInSleepMode (bool): Run in sleep mode
resumeSayAllMode: Resume say all mode
speakOnDemand (bool): Speak on-demand
speech
Speech output.
Basic Speech
Speech Sequences
Speech Modes
import speech
# Speak text
speech.speak([ "Hello world" ])
# Cancel speech
speech.cancelSpeech()
# Spell text
speech.speakSpelling( "word" )
# Speak character
speech.speakCharacter( "a" )
tones
Audio feedback.
import tones
# Beep (frequency, duration in ms)
tones.beep( 550 , 50 )
# Error beep
tones.beep( 220 , 150 )
# Success beep
tones.beep( 880 , 100 )
config
Configuration management.
Reading Config
Writing Config
Profile Triggers
import config
# Access settings
rate = config.conf[ "speech" ][ "rate" ]
verbosity = config.conf[ "speech" ][ "symbolLevel" ]
# Check if value exists
if "myAddon" in config.conf:
enabled = config.conf[ "myAddon" ][ "enabled" ]
textInfos
Text access and manipulation.
TextInfo Basics
Units
Positions
import textInfos
# Get text
info = obj.makeTextInfo(textInfos. POSITION_CARET )
text = info.text
# Move
info.move(textInfos. UNIT_CHARACTER , 1 )
info.move(textInfos. UNIT_WORD , - 1 )
info.move(textInfos. UNIT_LINE , 1 )
# Expand
info.expand(textInfos. UNIT_LINE )
info.expand(textInfos. UNIT_PARAGRAPH )
queueHandler
Thread-safe queue operations.
import queueHandler
import ui
# Queue function on main thread
def myFunction ( arg1 , arg2 ):
ui.message( f " { arg1 } , { arg2 } " )
queueHandler.queueFunction(
queueHandler.eventQueue,
myFunction,
"hello" ,
"world"
)
# Register generator (for long operations)
def myGenerator ():
for i in range ( 10 ):
yield lambda : ui.message( str (i))
queueHandler.registerGeneratorObject(myGenerator())
winUser
Windows API functions.
import winUser
# Window functions
hwnd = winUser.getForegroundWindow()
winUser.setForegroundWindow(hwnd)
winUser.isWindow(hwnd)
# Window text
text = winUser.getWindowText(hwnd)
winUser.setWindowText(hwnd, "New title" )
# Window class
className = winUser.getClassName(hwnd)
# Process/thread
threadId, processId = winUser.getWindowThreadProcessID(hwnd)
# Send messages
winUser.sendMessage(hwnd, message, wParam, lParam)
# Get control ID
controlId = winUser.getControlID(hwnd)
gui
GUI dialogs and utilities.
Dialogs
Running on Main Thread
import gui
import wx
# Message dialog
gui.messageBox(
"Message text" ,
"Title" ,
wx. OK | wx. ICON_INFORMATION
)
# Input dialog
result = gui.textEntryDialog(
"Enter text:" ,
"Title" ,
defaultValue = ""
)
NVDAObjects Classes
Base Classes
from NVDAObjects.IAccessible import IAccessible
class MyControl ( IAccessible ):
"""MSAA/IAccessible object."""
pass
Behaviors
from NVDAObjects.behaviors import (
EditableText, # Editable text with caret
Dialog, # Dialog handling
ProgressBar, # Progress announcements
RowWithFakeNavigation, # Table row navigation
KeyboardHandlerBasedTypedCharSupport, # Typed chars
)
Events
Common NVDA Object events:
Object gained keyboard focus
Object lost keyboard focus
Focus moved inside container (object is ancestor)
Object became foreground window
Selection changed in container
Caret moved within object
Object’s screen location changed
Gesture Identifiers
Keyboard
# Standard
"kb:NVDA+shift+v"
"kb:control+alt+delete"
"kb:f1"
# Laptop layout
"kb(laptop):NVDA+t"
# Named keys
"kb:escape"
"kb:enter"
"kb:space"
"kb:tab"
"kb:backspace"
"kb:delete"
"kb:home"
"kb:end"
"kb:pageUp"
"kb:pageDown"
"kb:upArrow"
"kb:downArrow"
"kb:leftArrow"
"kb:rightArrow"
"kb:numpad0" through "kb:numpad9"
"kb:numpadPlus"
"kb:numpadMinus"
"kb:numpadMultiply"
"kb:numpadDivide"
"kb:numpadEnter"
Braille
# Freedom Scientific
"br(freedomScientific):leftWizWheelUp"
"br(freedomScientific):rightWizWheelDown"
# Alva
"br(alva):t1"
"br(alva):etouch1"
# Generic
"br:space+dot1"
Touch
"ts:tap"
"ts:2finger_tap"
"ts:3finger_flickRight"
"ts:4finger_flickUp"
Logging
from logHandler import log
# Log levels
log.debug( "Debug info" )
log.info( "Information" )
log.warning( "Warning" )
log.error( "Error" )
log.exception( "Exception with traceback" )
# With exc_info for stack traces
log.error( "Error occurred" , exc_info = True )
# Stack info without exception
log.warning( "Check this" , stack_info = True )
Utility Modules
locationHelper
import locationHelper
# Rectangle operations
rect1 = locationHelper.RectLTWH( 0 , 0 , 100 , 100 )
rect2 = locationHelper.RectLTWH( 50 , 50 , 100 , 100 )
# Check if rectangles intersect
if rect1.intersection(rect2):
pass
# Get center point
center = rect1.center
textUtils
import textUtils
# Unicode normalization
normalized = textUtils.normalizeText(text)
# Word boundaries
words = textUtils.WideStringOffsetConverter(text)
Best Practices
Always import from the original module (check source code)
Don’t rely on transitive imports
Private symbols (starting with _) may change without notice
Package pip dependencies with your add-on
Use ui.message() for user feedback
Use log.debug() for development
Use queueHandler for thread safety
Cache expensive operations
Handle exceptions gracefully
Version Compatibility
Check NVDA version:
import versionInfo
# Version tuple: (year, major, minor)
if versionInfo.version_year >= 2024 :
# Use newer API
pass
# Version string
version = versionInfo.version # e.g., "2024.1"