Acessibilidade do teclado
A criação de acessibilidade de teclado (para hardware tradicional, modificado ou de emulação de teclado) em seu aplicativo fornece aos usuários cegos, com baixa visão, deficiências motoras ou pouco ou nenhum uso das mãos a capacidade de navegar e usar todas as funcionalidades do seu aplicativo. Além disso, os usuários sem deficiência podem escolher o teclado para navegação devido à preferência ou eficiência.
Se o app não fornecer um bom acesso ao teclado, os usuários cegos ou com problemas de mobilidade poderão ter dificuldade em usá-lo.
Navegação de teclado entre elementos da interface do usuário
Para interagir com um controle usando o teclado, o controle deve ter foco. Para receber o foco (sem usar um ponteiro), o controle deve estar acessível por meio da navegação por guias. Por padrão, a ordem de tabulação dos controles é a mesma que a ordem na qual eles são adicionados a uma superfície de design, declarados em XAML ou adicionados programaticamente a um contêiner.
Normalmente, a ordem de tabulação padrão é baseada em como os controles são definidos em XAML, especialmente porque essa é a ordem na qual os controles são percorridos por leitores de tela. No entanto, a ordem padrão não corresponde necessariamente à ordem visual. A posição de exibição real pode depender do contêiner de layout pai e de várias propriedades de elementos filho que podem afetar o layout.
Para garantir que seu aplicativo tenha uma ordem de tabulação ideal, teste o comportamento por conta própria. Se você usar uma grade ou tabela para seu layout, a ordem na qual os usuários podem ler a tela versus a ordem de tabulação pode ser muito diferente. Isso nem sempre é um problema, mas certifique-se de testar a funcionalidade do seu aplicativo por meio do toque e do teclado para verificar se a interface do usuário está otimizada para ambos os métodos de entrada.
Você pode fazer com que a ordem de tabulação corresponda à ordem visual ajustando o XAML ou substituindo a ordem de tabulação padrão. O exemplo a seguir mostra como usar a propriedade TabIndex com um layout Grid que usa a navegação de guia em primeiro lugar.
<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>
Em alguns casos, talvez você queira excluir um controle específico da ordem de tabulação. Isso normalmente é feito tornando o controle não interativo definindo sua propriedade IsEnabled como false. Um controle desabilitado é excluído automaticamente da ordem de tabulação.
Se você quiser excluir um controle interativo da ordem de tabulação, poderá definir a propriedade IsTabStop como false.
Por padrão, os elementos da interface do usuário que dão suporte ao foco normalmente são incluídos na ordem de tabulação. Algumas exceções a isso incluem determinados tipos de exibição de texto (como RichTextBlock) que dão suporte ao foco para seleção de texto e acesso à área de transferência, mas não estão na ordem de tabulação porque são elementos de texto estáticos. Esses controles não são convencionalmente interativos (eles não podem ser invocados e não exigem entrada de texto, mas dão suporte ao padrão de controle Text que dá suporte à localização e ao ajuste de pontos de seleção no texto). Os controles de texto ainda serão detectados por tecnologias adaptativas e lidos em voz alta em leitores de tela, mas isso depende de técnicas diferentes da ordem de tabulação.
Se você ajustar os valores de TabIndex ou usar a ordem padrão, estas regras se aplicarão:
- Se TabIndex não estiver definido em um elemento, o valor padrão será Int32.MaxValue e a ordem de tabulação será baseada na ordem de declaração nas coleções XAML ou filho.
- Se TabIndex for definido em um elemento:
- Os elementos da interface do usuário com TabIndex igual a 0 são adicionados à ordem de tabulação com base na ordem de declaração em coleções XAML ou filho.
- Os elementos da interface do usuário com TabIndex maior que 0 são adicionados à ordem de tabulação com base no valor de TabIndex.
- Os elementos da interface do usuário com TabIndex menor que 0 são adicionados à ordem de tabulação e aparecem antes de qualquer valor zero.
O snippet de código a seguir mostra uma coleção de elementos com várias configurações de TabIndex (B
recebe o valor de Int32.MaxValue ou 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>
Isso resulta na seguinte ordem de tabulação:
- F
- D
- E
- A
- B
- C
Navegação de teclado entre painéis de aplicativos com F6
Um painel de aplicativo é uma área lógica de interface do usuário proeminente e relacionada em uma janela de aplicativo (por exemplo, os painéis do Microsoft Edge incluem a barra de endereços, a barra de indicadores, a barra de guias e o painel de conteúdo). A tecla F6 pode ser usada para navegar entre esses painéis, onde grupos de elementos filho podem ser acessados usando a navegação padrão do teclado.
Embora a navegação pelo teclado possa fornecer uma interface do usuário compatível com o acessibilidade, fazer uma interface do usuário utilizável de forma acessível geralmente requer mais algumas etapas. Normalmente, isso inclui:
- Ouvir F6 para navegar entre seções importantes da interface do usuário.
- Adicionando atalhos de teclado para ações comuns em sua interface do usuário.
- Adicionando chaves de acesso a controles importantes em sua interface do usuário.
Consulte Atalhos de teclado abaixo e Teclas de acesso para obter mais orientações sobre como implementar atalhos e teclas de acesso.
Otimizar para F6
F6 permite que os usuários de teclado naveguem com eficiência entre os painéis da interface do usuário sem passar por centenas de controles.
Por exemplo, F6 no Microsoft Edge alterna entre a barra de endereços, a barra de indicadores, a barra de guias e o painel de conteúdo. Como uma página da Web pode ter centenas de controles tabulares, o F6 pode tornar mais fácil para os usuários do teclado acessar a barra de guias e a barra de endereços sem usar atalhos específicos do aplicativo.
O ciclo de tabulação F6 também pode corresponder vagamente a pontos de referência ou títulos no conteúdo, embora não precise corresponder exatamente. F6 deve se concentrar em regiões grandes e distintas em sua interface do usuário, enquanto os pontos de referência podem ser mais granulares. Por exemplo, você pode marcar uma barra de aplicativos e sua caixa de pesquisa como pontos de referência, mas incluir apenas a própria barra de aplicativos no ciclo F6.
Importante
Você deve implementar a navegação F6 em seu aplicativo, pois ela não tem suporte nativo.
Sempre que possível, as regiões no ciclo F6 devem ter um nome acessível: por meio de um ponto de referência ou adicionando manualmente um AutomationProperties.Name ao elemento "raiz" da região.
Shift-F6 deve circular na direção oposta.
Navegação por teclado em um elemento de interface do usuário
Para controles compostos, é importante garantir a navegação interna adequada entre os elementos contidos. Um controle composto pode gerenciar o elemento filho ativo no momento para reduzir a sobrecarga de ter todos os elementos filho dando suporte ao foco. O controle composto é incluído na ordem de tabulação e manipula os eventos de navegação do teclado em si. Muitos controles compostos já têm alguma lógica de navegação interna incorporada em sua manipulação de eventos. Por exemplo, a passagem de itens com tecla de seta é habilitada por padrão nos controles ListView, GridView, ListBox e FlipView.
Alternativas de teclado para ações e eventos de ponteiro para elementos de controle específicos
Os elementos da interface do usuário que podem ser clicados também devem ser invocados por meio do teclado. Para usar o teclado com um elemento de interface do usuário, o elemento deve ter foco (somente as classes derivadas de Control dão suporte ao foco e à navegação por guias).
Para elementos de interface do usuário que podem ser invocados, implemente manipuladores de eventos de teclado para as teclas Barra de espaço e Enter. Isso garante o suporte básico à acessibilidade do teclado e permite que os usuários acessem todos os elementos interativos da interface do usuário e ativem a funcionalidade usando apenas o teclado.
Quando um elemento não dá suporte ao foco, você pode criar seu próprio controle personalizado. Nesse caso, para habilitar o foco, você deve definir a propriedade IsTabStop como true e fornecer uma indicação visual do estado visual focalizado com um indicador de foco.
No entanto, pode ser mais fácil usar a composição de controle para que o suporte para paradas de tabulação, foco e pares e padrões de automação da interface do usuário da Microsoft sejam tratados pelo controle no qual você escolhe compor seu conteúdo. Por exemplo, em vez de manipular um evento pressionado por ponteiro em uma Image, encapsule esse elemento em um Button para obter suporte a ponteiro, teclado e foco.
<!--Don't do this.-->
<Image Source="sample.jpg" PointerPressed="Image_PointerPressed"/>
<!--Do this instead.-->
<Button Click="Button_Click"><Image Source="sample.jpg"/></Button>
Atalhos do teclado
Além de implementar a navegação e a ativação do teclado, também é uma boa prática implementar atalhos de teclado, como aceleradores de teclado e teclas de acesso para funcionalidades importantes ou usadas com frequência.
Um atalho é uma combinação de teclado que fornece uma maneira eficiente para o usuário acessar a funcionalidade do aplicativo. Existem dois tipos de atalhos:
- Aceleradores são atalhos que invocam um comando do aplicativo. Seu aplicativo pode ou não fornecer uma interface do usuário específica que corresponda ao comando. Os aceleradores normalmente consistem na tecla Ctrl mais uma tecla de letra.
- As teclas de acesso são atalhos que definem o foco para uma interface do usuário específica em seu aplicativo. As teclas de acesso geralmente consistem na tecla Alt mais uma tecla de letra.
Sempre forneça uma maneira fácil para os usuários que dependem de leitores de tela e outras tecnologias adaptativas descobrirem as teclas de atalho do seu aplicativo. Comunique as teclas de atalho usando dicas de ferramentas, nomes acessíveis, descrições acessíveis ou alguma outra forma de comunicação na tela. No mínimo, as teclas de atalho devem estar bem documentadas no conteúdo da Ajuda do seu aplicativo.
Você pode documentar as teclas de acesso por meio de leitores de tela definindo a propriedade anexada AutomationProperties.AccessKey como uma cadeia de caracteres que descreve a tecla de atalho. Há também uma propriedade anexada AutomationProperties.AcceleratorKey para documentar teclas de atalho não mnemônicas, embora os leitores de tela geralmente tratem ambas as propriedades da mesma maneira. Tente documentar as teclas de atalho de várias maneiras, usando dicas de ferramentas, propriedades de automação e documentação de Ajuda escrita.
O exemplo a seguir demonstra como documentar teclas de atalho para botões de reprodução, pausa e parada de mídia.
<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>
Importante
Definir o AutomationProperties.AcceleratorKey ou AutomationProperties.AccessKey não habilita a funcionalidade do teclado. Isso indica apenas quais chaves devem ser usadas para a estrutura de Automação da Interface do Usuário e, em seguida, podem ser passadas aos usuários por meio de tecnologias adaptativas.
O tratamento de chaves é implementado no code-behind, não no XAML. Você ainda precisa anexar manipuladores para eventos KeyDown ou KeyUp no controle relevante para realmente implementar o comportamento de atalho de teclado em seu aplicativo. Além disso, a decoração de texto sublinhado para uma chave de acesso não é fornecida automaticamente. Você deve sublinhar explicitamente o texto da chave específica em seu mnemônico como formatação de sublinhado embutida se desejar mostrar o texto sublinhado na interface do usuário.
Para simplificar, o exemplo anterior omite o uso de recursos para cadeias de caracteres como "Ctrl+A". No entanto, você também deve considerar as teclas de atalho durante a localização. A localização de teclas de atalho é relevante porque a escolha da tecla a ser usada como tecla de atalho normalmente depende do rótulo de texto visível do elemento.
Para obter mais diretrizes sobre como implementar teclas de atalho, consulte Teclas de atalho nas Diretrizes de interação da experiência do usuário do Windows.
Implementando um manipulador de eventos chave
Os eventos de entrada (como os eventos de chave) usam um conceito de evento chamado eventos roteados. Um evento roteado pode aparecer por meio dos elementos filho de um controle composto pai, de modo que o controle pai possa manipular eventos para vários elementos filho. Esse modelo de evento é conveniente para definir ações de tecla de atalho para um controle que contém vários elementos filho, nenhum dos quais pode ter foco ou fazer parte da ordem de tabulação.
Para obter um código de exemplo que mostra como escrever um manipulador de eventos de tecla que inclui a verificação de modificadores, como a tecla Ctrl, consulte Interações de teclado.
Navegação por teclado para controles personalizados
Recomendamos usar as teclas de seta como atalhos de teclado para navegar entre elementos filho nos casos em que os elementos filho têm uma relação espacial entre si. Se os nós de exibição de árvore tiverem subelementos separados para lidar com a expansão e o recolhimento e a ativação do nó, use as teclas de seta para a esquerda e para a direita para fornecer a funcionalidade de expansão e recolhimento do teclado. Se você tiver um controle orientado que ofereça suporte à passagem direcional dentro do conteúdo do controle, use as teclas de seta apropriadas.
Geralmente, você implementa a manipulação de chaves personalizadas para controles personalizados, incluindo uma substituição dos métodos OnKeyDown e OnKeyUp como parte da lógica de classe.
Um exemplo de um estado visual para um indicador de foco
Conforme mencionado anteriormente, qualquer controle personalizado que dê suporte ao foco deve ter um indicador de foco visual. Normalmente, esse indicador de foco é apenas um retângulo que descreve o retângulo delimitador do controle. O Rectangle para foco visual é um elemento par para o restante da composição do controle em um modelo de controle, mas é inicialmente definido com um valor de Visibility de Collapsed porque o controle ainda não está focado. Quando o controle obtém foco, um estado visual é invocado que define especificamente a Visibilidade do visual de foco como Visível. Quando o foco é movido para outro lugar, outro estado visual é chamado e a Visibilidade fica recolhida.
Todos os controles XAML focalizáveis exibem um indicador de foco visual apropriado quando focados. O usuário os selecionou também pode afetar a aparência do indicador (principalmente se o usuário estiver usando um modo de alto contraste). Se você estiver usando os controles XAML em sua interface do usuário (e não estiver substituindo os modelos de controle), não precisará fazer nada extra para obter indicadores de foco visual padrão. No entanto, se você pretende repensar um controle ou se estiver curioso sobre como os controles XAML fornecem seus indicadores de foco visual, o restante desta seção explica como isso é feito em XAML e na lógica de controle.
Aqui está um exemplo de XAML que vem do modelo XAML padrão para um Button.
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>
Até agora, esta é apenas a composição. Para controlar a visibilidade do indicador de foco, defina estados visuais que alternam a propriedade Visibility. Isso é feito usando a propriedade anexada VisualStateManager e VisualStateManager.VisualStateGroups, conforme aplicado ao elemento raiz que define a composição.
<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>
Observe como apenas um dos estados nomeados ajusta a visibilidade diretamente, enquanto os outros estão aparentemente vazios. Com estados visuais, assim que o controle usa outro estado do mesmo VisualStateGroup, todas as animações aplicadas pelo estado anterior são canceladas imediatamente. Como a visibilidade padrão da composição é Recolhida, o retângulo não aparecerá. A lógica de controle controla isso ouvindo eventos de foco como GotFocus e alterando os estados com GoToState. Muitas vezes, isso já é tratado para você se você estiver usando um controle padrão ou personalizando com base em um controle que já tenha esse comportamento.
Acessibilidade do teclado e dispositivos sem teclado físico
Alguns dispositivos não têm um teclado de hardware dedicado e dependem de um SIP (Painel de Entrada Suave). Os leitores de tela podem ler a entrada de texto do SIP de texto e os usuários podem descobrir onde estão seus dedos porque o leitor de tela pode detectar que o usuário está digitalizando as chaves e lê o nome da chave digitalizada em voz alta. Além disso, alguns dos conceitos de acessibilidade orientados ao teclado podem ser mapeados para comportamentos de tecnologia assistencial relacionados que não usam um teclado. Por exemplo, mesmo que um SIP não inclua uma tecla Tab, o Narrador dá suporte a um gesto de toque que é o equivalente a pressionar a tecla Tab, portanto, ter uma ordem de tabulação útil por meio dos controles em uma interface do usuário ainda é essencial para acessibilidade. O Narrador também oferece suporte a muitos outros gestos de toque, incluindo teclas de seta para navegar em controles complexos (consulte Comandos de teclado e gestos de toque do Narrador).
Exemplos
Dica
O aplicativo Galeria da WinUI 3 inclui exemplos interativos da maioria dos controles, recursos e funcionalidades da WinUI 3. Obtenha o aplicativo na Microsoft Store ou o código-fonte no GitHub
Tópicos relacionados
Windows developer