Dela via


Tillgänglighet för tangentbord

Tangentbordstillgänglighet bör behandlas som en primär interaktionsmodell, inte som en sekundär reservlösning. En robust tangentbordsupplevelse stöder användare som har olika funktionsnedsättningar och begränsningar (inklusive syn, inlärning, fingerfärdighet/rörlighet och språk-/kommunikationssvårigheter). Det förbättrar också produktiviteten för användare som föredrar tangentbordsinteraktion för hastighet och precision.

Om tangentbordsåtkomsten är ofullständig eller inkonsekvent kan användarna förlora åtkomsten till kärnappens funktioner även när pekarinteraktion verkar vara helt implementerad.

Tangentbordsnavigering mellan gränssnittselement

Om du vill interagera med en kontroll med hjälp av tangentbordet måste kontrollerna vara fokusbara och nåbara via fokusblädering. För att få fokus (utan att använda en pekare) måste kontrollen vara tillgänglig via tabbnavigeringen. Som standard är flikordningen för kontroller samma som i vilken ordning de läggs till i en design surface, deklareras i XAML eller programmatiskt läggs till i en container.

I många UIs är det här standardbeteendet acceptabelt och överensstämmer med läsflödet. Visuell ordning och tangentbordsordning kan dock variera beroende på containerlayouten och positionering av underordnade element. Denna divergering bör vara avsiktlig och testas.

Verifiera flikbeteende explicitt. Rutnät, tabell och liknande layouter är vanliga källor till matchningsfel mellan upplevd läsordning och fokusordning. Testa sökvägarna för både tangentbords- och pekinteraktion för att säkerställa att bläddering förblir effektiv och förutsägbar.

Om du vill justera bläddering med visuellt flöde kan du omstrukturera XAML eller uttryckligen tilldela TabIndex. I följande exempel används ett rutnät med sekvensering av kolumn-första flik.

<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>

I vissa scenarier bör ett element undantas från flikbläddering. Standardmetoden är att ange IsEnabled till false, vilket också inaktiverar interaktion. Inaktiverade kontroller tas automatiskt bort från tabbordningen.

Om ett element förblir interaktivt via andra mekanismer men inte ska nås med Tab anger du IsTabStop till false.

De flesta fokuskompatibla kontroller ingår som standard i tabbordning. Ett vanligt undantag är textvisningskontroller som RichTextBlock, som kan ha stöd för fokus för textval och Urklippsåtgärder, men som vanligtvis inte är tabbstopp eftersom de inte är kommandoanropsbara kontroller. Dessa kontroller kan fortfarande identifieras med hjälptekniker via automationssemantik, till exempel textkontrollmönstret.

Oavsett om du använder standardbläddering eller explicit TabIndex gäller följande regler:

  • Om TabIndex inte har angetts för ett element är standardvärdet Int32.MaxValue och ordningen baseras på deklaration/infogningsordning.
  • Om TabIndex har angetts för ett element:
    • Element med TabIndex lika med 0 läggs till baserat på deklaration/infogningsordning.
    • Element med TabIndex större än 0 läggs till i stigande TabIndex-ordning .
    • Element med TabIndex mindre än 0 läggs till före element med noll värden.

