浏览代码

More refactoring. Application scope is gone.

Tig 8 月之前
父节点
当前提交
b443d52917

+ 24 - 24
Terminal.Gui/Application/Application.Keyboard.cs

@@ -45,16 +45,16 @@ 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<Key, KeyBinding> binding in KeyBindings.Bindings.Where (b => b.Key == key.KeyCode))
+        foreach (KeyValuePair<Key, ApplicationKeyBinding> binding in KeyBindings.Bindings.Where (b => b.Key == key.KeyCode))
         {
-            if (binding.Value.BoundView is { })
+            if (binding.Value.Target is { })
             {
-                if (!binding.Value.BoundView.Enabled)
+                if (!binding.Value.Target.Enabled)
                 {
                     return false;
                 }
 
-                bool? handled = binding.Value.BoundView?.InvokeCommands<KeyBinding> (binding.Value.Commands, binding.Value);
+                bool? handled = binding.Value.Target?.InvokeCommands<ApplicationKeyBinding> (binding.Value.Commands, binding.Value);
 
                 if (handled != null && (bool)handled)
                 {
@@ -63,7 +63,7 @@ public static partial class Application // Keyboard handling
             }
             else
             {
-                if (!KeyBindings.TryGet (key, KeyBindingScope.Application, out KeyBinding appBinding))
+                if (!KeyBindings.TryGet (key, out ApplicationKeyBinding appBinding))
                 {
                     continue;
                 }
@@ -81,7 +81,7 @@ public static partial class Application // Keyboard handling
 
         return false;
 
-        static bool? InvokeCommand (Command command, Key key, KeyBinding appBinding)
+        static bool? InvokeCommand (Command command, Key key, ApplicationKeyBinding appBinding)
         {
             if (!CommandImplementations!.ContainsKey (command))
             {
@@ -92,7 +92,7 @@ public static partial class Application // Keyboard handling
 
             if (CommandImplementations.TryGetValue (command, out View.CommandImplementation? implementation))
             {
-                var context = new CommandContext<KeyBinding> (command, appBinding); // Create the context here
+                var context = new CommandContext<ApplicationKeyBinding> (command, appBinding); // Create the context here
 
                 return implementation (context);
             }
@@ -158,7 +158,7 @@ public static partial class Application // Keyboard handling
     static Application () { AddApplicationKeyBindings (); }
 
     /// <summary>Gets the Application-scoped key bindings.</summary>
-    public static KeyBindings KeyBindings { get; internal set; } = new ();
+    public static ApplicationKeyBindings KeyBindings { get; internal set; } = new ();
 
     internal static void AddApplicationKeyBindings ()
     {
@@ -241,42 +241,42 @@ public static partial class Application // Keyboard handling
         QuitKey = Key.Esc;
         ArrangeKey = Key.F5.WithCtrl;
 
-        KeyBindings.Add (QuitKey, KeyBindingScope.Application, Command.Quit);
+        KeyBindings.Add (QuitKey, Command.Quit);
 
-        KeyBindings.Add (Key.CursorRight, KeyBindingScope.Application, Command.NextTabStop);
-        KeyBindings.Add (Key.CursorDown, KeyBindingScope.Application, Command.NextTabStop);
-        KeyBindings.Add (Key.CursorLeft, KeyBindingScope.Application, Command.PreviousTabStop);
-        KeyBindings.Add (Key.CursorUp, KeyBindingScope.Application, Command.PreviousTabStop);
-        KeyBindings.Add (NextTabKey, KeyBindingScope.Application, Command.NextTabStop);
-        KeyBindings.Add (PrevTabKey, KeyBindingScope.Application, Command.PreviousTabStop);
+        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, KeyBindingScope.Application, Command.NextTabGroup);
-        KeyBindings.Add (PrevTabGroupKey, KeyBindingScope.Application, Command.PreviousTabGroup);
+        KeyBindings.Add (NextTabGroupKey, Command.NextTabGroup);
+        KeyBindings.Add (PrevTabGroupKey, Command.PreviousTabGroup);
 
-        KeyBindings.Add (ArrangeKey, KeyBindingScope.Application, Command.Edit);
+        KeyBindings.Add (ArrangeKey, Command.Edit);
 
         // TODO: Refresh Key should be configurable
-        KeyBindings.Add (Key.F5, KeyBindingScope.Application, Command.Refresh);
+        KeyBindings.Add (Key.F5, Command.Refresh);
 
         // TODO: Suspend Key should be configurable
         if (Environment.OSVersion.Platform == PlatformID.Unix)
         {
-            KeyBindings.Add (Key.Z.WithCtrl, KeyBindingScope.Application, Command.Suspend);
+            KeyBindings.Add (Key.Z.WithCtrl, Command.Suspend);
         }
     }
 
     /// <summary>
-    ///     Gets the list of Views that have <see cref="KeyBindingScope.Application"/> key bindings.
+    ///     Gets the list of <see cref="ApplicationKeyBinding"/>s.
     /// </summary>
     /// <remarks>
     ///     This is an internal method used by the <see cref="View"/> class to add Application key bindings.
     /// </remarks>
     /// <returns>The list of Views that have Application-scoped key bindings.</returns>
-    internal static List<KeyBinding> GetViewKeyBindings ()
+    internal static List<ApplicationKeyBinding> GetViewKeyBindings ()
     {
         // Get the list of views that do not have Application-scoped key bindings
         return KeyBindings.Bindings
-                          .Where (kv => kv.Value.Scope != KeyBindingScope.Application)
+                          .Where (kv => kv.Value.Target is {})
                           .Select (kv => kv.Value)
                           .Distinct ()
                           .ToList ();
@@ -295,7 +295,7 @@ public static partial class Application // Keyboard handling
         }
         else
         {
-            if (KeyBindings.TryGet(oldKey, out KeyBinding binding))
+            if (KeyBindings.TryGet (oldKey, out ApplicationKeyBinding binding))
             {
                 KeyBindings.Remove (oldKey);
                 KeyBindings.Add (newKey, binding);

+ 41 - 0
Terminal.Gui/Input/Keyboard/ApplicationKeyBinding.cs

@@ -0,0 +1,41 @@
+#nullable enable
+
+// These classes use a key binding system based on the design implemented in Scintilla.Net which is an
+// MIT licensed open source project https://github.com/jacobslusser/ScintillaNET/blob/master/src/ScintillaNET/Command.cs
+
+namespace Terminal.Gui;
+
+/// <summary>
+/// Provides a collection of <see cref="Command"/> objects that are scoped to the <see cref="Application"/>.
+/// </summary>
+/// <seealso cref="Command"/>
+public record struct ApplicationKeyBinding
+{
+    /// <summary>Initializes a new instance.</summary>
+    /// <param name="commands">The commands this key binding will invoke.</param>
+    public ApplicationKeyBinding (Command [] commands)
+    {
+        Commands = commands;
+    }
+
+    /// <summary>Initializes a new instance.</summary>
+    /// <param name="commands">The commands this key binding will invoke.</param>
+    /// <param name="target">The view the Application-scoped key binding is bound to. If <see langword="null"/> the commands will be invoked on
+    /// the <see cref="Application"/>.</param>
+    public ApplicationKeyBinding (Command [] commands, View? target)
+    {
+        Commands = commands;
+        Target = target;
+    }
+
+    /// <summary>The commands this binding will invoke.</summary>
+    public Command [] Commands { get; set; }
+
+    /// <summary>
+    ///     The Key that is bound to the <see cref="Commands"/>.
+    /// </summary>
+    public Key? Key { get; set; }
+
+    /// <summary>The view the Application-scoped key binding is bound to.</summary>
+    public View? Target { get; set; }
+}

+ 236 - 0
Terminal.Gui/Input/Keyboard/ApplicationKeyBindings.cs

@@ -0,0 +1,236 @@
+#nullable enable
+namespace Terminal.Gui;
+
+/// <summary>
+///     Provides a collection of <see cref="ApplicationKeyBinding"/> objects bound to a <see cref="Key"/>.
+/// </summary>
+/// <remarks>
+///     This is used for <see cref="Application.KeyBindings"/>.
+/// </remarks>
+/// <seealso cref="Application.KeyBindings"/>
+/// <seealso cref="Command"/>
+public class ApplicationKeyBindings
+{
+    /// <summary>
+    ///     Initializes a new instance. This constructor is used when the <see cref="ApplicationKeyBindings"/> are not bound to a
+    ///     <see cref="View"/>. This is used for <see cref="Application.KeyBindings"/>.
+    /// </summary>
+    public ApplicationKeyBindings () { }
+
+    /// <summary>Adds a <see cref="ApplicationKeyBinding"/> to the collection.</summary>
+    /// <param name="key"></param>
+    /// <param name="binding"></param>
+    public void Add (Key key, ApplicationKeyBinding binding)
+    {
+        if (TryGet (key, out ApplicationKeyBinding _))
+        {
+            throw new InvalidOperationException (@$"A key binding for {key} exists ({binding}).");
+        }
+
+        // IMPORTANT: Add a COPY of the key. This is needed because ConfigurationManager.Apply uses DeepMemberWiseCopy 
+        // IMPORTANT: update the memory referenced by the key, and Dictionary uses caching for performance, and thus 
+        // IMPORTANT: Apply will update the Dictionary with the new key, but the old key will still be in the dictionary.
+        // IMPORTANT: See the ConfigurationManager.Illustrate_DeepMemberWiseCopy_Breaks_Dictionary test for details.
+        Bindings.Add (new (key), binding);
+    }
+
+    /// <summary>
+    ///     <para>
+    ///         Adds a new key combination that will trigger the commands in <paramref name="commands"/> on the View
+    ///         specified by <paramref name="boundView"/>.
+    ///     </para>
+    ///     <para>
+    ///         If the key is already bound to a different array of <see cref="Command"/>s it will be rebound
+    ///         <paramref name="commands"/>.
+    ///     </para>
+    /// </summary>
+    /// <remarks>
+    /// </remarks>
+    /// <param name="key">The key to check.</param>
+    /// <param name="boundView">The View the commands will be invoked on. If <see langword="null"/>, the key will be bound to <see cref="Application"/>.</param>
+    /// <param name="commands">
+    ///     The command to invoked on the <see paramref="boundView"/> when <paramref name="key"/> is pressed. When
+    ///     multiple commands are provided,they will be applied in sequence. The bound <paramref name="key"/> strike will be
+    ///     consumed if any took effect. 
+    /// </param>
+    public void Add (Key key, View? boundView, params Command [] commands)
+    {
+        ApplicationKeyBinding binding = new (commands, boundView);
+        Add (key, binding);
+    }
+
+    /// <summary>
+    ///     <para>
+    ///         Adds a new key combination that will trigger the commands in <paramref name="commands"/> on <see cref="Application"/>.
+    ///     </para>
+    ///     <para>
+    ///         If the key is already bound to a different array of <see cref="Command"/>s it will be rebound
+    ///         <paramref name="commands"/>.
+    ///     </para>
+    /// </summary>
+    /// <remarks>
+    /// </remarks>
+    /// <param name="key">The key to check.</param>
+    /// <param name="commands">
+    ///     The commands to invoke on <see cref="Application"/> when <paramref name="key"/> is pressed. When
+    ///     multiple commands are provided,they will be applied in sequence. The bound <paramref name="key"/> strike will be
+    ///     consumed if any took effect.
+    /// </param>
+    public void Add (Key key, params Command [] commands)
+    {
+        ApplicationKeyBinding binding = new (commands, null);
+        Add (key, binding);
+    }
+
+    // TODO: This should not be public!
+    /// <summary>The collection of <see cref="ApplicationKeyBinding"/> objects.</summary>
+    public Dictionary<Key, ApplicationKeyBinding> Bindings { get; } = new (new KeyEqualityComparer ());
+
+    /// <summary>
+    ///     Gets the keys that are bound.
+    /// </summary>
+    /// <returns></returns>
+    public IEnumerable<Key> GetBoundKeys ()
+    {
+        return Bindings.Keys;
+    }
+
+    /// <summary>Removes all <see cref="ApplicationKeyBinding"/> objects from the collection.</summary>
+    public void Clear () { Bindings.Clear (); }
+
+    /// <summary>
+    ///     Removes all key bindings that trigger the given command set. Views can have multiple different keys bound to
+    ///     the same command sets and this method will clear all of them.
+    /// </summary>
+    /// <param name="command"></param>
+    public void Clear (params Command [] command)
+    {
+        KeyValuePair<Key, ApplicationKeyBinding> [] kvps = Bindings
+                                                .Where (kvp => kvp.Value.Commands.SequenceEqual (command))
+                                                .ToArray ();
+
+        foreach (KeyValuePair<Key, ApplicationKeyBinding> kvp in kvps)
+        {
+            Remove (kvp.Key);
+        }
+    }
+
+    /// <summary>Gets the <see cref="ApplicationKeyBinding"/> for the specified <see cref="Key"/>.</summary>
+    /// <param name="key"></param>
+    /// <returns></returns>
+    public ApplicationKeyBinding Get (Key key)
+    {
+        if (TryGet (key, out ApplicationKeyBinding binding))
+        {
+            return binding;
+        }
+
+        throw new InvalidOperationException ($"Key {key} is not bound.");
+    }
+
+    /// <summary>Gets the array of <see cref="Command"/>s bound to <paramref name="key"/> if it exists.</summary>
+    /// <param name="key">The key to check.</param>
+    /// <returns>
+    ///     The array of <see cref="Command"/>s if <paramref name="key"/> is bound. An empty <see cref="Command"/> array
+    ///     if not.
+    /// </returns>
+    public Command [] GetCommands (Key key)
+    {
+        if (TryGet (key, out ApplicationKeyBinding bindings))
+        {
+            return bindings.Commands;
+        }
+
+        return [];
+    }
+
+    /// <summary>Gets the first Key bound to the set of commands specified by <paramref name="commands"/>.</summary>
+    /// <param name="commands">The set of commands to search.</param>
+    /// <returns>The first <see cref="Key"/> bound to the set of commands specified by <paramref name="commands"/>. <see langword="null"/> if the set of caommands was not found.</returns>
+    public Key? GetKeyFromCommands (params Command [] commands)
+    {
+        return Bindings.FirstOrDefault (a => a.Value.Commands.SequenceEqual (commands)).Key;
+    }
+
+    /// <summary>Gets Keys bound to the set of commands specified by <paramref name="commands"/>.</summary>
+    /// <param name="commands">The set of commands to search.</param>
+    /// <returns>The <see cref="Key"/>s bound to the set of commands specified by <paramref name="commands"/>. An empty list if the set of caommands was not found.</returns>
+    public IEnumerable<Key> GetKeysFromCommands (params Command [] commands)
+    {
+        return Bindings.Where (a => a.Value.Commands.SequenceEqual (commands)).Select (a => a.Key);
+    }
+
+    /// <summary>Removes a <see cref="ApplicationKeyBinding"/> from the collection.</summary>
+    /// <param name="key"></param>
+    public void Remove (Key key)
+    {
+        if (!TryGet (key, out ApplicationKeyBinding _))
+        {
+            return;
+        }
+
+        Bindings.Remove (key);
+    }
+
+    /// <summary>Replaces the commands already bound to a key.</summary>
+    /// <remarks>
+    ///     <para>
+    ///         If the key is not already bound, it will be added.
+    ///     </para>
+    /// </remarks>
+    /// <param name="key">The key bound to the command to be replaced.</param>
+    /// <param name="newCommands">The set of commands to replace the old ones with.</param>
+    public void ReplaceCommands (Key key, params Command [] newCommands)
+    {
+        if (TryGet (key, out ApplicationKeyBinding binding))
+        {
+            Remove (key);
+            Add (key, binding.Target, newCommands);
+
+            return;
+        }
+
+        throw new InvalidOperationException ($"Key {key} is not bound.");
+    }
+
+    /// <summary>Replaces a key combination already bound to a set of <see cref="Command"/>s.</summary>
+    /// <remarks></remarks>
+    /// <param name="oldKey">The key to be replaced.</param>
+    /// <param name="newKey">The new key to be used. If <see cref="Key.Empty"/> no action will be taken.</param>
+    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);
+    }
+
+    /// <summary>Gets the commands bound with the specified Key.</summary>
+    /// <remarks></remarks>
+    /// <param name="key">The key to check.</param>
+    /// <param name="binding">
+    ///     When this method returns, contains the commands bound with the specified Key, if the Key is
+    ///     found; otherwise, null. This parameter is passed uninitialized.
+    /// </param>
+    /// <returns><see langword="true"/> if the Key is bound; otherwise <see langword="false"/>.</returns>
+    public bool TryGet (Key key, out ApplicationKeyBinding binding)
+    {
+        binding = new ([], null);
+
+        if (key.IsValid)
+        {
+            return Bindings.TryGetValue (key, out binding);
+        }
+
+        return false;
+    }
+}

+ 1 - 16
Terminal.Gui/Input/Keyboard/KeyBindingScope.cs

@@ -39,20 +39,5 @@ public enum KeyBindingScope
     /// </summary>
     /// <seealso cref="View.KeyBindings"/>
     /// <seeals cref="View.HotKey"/>
-    HotKey = 2,
-
-    /// <summary>
-    ///     The and the bound <see cref="Command"/>s will be invoked regardless of which View has focus. This is typically used
-    ///     for global
-    ///     commands, which are called Shortcuts.
-    ///     <para>
-    ///         The View does not need to be visible.
-    ///     </para>
-    ///     <para>
-    ///         Application-scoped key bindings are only invoked if the key down event was not handled by the focused view or
-    ///         any of its subviews, and if the key was not bound to a <see cref="View.HotKey"/>.
-    ///     </para>
-    /// </summary>
-    /// <seealso cref="Application.KeyBindings"/>
-    Application = 4
+    HotKey = 2
 }

+ 10 - 124
Terminal.Gui/Input/Keyboard/KeyBindings.cs

@@ -9,11 +9,11 @@ namespace Terminal.Gui;
 /// <seealso cref="Command"/>
 public class KeyBindings
 {
-    /// <summary>
-    ///     Initializes a new instance. This constructor is used when the <see cref="KeyBindings"/> are not bound to a
-    ///     <see cref="View"/>. This is used for Application.KeyBindings and unit tests.
-    /// </summary>
-    public KeyBindings () { }
+    ///// <summary>
+    /////     Initializes a new instance. This constructor is used when the <see cref="KeyBindings"/> are not bound to a
+    /////     <see cref="View"/>. This is used for Application.KeyBindings and unit tests.
+    ///// </summary>
+    //public KeyBindings () { }
 
     /// <summary>Initializes a new instance bound to <paramref name="boundView"/>.</summary>
     public KeyBindings (View? boundView) { BoundView = boundView; }
@@ -21,18 +21,8 @@ public class KeyBindings
     /// <summary>Adds a <see cref="KeyBinding"/> to the collection.</summary>
     /// <param name="key"></param>
     /// <param name="binding"></param>
-    /// <param name="boundViewForAppScope">Optional View for <see cref="KeyBindingScope.Application"/> bindings.</param>
-    public void Add (Key key, KeyBinding binding, View? boundViewForAppScope = null)
+    public void Add (Key key, KeyBinding binding)
     {
-        if (BoundView is { } && binding.Scope.FastHasFlags (KeyBindingScope.Application))
-        {
-            throw new InvalidOperationException ("Application scoped KeyBindings must be added via Application.KeyBindings.Add");
-        }
-
-        if (BoundView is { } && boundViewForAppScope is null)
-        {
-            boundViewForAppScope = BoundView;
-        }
 
         if (TryGet (key, out KeyBinding _))
         {
@@ -45,10 +35,6 @@ public class KeyBindings
         {
             binding.BoundView = BoundView;
         }
-        else
-        {
-            binding.BoundView = boundViewForAppScope;
-        }
 
         // IMPORTANT: Add a COPY of the key. This is needed because ConfigurationManager.Apply uses DeepMemberWiseCopy 
         // IMPORTANT: update the memory referenced by the key, and Dictionary uses caching for performance, and thus 
@@ -57,55 +43,6 @@ public class KeyBindings
         Bindings.Add (new (key), binding);
     }
 
-    /// <summary>
-    ///     <para>Adds a new key combination that will trigger the commands in <paramref name="commands"/>.</para>
-    ///     <para>
-    ///         If the key is already bound to a different array of <see cref="Command"/>s it will be rebound
-    ///         <paramref name="commands"/>.
-    ///     </para>
-    /// </summary>
-    /// <remarks>
-    ///     Commands are only ever applied to the current <see cref="View"/> (i.e. this feature cannot be used to switch
-    ///     focus to another view and perform multiple commands there).
-    /// </remarks>
-    /// <param name="key">The key to check.</param>
-    /// <param name="scope">The scope for the command.</param>
-    /// <param name="boundViewForAppScope">Optional View for <see cref="KeyBindingScope.Application"/> bindings.</param>
-    /// <param name="commands">
-    ///     The command to invoked on the <see cref="View"/> when <paramref name="key"/> is pressed. When
-    ///     multiple commands are provided,they will be applied in sequence. The bound <paramref name="key"/> strike will be
-    ///     consumed if any took effect.
-    /// </param>
-    public void Add (Key key, KeyBindingScope scope, View? boundViewForAppScope = null, params Command [] commands)
-    {
-        if (BoundView is { } && scope.FastHasFlags (KeyBindingScope.Application))
-        {
-            throw new ArgumentException ("Application scoped KeyBindings must be added via Application.KeyBindings.Add");
-        }
-        else
-        {
-            // boundViewForAppScope = BoundView;
-        }
-
-        if (key is null || !key.IsValid)
-        {
-            //throw new ArgumentException ("Invalid Key", nameof (commands));
-            return;
-        }
-
-        if (commands.Length == 0)
-        {
-            throw new ArgumentException (@"At least one command must be specified", nameof (commands));
-        }
-
-        if (TryGet (key, out KeyBinding binding))
-        {
-            throw new InvalidOperationException (@$"A key binding for {key} exists ({binding}).");
-        }
-
-        Add (key, new KeyBinding (commands, scope, boundViewForAppScope), boundViewForAppScope);
-    }
-
     /// <summary>
     ///     <para>Adds a new key combination that will trigger the commands in <paramref name="commands"/>.</para>
     ///     <para>
@@ -126,16 +63,6 @@ public class KeyBindings
     /// </param>
     public void Add (Key key, KeyBindingScope scope, params Command [] commands)
     {
-        if (BoundView is null && !scope.FastHasFlags (KeyBindingScope.Application))
-        {
-            throw new InvalidOperationException ("BoundView cannot be null.");
-        }
-
-        if (BoundView is { } && scope.FastHasFlags (KeyBindingScope.Application))
-        {
-            throw new InvalidOperationException ("Application scoped KeyBindings must be added via Application.KeyBindings.Add");
-        }
-
         if (key == Key.Empty || !key.IsValid)
         {
             throw new ArgumentException (@"Invalid Key", nameof (commands));
@@ -151,43 +78,7 @@ public class KeyBindings
             throw new InvalidOperationException (@$"A key binding for {key} exists ({binding}).");
         }
 
-        Add (key, new KeyBinding (commands, scope, BoundView), BoundView);
-    }
-
-    /// <summary>
-    ///     <para>
-    ///         Adds a new key combination that will trigger the commands in <paramref name="commands"/> (if supported by the
-    ///         View - see <see cref="View.GetSupportedCommands"/>).
-    ///     </para>
-    ///     <para>
-    ///         This is a helper function for <see cref="Add(Key,KeyBinding,View?)"/>. If used for a View (
-    ///         <see cref="BoundView"/> is set), the scope will be set to <see cref="KeyBindingScope.Focused"/>.
-    ///         Otherwise, it will be set to <see cref="KeyBindingScope.Application"/>.
-    ///     </para>
-    ///     <para>
-    ///         If the key is already bound to a different array of <see cref="Command"/>s it will be rebound
-    ///         <paramref name="commands"/>.
-    ///     </para>
-    /// </summary>
-    /// <remarks>
-    ///     Commands are only ever applied to the current <see cref="View"/> (i.e. this feature cannot be used to switch
-    ///     focus to another view and perform multiple commands there).
-    /// </remarks>
-    /// <param name="key">The key to check.</param>
-    /// <param name="boundViewForAppScope">Optional View for <see cref="KeyBindingScope.Application"/> bindings.</param>
-    /// <param name="commands">
-    ///     The command to invoked on the <see cref="View"/> when <paramref name="key"/> is pressed. When
-    ///     multiple commands are provided,they will be applied in sequence. The bound <paramref name="key"/> strike will be
-    ///     consumed if any took effect.
-    /// </param>
-    public void Add (Key key, View? boundViewForAppScope = null, params Command [] commands)
-    {
-        if (BoundView is null && boundViewForAppScope is null)
-        {
-            throw new ArgumentException (@"Application scoped KeyBindings must provide a bound view to Add.", nameof (boundViewForAppScope));
-        }
-
-        Add (key, BoundView is { } ? KeyBindingScope.Focused : KeyBindingScope.Application, boundViewForAppScope, commands);
+        Add (key, new KeyBinding (commands, scope, BoundView));
     }
 
     /// <summary>
@@ -197,7 +88,7 @@ public class KeyBindings
     ///     </para>
     ///     <para>
     ///         This is a helper function for <see cref="Add(Key,KeyBinding,View?)"/>. If used for a View (
-    ///         <see cref="BoundView"/> is set), the scope will be set to <see cref="KeyBindingScope.Focused"/>.
+    ///         <see cref="Target"/> is set), the scope will be set to <see cref="KeyBindingScope.Focused"/>.
     ///         Otherwise, it will be set to <see cref="KeyBindingScope.Application"/>.
     ///     </para>
     ///     <para>
@@ -217,12 +108,7 @@ public class KeyBindings
     /// </param>
     public void Add (Key key, params Command [] commands)
     {
-        if (BoundView is null)
-        {
-            throw new ArgumentException (@"Application scoped KeyBindings must provide a boundViewForAppScope to Add.");
-        }
-
-        Add (key, BoundView is { } ? KeyBindingScope.Focused : KeyBindingScope.Application, null, commands);
+        Add (key, KeyBindingScope.Focused, commands);
     }
 
     // TODO: Add a dictionary comparer that ignores Scope
@@ -245,7 +131,7 @@ public class KeyBindings
     /// <remarks>
     ///     If <see langword="null"/> the KeyBindings object is being used for Application.KeyBindings.
     /// </remarks>
-    internal View? BoundView { get; }
+    public View? BoundView { get; init; }
 
     /// <summary>Removes all <see cref="KeyBinding"/> objects from the collection.</summary>
     public void Clear () { Bindings.Clear (); }

+ 19 - 20
Terminal.Gui/Views/Shortcut.cs

@@ -18,7 +18,7 @@ namespace Terminal.Gui;
 ///         - Pressing the HotKey specified by <see cref="CommandView"/>.
 ///     </para>
 ///     <para>
-///         If <see cref="KeyBindingScope"/> is <see cref="KeyBindingScope.Application"/>, <see cref="Key"/> will invoke
+///         If <see cref="BindKeyToApplication"/> is <see cref="KeyBindingScope.Application"/>, <see cref="Key"/> will invoke
 ///         <see cref="Command.Accept"/>
 ///         regardless of what View has focus, enabling an application-wide keyboard shortcut.
 ///     </para>
@@ -117,7 +117,7 @@ public class Shortcut : View, IOrientation, IDesignable
         {
             Id = "CommandView",
             Width = Dim.Auto (),
-            Height = Dim.Fill()
+            Height = Dim.Fill ()
         };
         Title = commandText ?? string.Empty;
 
@@ -144,7 +144,7 @@ public class Shortcut : View, IOrientation, IDesignable
                          DimAutoStyle.Content,
                          minimumContentDim: Dim.Func (() => _minimumNaturalWidth ?? 0),
                          maximumContentDim: Dim.Func (() => _minimumNaturalWidth ?? 0))!;
-}
+    }
 
     private AlignmentModes _alignmentModes = AlignmentModes.StartToEnd | AlignmentModes.IgnoreFirstOrLast;
 
@@ -224,7 +224,7 @@ public class Shortcut : View, IOrientation, IDesignable
         _minimumNaturalWidth = PosAlign.CalculateMinDimension (0, Subviews, Dimension.Width);
 
         // Reset our relative layout
-        SetRelativeLayout (SuperView?.GetContentSize() ?? Application.Screen.Size);
+        SetRelativeLayout (SuperView?.GetContentSize () ?? Application.Screen.Size);
     }
 
     // TODO: Enable setting of the margin thickness
@@ -331,7 +331,7 @@ public class Shortcut : View, IOrientation, IDesignable
 
         if (commandContext?.Command != Command.Accept)
         {
-           // return false;
+            // return false;
         }
 
         if (Action is { })
@@ -615,32 +615,31 @@ public class Shortcut : View, IOrientation, IDesignable
         }
     }
 
