Compartir a través de


Navegación de foco para herramientas de teclado, controlador para juegos, control remoto y accesibilidad

Teclado, remoto y panel D

Usa la navegación de foco para proporcionar experiencias de interacción completas y coherentes en tus aplicaciones de Windows y controles personalizados para los usuarios avanzados del teclado, aquellos con discapacidades y otros requisitos de accesibilidad, así como la experiencia de 10 pies de pantallas de televisión y Xbox One.

Información general

La navegación de foco hace referencia al mecanismo subyacente que permite a los usuarios navegar e interactuar con la interfaz de usuario de una aplicación de Windows mediante un teclado, un controlador para juegos o un control remoto.

Nota:

Normalmente, los dispositivos de entrada se clasifican como dispositivos apuntados, como dispositivos táctiles, táctiles, lápiz y mouse, y dispositivos que no apuntan, como teclado, controlador para juegos y control remoto.

En este tema se describe cómo optimizar una aplicación de Windows y crear experiencias de interacción personalizadas para los usuarios que dependen de tipos de entrada no apuntados.

Aunque nos centramos en la entrada de teclado para controles personalizados en aplicaciones de Windows en equipos, una experiencia de teclado bien diseñada también es importante para los teclados de software, como el teclado táctil y el Teclado en pantalla (OSK), la compatibilidad con herramientas de accesibilidad como Narrador de Windows y la experiencia de 10 pies.

Consulte Handle pointer input (Controlar la entrada del puntero) para obtener instrucciones sobre cómo crear experiencias personalizadas en aplicaciones windows para dispositivos que apunten.

Para obtener más información general sobre la creación de aplicaciones y experiencias para el teclado, consulte Interacción con el teclado.

Instrucciones generales

Solo los elementos de la interfaz de usuario que requieren interacción del usuario deben admitir la navegación de foco, los elementos que no requieren una acción, como imágenes estáticas, no necesitan el foco del teclado. Los lectores de pantalla y las herramientas de accesibilidad similares siguen anunciando estos elementos estáticos, incluso cuando no se incluyen en la navegación de foco.

Es importante recordar que, a diferencia de navegar con un dispositivo de puntero, como un mouse o un toque, la navegación de foco es lineal. Al implementar la navegación de foco, considere cómo interactuará un usuario con la aplicación y cuál debe ser la navegación lógica. En la mayoría de los casos, se recomienda que el comportamiento de navegación de foco personalizado siga el patrón de lectura preferido de la referencia cultural del usuario.

Entre otras consideraciones de navegación de foco se incluyen:

  • ¿Los controles se agrupan lógicamente?
  • ¿Hay grupos de controles con mayor importancia?
    • Si es así, ¿esos grupos contienen subgrupos?
  • ¿El diseño requiere navegación direccional personalizada (teclas de dirección) y orden de tabulación?

El libro electrónico Engineering Software for Accessibility tiene un excelente capítulo sobre diseño de la jerarquía lógica.

Navegación direccional 2D para el teclado

La región de navegación interna 2D de un control o grupo de controles se conoce como su "área direccional". Cuando el foco cambia a este objeto, las teclas de dirección del teclado (izquierda, derecha, arriba y abajo) se pueden usar para navegar entre los elementos secundarios dentro del área direccional.

área direccionalRegión de navegación interna 2D, o área direccional, de un grupo de control

Puede usar la propiedad XYFocusKeyboardNavigation (que tiene valores posibles de Auto, Enabled o Disabled) para administrar la navegación interna 2D con las teclas de dirección del teclado.

Nota:

El orden de tabulación no se ve afectado por esta propiedad. Para evitar una experiencia de navegación confusa, se recomienda que los elementos secundarios de un área direccional no se especifiquen explícitamente en el orden de navegación de tabulación de la aplicación. Consulte las propiedades UIElement.TabFocusNavigation y TabIndex para obtener más detalles sobre el comportamiento de tabulación de un elemento.

Automático (comportamiento predeterminado)

