> ## 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.

# Controller Client API

> External API for applications to communicate with NVDA

## Introduction

The NVDA Controller Client API allows external applications to communicate with NVDA, enabling them to:

* Speak text programmatically
* Display braille messages
* Cancel speech
* Check if NVDA is running
* Speak SSML (Speech Synthesis Markup Language)

The API is implemented as a DLL (Dynamic Link Library) that can be called from any programming language that supports loading and calling functions from DLLs.

<Info>
  The Controller Client API is primarily designed for applications that want to provide their own accessibility layer or need to communicate information directly to NVDA users.
</Info>

## Getting the API

<Tabs>
  <Tab title="Download Pre-built">
    Download the `*controllerClient.zip` from:

    * [Latest stable release](https://download.nvaccess.org/releases/stable/)
    * [GitHub Actions artifacts](https://github.com/nvaccess/nvda/actions) for development versions
  </Tab>

  <Tab title="Build from Source">
    Build the controller client yourself:

    ```bash theme={null}
    scons source client
    ```

    Build output is available in `./build/[x86|x64|arm64]/client/`
  </Tab>
</Tabs>

## What's Included

<CardGroup cols={2}>
  <Card title="DLL Files" icon="file-code">
    Platform-specific `nvdaControllerClient.dll` files for x86, x64, and ARM64
  </Card>

  <Card title="Header File" icon="file">
    `nvdaController.h` with C declarations for all functions
  </Card>

  <Card title="Import Libraries" icon="book">
    `.lib` and `.exp` files for C/C++ linking
  </Card>

  <Card title="Examples" icon="code">
    Sample code in Python, C, C#, and Rust
  </Card>
</CardGroup>

## API Versions

### Version 2.0 (NVDA 2024.1+)

Added support for:

* `nvdaController_getProcessId` - Get NVDA's process ID
* `nvdaController_speakSsml` - Speak SSML with markup support

<Warning>
  These functions return error code 1717 (RPC\_S\_UNKNOWN\_IF) on NVDA versions older than 2024.1.
</Warning>

### Version 1.0

Core functions available in all NVDA versions:

* Test if NVDA is running
* Speak text
* Braille messages
* Cancel speech

## Security Considerations

<Warning>
  NVDA runs on the lock screen and secure screens. Before providing information to users via the Controller Client API, check if Windows is locked or on a secure screen to prevent leaking secure data.
</Warning>

Applications should implement security checks:

```python theme={null}
import ctypes

# Check if on secure desktop
def is_secure_desktop():
    # Implementation depends on your security requirements
    # Check for locked workstation or secure screen
    pass

# Only speak if not on secure desktop
if not is_secure_desktop():
    clientLib.nvdaController_speakText("Sensitive information")
```

## Core Functions

### nvdaController\_testIfRunning()

Test if NVDA is running and accessible.

<ParamField path="Return Value" type="int">
  0 on success, non-zero Windows error code on failure
</ParamField>

```python theme={null}
import ctypes

clientLib = ctypes.windll.LoadLibrary("./nvdaControllerClient.dll")

res = clientLib.nvdaController_testIfRunning()
if res != 0:
    errorMessage = str(ctypes.WinError(res))
    print(f"NVDA not running: {errorMessage}")
```

### nvdaController\_speakText(text)

Speak the provided text through NVDA.

<ParamField path="text" type="wchar_t*" required>
  The text to speak (wide character string)
</ParamField>

<ParamField path="Return Value" type="int">
  0 on success, non-zero error code on failure
</ParamField>

```python theme={null}
# Speak a message
clientLib.nvdaController_speakText("Hello from my application!")
```

### nvdaController\_brailleMessage(message)

Display a message on the user's braille display.

<ParamField path="message" type="wchar_t*" required>
  The message to display in braille
</ParamField>

<ParamField path="Return Value" type="int">
  0 on success, non-zero error code on failure
</ParamField>

```python theme={null}
# Show a braille message
clientLib.nvdaController_brailleMessage("Status: Connected")
```

### nvdaController\_cancelSpeech()

Cancel all currently queued speech.

<ParamField path="Return Value" type="int">
  0 on success, non-zero error code on failure
</ParamField>

```python theme={null}
# Stop speaking
clientLib.nvdaController_cancelSpeech()
```

### nvdaController\_getProcessId()

Get the process ID of the running NVDA instance.

<ParamField path="processId" type="DWORD*" required>
  Pointer to receive the process ID
</ParamField>

<ParamField path="Return Value" type="int">
  0 on success, 1717 if not supported, other non-zero on failure
</ParamField>

<Note>
  Available in NVDA 2024.1 and later
</Note>

```python theme={null}
processId = ctypes.c_ulong()
res = clientLib.nvdaController_getProcessId(ctypes.byref(processId))
if res == 0:
    print(f"NVDA Process ID: {processId.value}")
```

### nvdaController\_speakSsml()

Speak SSML (Speech Synthesis Markup Language) with support for prosody, marks, and breaks.

<ParamField path="ssml" type="wchar_t*" required>
  The SSML string to speak
</ParamField>

<ParamField path="symbolLevel" type="int">
  Symbol verbosity level (-1 for user's setting)
</ParamField>

<ParamField path="priority" type="int">
  Speech priority (0 = normal)
</ParamField>

<ParamField path="asynchronous" type="bool">
  Whether to speak asynchronously
</ParamField>

<ParamField path="Return Value" type="int">
  0 on success, 1717 if not supported, other non-zero on failure
</ParamField>

<Note>
  Available in NVDA 2024.1 and later
</Note>

```python theme={null}
ssml = """<speak>
    This is one sentence.
    <mark name="test" />
    <prosody pitch="200%">This sentence is pronounced with higher pitch.</prosody>
    <break time="1000ms" />
    This is after a one second pause.
</speak>"""

clientLib.nvdaController_speakSsml(ssml, -1, 0, False)
```

### nvdaController\_setOnSsmlMarkReachedCallback()

Set a callback function to be called when SSML marks are reached.

<ParamField path="callback" type="function pointer">
  Function with signature: `int callback(wchar_t* markName)`
</ParamField>

<ParamField path="Return Value" type="int">
  0 on success, non-zero error code on failure
</ParamField>

```python theme={null}
@ctypes.WINFUNCTYPE(ctypes.c_ulong, ctypes.c_wchar_p)
def onMarkReached(name: str) -> int:
    print(f"Reached SSML mark: {name}")
    return 0

clientLib.nvdaController_setOnSsmlMarkReachedCallback(onMarkReached)
# Speak SSML with marks
clientLib.nvdaController_speakSsml(ssml, -1, 0, False)
# Clear callback when done
clientLib.nvdaController_setOnSsmlMarkReachedCallback(None)
```

## Complete Examples

### Python Example

<CodeGroup>
  ```python Basic Usage theme={null}
  import ctypes
  import time

  # Load the library
  clientLib = ctypes.windll.LoadLibrary("./nvdaControllerClient.dll")

  # Test if NVDA is running
  res = clientLib.nvdaController_testIfRunning()
  if res != 0:
      errorMessage = str(ctypes.WinError(res))
      print(f"Error: {errorMessage}")
      exit(1)

  # Speak and braille messages
  clientLib.nvdaController_speakText("Application started successfully")
  clientLib.nvdaController_brailleMessage("Ready")

  # Cancel speech if needed
  time.sleep(2)
  clientLib.nvdaController_cancelSpeech()
  ```

  ```python SSML with Callbacks theme={null}
  import ctypes

  clientLib = ctypes.windll.LoadLibrary("./nvdaControllerClient.dll")

  # Define callback
  @ctypes.WINFUNCTYPE(ctypes.c_ulong, ctypes.c_wchar_p)
  def onMarkReached(name: str) -> int:
      print(f"Reached mark: {name}")
      return 0

  # Set callback
  clientLib.nvdaController_setOnSsmlMarkReachedCallback(onMarkReached)

  # Speak SSML
  ssml = """<speak>
      Progress: <mark name="start" />
      50 percent complete.
      <mark name="halfway" />
      100 percent complete.
      <mark name="done" />
  </speak>"""

  clientLib.nvdaController_speakSsml(ssml, -1, 0, False)

  # Clean up
  clientLib.nvdaController_setOnSsmlMarkReachedCallback(None)
  ```
</CodeGroup>

### C Example

```c example_c.c theme={null}
#include "nvdaController.h"
#include <windows.h>

int main(int argc, char **argv) {
    // Test if NVDA is running
    long res = nvdaController_testIfRunning();
    if (res != 0) {
        MessageBoxA(NULL, "Error communicating with NVDA", "Error", MB_OK);
        return 1;
    }
    
    // Speak text
    nvdaController_speakText(L"Hello from C application!");
    
    // Display braille message
    nvdaController_brailleMessage(L"C App Running");
    
    // Cancel speech
    Sleep(2000);
    nvdaController_cancelSpeech();
    
    return 0;
}
```

### C# Example

```csharp Program.cs theme={null}
using System;
using System.Runtime.InteropServices;
using System.Threading;

class Program
{
    [DllImport("nvdaControllerClient.dll")]
    static extern int nvdaController_testIfRunning();
    
    [DllImport("nvdaControllerClient.dll")]
    static extern int nvdaController_speakText([MarshalAs(UnmanagedType.LPWStr)] string text);
    
    [DllImport("nvdaControllerClient.dll")]
    static extern int nvdaController_brailleMessage([MarshalAs(UnmanagedType.LPWStr)] string message);
    
    [DllImport("nvdaControllerClient.dll")]
    static extern int nvdaController_cancelSpeech();
    
    static void Main(string[] args)
    {
        // Test if NVDA is running
        int res = nvdaController_testIfRunning();
        if (res != 0)
        {
            Console.WriteLine("NVDA is not running");
            return;
        }
        
        // Speak and braille
        nvdaController_speakText("Hello from C# application!");
        nvdaController_brailleMessage("C# App");
        
        Thread.Sleep(2000);
        nvdaController_cancelSpeech();
    }
}
```

## Error Handling

All functions return 0 on success and a non-zero Windows error code on failure. Common error codes:

| Error Code | Meaning                                                               |
| ---------- | --------------------------------------------------------------------- |
| 0          | Success                                                               |
| 1717       | RPC\_S\_UNKNOWN\_IF - Function not supported in this NVDA version     |
| Other      | Standard Windows error codes (use `WinError` or equivalent to decode) |

<Tip>
  Always check the return value of controller client functions and handle errors gracefully. NVDA might not be running, or the user might have disabled it temporarily.
</Tip>

## Best Practices

<CardGroup cols={2}>
  <Card title="Test Availability" icon="check">
    Always call `nvdaController_testIfRunning()` before other operations
  </Card>

  <Card title="Security First" icon="shield">
    Check for secure desktops before speaking sensitive information
  </Card>

  <Card title="Graceful Degradation" icon="code-branch">
    Handle errors gracefully - user might not have NVDA installed
  </Card>

  <Card title="Version Detection" icon="code-compare">
    Check return codes to detect unsupported functions on older NVDA versions
  </Card>
</CardGroup>

## Use Cases

### Progress Notifications

```python theme={null}
def report_progress(percent):
    clientLib.nvdaController_brailleMessage(f"Progress: {percent}%")
    if percent == 100:
        clientLib.nvdaController_speakText("Operation complete")
```

### Form Validation

```python theme={null}
def announce_error(field_name, error_message):
    message = f"{field_name}: {error_message}"
    clientLib.nvdaController_speakText(message)
    clientLib.nvdaController_brailleMessage(f"Error: {field_name}")
```

### Status Updates

```python theme={null}
def announce_connection_status(status):
    ssml = f"""<speak>
        Connection status:
        <mark name="status_start" />
        <prosody rate="slow">{status}</prosody>
        <mark name="status_end" />
    </speak>"""
    clientLib.nvdaController_speakSsml(ssml, -1, 0, False)
```

## License

The NVDA Controller Client API is licensed under the **GNU Lesser General Public License (LGPL), version 2.1**.

This means:

* ✅ You can use this library in any application (commercial or open source)
* ✅ You can distribute the DLL with your application
* ⚠️ If you modify the library, you must contribute changes back under LGPL 2.1

<Card title="View Full License" icon="scale-balanced" href="https://github.com/nvaccess/nvda/blob/master/extras/controllerClient/license.txt">
  Read the complete LGPL 2.1 license text
</Card>

## Additional Resources

<CardGroup cols={2}>
  <Card title="Example Code" icon="code" href="https://github.com/nvaccess/nvda/tree/master/extras/controllerClient/examples">
    Complete working examples in multiple languages
  </Card>

  <Card title="Header File" icon="file-code" href="https://github.com/nvaccess/nvda/blob/master/extras/controllerClient/">
    nvdaController.h with full API documentation
  </Card>

  <Card title="Download Client" icon="download" href="https://download.nvaccess.org/releases/stable/">
    Download pre-built controller client DLLs
  </Card>

  <Card title="GitHub Issues" icon="bug" href="https://github.com/nvaccess/nvda/issues">
    Report issues or request features
  </Card>
</CardGroup>
