GTK无障碍访问 [源]
标准无障碍接口
GtkAccessible
接口提供了一个应用程序的用户界面元素的辅助功能信息。辅助技术(AT)应用程序,如Orca,将该信息传达给有残疾或能力受限的用户,帮助他们使用应用程序。
标准的GTK控件实现了GtkAccessible
接口,因此默认情况下可由辅助技术访问。这意味着,如果您使用GTK控件如GtkButton
、GtkEntry
或GtkListView
,只有当默认值不完整时,您需要提供特定的应用程序细节。您可以通过设置您的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 |
按下时执行操作的控件 | GtkButton 、GtkLinkButton 、GtkExpander |
CHECKBOX |
有三个可能值的控制:true、false或undefined | GtkCheckButton |
COMBOBOX |
一个可以展开以显示要选择的可能值的列表的控件 | GtkComboBox |
COLUMN_HEADER |
列列表中的标题 | GtkColumnView |
DIALOG |
提示用户输入信息或需要响应的对话框 | GtkDialog 和其子类 |
GRID |
项目网格 | GtkFlowBox 、GtkGridView |
GRID_CELL |
网格中的项目 | GtkFlowBoxChild 、GtkGridView 、GtkColumnView |
IMG |
一个图片 | GtkImage 、GtkPicture |
LABEL |
用户界面组件的可见名称或标题 | GtkLabel |
LINK |
一个可点击的超链接 | GtkLinkButton |
LIST |
项目列表 | GtkListBox |
列表项 |
列表中的一个项目 | GtkListBoxRow |
菜单 |
一个菜单 | GtkPopoverMenu |
菜单栏 |
一个菜单栏 | GtkPopoverMenuBar |
菜单项 |
一个菜单项 | GtkPopoverMenu 中的项目 |
复选菜单项 |
复选菜单项 | GtkPopoverMenu 中的项目 |
单选菜单项 |
单选菜单项 | GtkPopoverMenu 中的项目 |
仪表 |
表示在已知范围内的值 | GtkLevelBar |
无 |
不在可访问性树中表示 | GtkScale 的滑块 |
进度条 |
显示进度的元素 | GtkProgressBar |
单选按钮 |
单选组中的一个可检查的输入 | GtkCheckButton |
行 |
列列表中的一个行 | GtkColumnView |
滚动条 |
控制内容滚动的图形对象 | GtkScrollbar |
搜索框 |
用于输入搜索条件的文本框 | GtkSearchEntry |
分隔符 |
分隔内容部分或项目组的分隔符 | GtkSeparator |
旋转按钮 |
一个允许从离散选项中选择的范围控制 | GtkSpinButton |
开关 |
表示开/关值的控件 | GtkSwitch |
标签 |
用于切换页面的标签列表中的一个标签 | GtkStackSwitcher ,GtkNotebook |
标签列表 |
用于切换页面的标签列表 | GtkStackSwitcher ,GtkNotebook |
标签面板 |
笔记本或堆栈中的一个页面 | GtkStack |
文本框 |
一种允许将自由形式文本作为其值的输入类型。 | GtkEntry ,GtkPasswordEntry ,GtkTextView |
树形网格 |
类似树形视图的列列表 | GtkColumnView |
... |
…… |
有关更多信息,请参阅WAI-ARIA角色列表。
属性
属性提供关于可访问UI控件的特定信息,并为其描述辅助技术应用程序。GTK将可访问属性分为三个类别
- 属性,由
GtkAccessibleProperty
枚举的值描述 - 关系,由
GtkAccessibleRelation
枚举的值描述 - 状态,由
GtkAccessibleState
枚举的值描述
每个属性接受特定类型的一个值。
与角色不同,属性可能会随着时间的推移而变化,或者对用户操作做出响应;例如
- 一个切换按钮将在每次切换时更改其
GTK_ACCESSIBLE_STATE_CHECKED
状态,无论是用户还是程序性地切换 - 设置
GtkLabel
上的助记符小部件将更新小部件的GTK_ACCESSIBLE_RELATION_LABELLED_BY
关系,包含对标签的引用 - 更改
GtkScrollbar
上的GtkAdjustment
实例将更改GTK_ACCESSIBLE_PROPERTY_VALUE_MAX
、GTK_ACCESSIBLE_PROPERTY_VALUE_MIN
和GTK_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
流水线中问题的可重复性。
作者实践
作者实践旨在针对应用开发者以及基于GTK
的GUI
元素的开发者。
功能上,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将使您的文本编辑功能与GtkSpinButton
或GtkSearchEntry
一样可访问。
基于标签的UI
如果你要创建基于标签的界面,应该考虑使用 GtkStack
作为核心,然后只创建一个自定义标签控件来控制活动堆叠页面。在这种情况下,以下额外步骤将确保你的标签与 GtkStackSwitcher
或 GtkNotebook
以相同的方式进行访问。
- 请给你的标签容器分配角色
GTK_ACCESSIBLE_ROLE_TAB_LIST
- 请给你的标签控件分配角色
GTK_ACCESSIBLE_ROLE_TAB
- 在每个标签和其页面的
GtkStackPage
对象之间设置GTK_ACCESSIBLE_RELATION_CONTROLS
关系 - 为每个标签设置
GTK_ACCESSIBLE_PROPERTY_SELECTED
属性,活动标签设置为TRUE
,所有其他标签设置为FALSE
要允许通过辅助技术更改活动标签,你可以导出操作。由于辅助接口只支持无参数的操作,你可以在标签容器上提供如 previous-tab
和 next-tab
的操作,让用户逐个浏览标签,或者在每个标签上添加一个 activate-tab
操作。
值控件
值控件(即控制可以表示为 GtkAdjustment
的一维量的控件)可以通过设置 GTK_ACCESSIBLE_PROPERTY_VALUE_MIN
、GTK_ACCESSIBLE_PROPERTY_VALUE_MAX
和 GTK_ACCESSIBLE_PROPERTY_VALUE_NOW
属性来表示给辅助技术。
要允许通过辅助技术更改值,你可以导出操作。由于辅助接口只支持无参数的操作,你应该提供如 increase-value
和 decrease-value
的操作。
自 GTK 4.10 以来,假设值改变的最佳方式是实现 GtkAccessibleRange
接口。