Cuando se establece en Automático, el comportamiento de navegación direccional viene determinado por la herencia o la jerarquía de herencia del elemento. Si todos los antecesores están en modo predeterminado (establecido en Automático), no se admite la navegación direccional con el teclado.

Deshabilitado

Establezca XYFocusKeyboardNavigation en Disabled para bloquear la navegación direccional al control y sus elementos secundarios.

Comportamiento deshabilitado de XYFocusKeyboardNavigationComportamiento deshabilitado de XYFocusKeyboardNavigation

En este ejemplo, el StackPanel principal (ContainerPrimary) tiene XYFocusKeyboardNavigation establecido en Habilitado. Todos los elementos secundarios heredan esta configuración y se pueden navegar a con las teclas de dirección. Sin embargo, los elementos B3 y B4 están en un StackPanel secundario (ContainerSecondary) con XYFocusKeyboardNavigation establecido en Disabled, que invalida el contenedor principal y deshabilita la navegación por la tecla de flecha a sí misma y entre sus elementos secundarios.

<Grid 
    Background="{ThemeResource ApplicationPageBackgroundThemeBrush}" 
    TabFocusNavigation="Cycle">
    <Grid.RowDefinitions>
        <RowDefinition Height="40"/>
        <RowDefinition Height="75"/>
        <RowDefinition Height="*"/>
    </Grid.RowDefinitions>
    <TextBlock Name="KeyPressed"
                Grid.Row="0" 
                FontWeight="ExtraBold" 
                HorizontalTextAlignment="Center"
                TextWrapping="Wrap" 
                Padding="10" />
    <StackPanel Name="ContainerPrimary" 
                XYFocusKeyboardNavigation="Enabled" 
                KeyDown="ContainerPrimary_KeyDown" 
                Orientation="Horizontal" 
                BorderBrush="Green" 
                BorderThickness="2" 
                Grid.Row="1" 
                Padding="10" 
                MaxWidth="200">
        <Button Name="B1" 
                Content="B1" 
                GettingFocus="Btn_GettingFocus" />
        <Button Name="B2" 
                Content="B2" 
                GettingFocus="Btn_GettingFocus" />
        <StackPanel Name="ContainerSecondary" 
                    XYFocusKeyboardNavigation="Disabled" 
                    Orientation="Horizontal" 
                    BorderBrush="Red" 
                    BorderThickness="2">
            <Button Name="B3" 
                    Content="B3" 
                    GettingFocus="Btn_GettingFocus" />
            <Button Name="B4" 
                    Content="B4" 
                    GettingFocus="Btn_GettingFocus" />
        </StackPanel>
    </StackPanel>
</Grid>

Habilitado

Establezca XYFocusKeyboardNavigation en Habilitado para admitir la navegación direccional 2D en un control y cada uno de sus objetos secundarios UIElement .

Cuando se establece, la navegación con las teclas de dirección está restringida a elementos dentro del área direccional. La navegación por tabulación no se ve afectada, ya que todos los controles permanecen accesibles a través de su jerarquía de orden de tabulación.

Comportamiento habilitado para XYFocusKeyboardNavigationComportamiento habilitado para XYFocusKeyboardNavigation

En este ejemplo, el StackPanel principal (ContainerPrimary) tiene XYFocusKeyboardNavigation establecido en Habilitado. Todos los elementos secundarios heredan esta configuración y se pueden navegar a con las teclas de dirección. Los elementos B3 y B4 están en un stackPanel secundario (ContainerSecondary) donde XYFocusKeyboardNavigation no está establecido, lo que hereda la configuración del contenedor principal. El elemento B5 no está dentro de un área direccional declarada y no admite la navegación por teclas de flecha, pero sí admite el comportamiento de navegación por tabulación estándar.

