in src/Avalonia.Base/Input/FocusManager.cs [714:832]
private IInputElement? GetPreviousTabStop(IInputElement? currentTabStop = null, bool ignoreCurrentTabStop = false)
{
var focused = currentTabStop ?? Current;
if (focused == null || _contentRoot == null)
{
return null;
}
IInputElement? newTabStop = (focused as InputElement)?.GetPreviousTabStopOverride();
IInputElement? currentCompare = focused;
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)
{
newTabStop = GetFirstFocusableElement(current, current);
break;
}
if (IsValidTabStopSearchCandidate(parent) && parent is InputElement p && KeyboardNavigation.GetTabNavigation(p) == KeyboardNavigationMode.Once)
{
if (FocusHelpers.IsFocusable(parent))
{
newTabStop = parent;
}
else
{
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, false, ref currentPassed, ref currentCompare);
if (newTabStop != null && !FocusHelpers.IsFocusable(newTabStop))
{
newTabStop = GetLastFocusableElement(newTabStop, null);
}
if (newTabStop == null)
{
newTabStop = GetLastFocusableElement(parent, null);
}
break;
}
parent = (_contentRoot as Visual)?.VisualRoot as IInputElement;
}
else if (parentElement is InputElement pIE && KeyboardNavigation.GetTabNavigation(pIE) == KeyboardNavigationMode.None)
{
if (FocusHelpers.IsFocusable(parent))
{
newTabStop = parent;
}
else
{
current = parent;
parent = FocusHelpers.GetFocusParent(focused);
if (parent == null)
break;
}
}
else
{
parent = parentElement as IInputElement;
}
}
newTabStop = GetNextOrPreviousTabStopInternal(parent, current, newTabStop, false, ref currentPassed, ref currentCompare);
if (newTabStop == null && FocusHelpers.IsPotentialTabStop(parent) && FocusHelpers.IsFocusable(parent))
{
if (parent is InputElement iE && KeyboardNavigation.GetTabNavigation(iE) == KeyboardNavigationMode.Cycle)
{
newTabStop = GetLastFocusableElement(parent, null);
}
else
{
newTabStop = parent;
}
}
else
{
if (newTabStop != null && FocusHelpers.CanHaveFocusableChildren(newTabStop as AvaloniaObject))
{
newTabStop = GetLastFocusableElement(newTabStop, null);
}
}
if (newTabStop != null)
break;
if (IsValidTabStopSearchCandidate(parent))
{
current = parent;
}
parent = FocusHelpers.GetFocusParent(parent);
currentPassed = false;
}
}
return newTabStop;
}