From 0c7d1aee8fa99e0478d753df4bedae325c3d5788 Mon Sep 17 00:00:00 2001 From: Tig Date: Fri, 6 Dec 2024 14:16:22 -0700 Subject: [PATCH] More refactoring. Broke CM --- Terminal.Gui/Input/Command.cs | 9 ++- .../Input/Keyboard/KeyBindingScope.cs | 2 +- Terminal.Gui/View/View.Keyboard.cs | 62 +++++++------------ Terminal.Gui/Views/Menu/ContextMenu.cs | 5 ++ UnitTests/Application/KeyboardTests.cs | 1 + 5 files changed, 37 insertions(+), 42 deletions(-) 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);