키보드 접근성

키보드 접근성(기존, 수정 또는 키보드 에뮬레이션 하드웨어용)을 앱에 빌드하면 시각 장애가 있거나 시력이 낮거나 운동 장애가 있거나 손을 거의 또는 전혀 사용하지 않는 사용자에게 앱의 전체 기능을 탐색하고 사용할 수 있습니다. 또한 장애가 없는 사용자는 기본 설정 또는 효율성으로 인해 탐색용 키보드를 선택할 수 있습니다.

앱이 좋은 키보드 액세스를 제공하지 않는 경우 시각 장애가 있거나 이동성 문제가 있는 사용자는 앱을 사용하는 데 어려움을 겪을 수 있습니다.

UI 요소 간의 키보드 탐색

키보드를 사용하여 컨트롤과 상호 작용하려면 컨트롤에 포커스가 있어야 합니다. 포인터를 사용하지 않고 포커스를 받으려면 탭 탐색을 통해 컨트롤에 액세스할 수 있어야 합니다. 기본적으로 컨트롤의 탭 순서는 디자인 화면에 추가되거나, XAML로 선언되거나, 프로그래밍 방식으로 컨테이너에 추가되는 순서와 동일합니다.

일반적으로 기본 탭 순서는 컨트롤이 XAML에서 정의되는 방식을 기반으로 하며, 특히 화면 읽기 프로그램에서 컨트롤을 트래버스하는 순서입니다. 그러나 기본 순서가 반드시 시각적 순서와 일치하는 것은 아닙니다. 실제 표시 위치는 부모 레이아웃 컨테이너 및 레이아웃에 영향을 줄 수 있는 자식 요소의 다양한 속성에 따라 달라질 수 있습니다.

앱에 최적의 탭 순서가 있는지 확인하려면 동작을 직접 테스트합니다. 레이아웃에 그리드 또는 테이블을 사용하는 경우 사용자가 화면을 읽을 수 있는 순서와 탭 순서가 매우 다를 수 있습니다. 항상 문제가 되는 것은 아니지만 터치와 키보드를 통해 앱의 기능을 테스트하여 UI가 두 입력 방법 모두에 최적화되어 있는지 확인합니다.

XAML을 조정하거나 기본 탭 순서를 재정의하여 탭 순서를 시각적 순서와 일치시킬 수 있습니다. 다음 예제에서는 열 우선 탭 탐색을 사용하는 그리드 레이아웃에서 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>

경우에 따라 탭 순서에서 특정 컨트롤을 제외할 수 있습니다. 이 작업은 일반적으로 IsEnabled 속성을 false로 설정하여 컨트롤을 비터활성으로 설정하여 수행됩니다. 비활성화된 컨트롤은 탭 순서에서 자동으로 제외됩니다.

탭 순서에서 대화형 컨트롤을 제외하려면 IsTabStop 속성을 false설정할 수 있습니다.

기본적으로 포커스를 지원하는 UI 요소는 일반적으로 탭 순서에 포함됩니다. 이에 대한 몇 가지 예외로는 텍스트 선택 및 클립보드 액세스에 대한 포커스를 지원하지만 정적 텍스트 요소이므로 탭 순서가 아닌 특정 텍스트 표시 형식(예: RichTextBlock)이 포함됩니다. 이러한 컨트롤은 일반적으로 대화형이 아닙니다(호출할 수 없고 텍스트 입력이 필요하지는 않지만 텍스트에서 선택점 찾기 및 조정을 지원하는 텍스트 컨트롤 패턴을 지원). 텍스트 컨트롤은 보조 기술에서 여전히 검색되고 화면 읽기 프로그램에서 소리내어 읽지만 탭 순서 이외의 기술에 의존합니다.

기본 순서를 사용하든 TabIndex 값을 조정하든 관계없이 다음 규칙이 적용됩니다.

  • 요소에 TabIndex가 설정되지 않은 경우 기본값은 Int32.MaxValue이고 탭 순서는 XAML 또는 자식 컬렉션의 선언 순서를 기반으로 합니다.
  • 요소에 TabIndex가 설정된 경우:
    • 0과 동일한 TabIndex 가 있는 UI 요소는 XAML 또는 자식 컬렉션의 선언 순서에 따라 탭 순서에 추가됩니다.
    • 0보다 큰 TabIndex 가 있는 UI 요소는 TabIndex 값에 따라 탭 순서에 추가됩니다.
    • 0보다 작은 TabIndex UI 요소는 탭 순서에 추가되고 모든 0값 앞에 나타납니다.

