in src/Avalonia.Base/Input/FocusManager.cs [606:712]
private IInputElement? GetNextTabStop(IInputElement? currentTabStop = null, bool ignoreCurrentTabStop = false)
{
var focused = currentTabStop ?? Current;
if (focused == null || _contentRoot == null)
{
return null;
}
IInputElement? currentCompare = focused;
IInputElement? newTabStop = (focused as InputElement)?.GetNextTabStopOverride();
if (newTabStop == null && !ignoreCurrentTabStop
&& (FocusHelpers.IsVisible(focused) && (FocusHelpers.CanHaveFocusableChildren(focused as AvaloniaObject) || FocusHelpers.CanHaveChildren(focused))))
{
newTabStop = GetFirstFocusableElement(focused, newTabStop);
}
if (newTabStop == null)
{
var currentPassed = false;
var current = focused;
var parent = FocusHelpers.GetFocusParent(focused);
var parentIsRootVisual = parent == (_contentRoot as Visual)?.VisualRoot;
while (parent != null && !parentIsRootVisual && newTabStop == null)
{
if (IsValidTabStopSearchCandidate(current) && current is InputElement c && KeyboardNavigation.GetTabNavigation(c) == KeyboardNavigationMode.Cycle)
{
if (current == GetParentTabStopElement(focused))
{
newTabStop = GetFirstFocusableElement(focused, null);
}
else
{
newTabStop = GetFirstFocusableElement(current, current);
}
break;
}
if (IsValidTabStopSearchCandidate(parent) && parent is InputElement p && KeyboardNavigation.GetTabNavigation(p) == KeyboardNavigationMode.Once)
{
current = parent;
parent = FocusHelpers.GetFocusParent(focused);
if (parent == null)
break;
}
else if (!IsValidTabStopSearchCandidate(parent))
{
var parentElement = GetParentTabStopElement(parent);
if (parentElement == null)
{
parent = GetRootOfPopupSubTree(current) as IInputElement;
if (parent != null)
{
newTabStop = GetNextOrPreviousTabStopInternal(parent, current, newTabStop, true, ref currentPassed, ref currentCompare);
if (newTabStop != null && !FocusHelpers.IsFocusable(newTabStop))
{
newTabStop = GetFirstFocusableElement(newTabStop, null);
}
if (newTabStop == null)
{
newTabStop = GetFirstFocusableElement(parent, null);
}
break;
}
parent = (_contentRoot as Visual)?.VisualRoot as IInputElement;
}
else if (parentElement is InputElement pIE && KeyboardNavigation.GetTabNavigation(pIE) == KeyboardNavigationMode.None)
{
current = pIE;
parent = FocusHelpers.GetFocusParent(current);
if (parent == null)
break;
}
else
{
parent = parentElement as IInputElement;
}
}
newTabStop = GetNextOrPreviousTabStopInternal(parent, current, newTabStop, true, ref currentPassed, ref currentCompare);
if (newTabStop != null && !FocusHelpers.IsFocusable(newTabStop) && FocusHelpers.CanHaveFocusableChildren(newTabStop as AvaloniaObject))
{
newTabStop = GetFirstFocusableElement(newTabStop, null);
}
if (newTabStop != null)
break;
if (IsValidTabStopSearchCandidate(parent))
{
current = parent;
}
parent = FocusHelpers.GetFocusParent(parent);
currentPassed = false;
parentIsRootVisual = parent == (_contentRoot as Visual)?.VisualRoot;
}
}
return newTabStop;
}