<Grid
    Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
    TabFocusNavigation="Cycle">
    <Grid.RowDefinitions>
        <RowDefinition Height="40"/>
        <RowDefinition Height="100"/>
        <RowDefinition Height="*"/>
    </Grid.RowDefinitions>
    <TextBlock Name="KeyPressed"
               Grid.Row="0"
               FontWeight="ExtraBold"
               HorizontalTextAlignment="Center"
               TextWrapping="Wrap"
               Padding="10" />
    <StackPanel Grid.Row="1"
                Orientation="Horizontal"
                HorizontalAlignment="Center">
        <StackPanel Name="ContainerPrimary"
                    XYFocusKeyboardNavigation="Enabled"
                    KeyDown="ContainerPrimary_KeyDown"
                    Orientation="Horizontal"
                    BorderBrush="Green"
                    BorderThickness="2"
                    Padding="5" Margin="5">
            <Button Name="B1"
                    Content="B1"
                    GettingFocus="Btn_GettingFocus" Margin="5" />
            <Button Name="B2"
                    Content="B2"
                    GettingFocus="Btn_GettingFocus" />
            <StackPanel Name="ContainerSecondary"
                        Orientation="Horizontal"
                        BorderBrush="Red"
                        BorderThickness="2"
                        Margin="5">
                <Button Name="B3"
                        Content="B3"
                        GettingFocus="Btn_GettingFocus"
                        Margin="5" />
                <Button Name="B4"
                        Content="B4"
                        GettingFocus="Btn_GettingFocus"
                        Margin="5" />
            </StackPanel>
        </StackPanel>
        <Button Name="B5"
                Content="B5"
                GettingFocus="Btn_GettingFocus"
                Margin="5" />
    </StackPanel>
</Grid>

Puede tener varios niveles de áreas direccionales anidadas. Si todos los elementos primarios tienen XYFocusKeyboardNavigation establecido en Habilitado, se omiten los límites de la región de navegación interna.

Este es un ejemplo de dos áreas direccionales anidadas dentro de un elemento que no admite explícitamente la navegación direccional 2D. En este caso, no se admite la navegación direccional entre las dos áreas anidadas.

Comportamiento anidado y habilitado de XYFocusKeyboardNavigationComportamiento anidado y habilitado de XYFocusKeyboardNavigation

Este es un ejemplo más complejo de tres áreas direccionales anidadas donde:

  • Cuando B1 tiene el foco, solo B5 se puede navegar a (y viceversa) porque hay un límite de área direccional en el que XYFocusKeyboardNavigation se establece en Deshabilitado, lo que hace que B2, B3 y B4 no se pueda acceder con las teclas de dirección.
  • Cuando B2 tiene el foco, solo B3 se puede navegar a (y viceversa) porque el límite del área direccional impide la navegación de teclas de dirección a B1, B4 y B5.
  • Cuando B4 tiene el foco, se debe usar la tecla Tab para navegar entre los controles.

Comportamiento anidado complejo y habilitado de XYFocusKeyboardNavigation

Comportamiento anidado complejo y habilitado de XYFocusKeyboardNavigation

Navegación entre pestañas

Aunque las teclas de dirección se pueden usar para la navegación direccional 2D witin un control o un grupo de controles, se puede usar la tecla Tab para navegar entre todos los controles de una aplicación de Windows.

Todos los controles interactivos admiten la navegación por teclas tab de forma predeterminada (la propiedad IsEnabled e IsTabStop son true), con el orden de tabulación lógico derivado del diseño de control en la aplicación. Sin embargo, el orden predeterminado no corresponde necesariamente al orden visual. La posición de visualización real puede depender del contenedor de diseño primario y de determinadas propiedades que puede establecer en los elementos secundarios para influir en el diseño.

Evite un orden de tabulación personalizado que haga que el enfoque salte por la aplicación. Por ejemplo, una lista de controles de un formulario debe tener un orden de tabulación que fluya de arriba a abajo y de izquierda a derecha (dependiendo de la configuración regional).

En esta sección se describe cómo este orden de tabulación se puede personalizar completamente para adaptarse a la aplicación.

Establecimiento del comportamiento de navegación de pestañas

La propiedad TabFocusNavigation de UIElement especifica el comportamiento de navegación de tabulación para todo su árbol de objetos (o área direccional).

Nota:

Utilice esta propiedad en lugar de la propiedad Control.TabNavigation para los objetos que no usan controlTemplate para definir su apariencia.