다음 코드 조각은 다양한 TabIndex 설정이 있는 요소 컬렉션을 보여 줍니다(BInt32.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>

그 결과는 다음 탭 순서와 같습니다.

  1. F
  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 주기에 앱 바 자체만 포함할 수 있습니다.

Important

기본적으로 지원되지 않으므로 앱에서 F6 탐색을 구현해야 합니다.

가능한 경우 F6 주기의 지역에는 접근성 있는 이름(랜드마크를 통해 또는 지역의 "루트" 요소에 AutomationProperties.Name 수동으로 추가)이 있어야 합니다.

Shift-F6 은 반대 방향으로 순환해야 합니다.

UI 요소 내의 키보드 탐색

복합 컨트롤의 경우 포함된 요소 간에 적절한 내부 탐색을 보장하는 것이 중요합니다. 복합 컨트롤은 현재 활성 자식 요소를 관리하여 모든 자식 요소가 포커스를 지원하는 오버헤드를 줄일 수 있습니다. 복합 컨트롤은 탭 순서에 포함되며 키보드 탐색 이벤트 자체를 처리합니다. 많은 복합 컨트롤에는 이미 이벤트 처리에 기본 제공되는 일부 내부 탐색 논리가 있습니다. 예를 들어, 항목의 화살표 키 통과를 활성화하려면 기본적으로 ListView, GridView, ListBoxFlipView 컨트롤에서 설정되어야 합니다.

특정 컨트롤 요소에 대한 포인터 작업 및 이벤트에 대한 키보드 대안

클릭할 수 있는 UI 요소도 키보드를 통해 호출할 수 있어야 합니다. UI 요소와 함께 키보드를 사용하려면 요소에 포커스가 있어야 합니다(Control에서 파생된 클래스만 포커스 및 탭 탐색을 지원).

호출할 수 있는 UI 요소의 경우, 스페이스바 및 Enter 키에 대한 키보드 이벤트 처리기를 구현합니다. 이렇게 하면 기본 키보드 접근성이 지원되고 사용자가 모든 대화형 UI 요소에 도달하고 키보드만 사용하여 기능을 활성화할 수 있습니다.

요소가 포커스를 지원하지 않는 경우 사용자 지정 컨트롤을 직접 만들 수 있습니다. 이 경우 포커스를 사용하도록 설정하려면 IsTabStop 속성을 true설정해야 하며 포커스 표시기와 함께 포커스가 있는 시각적 상태의 시각적 표시를 제공해야 합니다.

그러나 탭 정지, 포커스 및 Microsoft UI 자동화 피어 및 패턴에 대한 지원이 콘텐츠를 작성하도록 선택한 컨트롤에서 처리되도록 컨트롤 컴퍼지션을 사용하는 것이 더 쉬울 수 있습니다. 예를 들어 이미지에서 포인터 누름 이벤트를 처리하는 대신 단추해당 요소를 래핑하여 포인터, 키보드 및 포커스 지원을 가져옵니다.

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

Important

AutomationProperties.AcceleratorKey 또는 AutomationProperties.AccessKey 설정을 통해 키보드 기능을 활성화할 수 없습니다. 이는 UI 자동화 프레임워크에 사용해야 하는 키를 나타내고 보조 기술을 통해 사용자에게 전달할 수 있습니다.

키 처리는 XAML이 아닌 코드 숨김에서 구현됩니다. 앱에서 바로 가기 키 동작을 실제로 구현하려면 관련 컨트롤에서 KeyDown 또는 KeyUp 이벤트에 대한 처리기를 연결해야 합니다. 액세스 키에 대한 밑줄 텍스트 장식도 자동으로 제공되지 않습니다. UI에 밑줄이 그어진 텍스트를 표시하려면 니모닉의 특정 키에 대한 텍스트를 인라인 밑줄 서식으로 명시적으로 밑줄을 지정해야 합니다.

편의상 앞의 예제에서는 "Ctrl+A"와 같은 문자열에 대한 리소스 사용을 생략합니다. 그러나 지역화 도중에 바로 가기 키도 고려해야 합니다. 바로 가기 키로 사용할 키 선택은 일반적으로 요소에 표시되는 텍스트 레이블에 따라 달라지므로 바로 가기 키 지역화는 관련이 있습니다.

바로 가기 키 구현에 대한 자세한 지침은 Windows 사용자 경험 상호작용 지침에 나온 바로 가기 키 를 참조하세요.

키 이벤트 처리기 구현

입력 이벤트(예: 키 이벤트)는 라우트된 이벤트라는 이벤트 개념을 사용합니다. 라우트된 이벤트는 부모 복합 컨트롤의 자식 요소를 통해 버블 업될 수 있으므로 부모 컨트롤은 여러 자식 요소에 대한 이벤트를 처리할 수 있습니다. 이 이벤트 모델은 포커스가 있거나 탭 순서의 일부가 될 수 없는 여러 자식 요소가 포함된 컨트롤에 대한 바로 가기 키 작업을 정의하는 데 편리합니다.

Ctrl 키와 같은 한정자에 대한 검사를 포함하는 키 이벤트 처리기를 작성하는 방법을 보여 주는 예제 코드를 원하시면 키보드 상호작용을 참조하세요.

사용자 지정 컨트롤을 위한 키보드 탐색

자식 요소가 서로 공간적 관계가 있는 경우 자식 요소 간 탐색을 위한 바로 가기 키로 화살표 키를 사용하는 것이 좋습니다. 트리 뷰 노드에 확장-축소 및 노드 활성화를 처리하기 위한 별도의 하위 요소가 있는 경우, 좌우 방향의 화살표 키를 사용하면 키보드 확장 축소 기능을 쓸 수 있습니다. 컨트롤 콘텐츠 내에서 방향 통과를 지원하는 지향 컨트롤이 있는 경우, 적절한 화살표 키를 사용합니다.

일반적으로 클래스 논리의 일부로 OnKeyDown OnKeyUp 메서드의 재정의를 포함하여 사용자 지정 컨트롤에 대한 사용자 지정 키 처리를 구현합니다.

포커스 표시기의 시각적 상태 예제

앞에서 설명한 것처럼 포커스를 지원하는 모든 사용자 지정 컨트롤에는 시각적 포커스 표시기가 있어야 합니다. 일반적으로 해당 포커스 표시기는 컨트롤의 경계 사각형을 요약하는 사각형일 뿐입니다. 시각적 포커스의 사각형 은 컨트롤 템플릿에서 컨트롤의 나머지 컴포지션에 대한 피어 요소이지만 아직 컨트롤이 없기 때문에 처음에는 표시 유형 값의 Collapsed 로 설정됩니다. 컨트롤에 포커스가 있으면 포커스 시각적 개체의 표시 유형을 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>

지금까지는 단지 컴포지션이었습니다. 포커스 표시기의 표시 유형을 제어하려면, 표시 유형 속성을 토글하는 시각적 상태를 정의합니다. 이 작업은 컴퍼지션을 정의하는 루트 요소에 적용되는 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의 다른 상태를 사용하는 즉시 이전 상태에서 적용된 모든 애니메이션이 즉시 취소됩니다. 컴퍼지션의 기본 표시 유형이 Collapsed이므로 사각형이 나타나지 않습니다. 컨트롤 논리는 GotFocus 같은 포커스 이벤트를 수신 대기하고 GoToState를 사용하여 상태를 변경하여 제어합니다. 기본 컨트롤을 사용하거나 해당 동작이 이미 있는 컨트롤을 기반으로 사용자 지정하는 경우 이미 처리되어 있는 경우가 많습니다.

하드웨어 키보드가 없는 키보드 접근성 및 디바이스

일부 디바이스에는 전용 하드웨어 키보드가 없으며 대신 SIP(소프트 입력 패널)를 사용합니다. 화면 읽기 프로그램은 텍스트 SIP에서 텍스트 입력을 읽을 수 있으며, 화면 읽기 프로그램은 사용자가 키를 스캔하고 있음을 감지하고 스캔한 키 이름을 소리 내어 읽을 수 있기 때문에 사용자가 손가락이 어디에 있는지 검색할 수 있습니다. 또한 키보드 지향 접근성 개념 중 일부는 키보드를 전혀 사용하지 않는 관련 보조 기술 동작에 매핑할 수 있습니다. 예를 들어 SIP에 Tab 키가 포함되지 않더라도 내레이터는 Tab 키를 누르는 것과 동일한 터치 제스처를 지원하므로 UI의 컨트롤을 통해 유용한 탭 순서를 갖는 것은 접근성을 위해 여전히 중요합니다. 내레이터는 복잡한 컨트롤 내에서 탐색하기 위한 화살표 키를 비롯한 다른 많은 터치 제스처도 지원합니다(내레이터 키보드 명령 및 터치 제스처 참조).

예제

WinUI 3 갤러리 앱에는 대부분의 WinUI 3 컨트롤, 특징, 기능의 대화형 예제가 포함되어 있습니다. 앱을 Microsoft Store 에서 다운로드하거나 GitHub에서 소스 코드를 가져오세요.