キーボード、ゲームパッド、リモコン、アクセシビリティ ツールのフォーカス ナビゲーション
フォーカス ナビゲーションを使用すると、キーボードを使い慣れているパワー ユーザーや障碍およびその他のアクセシビリティ要件を持っているユーザーは、総合的で一貫性のあるエクスペリエンスを Windows アプリやカスタム コントロールで利用できるようになります。また、テレビ画面と Xbox One の 10 フィート エクスペリエンスも利用することができます。
概要
フォーカス ナビゲーションとは、キーボード、ゲームパッド、リモコンを使用して、ユーザーが Windows アプリケーションの UI 間を移動したり、これらの UI を操作したりできるようにする基本的なメカニズムです。
Note
通常、入力デバイスは、タッチ、タッチパッド、ペン、マウスなどのポインティング デバイスとして分類され、キーボード、ゲームパッド、リモート コントロールなどの非ポインティング デバイスとして分類されます。
このトピックでは、Windows アプリケーションを最適化し、非ポインティングの入力タイプを必要としているユーザー向けにカスタム操作エクスペリエンスを構築する方法について説明します。
PC 上の Windows アプリのカスタム コントロールではキーボード入力に焦点を当てていますが、タッチ キーボードやスクリーン キーボード (OSK) などのソフトウェア キーボード、Windows ナレーターなどのアクセシビリティ ツールのサポート、および 10 フィート エクスペリエンスのサポートのために、適切に設計されたキーボード エクスペリエンスも重要となります。
ポインティング デバイスのために Windows アプリケーションでカスタム エクスペリエンスを構築する方法のガイダンスについては、「ポインター入力の処理」をご覧ください。
キーボード用のアプリとエクスペリエンスの構築に関する一般的な情報については、「 Keyboard Interaction」を参照してください。
一般的なガイダンス
ユーザーの操作を必要とする UI 要素のみがフォーカス ナビゲーションをサポートする必要があります。静的イメージなどのアクションを必要としない要素にはキーボード フォーカスは必要ありません。 スクリーン リーダーと同様のアクセシビリティ ツールでは、フォーカス ナビゲーションに含まれていない場合でも、これらの静的要素が読み上げられます。
マウスやタッチなどのポインター デバイスを使用して移動する場合とは異なり、フォーカス ナビゲーションは線形であることを覚えておく必要があります。 フォーカス ナビゲーションを実装する場合は、ユーザーがアプリケーションと対話する方法と、論理ナビゲーションの内容を検討します。 ほとんどの場合、カスタム フォーカス ナビゲーション動作は、ユーザーのカルチャの推奨される読み取りパターンに従うことをお勧めします。
フォーカス ナビゲーションに関するその他の考慮事項を次に示します。
- コントロールは論理的にグループ化されていますか?
- 重要度が高いコントロールのグループはありますか?
- "はい" の場合、それらのグループにはサブグループが含まれますか?
- レイアウトには、ユーザー設定の方向ナビゲーション (方向キー) とタブ オーダーが必要ですか?
アクセシビリティのための ソフトウェア 電子ブックには、論理階層の設計 に関する優れた章があります。
キーボード用の 2D 方向ナビゲーション
コントロールまたはコントロール グループの 2D 内部ナビゲーション領域は、その "方向領域" と呼ばれます。 フォーカスがこのオブジェクトに移動すると、キーボードの方向キー (左、右、上、下) を使用して、方向領域内の子要素間を移動できます。
コントロール グループの 2D 内部ナビゲーション領域または方向領域
XYFocusKeyboardNavigation プロパティ (使用可能な値は Auto、Enabled、または Disabled) を使用して、キーボードの方向キーを使用して 2D 内部ナビゲーションを管理できます。
Note
タブ オーダーは、このプロパティの影響を受けません。 混乱を招くナビゲーション エクスペリエンスを回避するために、方向領域の子要素 アプリケーションのタブ ナビゲーション順序で明示的に指定 しないことをお勧めします。 要素のタブ移動動作の詳細については、 UIElement.TabFocusNavigation および TabIndex プロパティを参照してください。
自動 (既定の動作)
Auto に設定すると、方向ナビゲーション動作は要素の先祖または継承階層によって決まります。 すべての先祖が既定のモード (Auto に設定) の場合、キーボードを使用した方向ナビゲーションはサポート。
Disabled
コントロールとその子要素への方向ナビゲーションをブロックするには XYFocusKeyboardNavigation を Disabled に設定します。
XYFocusKeyboardNavigation の無効な動作
この例では、プライマリ StackPanel (ContainerPrimary) は XYFocusKeyboardNavigation Enabled に設定されています。 すべての子要素はこの設定を継承し、方向キーを使用して移動できます。 ただし、B3 要素と B4 要素はセカンダリ StackPanel (ContainerSecondary) にあり、 XYFocusKeyboardNavigation Disabled に設定されています。これにより、プライマリ コンテナーがオーバーライドされ、それ自体とその子要素間の方向キー ナビゲーションが無効になります。
<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>
Enabled
XYFocusKeyboardNavigation を Enabled に設定すると、コントロールとその各UIElement子オブジェクトへの 2D 方向ナビゲーションがサポートされます。
設定すると、方向キーを使用したナビゲーションは方向領域内の要素に制限されます。 タブ ナビゲーションは影響を受けず、すべてのコントロールはタブ オーダー階層からアクセスできます。
XYFocusKeyboardNavigation が有効な動作
この例では、プライマリ StackPanel (ContainerPrimary) は XYFocusKeyboardNavigation Enabled に設定されています。 すべての子要素はこの設定を継承し、方向キーを使用して移動できます。 B3 要素と B4 要素はセカンダリ StackPanel (ContainerSecondary) にあり、 XYFocusKeyboardNavigation は設定されず、プライマリ コンテナー設定が継承されます。 B5 要素は、宣言された方向領域内にはなく、方向キー ナビゲーションをサポートしていませんが、標準のタブ ナビゲーション動作をサポートします。
<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>
複数のレベルの入れ子になった方向領域を持つことができます。 すべての親要素で XYFocusKeyboardNavigation が [有効] に設定されている場合、内部ナビゲーション領域の境界は無視されます。
2D 方向ナビゲーションを明示的にサポートしていない要素内の 2 つの入れ子になった方向領域の例を次に示します。 この場合、入れ子になった 2 つの領域間の方向ナビゲーションはサポートされません。
XYFocusKeyboardNavigation が有効で、入れ子になった動作
3 つの入れ子になった方向領域のより複雑な例を次に示します。
- B1 にフォーカスがある場合は、方向領域の境界が XYFocusKeyboardNavigation が [無効] に設定され、方向キーを使用して B2、B3、B4 に到達できなくなるため、B5 にのみ移動できます (その逆も同様です)。
- B2 にフォーカスがある場合、方向領域の境界によって B1、B4、B5 への方向キーナビゲーションが妨げられるため、B3 にのみ移動できます (その逆も可能)。
- B4 にフォーカスがある場合は、Tab キーを使用してコントロール間を移動する必要があります
XYFocusKeyboardNavigation が有効で、複雑な入れ子になった動作
タブのナビゲーション
方向キーはコントロールやコントロール グループ内の 2D 方向ナビゲーションで使用できますが、Tab キーを使用すると、Windows アプリケーションのすべてのコントロール間を移動することができます。
すべての対話型コントロールは、既定で Tab キー ナビゲーション (IsEnabled および IsTabStop プロパティが true) をサポートし、アプリケーションのコントロール レイアウトから派生した論理タブ オーダーを使用します。 ただし、既定の順序は必ずしも視覚的な順序に対応するとは限りません。 実際の表示位置は、親レイアウト コンテナーと、レイアウトに影響を与えるために子要素に設定できる特定のプロパティによって異なります。
フォーカスがアプリケーション内を飛び回るようなカスタム タブ オーダーは避けます。 たとえば、フォーム内のコントロールのリストのタブ オーダーは、上から下、左から右に流れるようにする必要があります (ロケールによります)。
このセクションでは、アプリに合わせてこのタブ オーダーを完全にカスタマイズする方法について説明します。
タブ ナビゲーションの動作を設定する
UIElement の TabFocusNavigation プロパティは、オブジェクト ツリー全体 (または方向領域) のタブ ナビゲーション動作を指定します。
Note
ControlTemplate を使用しないオブジェクトの外観を定義するには、Control.TabNavigation プロパティの代わりにこのプロパティを使用します。
前のセクションで説明したように、混乱を招くナビゲーション エクスペリエンスを回避するために、方向領域の子要素 アプリケーションのタブ ナビゲーション順序で明示的に指定 しないことをお勧めします。 要素のタブ移動動作の詳細については、 UIElement.TabFocusNavigation プロパティと TabIndex プロパティを参照してください。
Windows 10 Creators Update (ビルド 10.0.15063) より前のバージョンでは、タブ設定は ControlTemplate オブジェクトに制限されていました。 詳細については、「 Control.TabNavigationを参照してください。
TabFocusNavigation には、次の値 KeyboardNavigationMode の値があります (これらの例はカスタム コントロール グループではなく、方向キーを使用した内部ナビゲーションは必要ありません)。
Local (既定値) タブ インデックスは、コンテナー内のローカル サブツリーで認識されます。 この例では、タブ オーダーは B1、B2、B3、B4、B5、B6、B7、B1 です。
[ローカル] タブのナビゲーション動作
Once コンテナーとすべての子要素は、フォーカスを 1 回だけ受け取ります。 この例では、タブ オーダーは B1、B2、B7、B1 です (方向キーを使用した内部ナビゲーションも示されています)。
"1 回" タブのナビゲーション動作
サイクル
フォーカスは、コンテナー内の最初のフォーカス可能な要素に戻ります。 この例では、タブ オーダーは B1、B2、B3、B4、B5、B6、B2 です。[Cycle] タブのナビゲーション動作
前の例のコードを次に示します (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
TabIndexを使用して、ユーザーが Tab キーを使用してコントロール内を移動するときに要素がフォーカスを受け取る順序を指定します。 タブ インデックスが小さいコントロールは、インデックスが高いコントロールの前にフォーカスを受け取ります。
コントロールに TabIndex が指定されていない場合、スコープに基づいて、ビジュアル ツリー内のすべての対話型コントロールの現在の最も高いインデックス値 (および最も低い優先度) よりも高いインデックス値が割り当てられます。
コントロールのすべての子要素はスコープと見なされ、これらの要素の 1 つに子要素も含まれる場合は、別のスコープと見なされます。 あいまいさは、スコープのビジュアル ツリーの最初の要素を選択することで解決されます。
タブ オーダーからコントロールを除外するには、 IsTabStop プロパティを false に設定します。
TabIndex プロパティを設定して、既定のタブ オーダーをオーバーライドします。
Note
TabIndex は、 UIElement.TabFocusNavigation と Control.TabNavigation の両方で同じように動作します。
ここでは、特定の要素の TabIndex プロパティによってフォーカス ナビゲーションがどのように影響を受けるかを示します。
TabIndex 動作を使用した "ローカル" タブ ナビゲーション
前の例では、次の 2 つのスコープがあります。
- B1、方向領域 (B2 ~ B6)、B7
- 方向領域 (B2 ~ B6)
B3 (方向領域) がフォーカスを取得すると、スコープが変更され、タブ ナビゲーションは、後続のフォーカスに最適な候補が識別される方向領域に転送されます。 この場合、B2 の後に B4、B5、B6 が続きます。 スコープが再度変更され、フォーカスが B1 に移動します。
この例のコードを次に示します。
<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>
キーボード、ゲームパッド、およびリモート コントロール用の 2D 方向ナビゲーション
非ポインターの入力タイプ (キーボード、ゲームパッド、リモコン、および Windows ナレーターなどのアクセシビリティ ツール) では、Windows アプリケーションの UI 間を移動したり、これらの UI を操作したりするための、一般的で基本的なメカニズムを共有します。
このセクションでは、優先ナビゲーション戦略を指定し、すべてのフォーカス ベースの非ポインター入力の種類をサポートする一連のナビゲーション戦略プロパティを使用して、アプリケーション内のフォーカス ナビゲーションを微調整する方法について説明します。
Xbox/テレビ用にアプリとエクスペリエンスを構築する方法の一般的な情報については、「キーボード操作」、「Xbox およびテレビ向け設計」、「ゲームパッドとリモコンの操作」を参照してください。
ナビゲーション戦略
ナビゲーション戦略は、キーボード、ゲームパッド、リモート コントロール、およびさまざまなアクセシビリティ ツールに適用できます。
次のナビゲーション戦略プロパティを使用すると、方向キー、方向パッド (D パッド) ボタン、または同様の押下に基づいてフォーカスを受け取るコントロールに影響を与えます。
- XYFocusUpNavigationStrategy
- XYFocusDownNavigationStrategy
- XYFocusLeftNavigationStrategy
- XYFocusRightNavigationStrategy
これらのプロパティには、 Auto (既定値)、 NavigationDirectionDistance、 Projection、または RectilinearDistance の値があります。
Auto に設定すると、要素の動作は要素の先祖に基づいています。 すべての要素が Auto に設定されている場合は、 Projection が使用されます。
Note
以前にフォーカスされた要素やナビゲーション方向の軸への近接性など、その他の要因が結果に影響を与える可能性があります。
Projection
プロジェクション戦略は、現在フォーカスされている要素の端がナビゲーションの方向に 投影 したときに発生した最初の要素にフォーカスを移動します。
この例では、各フォーカス ナビゲーションの方向が [プロジェクション] に設定されています。 フォーカスが B1 から B4 に下がり、B3 をバイパスしていることに注目してください。 これは、B3 が投影ゾーンにないためです。 また、B1 から左に移動するときにフォーカス候補がどのように識別されないかにも注目してください。 これは、B1 に対する B2 の位置が候補として B3 を排除するためです。 B3 が B2 と同じ行にある場合は、左側のナビゲーションの候補になります。 B2 は、ナビゲーション方向の軸に対する遮るものがないため、実行可能な候補です。
プロジェクション ナビゲーション戦略
NavigationDirectionDistance
NavigationDirectionDistance 戦略は、ナビゲーション方向の軸に最も近い要素にフォーカスを移動します。
ナビゲーション方向に対応する境界 rect のエッジは候補ターゲットを識別するために投影されます。 最初に検出された要素がターゲットとして識別されます。 複数の候補がある場合、最も近い要素がターゲットとして識別されます。 複数の候補が存在する場合は、最上位/左端の要素が候補として識別されます。
NavigationDirectionDistance ナビゲーション戦略
RectilinearDistance
RectilinearDistance 戦略は、2D の直線距離 (Taxicab geometry) に基づいて最も近い要素にフォーカスを移動します。
各候補に対する一次距離と二次距離の合計は、最適な候補を識別するために使用されます。 タイでは、要求された方向が上下の場合は左の最初の要素が選択され、要求された方向が左または右の場合は先頭の要素が選択されます。
RectilinearDistance ナビゲーション戦略
この図は、B1 がフォーカスを持ち、下が要求された方向である場合、B3 が RectilinearDistance フォーカス候補である方法を示しています。 これは、この例の次の計算に基づいています。
- 距離 (B1、B3、下) は 10 + 0 = 10
- 距離 (B1、B2、Down) は 0 + 40 = 30 です
- 距離 (B1、D、Down) は 30 + 0 = 30 です
関連記事
Windows developer