Como hemos mencionado en la sección anterior, para evitar una experiencia de navegación confusa, se recomienda que los elementos secundarios de un área direccional no se especifiquen explícitamente en el orden de navegación de tabulación de la aplicación. Consulte las propiedades UIElement.TabFocusNavigation y TabIndex para obtener más detalles sobre el comportamiento de tabulación de un elemento.

En las versiones anteriores a Actualización de Windows 10 para creadores (compilación 10.0.15063), la configuración de tabulación se limitaba a los objetos ControlTemplate. Para obtener más información, consulta Control.TabNavigation.

TabFocusNavigation tiene un valor de tipo KeyboardNavigationMode con los siguientes valores posibles (tenga en cuenta que estos ejemplos no son grupos de controles personalizados y no requieren navegación interna con las teclas de dirección):

  • Los índices de tabulación local (predeterminado) se reconocen en el subárbol local dentro del contenedor. En este ejemplo, el orden de tabulación es B1, B2, B3, B4, B5, B6, B7, B1.

    Comportamiento de navegación de pestañas

    Comportamiento de navegación de pestañas "Local"

  • Una vez que el contenedor y todos los elementos secundarios reciben el foco una vez. En este ejemplo, el orden de tabulación es B1, B2, B7, B1 (también se muestra la navegación interna con la tecla de flecha).

    Comportamiento de navegación de pestañas

    Comportamiento de navegación de pestañas "Una vez"

  • Ciclo
    El foco vuelve al elemento centrado inicial dentro de un contenedor. En este ejemplo, el orden de tabulación es B1, B2, B3, B4, B5, B6, B2...

    Comportamiento de navegación por pestañas

    Comportamiento de navegación por pestañas "Ciclo"

Este es el código de los ejemplos anteriores (con TabFocusNavigation ="Cycle").

<Grid 
    Background="{ThemeResource ApplicationPageBackgroundThemeBrush}" 
    TabFocusNavigation="Cycle">
    <Grid.RowDefinitions>
        <RowDefinition Height="40"/>
        <RowDefinition Height="300"/>
        <RowDefinition Height="*"/>
    </Grid.RowDefinitions>
    <TextBlock Name="KeyPressed"
               Grid.Row="0" 
               FontWeight="ExtraBold" 
               HorizontalTextAlignment="Center"
               TextWrapping="Wrap" 
               Padding="10" />
    <StackPanel Name="ContainerPrimary"
                KeyDown="Container_KeyDown" 
                Orientation="Horizontal" 
                HorizontalAlignment="Center"
                BorderBrush="Green" 
                BorderThickness="2" 
                Grid.Row="1" 
                Padding="10" 
                MaxWidth="200">
        <Button Name="B1" 
                Content="B1" 
                GettingFocus="Btn_GettingFocus" 
                Margin="5"/>
        <StackPanel Name="ContainerSecondary" 
                    KeyDown="Container_KeyDown"
                    XYFocusKeyboardNavigation="Enabled" 
                    TabFocusNavigation ="Cycle"
                    Orientation="Vertical" 
                    VerticalAlignment="Center"
                    BorderBrush="Red" 
                    BorderThickness="2"
                    Padding="5" Margin="5">
            <Button Name="B2" 
                    Content="B2" 
                    GettingFocus="Btn_GettingFocus" 
                    Margin="5"/>
            <Button Name="B3" 
                    Content="B3" 
                    GettingFocus="Btn_GettingFocus" 
                    Margin="5"/>
            <Button Name="B4" 
                    Content="B4" 
                    GettingFocus="Btn_GettingFocus" 
                    Margin="5"/>
            <Button Name="B5" 
                    Content="B5" 
                    GettingFocus="Btn_GettingFocus" 
                    Margin="5"/>
            <Button Name="B6" 
                    Content="B6" 
                    GettingFocus="Btn_GettingFocus" 
                    Margin="5"/>
        </StackPanel>
        <Button Name="B7" 
                Content="B7" 
                GettingFocus="Btn_GettingFocus" 
                Margin="5"/>
    </StackPanel>
</Grid>

