键盘辅助功能

将键盘辅助功能(对于传统、修改或键盘仿真硬件)构建到应用中,为用户提供盲人、视力低下、运动障碍或手部很少或没有使用,能够浏览和使用应用的全部功能。 此外,由于首选项或效率,没有残疾的用户可能会选择用于导航的键盘。

如果你的应用不提供良好的键盘访问,则盲人或移动性问题的用户在使用你的应用时可能会遇到困难。

UI 元素之间的键盘导航

若要使用键盘与控件交互,控件必须具有焦点。 若要接收焦点(不使用指针),必须可通过选项卡导航访问控件。 默认情况下,控件的 Tab 键顺序与将控件添加到设计图面、在 XAML 中声明或以编程方式添加到容器的顺序相同。

通常,默认制表位顺序基于如何在 XAML 中定义控件,特别是作为屏幕阅读器遍历控件的顺序。 但是,默认顺序不一定对应于视觉顺序。 实际显示位置可能取决于父布局容器以及可能影响布局的子元素的各种属性。

若要确保应用具有最佳选项卡顺序,请自行测试行为。 如果将网格或表格用于布局,则用户可能阅读屏幕的顺序与选项卡顺序可能大相径庭。 这并不总是问题,但只需确保通过触摸和键盘测试应用的功能,以验证 UI 是否针对这两种输入方法进行优化。

可以通过调整 XAML 或重写默认制表位顺序,使 Tab 键顺序与视觉顺序匹配。 以下示例演示如何将 TabIndex 属性与使用列优先选项卡导航的网格布局配合使用。

<Grid>
  <Grid.RowDefinitions>...</Grid.RowDefinitions>
  <Grid.ColumnDefinitions>...</Grid.ColumnDefinitions>

  <TextBlock Grid.Column="1" HorizontalAlignment="Center">Groom</TextBlock>
  <TextBlock Grid.Column="2" HorizontalAlignment="Center">Bride</TextBlock>

  <TextBlock Grid.Row="1">First name</TextBlock>
  <TextBox x:Name="GroomFirstName" Grid.Row="1" Grid.Column="1" TabIndex="1"/>
  <TextBox x:Name="BrideFirstName" Grid.Row="1" Grid.Column="2" TabIndex="3"/>

  <TextBlock Grid.Row="2">Last name</TextBlock>
  <TextBox x:Name="GroomLastName" Grid.Row="2" Grid.Column="1" TabIndex="2"/>
  <TextBox x:Name="BrideLastName" Grid.Row="2" Grid.Column="2" TabIndex="4"/>
</Grid>

在某些情况下,可能需要从 Tab 键顺序中排除特定控件。 这通常是通过将控件 IsEnabled 属性设置为 false 来实现的。 禁用的控件会自动从 Tab 键顺序中排除。

如果要从 Tab 顺序中排除交互式控件,可以将 IsTabStop 属性设置为 false

默认情况下,支持焦点的 UI 元素通常包含在 Tab 键顺序中。 这一些例外情况包括某些文本显示类型(如 RichTextBlock),这些类型支持文本选择和剪贴板访问的焦点,但由于它们是静态文本元素,因此不在 Tab 键顺序中。 这些控件不是传统的交互式控件(不能调用它们,不需要文本输入,但支持文本 中查找和调整选择点的文本控件模式 )。 文本控件仍将由辅助技术检测到,并在屏幕阅读器中大声朗读,但这依赖于除 Tab 键顺序以外的技术。

无论是调整 TabIndex 值还是使用默认顺序,这些规则都适用:

以下代码片段显示了具有各种 TabIndex 设置的元素集合(B分配 Int32.MaxValue 的值或 2,147,483,647)。

<StackPanel Background="#333">
  <StackPanel Background="#FF33FF">
    <Button>A</Button>
    <Button TabIndex="2147483647">B</Button>
    <Button>C</Button>
  </StackPanel>
  <StackPanel Background="#33FFFF">
    <Button TabIndex="1">D</Button>
    <Button TabIndex="1">E</Button>
    <Button TabIndex="0">F</Button>
  </StackPanel>
</StackPanel>

这会生成以下 Tab 键顺序:

  1. 周五
  2. D
  3. E
  4. A
  5. B
  6. C

