> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/nvaccess/nvda/llms.txt
> Use this file to discover all available pages before exploring further.

# API Reference

> Key NVDA add-on development APIs and modules

## Core Modules

### appModuleHandler

Handles application-specific modules.

<ParamField path="AppModule" type="class">
  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
</ParamField>

<ParamField path="getAppModuleFromProcessID" type="function">
  Get app module for a process

  ```python theme={null}
  mod = appModuleHandler.getAppModuleFromProcessID(processID)
  ```
</ParamField>

<ParamField path="registerExecutableWithAppModule" type="function">
  Register custom executable-to-module mapping

  ```python theme={null}
  appModuleHandler.registerExecutableWithAppModule(
      "myapp", 
      "myAppModule"
  )
  ```
</ParamField>

### globalPluginHandler

Handles global plugins.

<ParamField path="GlobalPlugin" type="class">
  Base class for global plugins

  **Methods:**

  * `terminate()`: Called when plugin is unloaded
  * `chooseNVDAObjectOverlayClasses(obj, clsList)`: Choose overlay classes
</ParamField>

<ParamField path="runningPlugins" type="set">
  Set of currently running global plugins
</ParamField>

### api

Core API functions for accessing NVDA state.

<CodeGroup>
  ```python Focus theme={null}
  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()
  ```

  ```python Navigator theme={null}
  import api

  # Get navigator object
  nav = api.getNavigatorObject()

  # Set navigator object
  api.setNavigatorObject(obj)

  # Get desktop object
  desktop = api.getDesktopObject()
  ```

  ```python Mouse theme={null}
  import api

  # Get object under mouse
  obj = api.getMouseObject()

  # Set mouse to object
  api.setMouseObject(obj)
  ```

  ```python Review theme={null}
  import api

  # Get review position
  info = api.getReviewPosition()

  # Set review position  
  api.setReviewPosition(textInfo)
  ```
</CodeGroup>

### ui

User interface feedback.

<CodeGroup>
  ```python Messages theme={null}
  import ui

  # Simple message
  ui.message("Hello")

  # Browse mode message (interruptible)
  ui.browseableMessage("Long text...", title="Title")

  # Report status
  ui.reportTextCopied(text)
  ui.reportTextNotCopied()
  ```

  ```python Notifications theme={null}
  import ui

  # Message with speech priority
  from speech.priorities import Spri
  ui.message("Important", speechPriority=Spri.NOW)

  # Cancel speech before message
  ui.message("Text", cancelSpeech=True)
  ```
</CodeGroup>

### controlTypes

Control roles and states.

<CodeGroup>
  ```python Roles theme={null}
  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
  ```

  ```python States theme={null}
  import controlTypes

  # Common states
  controlTypes.State.FOCUSED
  controlTypes.State.FOCUSABLE
  controlTypes.State.SELECTED
  controlTypes.State.SELECTABLE
  controlTypes.State.CHECKED
  controlTypes.State.COLLAPSED
  controlTypes.State.EXPANDED
  controlTypes.State.READONLY
  controlTypes.State.UNAVAILABLE
  controlTypes.State.INVISIBLE
  controlTypes.State.OFFSCREEN
  controlTypes.State.BUSY
  controlTypes.State.PRESSED
  ```
</CodeGroup>

### scriptHandler

Script decorator and utilities.

<ParamField path="script" type="decorator">
  Decorator for defining scripts

  ```python theme={null}
  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
</ParamField>

### speech

Speech output.

<CodeGroup>
  ```python Basic Speech theme={null}
  import speech

  # Speak text
  speech.speak(["Hello world"])

  # Cancel speech
  speech.cancelSpeech()

  # Spell text
  speech.speakSpelling("word")

  # Speak character
  speech.speakCharacter("a")
  ```

  ```python Speech Sequences theme={null}
  import speech
  from speech import priorities

  # Build sequence
  sequence = [
      "Text",
      speech.IndexCommand(1),
      "More text",
      speech.PitchCommand(offset=50)
  ]

  speech.speak(sequence)

  # With priority
  speech.speak(
      sequence,
      priority=priorities.Spri.NOW
  )
  ```

  ```python Speech Modes theme={null}
  import speech

  # Get current mode
  mode = speech.getState().speechMode

  # Set mode
  speech.setSpeechMode(speech.SpeechMode.talk)
  speech.setSpeechMode(speech.SpeechMode.onDemand)
  speech.setSpeechMode(speech.SpeechMode.off)
  ```
</CodeGroup>

### tones

Audio feedback.

```python tones.py theme={null}
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.

