Prepping to combine keybinding classes 2

This commit is contained in:
Tig
2024-12-06 16:14:51 -07:00
parent 7360683152
commit 725df05f7b
25 changed files with 213 additions and 323 deletions

View File

@@ -54,7 +54,7 @@ public static partial class Application // Keyboard handling
return false;
}
bool? handled = binding.Value.Target?.InvokeCommands<ApplicationKeyBinding> (binding.Value.Commands, binding.Value);
bool? handled = binding.Value.Target?.InvokeCommands (binding.Value.Commands, binding.Value);
if (handled != null && (bool)handled)
{
@@ -83,16 +83,16 @@ public static partial class Application // Keyboard handling
static bool? InvokeCommand (Command command, Key key, ApplicationKeyBinding appBinding)
{
if (!CommandImplementations!.ContainsKey (command))
if (!_commandImplementations!.ContainsKey (command))
{
throw new NotSupportedException (
@$"A KeyBinding was set up for the command {command} ({key}) but that command is not supported by Application."
);
}
if (CommandImplementations.TryGetValue (command, out View.CommandImplementation? implementation))
if (_commandImplementations.TryGetValue (command, out View.CommandImplementation? implementation))
{
var context = new CommandContext<ApplicationKeyBinding> (command, appBinding); // Create the context here
CommandContext<ApplicationKeyBinding> context = new (command, appBinding); // Create the context here
return implementation (context);
}
@@ -116,7 +116,8 @@ public static partial class Application // Keyboard handling
public static event EventHandler<Key>? KeyDown;
/// <summary>
/// Called when the user releases a key (by the <see cref="IConsoleDriver"/>). Raises the cancelable <see cref="KeyUp"/>
/// Called when the user releases a key (by the <see cref="IConsoleDriver"/>). Raises the cancelable
/// <see cref="KeyUp"/>
/// event
/// then calls <see cref="View.NewKeyUpEvent"/> on all top level views. Called after <see cref="RaiseKeyDownEvent"/>.
/// </summary>
@@ -162,7 +163,7 @@ public static partial class Application // Keyboard handling
internal static void AddKeyBindings ()
{
CommandImplementations = new ();
_commandImplementations.Clear ();
// Things this view knows how to do
AddCommand (
@@ -231,7 +232,6 @@ public static partial class Application // Keyboard handling
return false;
});
// Resources/config.json overrides
QuitKey = Key.Esc;
NextTabKey = Key.Tab;
@@ -266,35 +266,6 @@ public static partial class Application // Keyboard handling
}
}
private static void ReplaceKey (Key oldKey, Key newKey)
{
KeyBindings.ReplaceKey (oldKey, newKey);
//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);
// }
//}
}
#endregion Application-scoped KeyBindings
/// <summary>
@@ -313,11 +284,10 @@ public static partial class Application // Keyboard handling
/// </remarks>
/// <param name="command">The command.</param>
/// <param name="f">The function.</param>
private static void AddCommand (Command command, Func<bool?> f) { CommandImplementations! [command] = ctx => f (); }
private static void AddCommand (Command command, Func<bool?> f) { _commandImplementations! [command] = ctx => f (); }
/// <summary>
/// Commands for Application.
/// </summary>
private static Dictionary<Command, View.CommandImplementation>? CommandImplementations { get; set; }
private static readonly Dictionary<Command, View.CommandImplementation> _commandImplementations = new ();
}

View File