应用程序窗格与 F6 之间的键盘导航

应用程序窗格是应用程序窗口中突出相关 UI 的逻辑区域(例如,Microsoft Edge 窗格包括地址栏、书签栏、选项卡栏和内容面板)。 F6 键可用于在这些窗格之间导航,然后可以使用标准键盘导航访问子元素组。

虽然键盘导航可以提供兼容易访问的 UI,但使可访问 UI 通常需要几个步骤。 通常,这包括:

  • 侦听 F6 以在 UI 的重要部分之间导航。
  • UI 中添加常见操作的 键盘快捷方式。
  • 将访问键添加到 UI 中的重要控件。

有关实现快捷方式和访问键的更多指南,请参阅下面的键盘快捷方式和访问键。

针对 F6 进行优化

F6 允许键盘用户在 UI 窗格之间高效导航,而无需通过可能数百个控件进行选项卡式导航。

例如,Microsoft Edge 中的 F6 在地址栏、书签栏、选项卡栏和内容面板之间循环。 由于网页可能具有数百个可选项卡控件,因此 F6 可以更轻松地让键盘用户访问选项卡栏和地址栏,而无需使用特定于应用程序的快捷方式。

F6 选项卡周期也可以松散地对应于 内容中的地标或标题 ,尽管它不需要完全匹配。 F6 应专注于 UI 中的大型不同区域,而地标可以更精细。 例如,可以将应用栏及其搜索框标记为地标,但仅在 F6 周期中包含应用栏本身。

重要

必须在应用中实现 F6 导航,因为它本身不受支持。

如果可能,F6 周期中的区域应具有可访问的名称:通过地标或手动将 AutomationProperties.Name 添加到该区域的“root”元素。

Shift-F6 应以相反的方向循环。

UI 元素中的键盘导航

对于复合控件,请务必确保包含元素之间的内部导航正确。 复合控件可以管理当前活动的子元素,以减少让所有子元素支持焦点的开销。 复合控件包含在 Tab 键顺序中,并处理键盘导航事件本身。 许多复合控件已经在其事件处理中内置了一些内部导航逻辑。 例如,默认情况下,在 ListView、GridViewListBoxFlipView 控件上启用项的箭头键遍历。

特定控件元素的指针操作和事件的键盘替代项

也可以通过键盘调用可单击的 UI 元素。 若要将键盘与 UI 元素一起使用,该元素必须具有焦点(仅派生自 控件 的类支持焦点和选项卡导航)。

对于可调用的 UI 元素,请为空格键和 Enter 键实现键盘事件处理程序。 这可确保基本的键盘辅助功能支持,并允许用户仅使用键盘访问所有交互式 UI 元素并激活功能。

如果元素不支持焦点,则可以创建自己的自定义控件。 在这种情况下,若要启用焦点,必须将 IsTabStop 属性设置为 true,并且必须提供具有焦点指示器的聚焦视觉状态的视觉指示。

但是,使用控件组合可能更容易,以便对制表位、焦点和Microsoft UI 自动化对等方和模式的支持由你选择在其中撰写内容的控件进行处理。 例如,不要在图像处理按下指针的事件,而是将该元素包装在 Button以获取指针、键盘和焦点支持。

<!--Don't do this.-->
<Image Source="sample.jpg" PointerPressed="Image_PointerPressed"/>

<!--Do this instead.-->
<Button Click="Button_Click"><Image Source="sample.jpg"/></Button>

键盘快捷键

除了实现键盘导航和激活外,还可以实现键盘快捷方式(如 键盘快捷键访问键 )以实现重要或常用功能。

快捷方式是一种键盘组合,为用户提供访问应用功能的有效方法。 有两种类型的快捷方式:

  • 加速器是调用应用命令的快捷方式。 你的应用可以提供与命令对应的特定 UI,也可以不提供。 加速器通常由 Ctrl 键和一个字母键组成。
  • 访问键是将焦点设置到应用程序中的特定 UI 的快捷方式。 访问键通常由 Alt 键和一个字母键组成。

始终为依赖屏幕阅读器和其他辅助技术的用户提供一种简单的方式来发现应用的快捷键。 使用工具提示、辅助名称、辅助说明或其他某种形式的屏幕通信来传达快捷键。 至少应在应用的帮助内容中记录快捷键。

