Skip to content

fix(controls): Stop HotKeyManager from triggering on hidden controls (#21708) - #21714

Merged
MrJul merged 2 commits into
AvaloniaUI:mainfrom
AutumnYuanc:fix/hotkey-hidden-controls-21708
Jul 20, 2026
Merged

MrJul merged 2 commits into
AvaloniaUI:mainfrom
AutumnYuanc:fix/hotkey-hidden-controls-21708

Conversation

@AutumnYuanc

Copy link
Copy Markdown
Contributor

Description

This PR fixes a global input-swallowing bug where HotKeyManager remains active and continues to intercept keyboard input even when the associated host control (or any of its parent layout containers) has been hidden via IsVisible="False".

Cause of the Bug

The HotkeyCommandWrapper.CanExecute method previously only checked for IsEffectivelyEnabled. However, when a control or its parent is hidden, IsEffectivelyEnabled often remains true. As a result, when the global shortcut key is pressed, the wrapper incorrectly approves execution, invokes the action, and sets args.Handled = true, effectively stealing the keyboard input from other visible parts of the application.

Solution

  • Refactored HotkeyCommandWrapper.CanExecute to securely cast the target to Control.
  • Added an explicit guard clause: if (!target.IsEffectivelyVisible) return false;. This ensures that shortcuts on invisible controls are gracefully ignored, letting the key event route freely to other focused elements.

Related Issues

Closes #21708

Type of Change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)

Checklist

  • My code follows the code style of this project (dotnet format has been executed).
  • I have performed a self-review of my own code.
  • I have added a unit test to Avalonia.Controls.UnitTests that proves my fix is effective.
  • All new and existing tests passed locally.

@AutumnYuanc
AutumnYuanc force-pushed the fix/hotkey-hidden-controls-21708 branch 2 times, most recently from db8a79a to 3b4b09a Compare July 7, 2026 03:45
@avaloniaui-bot

Copy link
Copy Markdown

You can test this PR using the following package version. 12.1.999-cibuild0067253-alpha. (feed url: https://nuget-feed-all.avaloniaui.net/v3/index.json) [PRBUILDID]

@cla-avalonia

cla-avalonia commented Jul 7, 2026 •

Copy link
Copy Markdown
Collaborator
  • All contributors have signed the CLA.

@AutumnYuanc

AutumnYuanc commented Jul 7, 2026 via email

Copy link
Copy Markdown
Contributor Author

@MrJul MrJul added bug backport-candidate-12.0.x Consider this PR for backporting to 12.0 branch labels Jul 7, 2026
@avaloniaui-bot

Copy link
Copy Markdown

You can test this PR using the following package version. 12.1.999-cibuild0067286-alpha. (feed url: https://nuget-feed-all.avaloniaui.net/v3/index.json) [PRBUILDID]

Comment thread src/Avalonia.Controls/HotkeyManager.cs Resolved
Comment on lines +44 to +51
while (current != null && current is not TopLevel)
{
if (!current.IsVisible)
{
return false;
}
current = current.VisualParent;
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would inputElement.IsEffectivelyVisible be sufficient?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I initially switched to IsEffectivelyVisible as suggested, but it turns out its
semantics include the TopLevel's own IsVisible in the ancestor chain. This broke
several existing unit tests where the test Window is constructed via ApplyTemplate()
without calling Show() (so Window.IsVisible defaults to false).

I think the original manual traversal (stopping before checking the TopLevel itself)
is actually more correct here — we want to detect a hidden container inside an
already-shown window, not conflate that with whether the window itself has been shown.
I've restored that approach, let me know if you'd prefer a different way to handle this.

@AutumnYuanc
AutumnYuanc force-pushed the fix/hotkey-hidden-controls-21708 branch from 7360cf9 to f6e549d Compare July 9, 2026 02:27
- 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 AvaloniaUI#21708
@AutumnYuanc
AutumnYuanc force-pushed the fix/hotkey-hidden-controls-21708 branch from f6e549d to 9638683 Compare July 9, 2026 03:21
@avaloniaui-bot

Copy link
Copy Markdown

You can test this PR using the following package version. 12.1.999-cibuild0067342-alpha. (feed url: https://nuget-feed-all.avaloniaui.net/v3/index.json) [PRBUILDID]

@MrJul MrJul added backport-candidate-12.1.x Consider this PR for backporting to 12.1 branch and removed backport-candidate-12.0.x Consider this PR for backporting to 12.0 branch labels Jul 9, 2026

@MrJul MrJul left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

@MrJul
MrJul enabled auto-merge July 20, 2026 08:11
@MrJul
MrJul added this pull request to the merge queue Jul 20, 2026
@avaloniaui-bot

Copy link
Copy Markdown

You can test this PR using the following package version. 12.2.999-cibuild0067537-alpha. (feed url: https://nuget-feed-all.avaloniaui.net/v3/index.json) [PRBUILDID]

Merged via the queue into AvaloniaUI:main with commit 6644982 Jul 20, 2026
10 checks passed
MrJul added a commit that referenced this pull request Jul 29, 2026
…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 <julien@lebosquain.net>
@MrJul MrJul added backported-12.1.x and removed backport-candidate-12.1.x Consider this PR for backporting to 12.1 branch labels Jul 29, 2026
@grokys

grokys commented Aug 26, 2026

Copy link
Copy Markdown
Member

Are we sure the behavior introduced in this PR is correct?

HotKey is similar to WinUI's KeyboardAccelerator which explicitly says:

An accelerator can be executed even if the element associated with the accelerator is not visible. For example, an item in the SecondaryCommands collection of the CommandBar can be invoked using an accelerator without expanding the overflow menu and displaying the element.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

HotKeys still work on hidden buttons and swallow keyboard input

6 participants