首页 > 系统相关 >Windows无障碍优化:为控件添加可访问标签

Windows无障碍优化:为控件添加可访问标签

时间:2024-11-10 19:40:40浏览次数:4  
标签:控件 get Windows 标签 WM IAccessible 无障碍 读屏

大家好,我是张赐荣。

作为一名专注于无障碍优化的工程师,在日常工作中经常会遇到需要为应用添加读屏软件可识别的控件标签的需求。本文将分享我在C/C++中实现这一需求的经验。

在c/c++开发的Windows原生应用程序中,通过实现IAccessible接口并处理WM_GETOBJECT消息,我们可以为控件提供可访问性标签,从而让读屏软件用户理解控件的作用,提升读屏使用体验。以下是实现这一过程的具体步骤。

背景知识

在Windows无障碍API中,IAccessible接口是Microsoft Active Accessibility(MSAA)的一部分,专为读屏软件等辅助技术服务。通过此接口,开发者可以向辅助技术提供控件的详细信息,例如名称、角色和状态等。本文将介绍如何在C/C++中实现IAccessible接口,特别是如何实现get_accName方法以便为控件提供标签。

实现步骤

定义并继承IAccessible接口

首先,我们需要定义一个类并使其继承自IAccessible接口。此接口包含许多方法,例如get_accNameget_accRole等,用于描述控件的各种属性。在本实现中,我们仅需关注get_accName方法,以返回控件的自定义标签。对于暂时不需要的其他方法,可以简单地返回E_NOTIMPL

以下是定义IAccessible接口的代码:

#include <windows.h>
#include <oleacc.h>

class MyAccessibleControl : public IAccessible {
public:
    // 实现IAccessible中的方法
    IFACEMETHODIMP get_accName(VARIANT varChild, BSTR* pszName) override;
    // 其他方法可以直接返回E_NOTIMPL
};

在这里,定义了一个名为MyAccessibleControl的类,它继承自IAccessible并且重点实现了get_accName方法。此方法将为控件提供读屏可以朗读的名称。

实现get_accName方法,定义控件的标签

get_accName方法用于返回控件的标签。在读屏软件读取控件时,此标签将被朗读。这个方法包含两个参数:

  • varChild:用于确定请求的对象。如果varChild.vtVT_I4lVal等于CHILDID_SELF,则表示请求控件本身的标签。
  • pszName:标签名的缓冲区。我们可以通过此参数为读屏软件设置标签内容。

以下代码演示了一个标签为“测试标签”的实现:

IFACEMETHODIMP MyAccessibleControl::get_accName(VARIANT varChild, BSTR* pszName) {
    if (varChild.vt == VT_I4 && varChild.lVal == CHILDID_SELF) {
        *pszName = SysAllocString(L"测试标签"); // 设置标签内容
        return S_OK; // 返回S_OK表示调用成功
    }
    return E_NOTIMPL; // 其他情况返回未实现
}

处理WM_GETOBJECT消息

为了让读屏软件调用我们自定义的IAccessible对象,我们需要在控件的窗口过程中处理WM_GETOBJECT消息。当读屏软件聚焦到控件时,它会发送WM_GETOBJECT消息,要求获取该控件的无障碍对象。我们通过拦截此消息并返回自定义的IAccessible对象来响应请求。

  1. 在窗口过程函数中拦截WM_GETOBJECT消息。
  2. 使用LresultFromObject函数将IAccessible对象返回给读屏软件。

以下是具体代码:

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
    static MyAccessibleControl* iAccessible = nullptr;

    switch (uMsg) {
        case WM_CREATE:
            iAccessible = new MyAccessibleControl(); // 初始化IAccessible对象
            break;

        case WM_GETOBJECT:
            if (lParam == OBJID_CLIENT) { 
                // 返回IAccessible对象
                return LresultFromObject(IID_IAccessible, wParam, static_cast<IAccessible*>(iAccessible));
            }
            break;

        case WM_DESTROY:
            delete iAccessible; // 释放资源
            PostQuitMessage(0);
            break;
    }
    return DefWindowProc(hwnd, uMsg, wParam, lParam);
}

WM_CREATE消息处理中,我们初始化了自定义的IAccessible对象;在WM_GETOBJECT消息处理中,我们通过LresultFromObject将其返回;在WM_DESTROY消息处理中释放资源,确保内存的正确管理。

测试验证

  1. 编译并运行程序。
  2. 使用读屏软件(例如NVDA)测试,通过读屏软件聚焦控件,听到朗读为“测试标签”。

完整代码示例

以下是完整的示例代码,包含了窗口的创建、IAccessible接口的实现以及消息处理。

#include <windows.h>
#include <oleacc.h>