可以通过屏幕阅读器记录访问密钥,方法是将 AutomationProperties.AccessKey 附加属性设置为描述快捷键的字符串。 还有一个 AutomationProperties.AcceleratorKey 附加属性用于记录非助记快捷键,尽管屏幕阅读器通常以相同的方式对待这两个属性。 尝试使用工具提示、自动化属性和书面帮助文档,以多种方式记录快捷键。

以下示例演示如何记录媒体播放、暂停和停止按钮的快捷键。

<Grid KeyDown="Grid_KeyDown">

  <Grid.RowDefinitions>
    <RowDefinition Height="Auto" />
    <RowDefinition Height="Auto" />
  </Grid.RowDefinitions>

  <MediaElement x:Name="DemoMovie" Source="xbox.wmv"
    Width="500" Height="500" Margin="20" HorizontalAlignment="Center" />

  <StackPanel Grid.Row="1" Margin="10"
    Orientation="Horizontal" HorizontalAlignment="Center">

    <Button x:Name="PlayButton" Click="MediaButton_Click"
      ToolTipService.ToolTip="Shortcut key: Ctrl+P"
      AutomationProperties.AcceleratorKey="Control P">
      <TextBlock>Play</TextBlock>
    </Button>

    <Button x:Name="PauseButton" Click="MediaButton_Click"
      ToolTipService.ToolTip="Shortcut key: Ctrl+A"
      AutomationProperties.AcceleratorKey="Control A">
      <TextBlock>Pause</TextBlock>
    </Button>

    <Button x:Name="StopButton" Click="MediaButton_Click"
      ToolTipService.ToolTip="Shortcut key: Ctrl+S"
      AutomationProperties.AcceleratorKey="Control S">
      <TextBlock>Stop</TextBlock>
    </Button>
  </StackPanel>
</Grid>

重要

设置 AutomationProperties.AcceleratorKeyAutomationProperties.AccessKey 不会启用键盘功能。 这仅指示应将哪些密钥用于UI 自动化框架,然后可以通过辅助技术传递给用户。

密钥处理在代码隐藏中实现,而不是 XAML。 仍需在相关控件上附加 KeyDown KeyUp 事件的处理程序,以便在应用中实际实现键盘快捷方式行为。 此外,不会自动为访问键提供带下划线的文本效果。 如果你希望在 UI 中显示带下划线的文本,则必须明确对助记键中特定键的文本标注下划线,作为嵌入式 Underline 格式。

为简单起见,前面的示例省略了对字符串(如“Ctrl+A”)的资源的使用。 但是,在本地化过程中,还必须考虑快捷键。 本地化快捷键是相关的,因为选择用作快捷键的键通常取决于元素的可见文本标签。

有关实现快捷键的更多指南,请参阅 Windows 用户体验交互指南中的快捷键

实现密钥事件处理程序

输入事件(如关键事件)使用名为 路由事件的事件概念。 路由事件可以通过父复合控件的子元素向上气泡,以便父控件可以处理多个子元素的事件。 此事件模型可用于为包含多个子元素的控件定义快捷键操作,其中任何元素都不能具有焦点或成为制表符顺序的一部分。

有关演示如何编写包含检查修饰符(如 Ctrl 键)的键事件处理程序的示例代码,请参阅 键盘交互

自定义控件的键盘导航

我们建议在子元素之间导航时使用箭头键作为键盘快捷方式,以防子元素彼此之间存在稀疏关系。 如果树视图节点具有单独的子元素来处理展开折叠和节点激活,请使用向左键和向右键提供键盘展开折叠功能。 如果你有支持控件内容中方向遍历的定向控件,请使用相应的箭头键。

通常,通过将 OnKeyDown OnKeyUp 方法的重写作为类逻辑的一部分来实现自定义控件的自定义键处理。

焦点指示器的视觉状态示例

如前所述,任何支持焦点的自定义控件都应具有可视焦点指示器。 通常,该焦点指示器只是一个矩形,显示控件的边界矩形。 视觉焦点矩形是控件模板中控件的其余部分的对等元素,但最初使用 Collapsed 的 Visibility进行设置,因为该控件尚未聚焦。 当控件获得焦点时,将调用一个视觉状态,该状态专门将 焦点视觉对象的可见性 设置为 Visible。 将焦点移到其他位置后,将调用另一个视觉状态,并且 可见性 变为 “折叠”。