@@ -22,7 +22,7 @@ public static partial class Application // Navigation stuff
{
if (_nextTabGroupKey != value)
{
ReplaceKey (_nextTabGroupKey, value);
KeyBindings.ReplaceKey (_nextTabGroupKey, value);
_nextTabGroupKey = value;
}
}
@@ -37,7 +37,7 @@ public static partial class Application // Navigation stuff
{
if (_nextTabKey != value)
{
ReplaceKey (_nextTabKey, value);
KeyBindings.ReplaceKey (_nextTabKey, value);
_nextTabKey = value;
}
}
@@ -66,7 +66,7 @@ public static partial class Application // Navigation stuff
{
if (_prevTabGroupKey != value)
{
ReplaceKey (_prevTabGroupKey, value);
KeyBindings.ReplaceKey (_prevTabGroupKey, value);
_prevTabGroupKey = value;
}
}
@@ -78,10 +78,10 @@ public static partial class Application // Navigation stuff
{
get => _prevTabKey;
set
{
{
if (_prevTabKey != value)
{
ReplaceKey (_prevTabKey, value);
KeyBindings.ReplaceKey (_prevTabKey, value);
_prevTabKey = value;
}
}

View File

@@ -19,7 +19,7 @@ public static partial class Application // Run (Begin, Run, End, Stop)
{
if (_quitKey != value)
{
ReplaceKey (_quitKey, value);
KeyBindings.ReplaceKey (_quitKey, value);
_quitKey = value;
}
}
@@ -37,7 +37,7 @@ public static partial class Application // Run (Begin, Run, End, Stop)
{
if (_arrangeKey != value)
{
ReplaceKey (_arrangeKey, value);
KeyBindings.ReplaceKey (_arrangeKey, value);
_arrangeKey = value;
}
}

View File

@@ -15,12 +15,10 @@ public record struct KeyBinding
{
/// <summary>Initializes a new instance.</summary>
/// <param name="commands">The commands this key binding will invoke.</param>
/// <param name="scope">The scope of the <see cref="Commands"/>.</param>
/// <param name="context">Arbitrary context that can be associated with this key binding.</param>
public KeyBinding (Command [] commands, KeyBindingScope scope, object? context = null)
public KeyBinding (Command [] commands, object? context = null)
{
Commands = commands;
Scope = scope;
Data = context;
}
@@ -29,10 +27,9 @@ public record struct KeyBinding
/// <param name="scope">The scope of the <see cref="Commands"/>.</param>
/// <param name="boundView">The view the key binding is bound to.</param>
/// <param name="data">Arbitrary data that can be associated with this key binding.</param>
public KeyBinding (Command [] commands, KeyBindingScope scope, View? boundView, object? data = null)
public KeyBinding (Command [] commands, View? boundView, object? data = null)
{
Commands = commands;
Scope = scope;
BoundView = boundView;
Data = data;
}
@@ -40,9 +37,6 @@ public record struct KeyBinding
/// <summary>The commands this key binding will invoke.</summary>
public Command [] Commands { get; set; }
/// <summary>The scope of the <see cref="Commands"/>.</summary>
public KeyBindingScope Scope { get; set; }
/// <summary>
/// The Key that is bound to the <see cref="Commands"/>.
/// </summary>

View File

@@ -22,22 +22,5 @@ public enum KeyBindingScope
/// </para>
/// </summary>
/// <seealso cref="View.KeyBindings"/>
Focused = 1,
/// <summary>
/// The key binding is scoped to the View's Superview hierarchy and the bound <see cref="Command"/>s will be invoked
/// even when the View does not have
/// focus, as
/// long as some View up the SuperView hierachy does have focus. This is typically used for <see cref="View.HotKey"/>s.
/// <para>
/// The View must be visible.
/// </para>
/// <para>
/// HotKey-scoped key bindings are only invoked if the key down event was not handled by the focused view or
/// any of its subviews.
/// </para>
/// </summary>
/// <seealso cref="View.KeyBindings"/>
/// <seealso cref="View.HotKey"/>
HotKey = 2
Focused = 1
}

View File

@@ -9,12 +9,6 @@ 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 bound to <paramref name="boundView"/>.</summary>
public KeyBindings (View? boundView) { BoundView = boundView; }
@@ -43,43 +37,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="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, params Command [] commands)
{
if (key == Key.Empty || !key.IsValid)
{
throw new ArgumentException (@"Invalid Key", nameof (commands));
}
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, BoundView));
}
/// <summary>
/// <para>
@@ -88,7 +45,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="Target"/> is set), the scope will be set to <see cref="KeyBindingScope.Focused"/>.
/// <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>
@@ -108,7 +65,7 @@ public class KeyBindings
/// </param>
public void Add (Key key, params Command [] commands)
{
Add (key, KeyBindingScope.Focused, commands);
Add (key, new KeyBinding(commands));
}
// TODO: Add a dictionary comparer that ignores Scope
@@ -166,20 +123,6 @@ public class KeyBindings
throw new InvalidOperationException ($"Key {key} is not bound.");
}
/// <summary>Gets the <see cref="KeyBinding"/> for the specified <see cref="Key"/>.</summary>
/// <param name="key"></param>
/// <param name="scope"></param>
/// <returns></returns>
public KeyBinding Get (Key key, KeyBindingScope scope)
{
if (TryGet (key, scope, out KeyBinding binding))
{
return binding;
}
throw new InvalidOperationException ($"Key {key}/{scope} 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>
@@ -238,7 +181,7 @@ public class KeyBindings
if (TryGet (key, out KeyBinding binding))
{
Remove (key);
Add (key, binding.Scope, newCommands);
Add (key, newCommands);
}
else
{
@@ -277,12 +220,7 @@ public class KeyBindings
/// <returns><see langword="true"/> if the Key is bound; otherwise <see langword="false"/>.</returns>
public bool TryGet (Key key, out KeyBinding binding)
{
//if (BoundView is null)
//{
// throw new InvalidOperationException ("KeyBindings must be bound to a View to use this method.");
//}
binding = new (Array.Empty<Command> (), KeyBindingScope.Disabled, null);
binding = new ([], null);
if (key.IsValid)
{
@@ -291,42 +229,4 @@ public class KeyBindings
return false;
}
/// <summary>Gets the commands bound with the specified Key that are scoped to a particular scope.</summary>
/// <remarks></remarks>
/// <param name="key">The key to check.</param>
/// <param name="scope">the scope to filter on</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, KeyBindingScope scope, out KeyBinding binding)
{
if (!key.IsValid)
{
//if (BoundView is null)
//{
// throw new InvalidOperationException ("KeyBindings must be bound to a View to use this method.");
//}
binding = new (Array.Empty<Command> (), KeyBindingScope.Disabled, null);
return false;
}
if (Bindings.TryGetValue (key, out binding))
{
if (scope.HasFlag (binding.Scope))
{
binding.Key = key;
return true;
}
}
else
{
binding = new (Array.Empty<Command> (), KeyBindingScope.Disabled, null);
}
return false;
}
}

View File

@@ -1390,15 +1390,15 @@ public class Border : Adornment
return true; // Always eat
});
KeyBindings.Add (Key.Esc, KeyBindingScope.HotKey, Command.Quit);
KeyBindings.Add (Application.ArrangeKey, KeyBindingScope.HotKey, Command.Quit);
KeyBindings.Add (Key.CursorUp, KeyBindingScope.HotKey, Command.Up);
KeyBindings.Add (Key.CursorDown, KeyBindingScope.HotKey, Command.Down);
KeyBindings.Add (Key.CursorLeft, KeyBindingScope.HotKey, Command.Left);
KeyBindings.Add (Key.CursorRight, KeyBindingScope.HotKey, Command.Right);
HotKeyBindings.Add (Key.Esc, Command.Quit);
HotKeyBindings.Add (Application.ArrangeKey, Command.Quit);
HotKeyBindings.Add (Key.CursorUp, Command.Up);
HotKeyBindings.Add (Key.CursorDown, Command.Down);
HotKeyBindings.Add (Key.CursorLeft, Command.Left);
HotKeyBindings.Add (Key.CursorRight, Command.Right);
KeyBindings.Add (Key.Tab, KeyBindingScope.HotKey, Command.Tab);
KeyBindings.Add (Key.Tab.WithShift, KeyBindingScope.HotKey, Command.BackTab);
HotKeyBindings.Add (Key.Tab, Command.Tab);
HotKeyBindings.Add (Key.Tab.WithShift, Command.BackTab);
}
private void ApplicationOnMouseEvent (object? sender, MouseEventArgs e)
@@ -1472,7 +1472,7 @@ public class Border : Adornment
_bottomSizeButton = null;
}
KeyBindings.Clear ();
HotKeyBindings.Clear ();
if (CanFocus)
{

View File

@@ -5,7 +5,7 @@ namespace Terminal.Gui;
public partial class View // Command APIs
{
private Dictionary<Command, CommandImplementation> CommandImplementations { get; } = new ();
private readonly Dictionary<Command, CommandImplementation> _commandImplementations = new ();
#region Default Implementation
@@ -95,7 +95,7 @@ public partial class View // Command APIs
if (isDefaultView != this && isDefaultView is Button { IsDefault: true } button)
{
bool? handled = isDefaultView.InvokeCommand<KeyBinding> (Command.Accept, new ([Command.Accept], 0, null, this));
bool? handled = isDefaultView.InvokeCommand<KeyBinding> (Command.Accept, new ([Command.Accept], null, this));
if (handled == true)
{
return true;
@@ -104,7 +104,7 @@ public partial class View // Command APIs
if (SuperView is { })
{
return SuperView?.InvokeCommand<KeyBinding> (Command.Accept, new ([Command.Accept], 0, null, this)) is true;
return SuperView?.InvokeCommand<KeyBinding> (Command.Accept, new ([Command.Accept], null, this)) is true;
}
}
@@ -249,7 +249,7 @@ public partial class View // Command APIs
/// </remarks>
/// <param name="command">The command.</param>
/// <param name="impl">The delegate.</param>
protected void AddCommand (Command command, CommandImplementation impl) { CommandImplementations [command] = impl; }
protected void AddCommand (Command command, CommandImplementation impl) { _commandImplementations [command] = impl; }
/// <summary>
/// <para>
@@ -270,11 +270,11 @@ public partial class View // Command APIs
/// </remarks>
/// <param name="command">The command.</param>
/// <param name="impl">The delegate.</param>
protected void AddCommand (Command command, Func<bool?> impl) { CommandImplementations [command] = ctx => impl (); }
protected void AddCommand (Command command, Func<bool?> impl) { _commandImplementations [command] = ctx => impl (); }
/// <summary>Returns all commands that are supported by this <see cref="View"/>.</summary>
/// <returns></returns>
public IEnumerable<Command> GetSupportedCommands () { return CommandImplementations.Keys; }
public IEnumerable<Command> GetSupportedCommands () { return _commandImplementations.Keys; }
/// <summary>
/// Invokes the specified commands.
@@ -292,7 +292,7 @@ public partial class View // Command APIs
foreach (Command command in commands)
{
if (!CommandImplementations.ContainsKey (command))
if (!_commandImplementations.ContainsKey (command))
{
throw new NotSupportedException (
@$"A Binding was set up for the command {command} ({binding}) but that command is not supported by this View ({GetType ().Name})"
@@ -327,7 +327,7 @@ public partial class View // Command APIs
/// </returns>
public bool? InvokeCommand<TBindingType> (Command command, TBindingType binding)
{
if (CommandImplementations.TryGetValue (command, out CommandImplementation? implementation))
if (_commandImplementations.TryGetValue (command, out CommandImplementation? implementation))
{
return implementation (new CommandContext<TBindingType> ()
{
@@ -350,7 +350,7 @@ public partial class View // Command APIs
/// </returns>
public bool? InvokeCommand (Command command)
{
if (CommandImplementations.TryGetValue (command, out CommandImplementation? implementation))
if (_commandImplementations.TryGetValue (command, out CommandImplementation? implementation))
{
return implementation (null);
}

View File

@@ -15,6 +15,8 @@ public partial class View // Keyboard APIs
KeyBindings.Add (Key.Space, Command.Select);
KeyBindings.Add (Key.Enter, Command.Accept);
HotKeyBindings = new (this);
// Note, setting HotKey will bind HotKey to Command.HotKey
HotKeySpecifier = (Rune)'_';
TitleTextFormatter.HotKeyChanged += TitleTextFormatter_HotKeyChanged;
@@ -153,50 +155,54 @@ public partial class View // Keyboard APIs
}
// Remove base version
if (KeyBindings.TryGet (prevHotKey, out _))
if (HotKeyBindings.TryGet (prevHotKey, out _))
{
KeyBindings.Remove (prevHotKey);
HotKeyBindings.Remove (prevHotKey);
}
// Remove the Alt version
if (KeyBindings.TryGet (prevHotKey.WithAlt, out _))
if (HotKeyBindings.TryGet (prevHotKey.WithAlt, out _))
{
KeyBindings.Remove (prevHotKey.WithAlt);
HotKeyBindings.Remove (prevHotKey.WithAlt);
}
if (_hotKey.IsKeyCodeAtoZ)
{
// Remove the shift version
if (KeyBindings.TryGet (prevHotKey.WithShift, out _))
if (HotKeyBindings.TryGet (prevHotKey.WithShift, out _))
{
KeyBindings.Remove (prevHotKey.WithShift);
HotKeyBindings.Remove (prevHotKey.WithShift);
}
// Remove alt | shift version
if (KeyBindings.TryGet (prevHotKey.WithShift.WithAlt, out _))
if (HotKeyBindings.TryGet (prevHotKey.WithShift.WithAlt, out _))
{
KeyBindings.Remove (prevHotKey.WithShift.WithAlt);
HotKeyBindings.Remove (prevHotKey.WithShift.WithAlt);
}
}
// Add the new
if (newKey != Key.Empty)
{
KeyBinding keyBinding = new ([Command.HotKey], KeyBindingScope.HotKey, context);
KeyBinding keyBinding = new ()
{
Commands = [Command.HotKey],
Data = context
};
// Add the base and Alt key
KeyBindings.Remove (newKey);
KeyBindings.Add (newKey, keyBinding);
KeyBindings.Remove (newKey.WithAlt);
KeyBindings.Add (newKey.WithAlt, keyBinding);
HotKeyBindings.Remove (newKey);
HotKeyBindings.Add (newKey, keyBinding);
HotKeyBindings.Remove (newKey.WithAlt);
HotKeyBindings.Add (newKey.WithAlt, keyBinding);
// If the Key is A..Z, add ShiftMask and AltMask | ShiftMask
if (newKey.IsKeyCodeAtoZ)
{
KeyBindings.Remove (newKey.WithShift);
KeyBindings.Add (newKey.WithShift, keyBinding);
KeyBindings.Remove (newKey.WithShift.WithAlt);
KeyBindings.Add (newKey.WithShift.WithAlt, keyBinding);
HotKeyBindings.Remove (newKey.WithShift);
HotKeyBindings.Add (newKey.WithShift, keyBinding);
HotKeyBindings.Remove (newKey.WithShift.WithAlt);
HotKeyBindings.Add (newKey.WithShift.WithAlt, keyBinding);
}
}
@@ -532,7 +538,7 @@ public partial class View // Keyboard APIs
// `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, KeyBindingScope.Focused);
bool? handled = InvokeCommandsBoundToFocusedKey (key);
if (handled is true)
{
@@ -541,17 +547,17 @@ public partial class View // Keyboard APIs
return handled;
}
if (Margin is { } && InvokeCommandsBoundToKeyOnAdornment (Margin, key, KeyBindingScope.Focused, ref handled))
if (Margin is { } && InvokeCommandsBoundToKeyOnAdornment (Margin, key, ref handled))
{
return true;
}
if (Padding is { } && InvokeCommandsBoundToKeyOnAdornment (Padding, key, KeyBindingScope.Focused, ref handled))
if (Padding is { } && InvokeCommandsBoundToKeyOnAdornment (Padding, key, ref handled))
{
return true;
}
if (Border is { } && InvokeCommandsBoundToKeyOnAdornment (Border, key, KeyBindingScope.Focused, ref handled))
if (Border is { } && InvokeCommandsBoundToKeyOnAdornment (Border, key, ref handled))
{
return true;
}
@@ -559,7 +565,7 @@ public partial class View // Keyboard APIs
return handled;
}
private static bool InvokeCommandsBoundToKeyOnAdornment (Adornment adornment, Key key, KeyBindingScope scope, ref bool? handled)
private static bool InvokeCommandsBoundToKeyOnAdornment (Adornment adornment, Key key, ref bool? handled)
{
bool? adornmentHandled = adornment.InvokeCommandsBoundToKey (key);
@@ -593,7 +599,7 @@ public partial class View // Keyboard APIs
internal bool InvokeCommandsBoundToHotKeyOnSubviews (Key key, ref bool? handled, bool invoke = true)
{
bool? weHandled = InvokeCommandsBoundToKey (key, KeyBindingScope.HotKey);
bool? weHandled = InvokeCommandsBoundToHotKey (key);
if (weHandled is true)
{
return true;
@@ -634,7 +640,7 @@ public partial class View // Keyboard APIs
foreach (View subview in Subviews)
{
if (subview.KeyBindings.TryGet (key, KeyBindingScope.HotKey, out _))
if (subview.HotKeyBindings.TryGet (key, out _))
{
boundView = subview;
@@ -650,6 +656,46 @@ public partial class View // Keyboard APIs
return false;
}
/// <summary>
/// Invokes the Commands bound to <paramref name="key"/>.
/// <para>See <see href="../docs/keyboard.md">for an overview of Terminal.Gui keyboard APIs.</see></para>
/// </summary>
/// <param name="key">The key event passed.</param>
/// <returns>
/// <see langword="null"/> if no command was invoked; input processing should continue.
/// <see langword="false"/> if at least one command was invoked and was not handled (or cancelled); input processing
/// should continue.
/// <see langword="true"/> if at least one command was invoked and handled (or cancelled); input processing should
/// stop.
/// </returns>
protected bool? InvokeCommandsBoundToFocusedKey (Key key)
{
if (!KeyBindings.TryGet (key, out KeyBinding binding))
{
return null;
}
#if DEBUG
//if (Application.KeyBindings.TryGet (key, out KeyBinding b))
//{
// Debug.WriteLine (
// $"WARNING: InvokeKeyBindings ({key}) - An Application scope binding exists for this key. The registered view will not invoke Command.");
//}
// TODO: This is a "prototype" debug check. It may be too annoying vs. useful.
// Scour the bindings up our View hierarchy
// to ensure that the key is not already bound to a different set of commands.
if (SuperView?.IsHotKeyBound (key, out View? previouslyBoundView) ?? false)
{
Debug.WriteLine ($"WARNING: InvokeKeyBindings ({key}) - A subview or peer has bound this Key and will not see it: {previouslyBoundView}.");
}
#endif
return InvokeCommands<KeyBinding> (binding.Commands, binding);
}
/// <summary>
/// Invokes the Commands bound to <paramref name="key"/>.
/// <para>See <see href="../docs/keyboard.md">for an overview of Terminal.Gui keyboard APIs.</see></para>
@@ -663,9 +709,9 @@ public partial class View // Keyboard APIs
/// <see langword="true"/> if at least one command was invoked and handled (or cancelled); input processing should
/// stop.
/// </returns>
protected bool? InvokeCommandsBoundToKey (Key key, KeyBindingScope scope)
protected bool? InvokeCommandsBoundToHotKey (Key key)
{
if (!KeyBindings.TryGet (key, scope, out KeyBinding binding))
if (!HotKeyBindings.TryGet (key, out KeyBinding binding))
{
return null;
}

View File

@@ -133,7 +133,7 @@ public class Button : View, IDesignable
}
// TODO: With https://github.com/gui-cs/Terminal.Gui/issues/3778 we won't have to pass data:
e.Handled = InvokeCommand<KeyBinding> (Command.HotKey, new KeyBinding ([Command.HotKey], KeyBindingScope.HotKey, this, null)) == true;
e.Handled = InvokeCommand<KeyBinding> (Command.HotKey, new KeyBinding ([Command.HotKey], this, data: null)) == true;
}
private void Button_TitleChanged (object sender, EventArgs<string> e)

View File

@@ -25,7 +25,7 @@ public class FrameView : View
private void FrameView_MouseClick (object sender, MouseEventArgs e)
{
// base sets focus on HotKey
e.Handled = InvokeCommand<KeyBinding> (Command.HotKey, new ([Command.HotKey], KeyBindingScope.Focused, null, this)) == true;
e.Handled = InvokeCommand<KeyBinding> (Command.HotKey, new ([Command.HotKey], this, this)) == true;
}

View File

@@ -36,7 +36,7 @@ public class Label : View, IDesignable
{
if (!CanFocus)
{
e.Handled = InvokeCommand<KeyBinding> (Command.HotKey, new ([Command.HotKey], KeyBindingScope.HotKey, this, this)) == true;
e.Handled = InvokeCommand<KeyBinding> (Command.HotKey, new ([Command.HotKey], this, data: this)) == true;
}
}

View File

@@ -171,8 +171,8 @@ public class ListView : View, IDesignable
KeyBindings.Add (Key.Space.WithShift, [Command.Select, Command.Down]);
// Use the form of Add that lets us pass context to the handler
KeyBindings.Add (Key.A.WithCtrl, new KeyBinding ([Command.SelectAll], KeyBindingScope.Focused, true));
KeyBindings.Add (Key.U.WithCtrl, new KeyBinding ([Command.SelectAll], KeyBindingScope.Focused, false));
KeyBindings.Add (Key.A.WithCtrl, new KeyBinding ([Command.SelectAll], true));
KeyBindings.Add (Key.U.WithCtrl, new KeyBinding ([Command.SelectAll], false));
}
/// <inheritdoc />

View File

@@ -130,7 +130,7 @@ internal sealed class Menu : View
if (menuItem.ShortcutKey != Key.Empty)
{
KeyBinding keyBinding = new ([Command.Select], KeyBindingScope.HotKey, menuItem);
KeyBinding keyBinding = new ([Command.Select], this, data: menuItem);
// Remove an existent ShortcutKey
menuItem._menuBar.KeyBindings.Remove (menuItem.ShortcutKey!);
@@ -251,7 +251,7 @@ internal sealed class Menu : View
{
// We didn't handle the key, pass it on to host
bool? handled = null;
return _host.InvokeCommandsBoundToHotKeyOnSubviews (keyEvent, ref handled, true ) == true;
return _host.InvokeCommandsBoundToHotKeyOnSubviews (keyEvent, ref handled, true) == true;
}
protected override bool OnMouseEvent (MouseEventArgs me)
@@ -480,14 +480,14 @@ internal sealed class Menu : View
foreach (MenuItem menuItem in menuItems)
{
KeyBinding keyBinding = new ([Command.Toggle], KeyBindingScope.HotKey, menuItem);
KeyBinding keyBinding = new ([Command.Toggle], this, data: menuItem);
if (menuItem.HotKey != Key.Empty)
{
KeyBindings.Remove (menuItem.HotKey!);
KeyBindings.Add (menuItem.HotKey!, keyBinding);
KeyBindings.Remove (menuItem.HotKey!.WithAlt);
KeyBindings.Add (menuItem.HotKey.WithAlt, keyBinding);
HotKeyBindings.Remove (menuItem.HotKey!);
HotKeyBindings.Add (menuItem.HotKey!, keyBinding);
HotKeyBindings.Remove (menuItem.HotKey!.WithAlt);
HotKeyBindings.Add (menuItem.HotKey.WithAlt, keyBinding);
}
}
}

View File

@@ -162,8 +162,8 @@ public class MenuBar : View, IDesignable
KeyBindings.Add (Key.Esc, Command.Cancel);
KeyBindings.Add (Key.CursorDown, Command.Accept);
KeyBinding keyBinding = new ([Command.Toggle], KeyBindingScope.HotKey, -1); // -1 indicates Key was used
KeyBindings.Add (Key, keyBinding);
KeyBinding keyBinding = new ([Command.Toggle], this, data: -1); // -1 indicates Key was used
HotKeyBindings.Add (Key, keyBinding);
// TODO: Why do we have two keybindings for opening the menu? Ctrl-Space and Key?
KeyBindings.Add (Key.Space.WithCtrl, keyBinding);
@@ -204,21 +204,21 @@ public class MenuBar : View, IDesignable
if (menuBarItem.HotKey != Key.Empty)
{
KeyBindings.Remove (menuBarItem.HotKey!);
KeyBinding keyBinding = new ([Command.Toggle], KeyBindingScope.Focused, menuBarItem);
KeyBindings.Add (menuBarItem.HotKey!, keyBinding);
KeyBindings.Remove (menuBarItem.HotKey!.WithAlt);
keyBinding = new ([Command.Toggle], KeyBindingScope.HotKey, menuBarItem);
KeyBindings.Add (menuBarItem.HotKey.WithAlt, keyBinding);
HotKeyBindings.Remove (menuBarItem.HotKey!);
KeyBinding keyBinding = new ([Command.Toggle], this, menuBarItem);
HotKeyBindings.Add (menuBarItem.HotKey!, keyBinding);
HotKeyBindings.Remove (menuBarItem.HotKey!.WithAlt);
keyBinding = new ([Command.Toggle], this, data: menuBarItem);
HotKeyBindings.Add (menuBarItem.HotKey.WithAlt, keyBinding);
}
if (menuBarItem.ShortcutKey != Key.Empty)
{
// Technically this will never run because MenuBarItems don't have shortcuts
// unless the IsTopLevel is true
KeyBindings.Remove (menuBarItem.ShortcutKey!);
KeyBinding keyBinding = new ([Command.Select], KeyBindingScope.HotKey, menuBarItem);
KeyBindings.Add (menuBarItem.ShortcutKey!, keyBinding);
HotKeyBindings.Remove (menuBarItem.ShortcutKey!);
KeyBinding keyBinding = new ([Command.Select], this, data: menuBarItem);
HotKeyBindings.Add (menuBarItem.ShortcutKey!, keyBinding);
}
menuBarItem.AddShortcutKeyBindings (this);
@@ -1310,9 +1310,9 @@ public class MenuBar : View, IDesignable
return;
}
KeyBindings.Remove (_key);
KeyBinding keyBinding = new ([Command.Toggle], KeyBindingScope.HotKey, -1); // -1 indicates Key was used
KeyBindings.Add (value, keyBinding);
HotKeyBindings.Remove (_key);
KeyBinding keyBinding = new ([Command.Toggle], this, data: -1); // -1 indicates Key was used
HotKeyBindings.Add (value, keyBinding);
_key = value;
}
}

View File

@@ -239,7 +239,7 @@ public class MenuBarItem : MenuItem
if (_menuBar.Menus [index].HotKey != Key.Empty)
{
// Remove an existent HotKey
_menuBar.KeyBindings.Remove (HotKey!.WithAlt);
_menuBar.HotKeyBindings.Remove (HotKey!.WithAlt);
}
_menuBar.Menus [index] = null!;

View File

@@ -149,11 +149,11 @@ public class MenuItem
if (AllowNullChecked)
{
Checked = previousChecked switch
{
null => true,
true => false,
false => null
};
{
null => true,
true => false,
false => null
};
}
else
{
@@ -242,9 +242,9 @@ public class MenuItem
}
else if (nextIsHot)
{
HotKey = char.ToLower (x);
HotKey = char.ToLower (x);
return;
return;
}
}
@@ -294,7 +294,7 @@ public class MenuItem
if (ShortcutKey != Key.Empty)
{
KeyBinding keyBinding = new ([Command.Select], KeyBindingScope.HotKey, this);
KeyBinding keyBinding = new ([Command.Select], null, data: this);
// Remove an existent ShortcutKey
_menuBar.KeyBindings.Remove (ShortcutKey!);
_menuBar.KeyBindings.Add (ShortcutKey!, keyBinding);
@@ -314,7 +314,7 @@ public class MenuItem
if (index > -1)
{
_menuBar.KeyBindings.Remove (oldKey.WithAlt);
_menuBar.HotKeyBindings.Remove (oldKey.WithAlt);
}
}
@@ -324,9 +324,9 @@ public class MenuItem
if (index > -1)
{
_menuBar.KeyBindings.Remove (HotKey!.WithAlt);
KeyBinding keyBinding = new ([Command.Toggle], KeyBindingScope.HotKey, this);
_menuBar.KeyBindings.Add (HotKey.WithAlt, keyBinding);
_menuBar.HotKeyBindings.Remove (HotKey!.WithAlt);
KeyBinding keyBinding = new ([Command.Toggle], null, data: this);
_menuBar.HotKeyBindings.Add (HotKey.WithAlt, keyBinding);
}
}
}

View File

@@ -248,7 +248,7 @@ public class RadioGroup : View, IDesignable, IOrientation
if (c > -1)
{
// Just like the user pressing the items' hotkey
e.Handled = InvokeCommand<KeyBinding> (Command.HotKey, new KeyBinding ([Command.HotKey], KeyBindingScope.HotKey, boundView: this, data: c)) == true;
e.Handled = InvokeCommand<KeyBinding> (Command.HotKey, new KeyBinding ([Command.HotKey], boundView: this, data: c)) == true;
}
}

View File

@@ -241,7 +241,7 @@ public class ScrollSlider : View, IOrientation, IDesignable
OnScrolled (distance);
Scrolled?.Invoke (this, new (in distance));
RaiseSelecting (new CommandContext<KeyBinding> (Command.Select, new KeyBinding ([Command.Select], KeyBindingScope.Focused, null, distance)));
RaiseSelecting (new CommandContext<KeyBinding> (Command.Select, new KeyBinding ([Command.Select], null, distance)));
}
/// <summary>

View File

@@ -69,7 +69,7 @@ public class Shortcut : View, IOrientation, IDesignable
/// <param name="helpText">The help text to display.</param>
public Shortcut (View targetView, Command command, string commandText, string? helpText = null)
: this (
targetView?.KeyBindings.GetKeyFromCommands (command)!,
targetView?.HotKeyBindings.GetKeyFromCommands (command)!,
commandText,
null,
helpText)
@@ -499,7 +499,7 @@ public class Shortcut : View, IOrientation, IDesignable
e.Context is CommandContext<MouseBinding>)
{
// Forward command to ourselves
InvokeCommand<KeyBinding> (Command.Select, new ([Command.Select], KeyBindingScope.Focused, null, this));
InvokeCommand<KeyBinding> (Command.Select, new ([Command.Select], null, this));
}
// BUGBUG: This prevents NumericUpDown on statusbar in HexEditor from working
@@ -618,7 +618,7 @@ public class Shortcut : View, IOrientation, IDesignable
private bool _bindKeyToApplication = false;
/// <summary>
/// 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"/>.
/// Gets or sets whether <see cref="Key"/> is bound to <see cref="Command"/> via <see cref="View.HotKeyBindings"/> or <see cref="Application.KeyBindings"/>.
/// </summary>
public bool BindKeyToApplication
{
@@ -636,7 +636,7 @@ public class Shortcut : View, IOrientation, IDesignable
}
else
{
KeyBindings.Remove (Key);
HotKeyBindings.Remove (Key);
}
_bindKeyToApplication = value;
@@ -716,11 +716,11 @@ public class Shortcut : View, IOrientation, IDesignable
{
if (oldKey != Key.Empty)
{
KeyBindings.Remove (oldKey);
HotKeyBindings.Remove (oldKey);
}
KeyBindings.Remove (Key);
KeyBindings.Add (Key, KeyBindingScope.HotKey, Command.HotKey);
HotKeyBindings.Remove (Key);
HotKeyBindings.Add (Key, Command.HotKey);
}
}
}

