GTK无障碍访问 [源]

标准无障碍接口

GtkAccessible 接口提供了一个应用程序的用户界面元素的辅助功能信息。辅助技术(AT)应用程序,如Orca,将该信息传达给有残疾或能力受限的用户,帮助他们使用应用程序。

标准的GTK控件实现了GtkAccessible接口,因此默认情况下可由辅助技术访问。这意味着,如果您使用GTK控件如GtkButtonGtkEntryGtkListView,只有当默认值不完整时,您需要提供特定的应用程序细节。您可以通过设置您的GtkBuilder模板和UI定义文件中的相关属性,或通过设置由GtkAccessible接口定义的属性来实现这一点。

如果您正在实现自己的GtkWidget派生类型,您将需要自己设置GtkAccessible属性,并提供GtkAccessible虚拟函数的实现。

无障碍角色和属性

无障碍小部件的基本概念是角色属性;每个GTK控件都有一个角色,而其功能则由一组属性描述。

角色

角色定义了辅助技术应用程序对UI控制的分类和语义;例如,按钮将有一个角色GTK_ACCESSIBLE_ROLE_BUTTON;输入框将有一个角色GTK_ACCESSIBLE_ROLE_TEXTBOX;检查按钮将有一个角色GTK_ACCESSIBLE_ROLE_CHECKBOX等。

每个角色都是小部件实例的一部分,并且不能在时间或用户操作的结果下改变。角色允许辅助技术应用程序识别UI控制,并决定如何向用户展示它;如果应用程序的UI的一部分改变了角色,控制需要被移除,并用具有适当角色的另一个控制替换。

无障碍角色列表

每个角色名称是GtkAccessibleRole枚举的一部分。

角色名称 描述 相关的GTK小部件
APPLICATION 一个应用程序窗口 GtkWindow
BUTTON 按下时执行操作的控件 GtkButtonGtkLinkButtonGtkExpander
CHECKBOX 有三个可能值的控制:true、false或undefined GtkCheckButton
COMBOBOX 一个可以展开以显示要选择的可能值的列表的控件 GtkComboBox
COLUMN_HEADER 列列表中的标题 GtkColumnView
DIALOG 提示用户输入信息或需要响应的对话框 GtkDialog和其子类
GRID 项目网格 GtkFlowBoxGtkGridView
GRID_CELL 网格中的项目 GtkFlowBoxChildGtkGridViewGtkColumnView
IMG 一个图片 GtkImageGtkPicture
LABEL 用户界面组件的可见名称或标题 GtkLabel
LINK 一个可点击的超链接 GtkLinkButton
LIST 项目列表 GtkListBox
列表项 列表中的一个项目 GtkListBoxRow
菜单 一个菜单 GtkPopoverMenu
菜单栏 一个菜单栏 GtkPopoverMenuBar
菜单项 一个菜单项 GtkPopoverMenu中的项目
复选菜单项 复选菜单项 GtkPopoverMenu中的项目
单选菜单项 单选菜单项 GtkPopoverMenu中的项目
仪表 表示在已知范围内的值 GtkLevelBar
不在可访问性树中表示 GtkScale的滑块
进度条 显示进度的元素 GtkProgressBar
单选按钮 单选组中的一个可检查的输入 GtkCheckButton
列列表中的一个行 GtkColumnView
滚动条 控制内容滚动的图形对象 GtkScrollbar
搜索框 用于输入搜索条件的文本框 GtkSearchEntry
分隔符 分隔内容部分或项目组的分隔符 GtkSeparator
旋转按钮 一个允许从离散选项中选择的范围控制 GtkSpinButton
开关 表示开/关值的控件 GtkSwitch
标签 用于切换页面的标签列表中的一个标签 GtkStackSwitcherGtkNotebook
标签列表 用于切换页面的标签列表 GtkStackSwitcherGtkNotebook
标签面板 笔记本或堆栈中的一个页面 GtkStack
文本框 一种允许将自由形式文本作为其值的输入类型。 GtkEntryGtkPasswordEntryGtkTextView
树形网格 类似树形视图的列列表 GtkColumnView
... ……

有关更多信息,请参阅WAI-ARIA角色列表。

属性

属性提供关于可访问UI控件的特定信息,并为其描述辅助技术应用程序。GTK将可访问属性分为三个类别

  • 属性,由GtkAccessibleProperty枚举的值描述
  • 关系,由GtkAccessibleRelation枚举的值描述
  • 状态,由GtkAccessibleState枚举的值描述

每个属性接受特定类型的一个值。