-    private KeyBindingScope _keyBindingScope = KeyBindingScope.HotKey;
+    private bool _bindKeyToApplication = false;
 
     /// <summary>
-    ///     Gets or sets the scope for the key binding for how <see cref="Key"/> is bound to <see cref="Command"/>.
+    ///     Gets or sets whether <see cref="Key"/> is bound to <see cref="Command"/> via <see cref="View.KeyBindings"/> (as a HotKey) or <see cref="Application.KeyBindings"/>.
     /// </summary>
-    public KeyBindingScope KeyBindingScope
+    public bool BindKeyToApplication
     {
-        get => _keyBindingScope;
+        get => _bindKeyToApplication;
         set
         {
-            if (value == _keyBindingScope)
+            if (value == _bindKeyToApplication)
             {
                 return;
             }
 
-            if (_keyBindingScope == KeyBindingScope.Application)
+            if (_bindKeyToApplication)
             {
-                Application.KeyBindings.Remove (Key, this);
+                Application.KeyBindings.Remove (Key);
             }
-
-            if (_keyBindingScope is KeyBindingScope.HotKey or KeyBindingScope.Focused)
+            else
             {
                 KeyBindings.Remove (Key);
             }
 
-            _keyBindingScope = value;
+            _bindKeyToApplication = value;
 
             UpdateKeyBindings (Key.Empty);
         }
@@ -703,14 +702,14 @@ public class Shortcut : View, IOrientation, IDesignable
     {
         if (Key.IsValid)
         {
-            if (KeyBindingScope.FastHasFlags (KeyBindingScope.Application))
+            if (BindKeyToApplication)
             {
                 if (oldKey != Key.Empty)
                 {
-                    Application.KeyBindings.Remove (oldKey, this);
+                    Application.KeyBindings.Remove (oldKey);
                 }
 
-                Application.KeyBindings.Remove (Key, this);
+                Application.KeyBindings.Remove (Key);
                 Application.KeyBindings.Add (Key, this, Command.HotKey);
             }
             else
@@ -721,7 +720,7 @@ public class Shortcut : View, IOrientation, IDesignable
                 }
 
                 KeyBindings.Remove (Key);
-                KeyBindings.Add (Key, KeyBindingScope | KeyBindingScope.HotKey, Command.HotKey);
+                KeyBindings.Add (Key, KeyBindingScope.HotKey, Command.HotKey);
             }
         }
     }