<CodeGroup>
  ```python Reading Config theme={null}
  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"]
  ```

  ```python Writing Config theme={null}
  import config

  # Define spec
  config.conf.spec["myAddon"] = {
      "enabled": "boolean(default=True)",
      "level": "integer(default=1, min=0, max=3)",
      "name": "string(default=\"\")"
  }

  # Write values
  config.conf["myAddon"]["enabled"] = False
  config.conf["myAddon"]["level"] = 2

  # Save
  config.conf.save()
  ```

  ```python Profile Triggers theme={null}
  import config

  class MyTrigger(config.ProfileTrigger):
      def __init__(self):
          self.spec = "addon:myAddon"

  trigger = MyTrigger()
  trigger.enter()
  trigger.exit()
  ```
</CodeGroup>

### textInfos

Text access and manipulation.

<CodeGroup>
  ```python TextInfo Basics theme={null}
  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)
  ```

  ```python Units theme={null}
  import textInfos

  textInfos.UNIT_CHARACTER
  textInfos.UNIT_WORD  
  textInfos.UNIT_LINE
  textInfos.UNIT_SENTENCE
  textInfos.UNIT_PARAGRAPH
  textInfos.UNIT_PAGE
  textInfos.UNIT_STORY  # Entire document
  ```

  ```python Positions theme={null}
  import textInfos

  textInfos.POSITION_FIRST
  textInfos.POSITION_LAST
  textInfos.POSITION_CARET
  textInfos.POSITION_SELECTION
  textInfos.POSITION_ALL
  ```
</CodeGroup>

### queueHandler

Thread-safe queue operations.

```python queueHandler.py theme={null}
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.

```python winUser.py theme={null}
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.

<CodeGroup>
  ```python Dialogs theme={null}
  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=""
  )
  ```

  ```python Running on Main Thread theme={null}
  import gui
  import wx

  def myGuiFunction():
      # GUI code here
      pass

  # Run on main thread
  wx.CallAfter(myGuiFunction)

  # Run and wait for result
  if gui.isInMainThread():
      result = myGuiFunction()
  else:
      result = gui.runInMainThread(myGuiFunction)
  ```
</CodeGroup>

## NVDAObjects Classes

### Base Classes

<CodeGroup>
  ```python IAccessible theme={null}
  from NVDAObjects.IAccessible import IAccessible

  class MyControl(IAccessible):
      """MSAA/IAccessible object."""
      pass
  ```

  ```python UIA  theme={null}
  from NVDAObjects.UIA import UIA

  class MyControl(UIA):
      """UI Automation object."""
      pass
  ```

  ```python Window theme={null}
  from NVDAObjects.window import Window

  class MyControl(Window):
      """Basic window object."""
      pass
  ```

  ```python JAB theme={null}
  from NVDAObjects.JAB import JAB  

  class MyControl(JAB):
      """Java Access Bridge object."""
      pass
  ```
</CodeGroup>

### Behaviors

```python behaviors.py theme={null}
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:

<ParamField path="event_gainFocus" type="event">
  Object gained keyboard focus
</ParamField>

<ParamField path="event_loseFocus" type="event">
  Object lost keyboard focus
</ParamField>

<ParamField path="event_focusEntered" type="event">
  Focus moved inside container (object is ancestor)
</ParamField>

<ParamField path="event_foreground" type="event">
  Object became foreground window
</ParamField>

<ParamField path="event_nameChange" type="event">
  Object's name changed
</ParamField>

<ParamField path="event_valueChange" type="event">
  Object's value changed
</ParamField>

<ParamField path="event_stateChange" type="event">
  Object's state changed
</ParamField>

<ParamField path="event_selection" type="event">
  Selection changed in container
</ParamField>

<ParamField path="event_caret" type="event">
  Caret moved within object
</ParamField>

<ParamField path="event_locationChange" type="event">
  Object's screen location changed
</ParamField>

## Gesture Identifiers

### Keyboard

```python theme={null}
# 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

```python theme={null}
# Freedom Scientific
"br(freedomScientific):leftWizWheelUp"
"br(freedomScientific):rightWizWheelDown"

# Alva
"br(alva):t1"
"br(alva):etouch1"

# Generic
"br:space+dot1"
```

### Touch

```python theme={null}
"ts:tap"
"ts:2finger_tap"
"ts:3finger_flickRight"
"ts:4finger_flickUp"
```

## Logging

```python logging.py theme={null}
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

```python locationHelper.py theme={null}
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

```python textUtils.py theme={null}
import textUtils

# Unicode normalization
normalized = textUtils.normalizeText(text)

# Word boundaries
words = textUtils.WideStringOffsetConverter(text)
```

## Best Practices

<Warning>
  * 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
</Warning>

<Note>
  * Use `ui.message()` for user feedback
  * Use `log.debug()` for development
  * Use `queueHandler` for thread safety
  * Cache expensive operations
  * Handle exceptions gracefully
</Note>

## Version Compatibility

Check NVDA version:

```python version.py theme={null}
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"
```

## Related Resources

* [App Modules →](/development/addons/app-modules)
* [Global Plugins →](/development/addons/global-plugins)
* [Custom NVDA Objects →](/development/addons/custom-nvda-objects)
* [Distribution Guide →](/development/addons/distribution)