与角色不同,属性可能会随着时间的推移而变化,或者对用户操作做出响应;例如

  • 一个切换按钮将在每次切换时更改其GTK_ACCESSIBLE_STATE_CHECKED状态,无论是用户还是程序性地切换
  • 设置GtkLabel上的助记符小部件将更新小部件的GTK_ACCESSIBLE_RELATION_LABELLED_BY关系,包含对标签的引用
  • 更改GtkScrollbar上的GtkAdjustment实例将更改GTK_ACCESSIBLE_PROPERTY_VALUE_MAXGTK_ACCESSIBLE_PROPERTY_VALUE_MINGTK_ACCESSIBLE_PROPERTY_VALUE_NOW属性与GtkAdjustment的上限、下限和值属性

有关更多信息,请参阅WAI-ARIA属性列表。

可访问状态列表

每个状态名称都是GtkAccessibleState枚举的一部分。

状态名称 ARIA属性 值类型 说明
GTK_ACCESSIBLE_STATE_BUSY “aria-busy” 布尔值
GTK_ACCESSIBLE_STATE_CHECKED “aria-checked” GtkAccessibleTristate 表示当前状态
GTK_ACCESSIBLE_STATE_DISABLED “aria-disabled” 布尔值 对应于GtkWidget:sensitive属性,在GtkWidget类上
GTK_ACCESSIBLE_STATE_EXPANDED “aria-expanded” 布尔值或未定义 对应于GtkExpander:expanded属性,在GtkExpander类上
GTK_ACCESSIBLE_STATE_HIDDEN “aria-hidden” 布尔值 对应于GtkWidget:visible属性,在GtkWidget类上
GTK_ACCESSIBLE_STATE_INVALID “aria-invalid” GtkAccessibleInvalidState 当小部件显示错误时设置
GTK_ACCESSIBLE_STATE_PRESSED “aria-pressed” GtkAccessibleTristate 指示GtkToggleButton的当前状态
GTK_ACCESSIBLE_STATE_SELECTED “aria-selected” 布尔值或未定义 当选定时设置小部件
GTK_ACCESSIBLE_STATE_VISITED N/A 布尔值或未定义 当类似于链接的小部件被访问时设置

可访问属性列表

每个属性名称都是GtkAccessibleProperty枚举的一部分。

状态名称 ARIA属性 值类型
GTK_ACCESSIBLE_PROPERTY_AUTOCOMPLETE “aria-autocomplete” GtkAccessibleAutocomplete
GTK_ACCESSIBLE_PROPERTY_DESCRIPTION “aria-description” 可翻译字符串
GTK_ACCESSIBLE_PROPERTY_HAS_POPUP “aria-haspopup” 布尔值
GTK_ACCESSIBLE_PROPERTY_KEY_SHORTCUTS “aria-keyshortcuts” 字符串
GTK_ACCESSIBLE_PROPERTY_LABEL “aria-label” 可翻译字符串
GTK_ACCESSIBLE_PROPERTY_LEVEL “aria-level” 整数
GTK_ACCESSIBLE_PROPERTY_MODAL “aria-modal” 布尔值
GTK_ACCESSIBLE_PROPERTY_MULTI_LINE “aria-multiline” 布尔值
GTK_ACCESSIBLE_PROPERTY_MULTI_SELECTABLE “aria-multiselectable” 布尔值
GTK_ACCESSIBLE_PROPERTY_ORIENTATION “aria-orientation” GtkOrientation
GTK_ACCESSIBLE_PROPERTY_PLACEHOLDER “aria-placeholder” 可翻译字符串
GTK_ACCESSIBLE_PROPERTY_READ_ONLY “aria-readonly” 布尔值
GTK_ACCESSIBLE_PROPERTY_REQUIRED “aria-required” 布尔值
GTK_ACCESSIBLE_PROPERTY_ROLE_DESCRIPTION “aria-roledescription” 可翻译字符串
GTK_ACCESSIBLE_PROPERTY_SORT “aria-sort” GtkAccessibleSort
GTK_ACCESSIBLE_PROPERTY_VALUE_MAX “aria-valuemax” 双精度浮点数
GTK_ACCESSIBLE_PROPERTY_VALUE_MIN “aria-valuemin” 双精度浮点数
GTK_ACCESSIBLE_PROPERTY_VALUE_NOW “aria-valuenow” 双精度浮点数
GTK_ACCESSIBLE_PROPERTY_VALUE_TEXT “aria-valuetext” 可翻译字符串
GTK_ACCESSIBLE_PROPERTY_HELP_TEXT N/A 可翻译字符串

可访问关系列表

每个关系名称都是GtkAccessibleRelation枚举的一部分。

