diff --git a/dev/CommandBarFlyout/CommandBarFlyoutCommandBar.cpp b/dev/CommandBarFlyout/CommandBarFlyoutCommandBar.cpp index 8d60bdd9b3..7d009c0fc9 100644 --- a/dev/CommandBarFlyout/CommandBarFlyoutCommandBar.cpp +++ b/dev/CommandBarFlyout/CommandBarFlyoutCommandBar.cpp @@ -245,9 +245,42 @@ void CommandBarFlyoutCommandBar::AttachEventHandlers() } } } - loopCount++; // Looping again is needed when the last command has focus + + if (loopCount == 0 && PrimaryCommands().Size() > 0) + { + auto moreButton = m_moreButton.get(); + + if (deltaIndex == 1 && + FocusCommand( + PrimaryCommands() /*commands*/, + moreButton /*moreButton*/, + winrt::FocusState::Keyboard /*focusState*/, + true /*firstCommand*/, + true /*ensureTabStopUniqueness*/)) + { + // Being on the last secondary command, keyboard focus was given to the first primary command + args.Handled(true); + return; + } + else if (deltaIndex == -1 && + focusedControl && + moreButton && + IsControlFocusable(moreButton, false /*checkTabStop*/) && + FocusControl( + moreButton /*newFocus*/, + focusedControl /*oldFocus*/, + winrt::FocusState::Keyboard /*focusState*/, + true /*updateTabStop*/)) + { + // Being on the first secondary command, keyboard focus was given to the MoreButton + args.Handled(true); + return; + } + } + + loopCount++; // Looping again when focus could not be given to a MoreButton going up or primary command going down. } - while (loopCount < 2 && focusedControl && deltaIndex == 1); + while (loopCount < 2 && focusedControl); } args.Handled(true); break; @@ -774,11 +807,12 @@ void CommandBarFlyoutCommandBar::OnKeyDown( bool isRightToLeft = m_primaryItemsRoot && m_primaryItemsRoot.get().FlowDirection() == winrt::FlowDirection::RightToLeft; bool isLeft = (args.Key() == winrt::VirtualKey::Left && !isRightToLeft) || (args.Key() == winrt::VirtualKey::Right && isRightToLeft); bool isRight = (args.Key() == winrt::VirtualKey::Right && !isRightToLeft) || (args.Key() == winrt::VirtualKey::Left && isRightToLeft); - bool isUp = (args.Key() == winrt::VirtualKey::Up && !isRightToLeft) || (args.Key() == winrt::VirtualKey::Down && isRightToLeft); + bool isDown = args.Key() == winrt::VirtualKey::Down; + bool isUp = args.Key() == winrt::VirtualKey::Up; auto moreButton = m_moreButton.get(); - if (args.Key() == winrt::VirtualKey::Down && + if (isDown && moreButton && moreButton.FocusState() != winrt::FocusState::Unfocused && SecondaryCommands().Size() > 0) @@ -847,7 +881,7 @@ void CommandBarFlyoutCommandBar::OnKeyDown( if (!args.Handled()) { - if (isRight && + if ((isRight || isDown) && focusedControl && moreButton && IsControlFocusable(moreButton, false /*checkTabStop*/)) diff --git a/dev/CommandBarFlyout/InteractionTests/CommandBarFlyoutTests.cs b/dev/CommandBarFlyout/InteractionTests/CommandBarFlyoutTests.cs index f3c2ff9e36..fcb2ebc3cd 100644 --- a/dev/CommandBarFlyout/InteractionTests/CommandBarFlyoutTests.cs +++ b/dev/CommandBarFlyout/InteractionTests/CommandBarFlyoutTests.cs @@ -234,11 +234,13 @@ public void VerifyTabNavigationBetweenPrimaryAndSecondaryCommands() [TestMethod] public void VerifyLeftAndRightNavigationBetweenPrimaryCommands() { - VerifyLeftAndRightNavigationBetweenPrimaryCommands(false /*inRTL*/); - VerifyLeftAndRightNavigationBetweenPrimaryCommands(true /*inRTL*/); + VerifyLeftAndRightNavigationBetweenPrimaryCommands(inRTL: false, useUpDownKeys: false); + VerifyLeftAndRightNavigationBetweenPrimaryCommands(inRTL: true, useUpDownKeys: false); + VerifyLeftAndRightNavigationBetweenPrimaryCommands(inRTL: false, useUpDownKeys: true); + VerifyLeftAndRightNavigationBetweenPrimaryCommands(inRTL: true, useUpDownKeys: true); } - private void VerifyLeftAndRightNavigationBetweenPrimaryCommands(bool inRTL) + private void VerifyLeftAndRightNavigationBetweenPrimaryCommands(bool inRTL, bool useUpDownKeys) { if (PlatformConfiguration.IsOSVersionLessThan(OSVersion.Redstone2)) { @@ -259,15 +261,32 @@ private void VerifyLeftAndRightNavigationBetweenPrimaryCommands(bool inRTL) Wait.ForIdle(); } - string rightStr = inRTL ? "Left" : "Right"; - string leftStr = inRTL ? "Right" : "Left"; - Key rightKey = inRTL ? Key.Left : Key.Right; - Key leftKey = inRTL ? Key.Right : Key.Left; + string rightStr; + string leftStr; + Key rightKey; + Key leftKey; + + if (useUpDownKeys) + { + // Down and Up keys are used to move logically within the primary commands: Up to move to the previous command and Down to move to the next command. + rightStr = "Down"; + leftStr = "Up"; + rightKey = Key.Down; + leftKey = Key.Up; + } + else + { + // Left and Right keys are used to move physically within the primary commands: Left to move to the left command and Right to move to the right command. + rightStr = inRTL ? "Left" : "Right"; + leftStr = inRTL ? "Right" : "Left"; + rightKey = inRTL ? Key.Left : Key.Right; + leftKey = inRTL ? Key.Right : Key.Left; + } Log.Comment("Tap on a button to show the CommandBarFlyout."); InputHelper.Tap(showCommandBarFlyoutButton); - Log.Comment("Press " + rightStr + " key to move focus to second primary command: Copy."); + Log.Comment($"Press {rightStr} key to move focus to second primary command: Copy."); KeyboardHelper.PressKey(rightKey); Wait.ForIdle(); @@ -275,7 +294,7 @@ private void VerifyLeftAndRightNavigationBetweenPrimaryCommands(bool inRTL) var copyButtonElement = AutomationElement.FocusedElement; Verify.AreEqual(copyButtonElement.Current.AutomationId, copyButton1.AutomationId); - Log.Comment("Press " + leftStr + " key to move focus back to first primary command: Cut."); + Log.Comment($"Press {leftStr} key to move focus back to first primary command: Cut."); KeyboardHelper.PressKey(leftKey); Wait.ForIdle(); @@ -283,15 +302,18 @@ private void VerifyLeftAndRightNavigationBetweenPrimaryCommands(bool inRTL) var cutButtonElement = AutomationElement.FocusedElement; Verify.AreEqual(cutButtonElement.Current.AutomationId, cutButton1.AutomationId); - Log.Comment("Press " + leftStr + " key and remain on first primary command: Cut."); - KeyboardHelper.PressKey(leftKey); - Wait.ForIdle(); + if (!useUpDownKeys) + { + Log.Comment($"Press {leftStr} key and remain on first primary command: Cut."); + KeyboardHelper.PressKey(leftKey); + Wait.ForIdle(); - cutButtonElement = AutomationElement.FocusedElement; - Verify.AreEqual(cutButtonElement.Current.AutomationId, cutButton1.AutomationId); + cutButtonElement = AutomationElement.FocusedElement; + Verify.AreEqual(cutButtonElement.Current.AutomationId, cutButton1.AutomationId); + } - Log.Comment("Press " + rightStr + " key to move focus to MoreButton."); - for (int i = 0; i <= 6; i++) + Log.Comment($"Press {rightStr} key to move focus to MoreButton."); + for (int i = 0; i <= 5; i++) { KeyboardHelper.PressKey(rightKey); Wait.ForIdle(); @@ -301,12 +323,15 @@ private void VerifyLeftAndRightNavigationBetweenPrimaryCommands(bool inRTL) var moreButtonElement = AutomationElement.FocusedElement; Verify.AreEqual(moreButtonElement.Current.AutomationId, moreButton.AutomationId); - Log.Comment("Press " + rightStr + " key and remain on MoreButton."); - KeyboardHelper.PressKey(rightKey); - Wait.ForIdle(); + if (!useUpDownKeys) + { + Log.Comment($"Press {rightStr} key and remain on MoreButton."); + KeyboardHelper.PressKey(rightKey); + Wait.ForIdle(); - moreButtonElement = AutomationElement.FocusedElement; - Verify.AreEqual(moreButtonElement.Current.AutomationId, moreButton.AutomationId); + moreButtonElement = AutomationElement.FocusedElement; + Verify.AreEqual(moreButtonElement.Current.AutomationId, moreButton.AutomationId); + } } } @@ -353,15 +378,16 @@ public void VerifyUpAndDownNavigationBetweenPrimaryAndSecondaryCommands() var underlineButtonElement = AutomationElement.FocusedElement; Verify.AreEqual(underlineButtonElement.Current.AutomationId, underlineButton1.AutomationId); - Log.Comment("Press Down key and remain on last primary command: Underline."); + Log.Comment("Press Down key to move focus to MoreButton."); KeyboardHelper.PressKey(Key.Down); Wait.ForIdle(); - underlineButtonElement = AutomationElement.FocusedElement; - Verify.AreEqual(underlineButtonElement.Current.AutomationId, underlineButton1.AutomationId); + Button moreButton = FindElement.ById