View File

@@ -699,7 +699,7 @@ public class Editor : Scenario
Height = 11;
Arrangement = ViewArrangement.Movable;
KeyBindings.Add (Key.Esc, KeyBindingScope.Focused, Command.Cancel);
KeyBindings.Add (Key.Esc, Command.Cancel);
AddCommand (Command.Cancel, () =>
{
Visible = false;

View File

@@ -104,7 +104,7 @@ public sealed class KeyBindings : Scenario
foreach (var subview in appWindow.Subviews)
{
foreach (var binding in subview.KeyBindings.Bindings.Where (b => b.Value.Scope == KeyBindingScope.HotKey))
foreach (var binding in subview.HotKeyBindings.Bindings)
{
hotkeyBindings.Add ($"{binding.Key} -> {subview.GetType ().Name} - {binding.Value.Commands [0]}");
}
@@ -149,7 +149,7 @@ public sealed class KeyBindings : Scenario
_focusedBindingsListView.Title = $"_Focused ({focused?.GetType ().Name}) Bindings";
_focusedBindings.Clear();
foreach (var binding in focused?.KeyBindings!.Bindings.Where (b => b.Value.Scope == KeyBindingScope.Focused)!)
foreach (var binding in focused?.KeyBindings!.Bindings)
{
_focusedBindings.Add ($"{binding.Key} -> {binding.Value.Commands [0]}");
}
@@ -180,7 +180,7 @@ public class KeyBindingsDemo : View
return true;
});
KeyBindings.Add (Key.F2, KeyBindingScope.Focused, Command.Save);
KeyBindings.Add (Key.F2, Command.Save);
KeyBindings.Add (Key.F3, Command.New); // same as specifying KeyBindingScope.Focused
Application.KeyBindings.Add (Key.F4, this, Command.New);
@@ -190,7 +190,7 @@ public class KeyBindingsDemo : View
{
return false;
}
MessageBox.Query ($"{keyCommandContext.Binding.Scope}", $"Key: {keyCommandContext.Binding.Key}\nCommand: {ctx.Command}", buttons: "Ok");
MessageBox.Query ($"{keyCommandContext.Binding}", $"Key: {keyCommandContext.Binding.Key}\nCommand: {ctx.Command}", buttons: "Ok");
Application.RequestStop ();
return true;
});