@@ -769,7 +768,7 @@ public class Shortcut : View, IOrientation, IDesignable
             if (_nonFocusColorScheme is { })
             {
                 base.ColorScheme = _nonFocusColorScheme;
-               //_nonFocusColorScheme = null;
+                //_nonFocusColorScheme = null;
             }
             else
             {

+ 1 - 1
UICatalog/Scenarios/Arrangement.cs

@@ -134,7 +134,7 @@ public class Arrangement : Scenario
                        {
                            Title = "Toggle Hide",
                            Text = "App",
-                           KeyBindingScope = KeyBindingScope.Application,
+                           BindKeyToApplication = true,
                            Key = Key.F4.WithCtrl,
                            Action = () =>
                                     {

+ 1 - 1
UICatalog/Scenarios/Bars.cs

@@ -164,7 +164,7 @@ public class Bars : Scenario
         {
             Title = "Toggle Hide",
             Text = "App",
-            KeyBindingScope = KeyBindingScope.Application,
+            BindKeyToApplication = true,
             Key = Key.F4.WithCtrl,
         };
         popOverMenu.Add (toggleShortcut);

+ 4 - 16
UICatalog/Scenarios/KeyBindings.cs

@@ -83,7 +83,7 @@ public sealed class KeyBindings : Scenario
         foreach (var key in Application.KeyBindings.GetBoundKeys())
         {
             var binding = Application.KeyBindings.Get (key);
-            appBindings.Add ($"{key} -> {binding.BoundView?.GetType ().Name} - {binding.Commands [0]}");
+            appBindings.Add ($"{key} -> {binding.Target?.GetType ().Name} - {binding.Commands [0]}");
         }
 
         ObservableCollection<string> hotkeyBindings = new ();
@@ -165,29 +165,17 @@ public class KeyBindingsDemo : View
 
         AddCommand (Command.Save, ctx =>
                                  {
-                                     if (ctx is not CommandContext<KeyBinding> keyCommandContext)
-                                     {
-                                         return false;
-                                     }
-                                     MessageBox.Query ($"{keyCommandContext.Binding.Scope}", $"Key: {keyCommandContext.Binding.Key}\nCommand: {ctx.Command}", buttons: "Ok");
+                                     MessageBox.Query ($"{ctx.Command}", $"Ctx: {ctx}", buttons: "Ok");
                                      return true;
                                  });
         AddCommand (Command.New, ctx =>
                                 {
-                                    if (ctx is not CommandContext<KeyBinding> keyCommandContext)
-                                    {
-                                        return false;
-                                    }
-                                    MessageBox.Query ($"{keyCommandContext.Binding.Scope}", $"Key: {keyCommandContext.Binding.Key}\nCommand: {ctx.Command}", buttons: "Ok");
+                                    MessageBox.Query ($"{ctx.Command}", $"Ctx: {ctx}", buttons: "Ok");
                                     return true;
                                 });
         AddCommand (Command.HotKey, ctx =>
         {
-            if (ctx is not CommandContext<KeyBinding> keyCommandContext)
-            {
-                return false;
-            }
-            MessageBox.Query ($"{keyCommandContext.Binding.Scope}", $"Key: {keyCommandContext.Binding.Key}\nCommand: {ctx.Command}", buttons: "Ok");
+            MessageBox.Query ($"{ctx.Command}", $"Ctx: {ctx}\nCommand: {ctx.Command}", buttons: "Ok");
             SetFocus ();
             return true;
         });

+ 1 - 1
UICatalog/Scenarios/Navigation.cs

@@ -150,7 +150,7 @@ public class Navigation : Scenario
                        {
                            Title = "Toggle Hide",
                            Text = "App",
-                           KeyBindingScope = KeyBindingScope.Application,
+                           BindKeyToApplication = true,
                            Key = Key.F4.WithCtrl,
                            Action = () =>
                                     {

+ 2 - 8
UICatalog/Scenarios/Shortcuts.cs

@@ -63,7 +63,6 @@ public class Shortcuts : Scenario
                 HighlightStyle = HighlightStyle.None,
             },
             Key = Key.F5.WithCtrl.WithAlt.WithShift,
-            KeyBindingScope = KeyBindingScope.HotKey,
         };
 
         // ((CheckBox)vShortcut3.CommandView).CheckedStateChanging += (_, args) =>
@@ -111,7 +110,6 @@ public class Shortcuts : Scenario
                 HighlightStyle = HighlightStyle.None,
             },
             Key = Key.F.WithCtrl,
-            KeyBindingScope = KeyBindingScope.HotKey,
         };
         ((CheckBox)commandFirstShortcut.CommandView).CheckedState =
             commandFirstShortcut.AlignmentModes.HasFlag (AlignmentModes.EndToStart) ? CheckState.UnChecked : CheckState.Checked;
@@ -151,7 +149,6 @@ public class Shortcuts : Scenario
             Width = Dim.Fill ()! - Dim.Width (eventLog),
             Key = Key.F4,
             HelpText = "Changes all Command.CanFocus",
-            KeyBindingScope = KeyBindingScope.HotKey,
             CommandView = new CheckBox { Text = "_CanFocus" },
         };
 