状态名称 ARIA属性 值类型
GTK_ACCESSIBLE_RELATION_ACTIVE_DESCENDANT “aria-activedescendant” GtkAccessible
GTK_ACCESSIBLE_RELATION_COL_COUNT “aria-colcount” 整数
GTK_ACCESSIBLE_RELATION_COL_INDEX “aria-colindex” 整数
GTK_ACCESSIBLE_RELATION_COL_INDEX_TEXT “aria-colindextext” 可翻译字符串
GTK_ACCESSIBLE_RELATION_COL_SPAN “aria-colspan” 整数
GTK_ACCESSIBLE_RELATION_CONTROLS “aria-controls” 一列GtkAccessible
GTK_ACCESSIBLE_RELATION_DESCRIBED_BY “aria-describedby” 一列GtkAccessible
GTK_ACCESSIBLE_RELATION_DETAILS “aria-details” 一列GtkAccessible
GTK_ACCESSIBLE_RELATION_ERROR_MESSAGE “aria-errormessage” 一列GtkAccessible
GTK_ACCESSIBLE_RELATION_FLOW_TO “aria-flowto” 一列GtkAccessible
GTK_ACCESSIBLE_RELATION_LABELLED_BY “aria-labelledby” 一列GtkAccessible
GTK_ACCESSIBLE_RELATION_OWNS “aria-owns” 一列GtkAccessible
GTK_ACCESSIBLE_RELATION_POS_IN_SET “aria-posinset” 整数
GTK_ACCESSIBLE_RELATION_ROW_COUNT “aria-rowcount” 整数
GTK_ACCESSIBLE_RELATION_ROW_INDEX “aria-rowindex” 整数
GTK_ACCESSIBLE_RELATION_ROW_INDEX_TEXT “aria-rowindextext” 可翻译字符串
GTK_ACCESSIBLE_RELATION_ROW_SPAN “aria-rowspan” 整数
GTK_ACCESSIBLE_RELATION_SET_SIZE “aria-setsize” 整数

注意:在使用具有需要GtkAccessible实例列表的关系的gtk_accessible_update_relation()时,您应该分别传递每个可访问对象,随后跟NULL

应用程序开发规则

即使由GTK提供的标准UI控件自带无障碍信息,但应用开发者还需考虑一些额外的属性和注意事项。例如,如果您的应用提供了一个用于用户填写的表单,您应该确保:

  • 表单的容器具有GTK_ACCESSIBLE_ROLE_FORM角色
  • 表单中的每个文本输入小部件都有关联到描述它的标签小部件的GTK_ACCESSIBLE_RELATION_LABELLED_BY关系

另一个例子:如果您创建了一个包含只有图标的按钮的工具栏,您应该确保:

  • 容器具有GTK_ACCESSIBLE_ROLE_TOOLBAR角色
  • 每个按钮都设置了包含用户可读和本地化动作的GTK_ACCESSIBLE_PROPERTY_LABEL属性;例如“复制”、“粘贴”、“添加图层”或“删除”

GTK将尝试使用辅助的UI控件属性来填充一些信息,例如,可访问名称将从UI控件使用的标签中获取,或在其工具提示中获取,如果未设置GTK_ACCESSIBLE_PROPERTY_LABEL属性或GTK_ACCESSIBLE_RELATION_LABELLED_BY关系。可访问描述也是如此。尽管如此,显式指定可访问属性是良好的实践,就像显式指定工具提示和样式类一样。

使用GTK的软件开发者应该确保他们的小部件其有访问权限作为开发流程的一部分。GTK检查器显示了每个小部件的可访问属性,并提供了可以突出显示可访问问题的叠加层。

如果您为小部件支持一些非标准的键盘交互,您应该设置适当的GTK_ACCESSIBLE_PROPERTY_HELP_TEXT来帮助发现该行为。

您也可以在UI文件中设置可访问属性

<object class="GtkButton" id="button1">
  <accessibility>
    <property name="label">Download</property>
    <relation name="labelled-by">label1</relation>
  </accessibility>
</object>

实现

每个UI控件实现GtkAccessible接口,以允许小部件和应用开发者指定UI控件之间的角色、状态和关系。此API完全是描述性的。

每个GtkAccessible实现必须提供一个GtkATContext实例,该实例作为特定平台可访问性API的代理。

  • Linux/BSD上的AT-SPI
  • macOS上的NSAccessibility
  • Windows上的Active Accessibility

另外,对于GTK测试套件,有一个现场设计的可访问性后端,以确保在CI流水线中问题的可重复性。

作者实践

作者实践旨在针对应用开发者以及基于GTKGUI元素的开发者。

功能上,GtkAccessible作用域、状态、属性和关系类似于辅助技术的CSS。例如,对于屏幕阅读器用户,各种可访问属性控制他们的非视觉体验的呈现。错误的作用域和属性可能导致用户界面完全不可访问。

作用域是一种承诺

以下代码

gtk_widget_class_set_accessible_role (widget_class, GTK_ACCESSIBLE_ROLE_BUTTON);

