From 66449823060be98955f78c09e8a1226a0e3e0f48 Mon Sep 17 00:00:00 2001 From: Autumn <80438149+1419323749@users.noreply.github.com> Date: Mon, 20 Jul 2026 16:46:22 +0800 Subject: [PATCH] fix(controls): stop HotKeyManager from executing on hidden controls (#21714) - Added a check for 'target.IsEffectivelyVisible' inside 'HotkeyCommandWrapper.CanExecute'. - Prevents HotKey from globally triggering and swallowing keyboard input when the host control or its parent panels are invisible (IsVisible="False"). - Added a corresponding unit test to verify input routing for hidden clickable controls. Closes #21708 Co-authored-by: Julien Lebosquain --- src/Avalonia.Controls/HotkeyManager.cs | 12 ++++++- .../HotKeyedControlsTests.cs | 31 +++++++++++++++++++ 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/src/Avalonia.Controls/HotkeyManager.cs b/src/Avalonia.Controls/HotkeyManager.cs index 06ff9cb18c..584a56a135 100644 --- a/src/Avalonia.Controls/HotkeyManager.cs +++ b/src/Avalonia.Controls/HotkeyManager.cs @@ -38,8 +38,18 @@ namespace Avalonia.Controls public bool CanExecute(object? parameter) { - if (reference.Target is { } target) + if (reference.Target is InputElement target) { + var current = target as Visual; + while (current != null && current is not TopLevel) + { + if (!current.IsVisible) + { + return false; + } + current = current.VisualParent; + } + if (target is ICommandSource commandSource && commandSource.Command is { } command) { return commandSource.IsEffectivelyEnabled diff --git a/tests/Avalonia.Controls.UnitTests/HotKeyedControlsTests.cs b/tests/Avalonia.Controls.UnitTests/HotKeyedControlsTests.cs index bdaa8d6a98..d27bc8d85c 100644 --- a/tests/Avalonia.Controls.UnitTests/HotKeyedControlsTests.cs +++ b/tests/Avalonia.Controls.UnitTests/HotKeyedControlsTests.cs @@ -119,5 +119,36 @@ namespace Avalonia.Controls.UnitTests Assert.True(hotKeyedTextBox.IsFocused); } + + [Fact] + public void Hidden_Button_HotKey_Should_Not_Swallow_Input() + { + using var _ = CreateServicesWithFocus(); + + var keyboardDevice = new KeyboardDevice(); + var root = PreparedWindow(); + var panel = new StackPanel { IsVisible = false }; + var button = new Button { HotKey = KeyGesture.Parse("Escape") }; + + bool buttonClicked = false; + button.Click += (s, e) => buttonClicked = true; + + panel.Children.Add(button); + root.Content = panel; + root.Show(); + + keyboardDevice.ProcessRawEvent( + new RawKeyEventArgs( + keyboardDevice, + 0, + root.InputRoot, + RawKeyEventType.KeyDown, + Key.Escape, + RawInputModifiers.None, + PhysicalKey.Escape, + "")); + + Assert.False(buttonClicked); + } } }