所有可聚焦 XAML 控件在聚焦时显示适当的视觉焦点指示器。 用户选择的用户还可以影响指示器外观(尤其是如果用户使用的是高对比度模式)。 如果在 UI 中使用 XAML 控件(但不替换控件模板),则无需执行任何额外操作即可获取默认视觉焦点指示器。 但是,如果你打算重新模板化控件,或者你想知道 XAML 控件如何提供其视觉焦点指示器,本部分的其余部分介绍了如何在 XAML 和控件逻辑中完成此操作。

下面是一些来自按钮的默认 XAML 模板的示例 XAML。

XAML

<ControlTemplate TargetType="Button">
...
    <Rectangle
      x:Name="FocusVisualWhite"
      IsHitTestVisible="False"
      Stroke="{ThemeResource FocusVisualWhiteStrokeThemeBrush}"
      StrokeEndLineCap="Square"
      StrokeDashArray="1,1"
      Opacity="0"
      StrokeDashOffset="1.5"/>
    <Rectangle
      x:Name="FocusVisualBlack"
      IsHitTestVisible="False"
      Stroke="{ThemeResource FocusVisualBlackStrokeThemeBrush}"
      StrokeEndLineCap="Square"
      StrokeDashArray="1,1"
      Opacity="0"
      StrokeDashOffset="0.5"/>
...
</ControlTemplate>

到目前为止,这只是构成。 若要控制焦点指示器的可见性,请定义切换 Visibility 属性的视觉状态。 使用 VisualStateManager 和 VisualStateManager.VisualStateGroups 附加属性可完成此操作,该附加属性应用于用来定义此组合的根元素。

<ControlTemplate TargetType="Button">
  <Grid>
    <VisualStateManager.VisualStateGroups>
       <!--other visual state groups here-->
       <VisualStateGroup x:Name="FocusStates">
         <VisualState x:Name="Focused">
           <Storyboard>
             <DoubleAnimation
               Storyboard.TargetName="FocusVisualWhite"
               Storyboard.TargetProperty="Opacity"
               To="1" Duration="0"/>
             <DoubleAnimation
               Storyboard.TargetName="FocusVisualBlack"
               Storyboard.TargetProperty="Opacity"
               To="1" Duration="0"/>
         </VisualState>
         <VisualState x:Name="Unfocused" />
         <VisualState x:Name="PointerFocused" />
       </VisualStateGroup>
     <VisualStateManager.VisualStateGroups>
<!--composition is here-->
   </Grid>
</ControlTemplate>

请注意,只有一个命名状态直接调整 可见性 ,而其他状态显然为空。 使用视觉状态时,只要控件使用同一 VisualStateGroup 中的另一个状态,则由上一状态应用的任何动画都会立即取消。 由于组合的默认 可见性“折叠”,因此不会显示矩形。 控件逻辑通过侦听 GotFocus焦点事件并使用 GoToState 更改状态来控制这一点。 如果使用默认控件或基于已具有该行为的控件进行自定义,则通常已为你处理此问题。

没有硬件键盘的键盘辅助功能和设备

某些设备没有专用的硬件键盘,而是依赖于软输入面板(SIP)。 屏幕阅读器可以从文本 SIP 读取文本输入,用户可以发现其手指的位置,因为屏幕阅读器可以检测到用户正在扫描密钥,并大声读取扫描的密钥名称。 此外,某些面向键盘的辅助功能概念可以映射到根本不使用键盘的相关辅助技术行为。 例如,即使 SIP 不包含 Tab 键,讲述人也支持与按 Tab 键等效的触摸手势,因此,通过 UI 中的控件执行有用的制表符顺序仍适合辅助功能。 讲述人还支持许多其他触摸手势,包括用于在复杂控件中导航的箭头键(请参阅讲述人键盘命令和触摸手势)。

示例

提示

WinUI 3 库应用包括大多数 WinUI 3 控件、特性和功能的交互式示例。 通过 Microsoft Store 获取应用,或在 GitHub 上获取源代码