From 7360683152a240e8d672dc04645f856b9745d319 Mon Sep 17 00:00:00 2001 From: Tig Date: Fri, 6 Dec 2024 15:25:23 -0700 Subject: [PATCH] Prepping to combine keybinding classes --- .../Application/Application.Initialization.cs | 2 +- .../Application/Application.Keyboard.cs | 85 ++++++++----------- Terminal.Gui/Application/Application.cs | 3 +- .../Input/Keyboard/ApplicationKeyBindings.cs | 44 +++++++--- Terminal.Gui/Views/Menu/ContextMenu.cs | 2 +- UnitTests/Application/ApplicationTests.cs | 5 +- UnitTests/Views/ShortcutTests.cs | 4 +- 7 files changed, 73 insertions(+), 72 deletions(-) diff --git a/Terminal.Gui/Application/Application.Initialization.cs b/Terminal.Gui/Application/Application.Initialization.cs index d7ce7874b..56e774a14 100644 --- a/Terminal.Gui/Application/Application.Initialization.cs +++ b/Terminal.Gui/Application/Application.Initialization.cs @@ -92,7 +92,7 @@ public static partial class Application // Initialization (Init/Shutdown) } } - AddApplicationKeyBindings (); + AddKeyBindings (); // Start the process of configuration management. // Note that we end up calling LoadConfigurationFromAllSources diff --git a/Terminal.Gui/Application/Application.Keyboard.cs b/Terminal.Gui/Application/Application.Keyboard.cs index 0080ee010..143b63f91 100644 --- a/Terminal.Gui/Application/Application.Keyboard.cs +++ b/Terminal.Gui/Application/Application.Keyboard.cs @@ -45,7 +45,7 @@ public static partial class Application // Keyboard handling // Invoke any Application-scoped KeyBindings. // The first view that handles the key will stop the loop. - foreach (KeyValuePair binding in KeyBindings.Bindings.Where (b => b.Key == key.KeyCode)) + foreach (KeyValuePair binding in KeyBindings.GetBindings (key)) { if (binding.Value.Target is { }) { @@ -155,12 +155,12 @@ public static partial class Application // Keyboard handling #region Application-scoped KeyBindings - static Application () { AddApplicationKeyBindings (); } + static Application () { AddKeyBindings (); } /// Gets the Application-scoped key bindings. public static ApplicationKeyBindings KeyBindings { get; internal set; } = new (); - internal static void AddApplicationKeyBindings () + internal static void AddKeyBindings () { CommandImplementations = new (); @@ -231,29 +231,30 @@ public static partial class Application // Keyboard handling return false; }); - KeyBindings.Clear (); // Resources/config.json overrides + QuitKey = Key.Esc; NextTabKey = Key.Tab; PrevTabKey = Key.Tab.WithShift; NextTabGroupKey = Key.F6; PrevTabGroupKey = Key.F6.WithShift; - QuitKey = Key.Esc; ArrangeKey = Key.F5.WithCtrl; + // Need to clear after setting the above to ensure actually clear + // because set_QuitKey etc.. may call Add + KeyBindings.Clear (); + KeyBindings.Add (QuitKey, Command.Quit); + KeyBindings.Add (NextTabKey, Command.NextTabStop); + KeyBindings.Add (PrevTabKey, Command.PreviousTabStop); + KeyBindings.Add (NextTabGroupKey, Command.NextTabGroup); + KeyBindings.Add (PrevTabGroupKey, Command.PreviousTabGroup); + KeyBindings.Add (ArrangeKey, Command.Edit); KeyBindings.Add (Key.CursorRight, Command.NextTabStop); KeyBindings.Add (Key.CursorDown, Command.NextTabStop); KeyBindings.Add (Key.CursorLeft, Command.PreviousTabStop); KeyBindings.Add (Key.CursorUp, Command.PreviousTabStop); - KeyBindings.Add (NextTabKey, Command.NextTabStop); - KeyBindings.Add (PrevTabKey, Command.PreviousTabStop); - - KeyBindings.Add (NextTabGroupKey, Command.NextTabGroup); - KeyBindings.Add (PrevTabGroupKey, Command.PreviousTabGroup); - - KeyBindings.Add (ArrangeKey, Command.Edit); // TODO: Refresh Key should be configurable KeyBindings.Add (Key.F5, Command.Refresh); @@ -265,46 +266,32 @@ public static partial class Application // Keyboard handling } } - /// - /// Gets the list of s. - /// - /// - /// This is an internal method used by the class to add Application key bindings. - /// - /// The list of Views that have Application-scoped key bindings. - internal static List GetViewKeyBindings () - { - // Get the list of views that do not have Application-scoped key bindings - return KeyBindings.Bindings - .Where (kv => kv.Value.Target is {}) - .Select (kv => kv.Value) - .Distinct () - .ToList (); - } - private static void ReplaceKey (Key oldKey, Key newKey) { - if (KeyBindings.Bindings.Count == 0) - { - return; - } + KeyBindings.ReplaceKey (oldKey, newKey); - if (newKey == Key.Empty) - { - KeyBindings.Remove (oldKey); - } - else - { - if (KeyBindings.TryGet (oldKey, out ApplicationKeyBinding binding)) - { - KeyBindings.Remove (oldKey); - KeyBindings.Add (newKey, binding); - } - else - { - KeyBindings.Add (newKey, binding); - } - } + //return; + //if (KeyBindings.Bindings.Count == 0) + //{ + // return; + //} + + //if (newKey == Key.Empty) + //{ + // KeyBindings.Remove (oldKey); + //} + //else + //{ + // if (KeyBindings.TryGet (oldKey, out ApplicationKeyBinding binding)) + // { + // KeyBindings.Remove (oldKey); + // KeyBindings.Add (newKey, binding); + // } + // else + // { + // KeyBindings.Add (newKey, binding); + // } + //} } diff --git a/Terminal.Gui/Application/Application.cs b/Terminal.Gui/Application/Application.cs index 7c0ff5529..79198349f 100644 --- a/Terminal.Gui/Application/Application.cs +++ b/Terminal.Gui/Application/Application.cs @@ -214,7 +214,8 @@ public static partial class Application ClearScreenNextIteration = false; - AddApplicationKeyBindings (); + KeyBindings.Clear (); + AddKeyBindings (); // Reset synchronization context to allow the user to run async/await, // as the main loop has been ended, the synchronization context from diff --git a/Terminal.Gui/Input/Keyboard/ApplicationKeyBindings.cs b/Terminal.Gui/Input/Keyboard/ApplicationKeyBindings.cs index f4002203a..b0cd604bc 100644 --- a/Terminal.Gui/Input/Keyboard/ApplicationKeyBindings.cs +++ b/Terminal.Gui/Input/Keyboard/ApplicationKeyBindings.cs @@ -82,9 +82,7 @@ public class ApplicationKeyBindings Add (key, binding); } - // TODO: This should not be public! - /// The collection of objects. - public Dictionary Bindings { get; } = new (new KeyEqualityComparer ()); + private Dictionary Bindings { get; } = new (new KeyEqualityComparer ()); /// /// Gets the keys that are bound. @@ -95,6 +93,16 @@ public class ApplicationKeyBindings return Bindings.Keys; } + /// + /// Gets the bindings bound to . + /// + /// + /// + public IEnumerable> GetBindings (Key key) + { + return Bindings.Where (b => b.Key == key.KeyCode); + } + /// Removes all objects from the collection. public void Clear () { Bindings.Clear (); } @@ -193,25 +201,33 @@ public class ApplicationKeyBindings throw new InvalidOperationException ($"Key {key} is not bound."); } - /// Replaces a key combination already bound to a set of s. - /// + /// Replaces a key combination bound to a set of s. + /// If is not bound, this method has the same effect as . /// The key to be replaced. - /// The new key to be used. If no action will be taken. + /// The new key to be used. If this method has the same effect as . public void ReplaceKey (Key oldKey, Key newKey) { - if (!TryGet (oldKey, out ApplicationKeyBinding _)) - { - throw new InvalidOperationException ($"Key {oldKey} is not bound."); - } - if (!newKey.IsValid) { throw new InvalidOperationException ($"Key {newKey} is is not valid."); } - ApplicationKeyBinding binding = Bindings [oldKey]; - Remove (oldKey); - Add (newKey, binding); + if (newKey == Key.Empty) + { + Remove (oldKey); + return; + } + + + if (TryGet (oldKey, out ApplicationKeyBinding binding)) + { + Remove (oldKey); + Add (newKey, binding); + } + else + { + Add (newKey, binding); + } } /// Gets the commands bound with the specified Key. diff --git a/Terminal.Gui/Views/Menu/ContextMenu.cs b/Terminal.Gui/Views/Menu/ContextMenu.cs index 76908ce3a..851aae01e 100644 --- a/Terminal.Gui/Views/Menu/ContextMenu.cs +++ b/Terminal.Gui/Views/Menu/ContextMenu.cs @@ -109,7 +109,7 @@ public sealed class ContextMenu : IDisposable _menuBar?.Dispose (); _menuBar = null; IsShow = false; - ` + if (_container is { }) { _container.Closing -= Container_Closing; diff --git a/UnitTests/Application/ApplicationTests.cs b/UnitTests/Application/ApplicationTests.cs index cc7e1cbca..82e6846e1 100644 --- a/UnitTests/Application/ApplicationTests.cs +++ b/UnitTests/Application/ApplicationTests.cs @@ -317,9 +317,6 @@ public class ApplicationTests Assert.Empty (Application.TopLevels); Assert.Empty (Application._cachedViewsUnderMouse); - // Keyboard - Assert.Empty (Application.GetViewKeyBindings ()); - // Mouse Assert.Null (Application._lastMousePosition); @@ -555,7 +552,7 @@ public class ApplicationTests Assert.Equal (Key.Q.WithCtrl, Application.QuitKey); - Assert.Contains (Key.Q.WithCtrl, Application.KeyBindings.Bindings); + Assert.NotEmpty (Application.KeyBindings.GetBindings (Key.Q.WithCtrl)); Application.Shutdown (); Locations = ConfigLocations.Default; diff --git a/UnitTests/Views/ShortcutTests.cs b/UnitTests/Views/ShortcutTests.cs index 50f0e399a..760cb70f6 100644 --- a/UnitTests/Views/ShortcutTests.cs +++ b/UnitTests/Views/ShortcutTests.cs @@ -317,11 +317,11 @@ public class ShortcutTests shortcut.BindKeyToApplication = true; Assert.DoesNotContain (Key.A, shortcut.KeyBindings.Bindings.Keys); - Assert.Contains (Key.A, Application.KeyBindings.Bindings.Keys); + Assert.NotEmpty (Application.KeyBindings.GetBindings(Key.A)); shortcut.BindKeyToApplication = false; Assert.Contains (Key.A, shortcut.KeyBindings.Bindings.Keys); - Assert.DoesNotContain (Key.A, Application.KeyBindings.Bindings.Keys); + Assert.Empty (Application.KeyBindings.GetBindings (Key.A)); } [Theory]