View File

@@ -11,7 +11,7 @@ public class KeyBindingsTests ()
{
var keyBindings = new KeyBindings (new View ());
List<Command> commands = new ();
Assert.Throws<ArgumentException> (() => keyBindings.Add (Key.Empty, KeyBindingScope.HotKey, Command.Accept));
Assert.Throws<ArgumentException> (() => keyBindings.Add (Key.Empty, Command.Accept));
}
[Fact]
@@ -34,7 +34,7 @@ public class KeyBindingsTests ()
[Fact]
public void Add_No_Commands_Throws ()
{
var keyBindings = new KeyBindings (new());
var keyBindings = new KeyBindings (new ());
List<Command> commands = new ();
Assert.Throws<ArgumentException> (() => keyBindings.Add (Key.A, commands.ToArray ()));
}
@@ -42,7 +42,7 @@ public class KeyBindingsTests ()
[Fact]
public void Add_Single_Adds ()
{
var keyBindings = new KeyBindings (new());
var keyBindings = new KeyBindings (new ());
keyBindings.Add (Key.A, Command.HotKey);
Command [] resultCommands = keyBindings.GetCommands (Key.A);
Assert.Contains (Command.HotKey, resultCommands);
@@ -58,29 +58,29 @@ public class KeyBindingsTests ()
public void Add_With_Throws_If_Exists ()
{
var keyBindings = new KeyBindings (new View ());
keyBindings.Add (Key.A, KeyBindingScope.HotKey, Command.HotKey);
Assert.Throws<InvalidOperationException> (() => keyBindings.Add (Key.A, KeyBindingScope.HotKey, Command.Accept));
keyBindings.Add (Key.A, Command.HotKey);
Assert.Throws<InvalidOperationException> (() => keyBindings.Add (Key.A, Command.Accept));
Command [] resultCommands = keyBindings.GetCommands (Key.A);
Assert.Contains (Command.HotKey, resultCommands);
keyBindings = new (new View ());
keyBindings.Add (Key.A, KeyBindingScope.Focused, Command.HotKey);
Assert.Throws<InvalidOperationException> (() => keyBindings.Add (Key.A, KeyBindingScope.Focused, Command.Accept));
keyBindings.Add (Key.A, Command.HotKey);
Assert.Throws<InvalidOperationException> (() => keyBindings.Add (Key.A, Command.Accept));
resultCommands = keyBindings.GetCommands (Key.A);
Assert.Contains (Command.HotKey, resultCommands);
keyBindings = new (new View ());
keyBindings.Add (Key.A, KeyBindingScope.HotKey, Command.HotKey);
Assert.Throws<InvalidOperationException> (() => keyBindings.Add (Key.A, KeyBindingScope.HotKey, Command.Accept));
keyBindings.Add (Key.A, Command.HotKey);
Assert.Throws<InvalidOperationException> (() => keyBindings.Add (Key.A, Command.Accept));
resultCommands = keyBindings.GetCommands (Key.A);
Assert.Contains (Command.HotKey, resultCommands);
keyBindings = new (new View ());
keyBindings.Add (Key.A, new KeyBinding (new [] { Command.HotKey }, KeyBindingScope.HotKey));
Assert.Throws<InvalidOperationException> (() => keyBindings.Add (Key.A, new KeyBinding (new [] { Command.Accept }, KeyBindingScope.HotKey)));
keyBindings.Add (Key.A, new KeyBinding (new [] { Command.HotKey }));
Assert.Throws<InvalidOperationException> (() => keyBindings.Add (Key.A, new KeyBinding (new [] { Command.Accept })));
resultCommands = keyBindings.GetCommands (Key.A);
Assert.Contains (Command.HotKey, resultCommands);
@@ -102,7 +102,7 @@ public class KeyBindingsTests ()
[Fact]
public void Defaults ()
{
var keyBindings = new KeyBindings (new());
var keyBindings = new KeyBindings (new ());
Assert.Empty (keyBindings.Bindings);
Assert.Null (keyBindings.GetKeyFromCommands (Command.Accept));
Assert.NotNull (keyBindings.BoundView);
@@ -111,7 +111,7 @@ public class KeyBindingsTests ()
[Fact]
public void Get_Binding_Not_Found_Throws ()
{
var keyBindings = new KeyBindings (new());
var keyBindings = new KeyBindings (new ());
Assert.Throws<InvalidOperationException> (() => keyBindings.Get (Key.A));
Assert.Throws<InvalidOperationException> (() => keyBindings.Get (Key.B));
}
@@ -128,7 +128,7 @@ public class KeyBindingsTests ()
[Fact]
public void GetCommands_WithCommands_ReturnsCommands ()
{
var keyBindings = new KeyBindings (new());
var keyBindings = new KeyBindings (new ());
keyBindings.Add (Key.A, Command.HotKey);
Command [] resultCommands = keyBindings.GetCommands (Key.A);
Assert.Contains (Command.HotKey, resultCommands);
@@ -139,8 +139,8 @@ public class KeyBindingsTests ()
{
var keyBindings = new KeyBindings (new ());
Command [] commands = { Command.Right, Command.Left };
keyBindings.Add (Key.A,commands);
keyBindings.Add (Key.B,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);
@@ -152,7 +152,7 @@ public class KeyBindingsTests ()
[Fact]
public void GetCommands_WithMultipleCommands_ReturnsCommands ()
{
var keyBindings = new KeyBindings (new());
var keyBindings = new KeyBindings (new ());
Command [] commands = { Command.Right, Command.Left };
keyBindings.Add (Key.A, commands);
Command [] resultCommands = keyBindings.GetCommands (Key.A);
@@ -163,12 +163,12 @@ public class KeyBindingsTests ()
[Fact]
public void GetKeyFromCommands_MultipleCommands ()
{
var keyBindings = new KeyBindings (new());
var keyBindings = new KeyBindings (new ());
Command [] commands1 = { Command.Right, Command.Left };
keyBindings.Add (Key.A, commands1);
Command [] commands2 = { Command.Up, Command.Down };
keyBindings.Add (Key.B,commands2);
keyBindings.Add (Key.B, commands2);
Key key = keyBindings.GetKeyFromCommands (commands1);
Assert.Equal (Key.A, key);
@@ -180,7 +180,7 @@ public class KeyBindingsTests ()
[Fact]
public void GetKeyFromCommands_OneCommand ()
{
var keyBindings = new KeyBindings (new());
var keyBindings = new KeyBindings (new ());
keyBindings.Add (Key.A, Command.Right);
Key key = keyBindings.GetKeyFromCommands (Command.Right);
@@ -191,14 +191,14 @@ public class KeyBindingsTests ()
[Fact]
public void GetKeyFromCommands_Unknown_Returns_Key_Empty ()
{
var keyBindings = new KeyBindings(new());
var keyBindings = new KeyBindings (new ());
Assert.Null (keyBindings.GetKeyFromCommands (Command.Accept));
}
[Fact]
public void GetKeyFromCommands_WithCommands_ReturnsKey ()
{
var keyBindings = new KeyBindings (new());
var keyBindings = new KeyBindings (new ());
keyBindings.Add (Key.A, Command.HotKey);
Key resultKey = keyBindings.GetKeyFromCommands (Command.HotKey);
Assert.Equal (Key.A, resultKey);
@@ -208,10 +208,10 @@ public class KeyBindingsTests ()
public void ReplaceKey_Replaces ()
{
var keyBindings = new KeyBindings (new ());
keyBindings.Add (Key.A, KeyBindingScope.Focused, Command.HotKey);
keyBindings.Add (Key.B, KeyBindingScope.Focused, Command.HotKey);
keyBindings.Add (Key.C, KeyBindingScope.Focused, Command.HotKey);
keyBindings.Add (Key.D, KeyBindingScope.Focused, Command.HotKey);
keyBindings.Add (Key.A, Command.HotKey);
keyBindings.Add (Key.B, Command.HotKey);
keyBindings.Add (Key.C, Command.HotKey);
keyBindings.Add (Key.D, Command.HotKey);
keyBindings.ReplaceKey (Key.A, Key.E);
Assert.Empty (keyBindings.GetCommands (Key.A));
@@ -234,8 +234,8 @@ public class KeyBindingsTests ()
public void ReplaceKey_Replaces_Leaves_Old_Binding ()
{
var keyBindings = new KeyBindings (new ());
keyBindings.Add (Key.A, KeyBindingScope.Focused, Command.Accept);
keyBindings.Add (Key.B, KeyBindingScope.Focused, Command.HotKey);
keyBindings.Add (Key.A, Command.Accept);
keyBindings.Add (Key.B, Command.HotKey);
keyBindings.ReplaceKey (keyBindings.GetKeyFromCommands (Command.Accept), Key.C);
Assert.Empty (keyBindings.GetCommands (Key.A));
@@ -245,34 +245,33 @@ public class KeyBindingsTests ()
[Fact]
public void ReplaceKey_Throws_If_DoesNotContain_Old ()
{
var keyBindings = new KeyBindings(new());
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(new());
keyBindings.Add (Key.A,Command.HotKey);
var keyBindings = new KeyBindings (new ());
keyBindings.Add (Key.A, Command.HotKey);
Assert.Throws<InvalidOperationException> (() => keyBindings.ReplaceKey (Key.A, Key.Empty));
}
// Add with scope does the right things
[Theory]
[InlineData (KeyBindingScope.Focused)]
[InlineData (KeyBindingScope.HotKey)]
public void Scope_Add_Adds (KeyBindingScope scope)
{
var keyBindings = new KeyBindings (new ());
Command [] commands = { Command.Right, Command.Left };
var key = new Key (Key.A);
keyBindings.Add (Key.A, scope, commands);
keyBindings.Add (Key.A, commands);
KeyBinding binding = keyBindings.Get (key);
Assert.Contains (Command.Right, binding.Commands);
Assert.Contains (Command.Left, binding.Commands);
binding = keyBindings.Get (key, scope);
binding = keyBindings.Get (key);
Assert.Contains (Command.Right, binding.Commands);
Assert.Contains (Command.Left, binding.Commands);
@@ -283,43 +282,41 @@ public class KeyBindingsTests ()
[Theory]
[InlineData (KeyBindingScope.Focused)]
[InlineData (KeyBindingScope.HotKey)]
public void Scope_Get_Filters (KeyBindingScope scope)
{
var keyBindings = new KeyBindings (new ());
Command [] commands = { Command.Right, Command.Left };
var key = new Key (Key.A);
keyBindings.Add (key, scope, commands);
keyBindings.Add (key, commands);
KeyBinding binding = keyBindings.Get (key);
Assert.Contains (Command.Right, binding.Commands);
Assert.Contains (Command.Left, binding.Commands);
binding = keyBindings.Get (key, scope);
binding = keyBindings.Get (key);
Assert.Contains (Command.Right, binding.Commands);
Assert.Contains (Command.Left, binding.Commands);
}
[Theory]
[InlineData (KeyBindingScope.Focused)]
[InlineData (KeyBindingScope.HotKey)]
public void Scope_TryGet_Filters (KeyBindingScope scope)
{
var keyBindings = new KeyBindings (new ());
Command [] commands = { Command.Right, Command.Left };
var key = new Key (Key.A);
keyBindings.Add (key, scope, commands);
keyBindings.Add (key, commands);
bool success = keyBindings.TryGet (key, out KeyBinding binding);
Assert.Contains (Command.Right, binding.Commands);
Assert.Contains (Command.Left, binding.Commands);
success = keyBindings.TryGet (key, scope, out binding);
success = keyBindings.TryGet (key, out binding);
Assert.Contains (Command.Right, binding.Commands);
Assert.Contains (Command.Left, binding.Commands);
// negative test
success = keyBindings.TryGet (key, 0, out binding);
success = keyBindings.TryGet (key, out binding);
Assert.False (success);
Command [] resultCommands = keyBindings.GetCommands (key);
@@ -331,8 +328,8 @@ public class KeyBindingsTests ()
[Fact]
public void TryGet_Succeeds ()
{
var keyBindings = new KeyBindings(new());
keyBindings.Add (Key.Q.WithCtrl,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); ;
@@ -344,7 +341,7 @@ public class KeyBindingsTests ()
[Fact]
public void TryGet_Unknown_ReturnsFalse ()
{
var keyBindings = new KeyBindings(new());
var keyBindings = new KeyBindings (new ());
bool result = keyBindings.TryGet (Key.A, out KeyBinding _);
Assert.False (result);
}
@@ -352,8 +349,8 @@ public class KeyBindingsTests ()
[Fact]
public void TryGet_WithCommands_ReturnsTrue ()
{
var keyBindings = new KeyBindings(new());
keyBindings.Add (Key.A,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);
@@ -362,8 +359,8 @@ public class KeyBindingsTests ()
[Fact]
public void ReplaceCommands_Replaces ()
{
var keyBindings = new KeyBindings(new());
keyBindings.Add (Key.A,Command.Accept);
var keyBindings = new KeyBindings (new ());
keyBindings.Add (Key.A, Command.Accept);
keyBindings.ReplaceCommands (Key.A, Command.Refresh);

View File

@@ -108,7 +108,7 @@ public class HotKeyTests
public void NewKeyDownEvent_Honors_HotKey_KeyBindings_SuperView ()
{
var view = new View ();
view.KeyBindings.Add (Key.A, KeyBindingScope.HotKey, Command.HotKey);
view.HotKeyBindings.Add (Key.A, Command.HotKey);
bool hotKeyInvoked = false;
view.HandlingHotKey += (s, e) => { hotKeyInvoked = true; };

View File

@@ -139,7 +139,7 @@ public class ViewKeyBindingTests (ITestOutputHelper output)
Application.KeyBindings.Add (Key.A, this, Command.Save);
HotKey = KeyCode.H;
KeyBindings.Add (Key.F, KeyBindingScope.Focused, Command.Left);
KeyBindings.Add (Key.F, Command.Left);
}
public bool ApplicationCommand { get; set; }