TabIndex

Use TabIndex para especificar el orden en el que los elementos reciben el foco cuando el usuario navega por los controles mediante la tecla Tab. Un control con un índice de tabulación inferior recibe el foco antes de un control con un índice superior.

Cuando un control no tiene especificado TabIndex , se le asigna un valor de índice mayor que el valor de índice más alto actual (y la prioridad más baja) de todos los controles interactivos del árbol visual, en función del ámbito.

Todos los elementos secundarios de un control se consideran un ámbito y, si uno de estos elementos también tiene elementos secundarios, se consideran otro ámbito. Cualquier ambigüedad se resuelve eligiendo el primer elemento en el árbol visual del ámbito.

Para excluir un control del orden de tabulación, establezca la propiedad IsTabStop en false.

Invalide el orden de tabulación predeterminado estableciendo la propiedad TabIndex .

Nota:

TabIndex funciona de la misma manera con UIElement.TabFocusNavigation y Control.TabNavigation.

Aquí se muestra cómo la navegación de foco puede verse afectada por la propiedad TabIndex en elementos específicos.

Navegación por tabulación

Navegación por tabulación "Local" con el comportamiento de TabIndex

En el ejemplo anterior, hay dos ámbitos:

  • B1, área direccional (B2 - B6) y B7
  • área direccional (B2 - B6)

Cuando B3 (en el área direccional) obtiene el foco, el ámbito cambia y la navegación por tabulación se transfiere al área direccional donde se identifica el mejor candidato para el foco posterior. En este caso, B2 seguido de B4, B5 y B6. El ámbito vuelve a cambiar y el foco se mueve a B1.

Este es el código de este ejemplo.

<Grid
    Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
    TabFocusNavigation="Cycle">
    <Grid.RowDefinitions>
        <RowDefinition Height="40"/>
        <RowDefinition Height="300"/>
        <RowDefinition Height="*"/>
    </Grid.RowDefinitions>
    <TextBlock Name="KeyPressed"
               Grid.Row="0"
               FontWeight="ExtraBold"
               HorizontalTextAlignment="Center"
               TextWrapping="Wrap"
               Padding="10" />
    <StackPanel Name="ContainerPrimary"
                KeyDown="Container_KeyDown"
                Orientation="Horizontal"
                HorizontalAlignment="Center"
                BorderBrush="Green"
                BorderThickness="2"
                Grid.Row="1"
                Padding="10"
                MaxWidth="200">
        <Button Name="B1"
                Content="B1"
                TabIndex="1"
                ToolTipService.ToolTip="TabIndex = 1"
                GettingFocus="Btn_GettingFocus"
                Margin="5"/>
        <StackPanel Name="ContainerSecondary"
                    KeyDown="Container_KeyDown"
                    TabFocusNavigation ="Local"
                    Orientation="Vertical"
                    VerticalAlignment="Center"
                    BorderBrush="Red"
                    BorderThickness="2"
                    Padding="5" Margin="5">
            <Button Name="B2"
                    Content="B2"
                    GettingFocus="Btn_GettingFocus"
                    Margin="5"/>
            <Button Name="B3"
                    Content="B3"
                    TabIndex="3"
                    ToolTipService.ToolTip="TabIndex = 3"
                    GettingFocus="Btn_GettingFocus"
                    Margin="5"/>
            <Button Name="B4"
                    Content="B4"
                    GettingFocus="Btn_GettingFocus"
                    Margin="5"/>
            <Button Name="B5"
                    Content="B5"
                    GettingFocus="Btn_GettingFocus"
                    Margin="5"/>
            <Button Name="B6"
                    Content="B6"
                    GettingFocus="Btn_GettingFocus"
                    Margin="5"/>
        </StackPanel>
        <Button Name="B7"
                Content="B7"
                TabIndex="2"
                ToolTipService.ToolTip="TabIndex = 2"
                GettingFocus="Btn_GettingFocus"
                Margin="5"/>
    </StackPanel>
</Grid>

Navegación direccional 2D para teclado, controlador para juegos y control remoto

