in dev/CommandBarFlyout/CommandBarFlyoutCommandBar.cpp [928:1066]
void CommandBarFlyoutCommandBar::OnKeyDown(
winrt::KeyRoutedEventArgs const& args)
{
COMMANDBARFLYOUT_TRACE_INFO(*this, TRACE_MSG_METH_STR, METH_NAME, this,
TypeLogging::KeyRoutedEventArgsToString(args).c_str());
if (args.Handled())
{
return;
}
switch (args.Key())
{
case winrt::VirtualKey::Tab:
{
if (SecondaryCommands().Size() > 0 && !IsOpen())
{
// Ensure the secondary commands flyout is open ...
IsOpen(true);
// ... and focus the first focusable command
FocusCommand(
SecondaryCommands() /*commands*/,
nullptr /*moreButton*/,
winrt::FocusState::Keyboard /*focusState*/,
true /*firstCommand*/,
SharedHelpers::IsRS3OrHigher() /*ensureTabStopUniqueness*/);
}
break;
}
case winrt::VirtualKey::Escape:
{
if (auto owningFlyout = m_owningFlyout.get())
{
owningFlyout.Hide();
args.Handled(true);
}
break;
}
case winrt::VirtualKey::Right:
case winrt::VirtualKey::Left:
case winrt::VirtualKey::Down:
case winrt::VirtualKey::Up:
{
const bool isRightToLeft = m_primaryItemsRoot && m_primaryItemsRoot.get().FlowDirection() == winrt::FlowDirection::RightToLeft;
const bool isLeft = (args.Key() == winrt::VirtualKey::Left && !isRightToLeft) || (args.Key() == winrt::VirtualKey::Right && isRightToLeft);
const bool isRight = (args.Key() == winrt::VirtualKey::Right && !isRightToLeft) || (args.Key() == winrt::VirtualKey::Left && isRightToLeft);
const bool isDown = args.Key() == winrt::VirtualKey::Down;
const bool isUp = args.Key() == winrt::VirtualKey::Up;
// To avoid code duplication, we'll use the key directionality to determine
// both which control list to use and in which direction to iterate through
// it to find the next control to focus. Then we'll do that iteration
// to focus the next control.
auto const& accessibleControls{ isUp || isDown ? m_verticallyAccessibleControls : m_horizontallyAccessibleControls };
int const startIndex = isLeft || isUp ? accessibleControls.Size() - 1 : 0;
int const endIndex = isLeft || isUp ? -1 : accessibleControls.Size();
int const deltaIndex = isLeft || isUp ? -1 : 1;
bool const shouldLoop = isUp || isDown;
winrt::Control focusedControl{ nullptr };
int focusedControlIndex = -1;
for (int i = startIndex;
// We'll stop looping at the end index unless we're looping,
// in which case we want to wrap back around to the start index.
(i != endIndex || shouldLoop) ||
// If we found a focused control but have looped all the way back around,
// then there wasn't another control to focus, so we should quit.
(focusedControlIndex > 0 && i == focusedControlIndex);
i += deltaIndex)
{
// If we've reached the end index, that means we want to loop.
// We'll wrap around to the start index.
if (i == endIndex)
{
MUX_ASSERT(shouldLoop);
if (focusedControl)
{
i = startIndex;
}
else
{
// If no focused control was found after going through the entire list of controls,
// then we have nowhere for focus to go. Let's early-out in that case.
break;
}
}
auto const& control = accessibleControls.GetAt(i);
// If we've yet to find the focused control, we'll keep looking for it.
// Otherwise, we'll try to focus the next control after it.
if (!focusedControl)
{
if (control.FocusState() != winrt::FocusState::Unfocused)
{
focusedControl = control;
focusedControlIndex = i;
}
}
else if (IsControlFocusable(control, false /*checkTabStop*/))
{
// If the control we're trying to focus is in the secondary command list,
// then we'll make sure that that list is open before trying to focus the control.
if (auto const& controlAsCommandBarElement = control.try_as<winrt::ICommandBarElement>())
{
uint32_t index = 0;
if (SecondaryCommands().IndexOf(controlAsCommandBarElement, index) && !IsOpen())
{
IsOpen(true);
}
}
if (FocusControl(
accessibleControls.GetAt(i) /*newFocus*/,
focusedControl /*oldFocus*/,
winrt::FocusState::Keyboard /*focusState*/,
true /*updateTabStop*/))
{
args.Handled(true);
break;
}
}
}
if (!args.Handled())
{
// Occurs for example with Right key while MoreButton has focus. Stay on that MoreButton.
args.Handled(true);
}
break;
}
}
__super::OnKeyDown(args);
}