diff --git a/Terminal.Gui/Input/Command.cs b/Terminal.Gui/Input/Command.cs
index 39500a3d2..0d7be7ea8 100644
--- a/Terminal.Gui/Input/Command.cs
+++ b/Terminal.Gui/Input/Command.cs
@@ -4,9 +4,14 @@
namespace Terminal.Gui;
///
-/// Actions which can be performed by a . Commands are typically invoked via
-/// and .
+/// Actions which can be performed by a .
///
+///
+///
+///
+///
+/// supports a subset of these commands by default, which can be overriden via .
+///
public enum Command
{
#region Base View Commands
diff --git a/Terminal.Gui/Input/Keyboard/KeyBindingScope.cs b/Terminal.Gui/Input/Keyboard/KeyBindingScope.cs
index 066cedc74..4f553a376 100644
--- a/Terminal.Gui/Input/Keyboard/KeyBindingScope.cs
+++ b/Terminal.Gui/Input/Keyboard/KeyBindingScope.cs
@@ -38,6 +38,6 @@ public enum KeyBindingScope
///
///
///
- ///
+ ///
HotKey = 2
}
diff --git a/Terminal.Gui/View/View.Keyboard.cs b/Terminal.Gui/View/View.Keyboard.cs
index b3dbf94f9..7f3f97d02 100644
--- a/Terminal.Gui/View/View.Keyboard.cs
+++ b/Terminal.Gui/View/View.Keyboard.cs
@@ -1,5 +1,6 @@
#nullable enable
using System.Diagnostics;
+using System.Reflection.Metadata;
namespace Terminal.Gui;
@@ -296,6 +297,12 @@ public partial class View // Keyboard APIs
return true;
}
+ bool? handled = false;
+ if (InvokeCommandsBoundToHotKeyOnSubviews (key, ref handled))
+ {
+ return true;
+ }
+
// After
if (RaiseKeyDownNotHandled (key) || key.Handled)
{
@@ -499,9 +506,12 @@ public partial class View // Keyboard APIs
#region Key Bindings
- /// Gets the key bindings for this view.
+ /// Gets the bindings for this view that will be invoked only if this view has focus.
public KeyBindings KeyBindings { get; internal set; } = null!;
+ /// Gets the bindings for this view that will be invoked regardless of whehter this view has focus or not.
+ public KeyBindings HotKeyBindings { get; internal set; } = null!;
+
///
/// INTERNAL API: Invokes any commands bound to on this view, adornments, and subviews.
///
@@ -516,15 +526,13 @@ public partial class View // Keyboard APIs
///
internal bool? InvokeCommandsBoundToKey (Key key)
{
- KeyBindingScope scope = KeyBindingScope.Focused | KeyBindingScope.HotKey;
-
// * If no key binding was found, `InvokeKeyBindings` returns `null`.
// Continue passing the event (return `false` from `OnInvokeKeyBindings`).
// * If key bindings were found, but none handled the key (all `Command`s returned `false`),
// `InvokeKeyBindings` returns `false`. Continue passing the event (return `false` from `OnInvokeKeyBindings`)..
// * If key bindings were found, and any handled the key (at least one `Command` returned `true`),
// `InvokeKeyBindings` returns `true`. Continue passing the event (return `false` from `OnInvokeKeyBindings`).
- bool? handled = InvokeCommandsBoundToKey (key, scope);
+ bool? handled = InvokeCommandsBoundToKey (key, KeyBindingScope.Focused);
if (handled is true)
{
@@ -533,22 +541,17 @@ public partial class View // Keyboard APIs
return handled;
}
- if (Margin is { } && InvokeCommandsBoundToKeyOnAdornment (Margin, key, scope, ref handled))
+ if (Margin is { } && InvokeCommandsBoundToKeyOnAdornment (Margin, key, KeyBindingScope.Focused, ref handled))
{
return true;
}
- if (Padding is { } && InvokeCommandsBoundToKeyOnAdornment (Padding, key, scope, ref handled))
+ if (Padding is { } && InvokeCommandsBoundToKeyOnAdornment (Padding, key, KeyBindingScope.Focused, ref handled))
{
return true;
}
- if (Border is { } && InvokeCommandsBoundToKeyOnAdornment (Border, key, scope, ref handled))
- {
- return true;
- }
-
- if (InvokeCommandsBoundToKeyOnSubviews (key, scope, ref handled))
+ if (Border is { } && InvokeCommandsBoundToKeyOnAdornment (Border, key, KeyBindingScope.Focused, ref handled))
{
return true;
}
@@ -588,8 +591,14 @@ public partial class View // Keyboard APIs
return false;
}
- private bool InvokeCommandsBoundToKeyOnSubviews (Key key, KeyBindingScope scope, ref bool? handled, bool invoke = true)
+ private bool InvokeCommandsBoundToHotKeyOnSubviews (Key key, ref bool? handled, bool invoke = true)
{
+ bool? weHandled = InvokeCommandsBoundToKey (key, KeyBindingScope.HotKey);
+ if (weHandled is true)
+ {
+ return true;
+ }
+
// Now, process any key bindings in the subviews that are tagged to KeyBindingScope.HotKey.
foreach (View subview in Subviews)
{
@@ -598,32 +607,7 @@ public partial class View // Keyboard APIs
continue;
}
- if (subview.KeyBindings.TryGet (key, scope, out KeyBinding binding))
- {
- if (binding.Scope == KeyBindingScope.Focused && !subview.HasFocus)
- {
- continue;
- }
-
- if (!invoke)
- {
- return true;
- }
-
- bool? subViewHandled = subview.InvokeCommandsBoundToKey (key);
-
- if (subViewHandled is { })
- {
- handled = subViewHandled;
-
- if ((bool)subViewHandled)
- {
- return true;
- }
- }
- }
-
- bool recurse = subview.InvokeCommandsBoundToKeyOnSubviews (key, scope, ref handled, invoke);
+ bool recurse = subview.InvokeCommandsBoundToHotKeyOnSubviews (key, ref handled, invoke);
if (recurse || (handled is { } && (bool)handled))
{
diff --git a/Terminal.Gui/Views/Menu/ContextMenu.cs b/Terminal.Gui/Views/Menu/ContextMenu.cs
index a963036dc..614df8ea7 100644
--- a/Terminal.Gui/Views/Menu/ContextMenu.cs
+++ b/Terminal.Gui/Views/Menu/ContextMenu.cs
@@ -110,6 +110,8 @@ public sealed class ContextMenu : IDisposable
_menuBar = null;
IsShow = false;
+ Application.KeyBindings.Remove (Key);
+
if (_container is { })
{
_container.Closing -= Container_Closing;
@@ -250,6 +252,9 @@ public sealed class ContextMenu : IDisposable
_menuBar._isContextMenuLoading = true;
_menuBar.MenuAllClosed += MenuBar_MenuAllClosed;
+
+ Application.KeyBindings.Add (Key, _menuBar, Command.Cancel);
+
_menuBar.BeginInit ();
_menuBar.EndInit ();
IsShow = true;
diff --git a/UnitTests/Application/KeyboardTests.cs b/UnitTests/Application/KeyboardTests.cs
index 2869e55bc..a164b8842 100644
--- a/UnitTests/Application/KeyboardTests.cs
+++ b/UnitTests/Application/KeyboardTests.cs
@@ -189,6 +189,7 @@ public class KeyboardTests
keyWasHandled = false;
Application.RaiseKeyDownEvent (Key.H);
Assert.False (keyWasHandled);
+ Assert.True (view.HotKeyCommand);
keyWasHandled = false;
Assert.False (view.HasFocus);