@@ -183,7 +180,7 @@ public class Shortcuts : Scenario
             Title = "A_pp Shortcut",
             Key = Key.F1,
             Text = "Width is DimFill",
-            KeyBindingScope = KeyBindingScope.Application,
+            BindKeyToApplication = true,
         };
 
         Application.Top.Add (appShortcut);
@@ -203,7 +200,6 @@ public class Shortcuts : Scenario
                 HighlightStyle = HighlightStyle.None
             },
             Key = Key.K,
-            KeyBindingScope = KeyBindingScope.HotKey,
         };
         var button = (Button)buttonShortcut.CommandView;
         buttonShortcut.Accepting += Button_Clicked;
@@ -218,7 +214,6 @@ public class Shortcuts : Scenario
             Y = Pos.Bottom (buttonShortcut),
             Key = Key.F2,
             Width = Dim.Fill ()! - Dim.Width (eventLog),
-            KeyBindingScope = KeyBindingScope.HotKey,
             CommandView = new RadioGroup
             {
                 Orientation = Orientation.Vertical,
@@ -244,7 +239,6 @@ public class Shortcuts : Scenario
             X = 0,
             Y = Pos.Bottom (radioGroupShortcut),
             Width = Dim.Fill ()! - Dim.Width (eventLog),
-            KeyBindingScope = KeyBindingScope.HotKey,
             HelpText = "Sliders work!",
             CommandView = new Slider<string>
             {
@@ -457,7 +451,7 @@ public class Shortcuts : Scenario
             X = Pos.Align (Alignment.Start, AlignmentModes.IgnoreFirstOrLast, 1),
             Y = Pos.AnchorEnd () - 1,
             Key = Key.Esc,
-            KeyBindingScope = KeyBindingScope.Application,
+            BindKeyToApplication = true,
             Title = "Quit",
             HelpText = "App Scope",
         };

+ 1 - 1
UICatalog/UICatalog.cs

@@ -761,7 +761,7 @@ public class UICatalogApp
                     CanFocus = false
                 },
                 HelpText = "",