class MyAccessibleControl : public IAccessible {
public:
    IFACEMETHODIMP get_accName(VARIANT varChild, BSTR* pszName) override {
        if (varChild.vt == VT_I4 && varChild.lVal == CHILDID_SELF) {
            *pszName = SysAllocString(L"测试标签");
            return S_OK;
        }
        return E_NOTIMPL;
    }
    // 其他方法省略
};

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
    static MyAccessibleControl* iAccessible = nullptr;

    switch (uMsg) {
        case WM_CREATE:
            iAccessible = new MyAccessibleControl();
            break;

        case WM_GETOBJECT:
            if (lParam == OBJID_CLIENT) {
                return LresultFromObject(IID_IAccessible, wParam, static_cast<IAccessible*>(iAccessible));
            }
            break;

        case WM_DESTROY:
            delete iAccessible;
            PostQuitMessage(0);
            break;
    }
    return DefWindowProc(hwnd, uMsg, wParam, lParam);
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR, int nCmdShow) {
    WNDCLASS wc = {};
    wc.lpfnWndProc = WindowProc;
    wc.hInstance = hInstance;
    wc.lpszClassName = L"AccessibleWindowClass";
    RegisterClass(&wc);

    HWND hwnd = CreateWindowEx(
        0,
        L"AccessibleWindowClass",
        L"Accessible Window",
        WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
        nullptr,
        nullptr,
        hInstance,
        nullptr
    );

    ShowWindow(hwnd, nCmdShow);

    MSG msg = {};
    while (GetMessage(&msg, nullptr, 0, 0)) {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    return 0;
}

小结

通过实现IAccessible接口并处理WM_GETOBJECT消息,我们为控件添加了可访问性标签,使其能够被读屏软件识别并朗读。这一过程显著提升了应用的可访问能力,帮助视障用户更好地理解和使用控件。

在无障碍优化中,清晰明了的标签至关重要。我们应始终遵循以下最佳实践:

  1. 保持标签简洁和明确:让标签直观且符合控件功能。
  2. 充分测试和验证:使用不同的读屏软件验证标签的准确性。
  3. 考虑多语言支持:对不同语言的用户提供适配。

参考

《Microsoft Active Accessibility API》: https://learn.microsoft.com/en-us/windows/win32/winauto/microsoft-active-accessibility

标签:控件,get,Windows,标签,WM,IAccessible,无障碍,读屏
From: https://www.cnblogs.com/netlog/p/18538364

相关文章

  • %windir% 是一个环境变量,它指向当前操作系统中 Windows 安装目录的路径。它常用于批处
    %windir%是一个环境变量,它指向当前操作系统中Windows安装目录的路径。它常用于批处理文件、命令行或者脚本中,帮助系统或用户快速定位Windows系统文件夹的路径。类似的环境变量还有很多,它们通常用于在操作系统中快速访问重要的文件夹和目录,避免硬编码路径,从而提高脚本的可移植......
  • 在Qt中创建和使用自定义控件类时,可能会遇到以下一些常见问题
    在Qt中创建和使用自定义控件类时,可能会遇到以下一些常见问题:一、布局相关问题大小调整不正确:问题描述:自定义控件在不同的布局环境下,可能无法按照预期调整大小。例如,当将自定义控件添加到一个水平布局或垂直布局中时,它可能不会随着布局的拉伸或收缩而正确地改变自身大小。原......
  • 自定义圆形进度条控件
    以下将以创建一个简单的为例,详细说明在Qt中创建自定义控件的步骤:一、创建项目首先,打开QtCreator并创建一个新的QtWidgetsApplication项目。按照向导完成项目的基本设置,比如项目名称、存储路径等。二、创建自定义控件类继承基础控件类:在项目中创建一个新的C++类,命名为Ci......
  • Windows 10 配置为 NTP 时间服务器的操作步骤及解析
    之前有过将Windows10配置为NTP时间服务器的经历,但是没有做文字记录。这次又需要做一样的配置,对网上的资料和配置细节不太确定,所以设置完后写了本篇记录。操作步骤设置服务器类型为NTP;修改注册表键值HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\W32Time\Pa......
  • Repadmin 是一个由 Microsoft 提供的命令行工具,用于诊断和管理 Active Directory 域控
    Repadmin|MicrosoftLearnRepadmin是一个由Microsoft提供的命令行工具,用于诊断和管理ActiveDirectory域控制器间的复制问题。它最初是在Windows2000Server时期随ActiveDirectory服务一起推出的,并随着WindowsServer版本的更新不断增强和改进。其主要功能是帮助......
  • Windows系统安装部署C++基础开发环境
    目录前言安装MinGW-w64安装VSCode安装CMake完成前言这篇文章讨论一下Windows系统怎么安装部署C++基础开发环境,你或许在想这还不简单吗,安装vs不就可以了吗,很对,可以在官网下载vs集成开发环境然后进行安装,这也是非常推荐的一种方案,当然因为比较简单,这篇文章就不讲这个方......
  • 在Windows中,使用批处理(.bat)文件可以通过调用命令来实现自动拨号连接。以下是通过批处
    在Windows中,使用批处理(.bat)文件可以通过调用命令来实现自动拨号连接。以下是通过批处理文件实现PPPoE(拨号)连接的基本步骤:步骤1:配置拨号连接(PPPoE)在Windows中,你首先需要设置一个PPPoE拨号连接。以下是设置步骤:打开网络连接设置:点击开始菜单,输入“网络和共享中心”并打开......
  • 终端仿真软件:SecureCRT macOS+Windows电脑安装包
    SecureCRT是一款广受好评的终端仿真软件,专为IT专业人员设计。它支持SSH、Telnet、RLogin等多种协议,提供安全的远程访问功能。用户可以通过该软件安全地连接到远程服务器,进行命令行操作、文件传输等任务。SecureCRT还具备脚本自动化、会话管理、多窗口操作等核心功能,其稳定性和安......
  • Windows和Ubuntu系统如何远程连接Linux服务器
    前言因为很多实验都要在工作站上面运行,为了避免拿着装着数据的硬盘在自己电脑和工作站之间来回跑,我简单总结一下在windows和Ubuntu系统下远程访问Linux服务器的过程吧,也方便大家参考。Windows连接Ubuntu服务器准备工作xshell软件下载地址:链接:http://pan.baidu.com/s/1......
  • Windows 11 对于 BZip2、Gzip、XZ 和 Zstandard 这些压缩格式的支持情况如下表所示:Win
      BZip2、Gzip、XZ和Zstandard(Zstd)是四种常见的压缩算法,它们在不同的应用场景中有各自的优势。下面是它们的详细说明:1. BZip2 (Block-sortingcompressionalgorithm)格式扩展名:.bz2压缩算法原理:BZip2使用Burrows-WheelerTransform(BWT)和Move-to-Front......