From e86a2fca2f552d75f8f3d6516cb1a80cc5389c08 Mon Sep 17 00:00:00 2001 From: Tig Date: Mon, 5 Aug 2024 08:54:05 -0600 Subject: [PATCH] Simplfiied app scope key setters --- .../Application/Application.Keyboard.cs | 89 +++++++------------ Terminal.Gui/Application/Application.cs | 4 +- Terminal.Gui/Input/KeyBindings.cs | 15 ++-- Terminal.Gui/Views/Shortcut.cs | 2 +- Terminal.Gui/Views/TableView/TableView.cs | 14 +-- UnitTests/Application/ApplicationTests.cs | 10 ++- UnitTests/Application/KeyboardTests.cs | 2 +- UnitTests/Configuration/SettingsScopeTests.cs | 6 +- UnitTests/Input/KeyBindingTests.cs | 28 +++++- 9 files changed, 90 insertions(+), 80 deletions(-) diff --git a/Terminal.Gui/Application/Application.Keyboard.cs b/Terminal.Gui/Application/Application.Keyboard.cs index 0981bbd2d..48170eb22 100644 --- a/Terminal.Gui/Application/Application.Keyboard.cs +++ b/Terminal.Gui/Application/Application.Keyboard.cs @@ -5,7 +5,7 @@ namespace Terminal.Gui; public static partial class Application // Keyboard handling { - private static Key _nextTabKey = Key.Empty; // Defined in config.json + private static Key _nextTabKey = Key.Tab; // Resources/config.json overrrides /// Alternative key to navigate forwards through views. Ctrl+Tab is the primary key. [SerializableConfigurationProperty (Scope = typeof (SettingsScope))] @@ -17,22 +17,13 @@ public static partial class Application // Keyboard handling { if (_nextTabKey != value) { - Key oldKey = _nextTabKey; + ReplaceKey (_nextTabKey, value); _nextTabKey = value; - - if (_nextTabKey == Key.Empty) - { - KeyBindings.Remove (_nextTabKey); - } - else - { - KeyBindings.ReplaceKey (oldKey, _nextTabKey); - } } } } - private static Key _prevTabKey = Key.Empty; // Defined in config.json + private static Key _prevTabKey = Key.Tab.WithShift; // Resources/config.json overrrides /// Alternative key to navigate backwards through views. Shift+Ctrl+Tab is the primary key. [SerializableConfigurationProperty (Scope = typeof (SettingsScope))] @@ -44,22 +35,13 @@ public static partial class Application // Keyboard handling { if (_prevTabKey != value) { - Key oldKey = _prevTabKey; + ReplaceKey (_prevTabKey, value); _prevTabKey = value; - - if (_prevTabKey == Key.Empty) - { - KeyBindings.Remove (_prevTabKey); - } - else - { - KeyBindings.ReplaceKey (oldKey, _prevTabKey); - } } } } - private static Key _nextTabGroupKey = Key.Empty; // Defined in config.json + private static Key _nextTabGroupKey = Key.F6; // Resources/config.json overrrides /// Alternative key to navigate forwards through views. Ctrl+Tab is the primary key. [SerializableConfigurationProperty (Scope = typeof (SettingsScope))] @@ -71,22 +53,13 @@ public static partial class Application // Keyboard handling { if (_nextTabGroupKey != value) { - Key oldKey = _nextTabGroupKey; + ReplaceKey (_nextTabGroupKey, value); _nextTabGroupKey = value; - - if (_nextTabGroupKey == Key.Empty) - { - KeyBindings.Remove (_nextTabGroupKey); - } - else - { - KeyBindings.ReplaceKey (oldKey, _nextTabGroupKey); - } } } } - private static Key _prevTabGroupKey = Key.Empty; // Defined in config.json + private static Key _prevTabGroupKey = Key.F6.WithShift; // Resources/config.json overrrides /// Alternative key to navigate backwards through views. Shift+Ctrl+Tab is the primary key. [SerializableConfigurationProperty (Scope = typeof (SettingsScope))] @@ -98,22 +71,13 @@ public static partial class Application // Keyboard handling { if (_prevTabGroupKey != value) { - Key oldKey = _prevTabGroupKey; + ReplaceKey (_prevTabGroupKey, value); _prevTabGroupKey = value; - - if (_prevTabGroupKey == Key.Empty) - { - KeyBindings.Remove (_prevTabGroupKey); - } - else - { - KeyBindings.ReplaceKey (oldKey, _prevTabGroupKey); - } } } } - private static Key _quitKey = Key.Empty; // Defined in config.json + private static Key _quitKey = Key.Esc; // Resources/config.json overrrides /// Gets or sets the key to quit the application. [SerializableConfigurationProperty (Scope = typeof (SettingsScope))] @@ -125,21 +89,29 @@ public static partial class Application // Keyboard handling { if (_quitKey != value) { - Key oldKey = _quitKey; + ReplaceKey (_quitKey, value); _quitKey = value; - - if (_quitKey == Key.Empty) - { - KeyBindings.Remove (_quitKey); - } - else - { - KeyBindings.ReplaceKey (oldKey, _quitKey); - } } } } + private static void ReplaceKey (Key oldKey, Key newKey) + { + if (KeyBindings.Bindings.Count == 0) + { + return; + } + + if (newKey == Key.Empty) + { + KeyBindings.Remove (oldKey); + } + else + { + KeyBindings.ReplaceKey (oldKey, newKey); + } + } + /// /// Event fired when the user presses a key. Fired by . /// @@ -413,6 +385,13 @@ public static partial class Application // Keyboard handling KeyBindings.Clear (); + // Resources/config.json overrrides + NextTabKey = Key.Tab; + PrevTabKey = Key.Tab.WithShift; + NextTabGroupKey = Key.F6; + PrevTabGroupKey = Key.F6.WithShift; + QuitKey = Key.Esc; + KeyBindings.Add (QuitKey, KeyBindingScope.Application, Command.QuitToplevel); KeyBindings.Add (Key.CursorRight, KeyBindingScope.Application, Command.NextView); diff --git a/Terminal.Gui/Application/Application.cs b/Terminal.Gui/Application/Application.cs index e5332ee7f..e3912475f 100644 --- a/Terminal.Gui/Application/Application.cs +++ b/Terminal.Gui/Application/Application.cs @@ -142,14 +142,12 @@ public static partial class Application UnGrabbedMouse = null; // Keyboard - PrevTabGroupKey = Key.Empty; - NextTabGroupKey = Key.Empty; - QuitKey = Key.Empty; KeyDown = null; KeyUp = null; SizeChanging = null; Navigation = null; + AddApplicationKeyBindings (); Colors.Reset (); diff --git a/Terminal.Gui/Input/KeyBindings.cs b/Terminal.Gui/Input/KeyBindings.cs index 89ffde7ad..5dd69a260 100644 --- a/Terminal.Gui/Input/KeyBindings.cs +++ b/Terminal.Gui/Input/KeyBindings.cs @@ -136,10 +136,9 @@ public class KeyBindings throw new ArgumentException ("Application scoped KeyBindings must be added via Application.KeyBindings.Add"); } - if (key is null || !key.IsValid) + if (key == Key.Empty || !key.IsValid) { - //throw new ArgumentException ("Invalid Key", nameof (commands)); - return; + throw new ArgumentException (@"Invalid Key", nameof (commands)); } if (commands.Length == 0) @@ -150,7 +149,6 @@ public class KeyBindings if (TryGet (key, out KeyBinding binding)) { throw new InvalidOperationException (@$"A key binding for {key} exists ({binding})."); - //Bindings [key] = new (commands, scope, BoundView); } else { @@ -313,12 +311,17 @@ public class KeyBindings /// Replaces a key combination already bound to a set of s. /// /// The key to be replaced. - /// The new key to be used. + /// The new key to be used. If no action will be taken. public void ReplaceKey (Key oldKey, Key newKey) { if (!TryGet (oldKey, out KeyBinding _)) { - return; + throw new InvalidOperationException ($"Key {oldKey} is not bound."); + } + + if (!newKey.IsValid) + { + throw new InvalidOperationException ($"Key {newKey} is is not valid."); } KeyBinding value = Bindings [oldKey]; diff --git a/Terminal.Gui/Views/Shortcut.cs b/Terminal.Gui/Views/Shortcut.cs index c5e023ee7..6530d71bc 100644 --- a/Terminal.Gui/Views/Shortcut.cs +++ b/Terminal.Gui/Views/Shortcut.cs @@ -681,7 +681,7 @@ public class Shortcut : View, IOrientation, IDesignable private void UpdateKeyBinding (Key oldKey) { - if (Key != null) + if (Key != null && Key.IsValid) { // Disable the command view key bindings CommandView.KeyBindings.Remove (Key); diff --git a/Terminal.Gui/Views/TableView/TableView.cs b/Terminal.Gui/Views/TableView/TableView.cs index a1b69cb65..10c53513d 100644 --- a/Terminal.Gui/Views/TableView/TableView.cs +++ b/Terminal.Gui/Views/TableView/TableView.cs @@ -324,11 +324,15 @@ public class TableView : View { if (cellActivationKey != value) { - KeyBindings.ReplaceKey (cellActivationKey, value); + if (KeyBindings.TryGet (cellActivationKey, out _)) + { + KeyBindings.ReplaceKey (cellActivationKey, value); + } + else + { + KeyBindings.Add (value, Command.Accept); + } - // of API user is mixing and matching old and new methods of keybinding then they may have lost - // the old binding (e.g. with ClearKeybindings) so KeyBindings.Replace alone will fail - KeyBindings.Add (value, Command.Accept); cellActivationKey = value; } } @@ -792,7 +796,7 @@ public class TableView : View } /// - protected internal override bool OnMouseEvent (MouseEvent me) + protected internal override bool OnMouseEvent (MouseEvent me) { if (!me.Flags.HasFlag (MouseFlags.Button1Clicked) && !me.Flags.HasFlag (MouseFlags.Button1DoubleClicked) diff --git a/UnitTests/Application/ApplicationTests.cs b/UnitTests/Application/ApplicationTests.cs index ce03ac11f..b84dc8ae8 100644 --- a/UnitTests/Application/ApplicationTests.cs +++ b/UnitTests/Application/ApplicationTests.cs @@ -183,9 +183,11 @@ public class ApplicationTests Assert.Null (Application.Driver); Assert.Null (Application.MainLoop); Assert.False (Application.EndAfterFirstIteration); - Assert.Equal (Key.Empty, Application.PrevTabGroupKey); - Assert.Equal (Key.Empty, Application.NextTabGroupKey); - Assert.Equal (Key.Empty, Application.QuitKey); + Assert.Equal (Key.Tab.WithShift, Application.PrevTabKey); + Assert.Equal (Key.Tab, Application.NextTabKey); + Assert.Equal (Key.F6.WithShift, Application.PrevTabGroupKey); + Assert.Equal (Key.F6, Application.NextTabGroupKey); + Assert.Equal (Key.Esc, Application.QuitKey); Assert.Null (ApplicationOverlapped.OverlappedChildren); Assert.Null (ApplicationOverlapped.OverlappedTop); @@ -236,7 +238,7 @@ public class ApplicationTests Application.PrevTabGroupKey = Key.A; Application.NextTabGroupKey = Key.B; Application.QuitKey = Key.C; - Application.KeyBindings.Add (Key.A, KeyBindingScope.Application, Command.Cancel); + Application.KeyBindings.Add (Key.D, KeyBindingScope.Application, Command.Cancel); //ApplicationOverlapped.OverlappedChildren = new List (); //ApplicationOverlapped.OverlappedTop = diff --git a/UnitTests/Application/KeyboardTests.cs b/UnitTests/Application/KeyboardTests.cs index 899420d94..2f6d85d00 100644 --- a/UnitTests/Application/KeyboardTests.cs +++ b/UnitTests/Application/KeyboardTests.cs @@ -65,7 +65,7 @@ public class KeyboardTests { Application.ResetState (true); // Before Init - Assert.Equal (Key.Empty, Application.QuitKey); + Assert.Equal (Key.Esc, Application.QuitKey); Application.Init (new FakeDriver ()); // After Init diff --git a/UnitTests/Configuration/SettingsScopeTests.cs b/UnitTests/Configuration/SettingsScopeTests.cs index 5525e530a..ca4f6b830 100644 --- a/UnitTests/Configuration/SettingsScopeTests.cs +++ b/UnitTests/Configuration/SettingsScopeTests.cs @@ -29,9 +29,9 @@ public class SettingsScopeTests Settings.Apply (); // assert - Assert.Equal (KeyCode.Q, Application.QuitKey.KeyCode); - Assert.Equal (KeyCode.F, Application.NextTabGroupKey.KeyCode); - Assert.Equal (KeyCode.B, Application.PrevTabGroupKey.KeyCode); + Assert.Equal (Key.Q, Application.QuitKey); + Assert.Equal (Key.F, Application.NextTabGroupKey); + Assert.Equal (Key.B, Application.PrevTabGroupKey); } [Fact] diff --git a/UnitTests/Input/KeyBindingTests.cs b/UnitTests/Input/KeyBindingTests.cs index bf3b007fd..077fc38f1 100644 --- a/UnitTests/Input/KeyBindingTests.cs +++ b/UnitTests/Input/KeyBindingTests.cs @@ -8,11 +8,20 @@ public class KeyBindingTests public KeyBindingTests (ITestOutputHelper output) { _output = output; } [Fact] - public void Add_Empty_Throws () + public void Add_No_Commands_Throws () { var keyBindings = new KeyBindings (); List commands = new (); Assert.Throws (() => keyBindings.Add (Key.A, commands.ToArray ())); + + } + + [Fact] + public void Add_Invalid_Key_Throws () + { + var keyBindings = new KeyBindings (); + List commands = new (); + Assert.Throws (() => keyBindings.Add (Key.Empty, KeyBindingScope.HotKey, Command.Accept)); } [Fact] @@ -193,7 +202,7 @@ public class KeyBindingTests } [Fact] - public void Replace_Key () + public void ReplaceKey_Replaces () { var keyBindings = new KeyBindings (); keyBindings.Add (Key.A, KeyBindingScope.Application, Command.HotKey); @@ -218,6 +227,21 @@ public class KeyBindingTests Assert.Contains (Command.HotKey, keyBindings.GetCommands (Key.H)); } + [Fact] + public void ReplaceKey_Throws_If_DoesNotContain_Old () + { + var keyBindings = new KeyBindings (); + Assert.Throws (() => keyBindings.ReplaceKey (Key.A, Key.B)); + } + + [Fact] + public void ReplaceKey_Throws_If_New_Is_Empty () + { + var keyBindings = new KeyBindings (); + keyBindings.Add (Key.A, KeyBindingScope.Application, Command.HotKey); + Assert.Throws (() => keyBindings.ReplaceKey (Key.A, Key.Empty)); + } + // Add with scope does the right things [Theory] [InlineData (KeyBindingScope.Focused)]