-                KeyBindingScope = KeyBindingScope.Application,
+                BindKeyToApplication = true,
                 Key = Key.F7
             };
 

+ 1 - 1
UnitTests/Application/ApplicationTests.cs

@@ -358,7 +358,7 @@ public class ApplicationTests
         Application.PrevTabGroupKey = Key.A;
         Application.NextTabGroupKey = Key.B;
         Application.QuitKey = Key.C;
-        Application.KeyBindings.Add (Key.D, KeyBindingScope.Application, Command.Cancel);
+        Application.KeyBindings.Add (Key.D, Command.Cancel);
 
         Application._cachedViewsUnderMouse.Clear ();
 

+ 10 - 40
UnitTests/Application/KeyboardTests.cs

@@ -135,22 +135,22 @@ public class KeyboardTests
 
     [Fact]
     [AutoInitShutdown]
-    public void KeyBinding_Application_KeyBindings_Add_Adds ()
+    public void KeyBindings_Add_Adds ()
     {
-        Application.KeyBindings.Add (Key.A, KeyBindingScope.Application, Command.Accept);
-        Application.KeyBindings.Add (Key.B, KeyBindingScope.Application, Command.Accept);
+        Application.KeyBindings.Add (Key.A, Command.Accept);
+        Application.KeyBindings.Add (Key.B, Command.Accept);
 
-        Assert.True (Application.KeyBindings.TryGet (Key.A, out KeyBinding binding));
-        Assert.Null (binding.BoundView);
+        Assert.True (Application.KeyBindings.TryGet (Key.A, out ApplicationKeyBinding binding));
+        Assert.Null (binding.Target);
         Assert.True (Application.KeyBindings.TryGet (Key.B, out binding));
-        Assert.Null (binding.BoundView);
+        Assert.Null (binding.Target);
     }
 
     [Fact]
     [AutoInitShutdown]