是一种承诺,表明创建的小组件将提供与按钮预期相同的键盘交互。按钮的可访问作用域不会自动将任何组件转换为GtkButton;但是,如果您的组件表现像按钮,使用GTK_ACCESSIBLE_ROLE_BUTTON将允许任何辅助技术以处理GtkButton的方式处理它。

对于充当其他组件容器的小组件,如果对子组件的分组是语义性的,则应使用GTK_ACCESSIBLE_ROLE_GROUP;例如,GtkHeaderBar的子组件在窗口的标题上分组在一起。对于仅对其子组件施加布局的通用容器,应改用GTK_ACCESSIBLE_ROLE_GENERIC

属性既有隐藏也有增强的作用

可访问属性可用于覆盖UI元素的内容,例如

gtk_label_set_text (GTK_LABEL (label), "Some text");
gtk_accessible_update_property (GTK_ACCESSIBLE (label),
                GTK_ACCESSIBLE_PROPERTY_LABEL,
                "Assistive technologies users will perceive "
                "this text, not the contents of the label",
                -1);

在上面的示例中,“标签”属性将覆盖标签组件的内容。

属性也可增强UI

gtk_button_set_label (GTK_BUTTON (button), "Download");
gtk_box_append (GTK_BOX (box), button);

gtk_label_set_text (GTK_LABEL (label), "Final report.pdf");
gtk_box_append (GTK_BOX (box), label);

gtk_accessible_update_relation (GTK_ACCESSIBLE (button),
                GTK_ACCESSIBLE_RELATION_LABELLED_BY,
                g_list_append (NULL, label),
                -1);

在上面的示例中,辅助技术将读取按钮的可访问标签为“下载最终报告.pdf”。

隐藏和增强的威力可能是一把双刃剑,因为它可能导致无意中覆盖现有组件的辅助语义。

从可访问树中隐藏UI元素

可访问性API主要用于表达对辅助技术有用的语义,但它也可以用于隐藏元素。这样做的一种典范方法是使用GTK_ACCESSIBLE_ROLE_PRESENTATION,它声明一个UI元素纯粹是为了展示目的,因此它对界面的可访问性没有有意义的影响。

“展示”作用域不应与GTK_ACCESSIBLE_STATE_HIDDEN状态混淆;隐藏状态是短暂的,通常通过使用GtkWidget API显示和隐藏窗口来控制。

设计模式和自定义组件

在创建自定义组件时,遵循既定模式可以帮助确保这些组件能够很好地服务于辅助技术用户。

按钮

按钮是一种让用户能够触发操作的组件。虽然建议您为看起来和表现像按钮的任何内容使用GtkButton,但您可以使用GtkGestureClick手势将按钮行为应用于UI元素,例如图片。这样做时,您应:

  • 为您的组件设置作用域GTK_ACCESSIBLE_ROLE_BUTTON
  • 安装一个不带参数的操作,这将激活组件

自定义条目

对于自定义条目,非常推荐您通过使用一个GtkText小部件作为代理来实现GtkEditable接口。如果您这样做,GNOME将使您的文本编辑功能与GtkSpinButtonGtkSearchEntry一样可访问。

基于标签的UI

如果你要创建基于标签的界面,应该考虑使用 GtkStack 作为核心,然后只创建一个自定义标签控件来控制活动堆叠页面。在这种情况下,以下额外步骤将确保你的标签与 GtkStackSwitcherGtkNotebook 以相同的方式进行访问。

  • 请给你的标签容器分配角色 GTK_ACCESSIBLE_ROLE_TAB_LIST
  • 请给你的标签控件分配角色 GTK_ACCESSIBLE_ROLE_TAB
  • 在每个标签和其页面的 GtkStackPage 对象之间设置 GTK_ACCESSIBLE_RELATION_CONTROLS 关系
  • 为每个标签设置 GTK_ACCESSIBLE_PROPERTY_SELECTED 属性,活动标签设置为 TRUE,所有其他标签设置为 FALSE

要允许通过辅助技术更改活动标签,你可以导出操作。由于辅助接口只支持无参数的操作,你可以在标签容器上提供如 previous-tabnext-tab 的操作,让用户逐个浏览标签,或者在每个标签上添加一个 activate-tab 操作。

值控件

值控件(即控制可以表示为 GtkAdjustment 的一维量的控件)可以通过设置 GTK_ACCESSIBLE_PROPERTY_VALUE_MINGTK_ACCESSIBLE_PROPERTY_VALUE_MAXGTK_ACCESSIBLE_PROPERTY_VALUE_NOW 属性来表示给辅助技术。

要允许通过辅助技术更改值,你可以导出操作。由于辅助接口只支持无参数的操作,你应该提供如 increase-valuedecrease-value 的操作。

GTK 4.10 以来,假设值改变的最佳方式是实现 GtkAccessibleRange 接口。