You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让屏幕阅读器在Qt后台应用未获焦点时播报文本?

在Qt 5.15(Windows 10)后台无焦点状态下触发屏幕阅读器播报

你遇到的问题核心在于:Qt的QAccessibleEvent依赖于应用内控件的焦点状态,后台无焦点时系统无障碍框架会忽略这类事件。要实现无焦点播报,直接调用Windows原生API是更可靠的方案,以下提供两种可行思路:

方案1:直接调用系统语音合成接口(SAPI)

这种方式最直接,不依赖应用焦点或无障碍元素,直接触发系统语音引擎播报文本,所有主流屏幕阅读器(如讲述人、NVDA、JAWS)都会识别并输出语音。

代码示例

#include <sapi.h>
#include <sphelper.h>
#pragma comment(lib, "sapi.lib")

void announceText(const QString& content) {
    ISpVoice* voiceInterface = nullptr;
    
    // 初始化COM环境
    if (CoInitialize(nullptr) != S_OK) {
        return;
    }

    // 创建语音合成实例
    HRESULT hr = CoCreateInstance(CLSID_SpVoice, nullptr, CLSCTX_ALL, 
                                 IID_ISpVoice, reinterpret_cast<void**>(&voiceInterface));
    if (SUCCEEDED(hr)) {
        // 执行播报(SPF_DEFAULT表示同步播报,若需异步可改用SPF_ASYNC)
        voiceInterface->Speak((LPCWSTR)content.utf16(), SPF_DEFAULT, nullptr);
        voiceInterface->Release();
    }

    CoUninitialize();
}

使用方式

在后台事件触发时直接调用:

// 比如接收到特定事件后
announceText("后台事件触发,这是播报内容");

方案2:通过UI Automation发送无障碍警报事件

如果希望遵循无障碍框架规范,让屏幕阅读器自行处理播报逻辑(比如使用用户预设的语音设置),可以通过Windows UI Automation API发送Alert事件,无需获取应用焦点。

前置准备

后台应用需要一个隐藏窗口作为无障碍元素的载体(UI Automation事件需绑定到某个窗口句柄):

// 在应用启动时创建隐藏窗口
HWND hiddenAccessibilityWnd = CreateWindowEx(
    0, L"STATIC", L"Hidden Accessibility Host", 
    WS_POPUP, 0, 0, 0, 0, nullptr, nullptr, GetModuleHandle(nullptr), nullptr
);
ShowWindow(hiddenAccessibilityWnd, SW_HIDE);

播报代码示例

#include <windows.h>
#include <uiautomation.h>
#pragma comment(lib, "uiautomation.lib")

void triggerAccessibilityAlert(const QString& alertContent, HWND hostWnd) {
    IUIAutomation* uiAutomation = nullptr;
    IUIAutomationElement* targetElement = nullptr;

    if (CoInitialize(nullptr) != S_OK) {
        return;
    }

    // 创建UI Automation实例
    HRESULT hr = CoCreateInstance(CLSID_CUIAutomation, nullptr, CLSCTX_INPROC_SERVER,
                                 IID_IUIAutomation, reinterpret_cast<void**>(&uiAutomation));
    if (SUCCEEDED(hr)) {
        // 从窗口句柄获取无障碍元素
        hr = uiAutomation->ElementFromHandle(hostWnd, &targetElement);
        if (SUCCEEDED(hr)) {
            // 设置元素名称为要播报的内容
            targetElement->SetCurrentPropertyValue(UIA_NamePropertyId, alertContent.toVariant());
            // 触发Alert事件,屏幕阅读器会自动播报元素名称
            uiAutomation->RaiseAutomationEvent(targetElement, UIA_AlertEventId);
            targetElement->Release();
        }
        uiAutomation->Release();
    }

    CoUninitialize();
}

使用方式

在事件触发时传入隐藏窗口句柄:

triggerAccessibilityAlert("后台事件通知", hiddenAccessibilityWnd);

关键说明

  • Qt的QAccessibleEvent失效原因:系统无障碍服务默认仅监听前台焦点进程的无障碍事件,后台无焦点应用的这类事件会被过滤,因此必须绕开Qt封装,直接调用Windows原生API。
  • SAPI vs UI Automation:前者适合简单文本播报,后者更符合无障碍规范,能适配用户的屏幕阅读器设置,但需要额外维护隐藏窗口。

内容的提问来源于stack exchange,提问作者Gurushant

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 20:50:28