-    public void KeyBinding_Application_RemoveKeyBinding_Removes ()
+    public void KeyBindings_Remove_Removes ()
     {
-        Application.KeyBindings.Add (Key.A, KeyBindingScope.Application, Command.Accept);
+        Application.KeyBindings.Add (Key.A, Command.Accept);
 
         Assert.True (Application.KeyBindings.TryGet (Key.A, out _));
 
@@ -159,7 +159,7 @@ public class KeyboardTests
     }
 
     [Fact]
-    public void KeyBinding_OnKeyDown ()
+    public void KeyBindings_OnKeyDown ()
     {
         Application.Top = new Toplevel ();
         var view = new ScopedKeyBindingView ();
@@ -204,7 +204,7 @@ public class KeyboardTests
 
     [Fact]
     [AutoInitShutdown]
-    public void KeyBinding_OnKeyDown_Negative ()
+    public void KeyBindings_OnKeyDown_Negative ()
     {
         var view = new ScopedKeyBindingView ();
         var keyWasHandled = false;
@@ -230,36 +230,6 @@ public class KeyboardTests
         top.Dispose ();
     }
 
-    [Fact]
-    [AutoInitShutdown]
-    public void KeyBinding_View_KeyBindings_Add_Adds ()
-    {
-        View view1 = new ();
-        Application.KeyBindings.Add (Key.A, view1, Command.Accept);
-
-        View view2 = new ();
-        Application.KeyBindings.Add (Key.B, view2, Command.Accept);
-
-        Assert.True (Application.KeyBindings.TryGet (Key.A, out KeyBinding binding));
-        Assert.Equal (view1, binding.BoundView);
-        Assert.True (Application.KeyBindings.TryGet (Key.B, out binding));
-        Assert.Equal (view2, binding.BoundView);
-    }
-
-    [Fact]
-    [AutoInitShutdown]
-    public void KeyBinding_View_KeyBindings_RemoveKeyBinding_Removes ()
-    {
-        View view1 = new ();
-        Application.KeyBindings.Add (Key.A, view1, Command.Accept);
-
-        View view2 = new ();
-        Application.KeyBindings.Add (Key.B, view1, Command.Accept);
-
-        Application.KeyBindings.Remove (Key.A, view1);
-        Assert.False (Application.KeyBindings.TryGet (Key.A, out _));
-    }
-
     [Fact]
     public void KeyUp_Event ()
     {

+ 43 - 62
UnitTests/Input/Keyboard/KeyBindingsTests.cs

@@ -14,26 +14,18 @@ public class KeyBindingsTests ()
         Assert.Throws<ArgumentException> (() => keyBindings.Add (Key.Empty, KeyBindingScope.HotKey, Command.Accept));
     }
 
-    [Fact]
-    public void Add_BoundView_Null_Non_AppScope_Throws ()
-    {
-        var keyBindings = new KeyBindings ();
-        List<Command> commands = new ();
-        Assert.Throws<InvalidOperationException> (() => keyBindings.Add (Key.Empty, KeyBindingScope.HotKey, Command.Accept));
-    }
-
     [Fact]
     public void Add_Multiple_Adds ()
     {
-        var keyBindings = new KeyBindings ();
-        Command [] commands = { Command.Right, Command.Left };
+        var keyBindings = new KeyBindings (new ());
+        Command [] commands = [Command.Right, Command.Left];
 
-        keyBindings.Add (Key.A, KeyBindingScope.Application, commands);
+        keyBindings.Add (Key.A, commands);
         Command [] resultCommands = keyBindings.GetCommands (Key.A);
         Assert.Contains (Command.Right, resultCommands);
         Assert.Contains (Command.Left, resultCommands);
 
-        keyBindings.Add (Key.B, KeyBindingScope.Application, commands);
+        keyBindings.Add (Key.B, commands);
         resultCommands = keyBindings.GetCommands (Key.B);
         Assert.Contains (Command.Right, resultCommands);
         Assert.Contains (Command.Left, resultCommands);
@@ -42,7 +34,7 @@ public class KeyBindingsTests ()
     [Fact]
     public void Add_No_Commands_Throws ()
     {
-        var keyBindings = new KeyBindings ();
+        var keyBindings = new KeyBindings (new());
         List<Command> commands = new ();
         Assert.Throws<ArgumentException> (() => keyBindings.Add (Key.A, commands.ToArray ()));
     }
@@ -50,25 +42,17 @@ public class KeyBindingsTests ()
     [Fact]
     public void Add_Single_Adds ()
     {
-        var keyBindings = new KeyBindings ();
-        keyBindings.Add (Key.A, KeyBindingScope.Application, Command.HotKey);
+        var keyBindings = new KeyBindings (new());
+        keyBindings.Add (Key.A, Command.HotKey);
         Command [] resultCommands = keyBindings.GetCommands (Key.A);
         Assert.Contains (Command.HotKey, resultCommands);
 
-        keyBindings.Add (Key.B, KeyBindingScope.Application, Command.HotKey);
+        keyBindings.Add (Key.B, Command.HotKey);
         resultCommands = keyBindings.GetCommands (Key.B);
         Assert.Contains (Command.HotKey, resultCommands);
     }
 
 
-    // Add should not allow duplicates
-    [Fact]
-    public void Add_With_Bound_View_Throws_If_App_Scope ()
-    {
-        var keyBindings = new KeyBindings (new View ());
-        Assert.Throws<InvalidOperationException> (() => keyBindings.Add (Key.A, KeyBindingScope.Application, Command.Accept));
-    }
-
     // Add should not allow duplicates
     [Fact]
     public void Add_With_Throws_If_Exists ()
@@ -106,8 +90,8 @@ public class KeyBindingsTests ()
     [Fact]
     public void Clear_Clears ()
     {
-        var keyBindings = new KeyBindings ();
-        keyBindings.Add (Key.B, KeyBindingScope.Application, Command.HotKey);
+        var keyBindings = new KeyBindings (new ());
+        keyBindings.Add (Key.B, Command.HotKey);
         keyBindings.Clear ();
         Command [] resultCommands = keyBindings.GetCommands (Key.A);
         Assert.Empty (resultCommands);
@@ -118,25 +102,25 @@ public class KeyBindingsTests ()
     [Fact]
     public void Defaults ()
     {
-        var keyBindings = new KeyBindings ();
+        var keyBindings = new KeyBindings (new());
         Assert.Empty (keyBindings.Bindings);
         Assert.Null (keyBindings.GetKeyFromCommands (Command.Accept));
-        Assert.Null (keyBindings.BoundView);
+        Assert.NotNull (keyBindings.BoundView);
     }
 
     [Fact]
     public void Get_Binding_Not_Found_Throws ()
     {
-        var keyBindings = new KeyBindings ();
+        var keyBindings = new KeyBindings (new());
         Assert.Throws<InvalidOperationException> (() => keyBindings.Get (Key.A));
-        Assert.Throws<InvalidOperationException> (() => keyBindings.Get (Key.B, KeyBindingScope.Application));
+        Assert.Throws<InvalidOperationException> (() => keyBindings.Get (Key.B));
     }
 
     // GetCommands
     [Fact]
     public void GetCommands_Unknown_ReturnsEmpty ()
     {
-        var keyBindings = new KeyBindings ();
+        var keyBindings = new KeyBindings (new ());
         Command [] resultCommands = keyBindings.GetCommands (Key.A);
         Assert.Empty (resultCommands);
     }
@@ -144,8 +128,8 @@ public class KeyBindingsTests ()
     [Fact]
     public void GetCommands_WithCommands_ReturnsCommands ()
     {
-        var keyBindings = new KeyBindings ();
-        keyBindings.Add (Key.A, KeyBindingScope.Application, Command.HotKey);
+        var keyBindings = new KeyBindings (new());
+        keyBindings.Add (Key.A, Command.HotKey);
         Command [] resultCommands = keyBindings.GetCommands (Key.A);
         Assert.Contains (Command.HotKey, resultCommands);
     }
@@ -153,10 +137,10 @@ public class KeyBindingsTests ()
     [Fact]
     public void GetCommands_WithMultipleBindings_ReturnsCommands ()
     {
-        var keyBindings = new KeyBindings ();
+        var keyBindings = new KeyBindings (new ());
         Command [] commands = { Command.Right, Command.Left };
-        keyBindings.Add (Key.A, KeyBindingScope.Application, commands);
-        keyBindings.Add (Key.B, KeyBindingScope.Application, commands);
+        keyBindings.Add (Key.A,commands);
+        keyBindings.Add (Key.B,commands);
         Command [] resultCommands = keyBindings.GetCommands (Key.A);
         Assert.Contains (Command.Right, resultCommands);
         Assert.Contains (Command.Left, resultCommands);
@@ -168,9 +152,9 @@ public class KeyBindingsTests ()
     [Fact]
     public void GetCommands_WithMultipleCommands_ReturnsCommands ()
     {
-        var keyBindings = new KeyBindings ();
+        var keyBindings = new KeyBindings (new());
         Command [] commands = { Command.Right, Command.Left };
-        keyBindings.Add (Key.A, KeyBindingScope.Application, commands);
+        keyBindings.Add (Key.A, commands);
         Command [] resultCommands = keyBindings.GetCommands (Key.A);
         Assert.Contains (Command.Right, resultCommands);
         Assert.Contains (Command.Left, resultCommands);
@@ -179,12 +163,12 @@ public class KeyBindingsTests ()
     [Fact]
     public void GetKeyFromCommands_MultipleCommands ()
     {
-        var keyBindings = new KeyBindings ();
+        var keyBindings = new KeyBindings (new());
         Command [] commands1 = { Command.Right, Command.Left };
-        keyBindings.Add (Key.A, KeyBindingScope.Application, commands1);
+        keyBindings.Add (Key.A, commands1);
 
         Command [] commands2 = { Command.Up, Command.Down };
-        keyBindings.Add (Key.B, KeyBindingScope.Application, commands2);
+        keyBindings.Add (Key.B,commands2);
 
         Key key = keyBindings.GetKeyFromCommands (commands1);
         Assert.Equal (Key.A, key);
@@ -196,8 +180,8 @@ public class KeyBindingsTests ()
     [Fact]
     public void GetKeyFromCommands_OneCommand ()
     {
-        var keyBindings = new KeyBindings ();
-        keyBindings.Add (Key.A, KeyBindingScope.Application, Command.Right);
+        var keyBindings = new KeyBindings (new());
+        keyBindings.Add (Key.A, Command.Right);
 
         Key key = keyBindings.GetKeyFromCommands (Command.Right);
         Assert.Equal (Key.A, key);
@@ -207,15 +191,15 @@ public class KeyBindingsTests ()
     [Fact]
     public void GetKeyFromCommands_Unknown_Returns_Key_Empty ()
     {
-        var keyBindings = new KeyBindings ();
+        var keyBindings = new KeyBindings(new());
         Assert.Null (keyBindings.GetKeyFromCommands (Command.Accept));
     }
 
     [Fact]
     public void GetKeyFromCommands_WithCommands_ReturnsKey ()
     {
-        var keyBindings = new KeyBindings ();
-        keyBindings.Add (Key.A, KeyBindingScope.Application, Command.HotKey);
+        var keyBindings = new KeyBindings (new());
+        keyBindings.Add (Key.A, Command.HotKey);
         Key resultKey = keyBindings.GetKeyFromCommands (Command.HotKey);
         Assert.Equal (Key.A, resultKey);
     }
@@ -261,15 +245,15 @@ public class KeyBindingsTests ()
     [Fact]
     public void ReplaceKey_Throws_If_DoesNotContain_Old ()
     {
-        var keyBindings = new KeyBindings ();
+        var keyBindings = new KeyBindings(new());
         Assert.Throws<InvalidOperationException> (() => 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);
+        var keyBindings = new KeyBindings(new());
+        keyBindings.Add (Key.A,Command.HotKey);
         Assert.Throws<InvalidOperationException> (() => keyBindings.ReplaceKey (Key.A, Key.Empty));
     }
 
@@ -277,10 +261,9 @@ public class KeyBindingsTests ()
     [Theory]
     [InlineData (KeyBindingScope.Focused)]
     [InlineData (KeyBindingScope.HotKey)]
-    [InlineData (KeyBindingScope.Application)]
     public void Scope_Add_Adds (KeyBindingScope scope)
     {
-        var keyBindings = new KeyBindings (scope.FastHasFlags (KeyBindingScope.Application) ? null : new ());
+        var keyBindings = new KeyBindings (new ());
         Command [] commands = { Command.Right, Command.Left };
 
         var key = new Key (Key.A);
@@ -301,10 +284,9 @@ public class KeyBindingsTests ()
     [Theory]
     [InlineData (KeyBindingScope.Focused)]
     [InlineData (KeyBindingScope.HotKey)]
-    [InlineData (KeyBindingScope.Application)]
     public void Scope_Get_Filters (KeyBindingScope scope)
     {
-        var keyBindings = new KeyBindings (scope.FastHasFlags (KeyBindingScope.Application) ? null : new ());
+        var keyBindings = new KeyBindings (new ());
         Command [] commands = { Command.Right, Command.Left };
 
         var key = new Key (Key.A);
@@ -321,10 +303,9 @@ public class KeyBindingsTests ()
     [Theory]
     [InlineData (KeyBindingScope.Focused)]
     [InlineData (KeyBindingScope.HotKey)]
-    [InlineData (KeyBindingScope.Application)]
     public void Scope_TryGet_Filters (KeyBindingScope scope)
     {
-        var keyBindings = new KeyBindings (scope.FastHasFlags (KeyBindingScope.Application) ? null : new ());
+        var keyBindings = new KeyBindings (new ());
         Command [] commands = { Command.Right, Command.Left };
 
         var key = new Key (Key.A);
@@ -350,8 +331,8 @@ public class KeyBindingsTests ()
     [Fact]
     public void TryGet_Succeeds ()
     {
-        var keyBindings = new KeyBindings ();
-        keyBindings.Add (Key.Q.WithCtrl, KeyBindingScope.Application, Command.HotKey);
+        var keyBindings = new KeyBindings(new());
+        keyBindings.Add (Key.Q.WithCtrl,Command.HotKey);
         var key = new Key (Key.Q.WithCtrl);
         bool result = keyBindings.TryGet (key, out KeyBinding _);
         Assert.True (result); ;
@@ -363,7 +344,7 @@ public class KeyBindingsTests ()
     [Fact]
     public void TryGet_Unknown_ReturnsFalse ()
     {
-        var keyBindings = new KeyBindings ();
+        var keyBindings = new KeyBindings(new());
         bool result = keyBindings.TryGet (Key.A, out KeyBinding _);
         Assert.False (result);
     }
@@ -371,8 +352,8 @@ public class KeyBindingsTests ()
     [Fact]
     public void TryGet_WithCommands_ReturnsTrue ()
     {
-        var keyBindings = new KeyBindings ();
-        keyBindings.Add (Key.A, KeyBindingScope.Application, Command.HotKey);
+        var keyBindings = new KeyBindings(new());
+        keyBindings.Add (Key.A,Command.HotKey);
         bool result = keyBindings.TryGet (Key.A, out KeyBinding bindings);
         Assert.True (result);
         Assert.Contains (Command.HotKey, bindings.Commands);
@@ -381,8 +362,8 @@ public class KeyBindingsTests ()
     [Fact]
     public void ReplaceCommands_Replaces ()
     {
-        var keyBindings = new KeyBindings ();
-        keyBindings.Add (Key.A, KeyBindingScope.Application, Command.Accept);
+        var keyBindings = new KeyBindings(new());
+        keyBindings.Add (Key.A,Command.Accept);
 
         keyBindings.ReplaceCommands (Key.A, Command.Refresh);
 

+ 7 - 7
UnitTests/Views/ShortcutTests.cs

@@ -294,7 +294,7 @@ public class ShortcutTests
     {
         var shortcut = new Shortcut ();
 
-        Assert.Equal (KeyBindingScope.HotKey, shortcut.KeyBindingScope);
+        Assert.False (shortcut.BindKeyToApplication);
     }
 
     [Fact]
@@ -302,9 +302,9 @@ public class ShortcutTests
     {
         var shortcut = new Shortcut ();
 
-        shortcut.KeyBindingScope = KeyBindingScope.Application;
+        shortcut.BindKeyToApplication = true;
 
-        Assert.Equal (KeyBindingScope.Application, shortcut.KeyBindingScope);
+        Assert.True (shortcut.BindKeyToApplication);
     }
 
     [Fact]
@@ -315,11 +315,11 @@ public class ShortcutTests
         shortcut.Key = Key.A;
         Assert.Contains (Key.A, shortcut.KeyBindings.Bindings.Keys);
 
-        shortcut.KeyBindingScope = KeyBindingScope.Application;
+        shortcut.BindKeyToApplication = true;
         Assert.DoesNotContain (Key.A, shortcut.KeyBindings.Bindings.Keys);
         Assert.Contains (Key.A, Application.KeyBindings.Bindings.Keys);
 
-        shortcut.KeyBindingScope = KeyBindingScope.HotKey;
+        shortcut.BindKeyToApplication = false;
         Assert.Contains (Key.A, shortcut.KeyBindings.Bindings.Keys);
         Assert.DoesNotContain (Key.A, Application.KeyBindings.Bindings.Keys);
     }
@@ -789,7 +789,7 @@ public class ShortcutTests
         var shortcut = new Shortcut
         {
             Key = Key.A,
-            KeyBindingScope = KeyBindingScope.Application,
+            BindKeyToApplication = true,
             Text = "0",
             Title = "_C"
         };
@@ -867,7 +867,7 @@ public class ShortcutTests
         var shortcut = new Shortcut
         {
             Key = Key.A,
-            KeyBindingScope = KeyBindingScope.Application,
+            BindKeyToApplication = true,
             Text = "0",
             Title = "_C",
             CanFocus = canFocus