Los tipos de entrada que no son de puntero, como teclado, controlador para juegos, control remoto y herramientas de accesibilidad como Narrador de Windows, comparten un mecanismo común subyacente para navegar e interactuar con la interfaz de usuario de la aplicación Windows.

En esta sección, tratamos cómo especificar una estrategia de navegación preferida y ajustar la navegación de foco dentro de la aplicación a través de un conjunto de propiedades de estrategia de navegación que admiten todos los tipos de entrada de puntero y basados en foco.

Para obtener más información general sobre la creación de aplicaciones y experiencias para Xbox/TV, consulta Interacción del teclado, Diseño para Xbox y TV, y Controlador para juegos y interacciones de control remoto.

Las estrategias de navegación son aplicables al teclado, el controlador para juegos, el control remoto y varias herramientas de accesibilidad.

Las siguientes propiedades de estrategia de navegación permiten influir en qué control recibe el foco en función de la tecla de flecha, el botón de panel direccional (D-pad) o similar presionado.

  • XYFocusUpNavigationStrategy
  • XYFocusDownNavigationStrategy
  • XYFocusLeftNavigationStrategy
  • XYFocusRightNavigationStrategy

Estas propiedades tienen valores posibles de Auto (valor predeterminado), NavigationDirectionDistance, Projection o RectilinearDistance .

Si se establece en Auto, el comportamiento del elemento se basa en los antecesores del elemento. Si todos los elementos se establecen en Auto, se usa Proyección .

Nota:

Otros factores, como el elemento centrado anteriormente o la proximidad al eje de la dirección de navegación, pueden influir en el resultado.

Proyección

La estrategia de proyección mueve el foco al primer elemento encontrado cuando se proyecta el borde del elemento centrado actualmente en la dirección de la navegación.

En este ejemplo, cada dirección de navegación del foco se establece en Proyección. Observe cómo el foco se mueve de B1 a B4, pasando B3. Esto se debe a que B3 no está en la zona de proyección. Observe también cómo no se identifica un candidato de enfoque al moverse a la izquierda de B1. Esto se debe a que la posición de B2 relativa a B1 elimina B3 como candidato. Si B3 estuviera en la misma fila que B2, sería un candidato viable para la navegación izquierda. B2 es un candidato viable debido a su proximidad sin obstáculos al eje de la dirección de navegación.

Estrategia de navegación de proyección

Estrategia de navegación de proyección

La estrategia NavigationDirectionDistance mueve el foco al elemento más cercano al eje de la dirección de navegación.

El borde del rectángulo delimitador correspondiente a la dirección de navegación se extiende y se proyecta para identificar los destinos candidatos. El primer elemento encontrado se identifica como destino. En el caso de varios candidatos, el elemento más cercano se identifica como destino. Si todavía hay varios candidatos, el elemento más alto o izquierdo se identifica como candidato.

NavigationDirectionDistance navigation strategy (Estrategia de navegación de NavigationDirectionDistance)

NavigationDirectionDistance navigation strategy (Estrategia de navegación de NavigationDirectionDistance)

RectilinearDistance

La estrategia RectilinearDistance mueve el foco al elemento más cercano basado en la distancia rectilineal 2D (geometría Taxicab).

La suma de la distancia primaria y la distancia secundaria a cada candidato potencial se usa para identificar el mejor cándido. En un empate, se selecciona el primer elemento a la izquierda si la dirección solicitada está hacia arriba o hacia abajo y se selecciona el primer elemento a la parte superior si la dirección solicitada es izquierda o derecha.

Estrategia de navegación rectilinearDistance

Estrategia de navegación rectilinearDistance

En esta imagen se muestra cómo, cuando B1 tiene el foco y la dirección hacia abajo es la dirección solicitada, B3 es el candidato de enfoque RectilinearDistance. Esto se basa en las siguientes calcualizaciones para este ejemplo:

  • Distancia (B1, B3, Abajo) es 10 + 0 = 10
  • Distancia (B1, B2, Abajo) es 0 + 40 = 30
  • Distancia (B1, D, Abajo) es 30 + 0 = 30