diff --git a/src/Avalonia.Base/Input/FocusManager.cs b/src/Avalonia.Base/Input/FocusManager.cs index 72a13d385d..5b046ab682 100644 --- a/src/Avalonia.Base/Input/FocusManager.cs +++ b/src/Avalonia.Base/Input/FocusManager.cs @@ -142,6 +142,9 @@ namespace Avalonia.Input [PrivateApi] public void SetFocusScope(IFocusScope scope) { + if (KeyboardDevice.Instance is not { } keyboardDevice) + return; + if (GetFocusedElement(scope) is { } focused) { Focus(focused); @@ -153,6 +156,13 @@ namespace Avalonia.Input // focus etc. Focus(scopeElement); } + else + { + // If the scope isn't focusable, make sure we still set it as the current focus root, + // otherwise it will be completely ignored + _focusRoot = scope as StyledElement; + keyboardDevice.SetFocusedElement(null, NavigationMethod.Unspecified, KeyModifiers.None, false); + } } [PrivateApi] diff --git a/tests/Avalonia.Base.UnitTests/Input/InputElement_Focus.cs b/tests/Avalonia.Base.UnitTests/Input/InputElement_Focus.cs index 9e835b2427..580c80e79f 100644 --- a/tests/Avalonia.Base.UnitTests/Input/InputElement_Focus.cs +++ b/tests/Avalonia.Base.UnitTests/Input/InputElement_Focus.cs @@ -703,6 +703,41 @@ namespace Avalonia.Base.UnitTests.Input Assert.Same(innerButton, focusManager.GetFocusedElement()); } + // https://github.com/AvaloniaUI/Avalonia/issues/13134 + [Fact] + public void SetFocusScope_On_Non_Focusable_Scope_Changes_Scope() + { + using var app = UnitTestApplication.Start(TestServices.RealFocus); + + Button outerButton; + TestFocusScope innerScope; + var root = new TestRoot + { + Child = new StackPanel + { + Focusable = false, + Children = + { + (innerScope = new TestFocusScope()), + (outerButton = new Button()) + } + } + }; + + outerButton.Focus(); + + var focusManager = Assert.IsType(root.FocusManager); + Assert.Same(outerButton, focusManager.GetFocusedElement()); + + // Switch to a scope that has no previously focused element and isn't focusable itself. + // TestFocusScope is a Panel (Focusable = false) + IFocusScope. + focusManager.SetFocusScope(innerScope); + + // Focus must be cleared: the scope is not focusable and has no prior focused element. + // Before the fix this was a no-op and outerButton would still be reported as focused. + Assert.Null(focusManager.GetFocusedElement()); + } + [Fact] public void Can_Get_First_Focusable_Element() {