Följande kodfragment visar blandade TabIndex-inställningar (B använder Int32.MaxValue, eller 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>

Detta skapar följande flikordning:

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

Tangentbordsnavigering mellan programfönster med F6

Ett programfönster är en framträdande aktivitetsregion i ett fönster. I Microsoft Edge, till exempel, innehåller fönster adressfältet, bokmärkesfältet, flikremsan och innehållsområdet. F6 används ofta för att flytta fokus mellan dessa rutor där underordnade element kan nås med hjälp av standardtangentbordsnavigering.

En kompatibel tangentbordsnavigeringsmodell är baslinjen, men en användbar tangentbordsnavigeringsmodell innehåller vanligtvis:

  • Lyssnar efter F6 för att flytta mellan större användargränssnittsregioner.
  • Tillhandahålla kortkommandon för kommandon med hög frekvens.
  • Tillhandahålla åtkomstnycklar för viktiga kontroller.

Se Kortkommandon och åtkomstnycklar för implementeringsvägledning.

Optimera för F6

F6 minskar avsevärt traverseringskostnaden genom att låta användarna hoppa mellan huvudområden i stället för att tabba genom varje underliggande kontroll.

F6 i Microsoft Edge växlar till exempel mellan adressfältet, bokmärkesfältet, flikremsan och innehållet. Eftersom en sida kan innehålla många tabbstopp gör detta vanliga navigeringsuppgifter mycket mer effektiva.

F6-sekvensen kan anpassas efter landmärken eller rubriker, men den behöver inte matcha exakt. Använd F6 för bred rörelse på regionnivå och landmärken/rubriker för semantisk struktur inom och mellan regioner.

Viktigt!

Du måste implementera F6-navigering explicit i din app. den tillhandahålls inte automatiskt.

Om möjligt bör varje F6-målregion ha ett tydligt tillgängligt namn, antingen från landmärkessemantik eller genom att ange AutomationProperties.Name på regionroten.

Skift+F6 bör gå igenom samma cykel i omvänd ordning.

Tangentbordsnavigering i ett gränssnittselement

Sammansatta kontroller bör ge förutsägbar intern navigering mellan underordnade element. Ett vanligt mönster är att hålla den sammansatta roten i tabbordning och hantera aktiva underordnade internt, i stället för att exponera varje underordnad som ett separat tabbstopp.

Många inbyggda kontroller implementerar redan det här beteendet. Till exempel är piltangentsbläddering tillgängligt som standard för ListView, GridView, ListBox och FlipView.

Tangentbordsalternativ till pekaråtgärder och händelser för specifika kontrollelement

Alla användargränssnitt som kan aktiveras med pekare bör också anropas av tangentbordet. Aktivering kräver att elementet har fokus (endast klasser som härleds från kontrollstödfokus och fliknavigering).

För kontroller som kan anropas implementerar du tangentbordshändelsehanterare för blankstegstangenterna och Retur-tangenterna. Detta ger grundläggande tangentbordsparitet med pekarinteraktioner.

Om ett element inte är fokuskompatibelt som standard använder du antingen en fokuserbar kontrolltyp eller implementerar en anpassad kontroll med explicit fokusbeteende. I så fall anger du IsTabStop till sant och ger en synlig fokusindikator.

I många fall är kompositionen enklare och mer robust än det anpassade beteendet med endast pekare. I stället för att till exempel hantera pekarindata direkt på en bild placerar du den i en knapp för att ärva tangentbordsaktivering, fokushantering och automatiseringsbeteende.

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

<!--Do this instead.-->
<Button Click="Button_Click"
        AutomationProperties.Name="Open profile photo">
  <Image Source="Assets/profile-photo.png"/>
</Button>

Kortkommandon för tangentbord

Förutom navigering och aktivering implementerar du en genväg (en nyckelkombination som ger effektiv åtkomst till appfunktioner) för viktiga eller ofta använda kommandon med tangentbordsacceleratorer och åtkomstnycklar.

Två vanliga typer av genvägar är:

  • Acceleratorer: anropa kommandon direkt, med eller utan motsvarande synlig kontroll.
  • Åtkomstnycklar: Flytta fokus till specifika kontroller i användargränssnittet.

Gör alltid genvägarna identifierbara för användare av hjälpmedelsteknik. Kommunicera dem via knappbeskrivningar, automationsmetadata, synliga gränssnittsfunktioner och hjälpdokumentation.

Om du vill exponera genvägsmetadata för hjälpmedelstekniker använder du AutomationProperties.AccessKey för mnemonic-genvägar och AutomationProperties.AcceleratorKey för kommandogenvägar. Eftersom skärmläsare kan presentera dessa på liknande sätt, dokumentera genvägar i flera kanaler.

I följande exempel visas hur du dokumenterar genvägsnycklar för uppspelning av media, pausa och stoppa knappar.

<Grid>

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

  <MediaPlayerElement x:Name="DemoPlayer"
    Width="500" Height="300" Margin="20"
    HorizontalAlignment="Center"
    AutoPlay="False"
    AreTransportControlsEnabled="True" />

  <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="Ctrl+P"
      AutomationProperties.AccessKey="Alt+P">
      <Button.KeyboardAccelerators>
        <KeyboardAccelerator Modifiers="Control" Key="P"/>
      </Button.KeyboardAccelerators>
      <TextBlock>Play</TextBlock>
    </Button>

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

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

Viktigt!

Inställningen AutomationProperties.AcceleratorKey eller AutomationProperties.AccessKey implementerar inte tangentbordsbeteende. Dessa egenskaper exponerar metadata för UI Automation så att hjälpmedelstekniker kan meddela de förväntade genvägarna.

Tangentbordsbeteendet måste fortfarande implementeras i kod. Använd deklarativa KeyboardAccelerator-definitioner när det är möjligt och använd KeyDown - eller KeyUp-hanterare där du behöver anpassad routningslogik. Observera också att formateringen för understrykning av åtkomstnycklar inte är automatisk. Om du vill ha synliga mnemonic-understrykningar återger du dem explicit (till exempel med Understrykning).

För korthet utelämnar exemplet strängresurser som "Ctrl+A". I produktion lokaliserar du genvägstext och validerar mnemonic-val per språk, eftersom nyckelval ofta är beroende av översatta etiketter.

Mer information finns i Genvägsnycklar i riktlinjerna för interaktion med Windows-användare.

Implementera en nyckelhändelsehanterare

Nyckelindata använder routade händelser. Routade händelser kan bubbla från underordnade till en överordnad container, vilket gör att den överordnade kan bearbeta genvägar för flera underordnade element. Den här händelsemodellen är praktisk för att definiera genvägsnyckelåtgärder för en kontroll som innehåller flera underordnade element, varav ingen kan ha fokus eller vara en del av tabbordningen.

Kodexempel som inkluderar kontroller av modifierartangenter (till exempel Ctrl) se Tangentbordsinteraktioner.

Tangentbordsnavigering för anpassade kontroller

För anpassade kontroller ska du använda piltangenterna när underordnade element är rumsligt relaterade. I trädscenarier där expandera/komprimera och aktivera är separata interaktioner mappar du vänster- och högerpilar för att expandera/minimera beteendet. För orienterade kontroller mappar du riktningsnycklar till kontrollens visuella orientering.

Beteende för anpassad nyckel implementeras ofta genom att åsidosätta OnKeyDown och OnKeyUp.

Ett exempel på ett visuellt tillstånd för en fokusindikator

Alla fokuserbara anpassade kontroller bör exponera en tydlig visuell fokusindikator. Ett vanligt mallmönster använder ett rektangelöverlägg som börjar döljas via synlighet och visas när fokus kommer in.

Inbyggda XAML-kontroller innehåller redan fokusindikatorer. Det exakta utseendet kan variera med temainställningar, inklusive högkontrastläge. Om du försöker använda kontroller igen bevarar du motsvarande beteende för fokussynlighet.

Följande exempel är anpassat från standardmallen Knapp .

<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>

Om du vill växla fokusindikatorns synlighet använder du VisualStateManager vid VisualStateManager.VisualStateGroups mallroten.

<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"/>
          </Storyboard>
        </VisualState>
        <VisualState x:Name="Unfocused" />
        <VisualState x:Name="PointerFocused" />
      </VisualStateGroup>
    </VisualStateManager.VisualStateGroups>

    <!--composition is here-->
  </Grid>
</ControlTemplate>

Endast ett tillstånd i den här gruppen ändrar uttryckligen det visuella fokusobjektet. De andra tillstånden kan förbli tomma eftersom övergångar i samma VisualStateGroup avbryter tidigare tillståndsanimeringar. Fokushändelser som GotFocus, kombinerat med GoToState, driver vanligtvis dessa övergångar.

Tangentbordstillgänglighet och enheter utan maskinvarutangentbord

Vissa enheter förlitar sig på en SIP (Soft Input Panel) i stället för ett maskinvarutangentbord. Skärmläsare kan upptäcka att användaren genomsöker nycklar och meddelar en användares SIP-nyckelutforskning, och många tangentbordstillgänglighetsbegrepp gäller fortfarande via gestmotsvarigheter.

Även utan en fysisk Tab-tangent har Skärmläsaren till exempel stöd för gester som mappas till Tab-liknande navigering. Det innebär att sammanhängande tabbordning fortfarande är kritisk. Skärmläsaren tillhandahåller även gestmotsvarigheter för riktningsnavigering i komplexa kontroller (se Skärmläsarens tangentbordskommandon och pekgester).

Examples

WinUI 3-galleriikon WinUI 3-galleriappen innehåller interaktiva exempel på WinUI-kontroller och funktioner. Hämta appen från Microsoft Store eller bläddra i källkoden på GitHub.