|
@@ -1,13 +1,12 @@
|
|
#nullable enable
|
|
#nullable enable
|
|
-using System.ComponentModel;
|
|
|
|
using System.Diagnostics;
|
|
using System.Diagnostics;
|
|
|
|
|
|
namespace Terminal.Gui;
|
|
namespace Terminal.Gui;
|
|
|
|
|
|
-public partial class View // Keyboard APIs
|
|
|
|
|
|
+public partial class View // Keyboard APIs
|
|
{
|
|
{
|
|
/// <summary>
|
|
/// <summary>
|
|
- /// Helper to configure all things keyboard related for a View. Called from the View constructor.
|
|
|
|
|
|
+ /// Helper to configure all things keyboard related for a View. Called from the View constructor.
|
|
/// </summary>
|
|
/// </summary>
|
|
private void SetupKeyboard ()
|
|
private void SetupKeyboard ()
|
|
{
|
|
{
|
|
@@ -23,17 +22,14 @@ public partial class View // Keyboard APIs
|
|
}
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// <summary>
|
|
- /// Helper to dispose all things keyboard related for a View. Called from the View Dispose method.
|
|
|
|
|
|
+ /// Helper to dispose all things keyboard related for a View. Called from the View Dispose method.
|
|
/// </summary>
|
|
/// </summary>
|
|
- private void DisposeKeyboard ()
|
|
|
|
- {
|
|
|
|
- TitleTextFormatter.HotKeyChanged -= TitleTextFormatter_HotKeyChanged;
|
|
|
|
- }
|
|
|
|
|
|
+ private void DisposeKeyboard () { TitleTextFormatter.HotKeyChanged -= TitleTextFormatter_HotKeyChanged; }
|
|
|
|
|
|
#region HotKey Support
|
|
#region HotKey Support
|
|
|
|
|
|
/// <summary>
|
|
/// <summary>
|
|
- /// Called when the HotKey command (<see cref="Command.HotKey"/>) is invoked. Causes this view to be focused.
|
|
|
|
|
|
+ /// Called when the HotKey command (<see cref="Command.HotKey"/>) is invoked. Causes this view to be focused.
|
|
/// </summary>
|
|
/// </summary>
|
|
/// <returns>If <see langword="true"/> the command was canceled.</returns>
|
|
/// <returns>If <see langword="true"/> the command was canceled.</returns>
|
|
private bool? OnHotKey ()
|
|
private bool? OnHotKey ()
|
|
@@ -41,6 +37,7 @@ public partial class View // Keyboard APIs
|
|
if (CanFocus)
|
|
if (CanFocus)
|
|
{
|
|
{
|
|
SetFocus ();
|
|
SetFocus ();
|
|
|
|
+
|
|
return true;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -118,7 +115,8 @@ public partial class View // Keyboard APIs
|
|
/// <remarks>
|
|
/// <remarks>
|
|
/// <para>
|
|
/// <para>
|
|
/// By default, key bindings are added for both the base key (e.g. <see cref="Key.D3"/>) and the Alt-shifted key
|
|
/// By default, key bindings are added for both the base key (e.g. <see cref="Key.D3"/>) and the Alt-shifted key
|
|
- /// (e.g. <c>Key.D3.WithAlt</c>) This behavior can be overriden by overriding <see cref="AddKeyBindingsForHotKey"/>.
|
|
|
|
|
|
+ /// (e.g. <c>Key.D3.WithAlt</c>) This behavior can be overriden by overriding <see cref="AddKeyBindingsForHotKey"/>
|
|
|
|
+ /// .
|
|
/// </para>
|
|
/// </para>
|
|
/// <para>
|
|
/// <para>
|
|
/// By default, when <paramref name="hotKey"/> is <see cref="Key.A"/> through <see cref="Key.Z"/> key bindings
|
|
/// By default, when <paramref name="hotKey"/> is <see cref="Key.A"/> through <see cref="Key.Z"/> key bindings
|
|
@@ -196,6 +194,7 @@ public partial class View // Keyboard APIs
|
|
if (newKey != Key.Empty)
|
|
if (newKey != Key.Empty)
|
|
{
|
|
{
|
|
KeyBinding keyBinding = new ([Command.HotKey], KeyBindingScope.HotKey, context);
|
|
KeyBinding keyBinding = new ([Command.HotKey], KeyBindingScope.HotKey, context);
|
|
|
|
+
|
|
// Add the base and Alt key
|
|
// Add the base and Alt key
|
|
KeyBindings.Remove (newKey);
|
|
KeyBindings.Remove (newKey);
|
|
KeyBindings.Add (newKey, keyBinding);
|
|
KeyBindings.Add (newKey, keyBinding);
|
|
@@ -221,10 +220,7 @@ public partial class View // Keyboard APIs
|
|
/// </summary>
|
|
/// </summary>
|
|
public virtual Rune HotKeySpecifier
|
|
public virtual Rune HotKeySpecifier
|
|
{
|
|
{
|
|
- get
|
|
|
|
- {
|
|
|
|
- return TitleTextFormatter.HotKeySpecifier;
|
|
|
|
- }
|
|
|
|
|
|
+ get => TitleTextFormatter.HotKeySpecifier;
|
|
set
|
|
set
|
|
{
|
|
{
|
|
TitleTextFormatter.HotKeySpecifier = TextFormatter.HotKeySpecifier = value;
|
|
TitleTextFormatter.HotKeySpecifier = TextFormatter.HotKeySpecifier = value;
|
|
@@ -536,11 +532,11 @@ public partial class View // Keyboard APIs
|
|
if (KeyBindings.TryGet (keyEvent, scope, out KeyBinding kb))
|
|
if (KeyBindings.TryGet (keyEvent, scope, out KeyBinding kb))
|
|
{
|
|
{
|
|
InvokingKeyBindings?.Invoke (this, keyEvent);
|
|
InvokingKeyBindings?.Invoke (this, keyEvent);
|
|
|
|
+
|
|
if (keyEvent.Handled)
|
|
if (keyEvent.Handled)
|
|
{
|
|
{
|
|
return true;
|
|
return true;
|
|
}
|
|
}
|
|
-
|
|
|
|
}
|
|
}
|
|
|
|
|
|
// * If no key binding was found, `InvokeKeyBindings` returns `null`.
|
|
// * If no key binding was found, `InvokeKeyBindings` returns `null`.
|
|
@@ -615,6 +611,7 @@ public partial class View // Keyboard APIs
|
|
{
|
|
{
|
|
continue;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
+
|
|
if (subview.KeyBindings.TryGet (keyEvent, scope, out KeyBinding binding))
|
|
if (subview.KeyBindings.TryGet (keyEvent, scope, out KeyBinding binding))
|
|
{
|
|
{
|
|
if (binding.Scope == KeyBindingScope.Focused && !subview.HasFocus)
|
|
if (binding.Scope == KeyBindingScope.Focused && !subview.HasFocus)
|
|
@@ -632,6 +629,7 @@ public partial class View // Keyboard APIs
|
|
if (subViewHandled is { })
|
|
if (subViewHandled is { })
|
|
{
|
|
{
|
|
handled = subViewHandled;
|
|
handled = subViewHandled;
|
|
|
|
+
|
|
if ((bool)subViewHandled)
|
|
if ((bool)subViewHandled)
|
|
{
|
|
{
|
|
return true;
|
|
return true;
|
|
@@ -640,6 +638,7 @@ public partial class View // Keyboard APIs
|
|
}
|
|
}
|
|
|
|
|
|
bool recurse = subview.ProcessSubViewKeyBindings (keyEvent, scope, ref handled, invoke);
|
|
bool recurse = subview.ProcessSubViewKeyBindings (keyEvent, scope, ref handled, invoke);
|
|
|
|
+
|
|
if (recurse || (handled is { } && (bool)handled))
|
|
if (recurse || (handled is { } && (bool)handled))
|
|
{
|
|
{
|
|
return true;
|
|
return true;
|
|
@@ -653,7 +652,7 @@ public partial class View // Keyboard APIs
|
|
// TODO: A better approach would be to have Application hold a list of bound Hotkeys, similar to
|
|
// TODO: A better approach would be to have Application hold a list of bound Hotkeys, similar to
|
|
// TODO: how Application holds a list of Application Scoped key bindings and then check that list.
|
|
// TODO: how Application holds a list of Application Scoped key bindings and then check that list.
|
|
/// <summary>
|
|
/// <summary>
|
|
- /// Returns true if Key is bound in this view hierarchy. For debugging
|
|
|
|
|
|
+ /// Returns true if Key is bound in this view hierarchy. For debugging
|
|
/// </summary>
|
|
/// </summary>
|
|
/// <param name="key">The key to test.</param>
|
|
/// <param name="key">The key to test.</param>
|
|
/// <param name="boundView">Returns the view the key is bound to.</param>
|
|
/// <param name="boundView">Returns the view the key is bound to.</param>
|
|
@@ -668,6 +667,7 @@ public partial class View // Keyboard APIs
|
|
if (subview.KeyBindings.TryGet (key, KeyBindingScope.HotKey, out _))
|
|
if (subview.KeyBindings.TryGet (key, KeyBindingScope.HotKey, out _))
|
|
{
|
|
{
|
|
boundView = subview;
|
|
boundView = subview;
|
|
|
|
+
|
|
return true;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -675,8 +675,8 @@ public partial class View // Keyboard APIs
|
|
{
|
|
{
|
|
return true;
|
|
return true;
|
|
}
|
|
}
|
|
-
|
|
|
|
}
|
|
}
|
|
|
|
+
|
|
return false;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -714,7 +714,7 @@ public partial class View // Keyboard APIs
|
|
//var boundView = views [0];
|
|
//var boundView = views [0];
|
|
//var commandBinding = boundView.KeyBindings.Get (key);
|
|
//var commandBinding = boundView.KeyBindings.Get (key);
|
|
Debug.WriteLine (
|
|
Debug.WriteLine (
|
|
- $"WARNING: InvokeKeyBindings ({key}) - An Application scope binding exists for this key. The registered view will not invoke Command.");//{commandBinding.Commands [0]}: {boundView}.");
|
|
|
|
|
|
+ $"WARNING: InvokeKeyBindings ({key}) - An Application scope binding exists for this key. The registered view will not invoke Command."); //{commandBinding.Commands [0]}: {boundView}.");
|
|
}
|
|
}
|
|
|
|
|
|
// TODO: This is a "prototype" debug check. It may be too annoying vs. useful.
|
|
// TODO: This is a "prototype" debug check. It may be too annoying vs. useful.
|
|
@@ -727,7 +727,6 @@ public partial class View // Keyboard APIs
|
|
|
|
|
|
#endif
|
|
#endif
|
|
|
|
|
|
-
|
|
|
|
foreach (Command command in binding.Commands)
|
|
foreach (Command command in binding.Commands)
|
|
{
|
|
{
|
|
if (!CommandImplementations.ContainsKey (command))
|
|
if (!CommandImplementations.ContainsKey (command))
|
|
@@ -804,6 +803,7 @@ public partial class View // Keyboard APIs
|
|
if (CommandImplementations.TryGetValue (command, out Func<CommandContext, bool?>? implementation))
|
|
if (CommandImplementations.TryGetValue (command, out Func<CommandContext, bool?>? implementation))
|
|
{
|
|
{
|
|
var context = new CommandContext (command, key, keyBinding); // Create the context here
|
|
var context = new CommandContext (command, key, keyBinding); // Create the context here
|
|
|
|
+
|
|
return implementation (context);
|
|
return implementation (context);
|
|
}
|
|
}
|
|
|
|
|
|
@@ -813,7 +813,7 @@ public partial class View // Keyboard APIs
|
|
/// <summary>
|
|
/// <summary>
|
|
/// <para>
|
|
/// <para>
|
|
/// Sets the function that will be invoked for a <see cref="Command"/>. Views should call
|
|
/// Sets the function that will be invoked for a <see cref="Command"/>. Views should call
|
|
- /// AddCommand for each command they support.
|
|
|
|
|
|
+ /// AddCommand for each command they support.
|
|
/// </para>
|
|
/// </para>
|
|
/// <para>
|
|
/// <para>
|
|
/// If AddCommand has already been called for <paramref name="command"/> <paramref name="f"/> will
|
|
/// If AddCommand has already been called for <paramref name="command"/> <paramref name="f"/> will
|
|
@@ -821,22 +821,20 @@ public partial class View // Keyboard APIs
|
|
/// </para>
|
|
/// </para>
|
|
/// </summary>
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// <remarks>
|
|
- /// <para>
|
|
|
|
- /// This version of AddCommand is for commands that require <see cref="CommandContext"/>. Use <see cref="AddCommand(Command,Func{System.Nullable{bool}})"/>
|
|
|
|
- /// in cases where the command does not require a <see cref="CommandContext"/>.
|
|
|
|
- /// </para>
|
|
|
|
|
|
+ /// <para>
|
|
|
|
+ /// This version of AddCommand is for commands that require <see cref="CommandContext"/>. Use
|
|
|
|
+ /// <see cref="AddCommand(Command,Func{System.Nullable{bool}})"/>
|
|
|
|
+ /// in cases where the command does not require a <see cref="CommandContext"/>.
|
|
|
|
+ /// </para>
|
|
/// </remarks>
|
|
/// </remarks>
|
|
/// <param name="command">The command.</param>
|
|
/// <param name="command">The command.</param>
|
|
/// <param name="f">The function.</param>
|
|
/// <param name="f">The function.</param>
|
|
- protected void AddCommand (Command command, Func<CommandContext, bool?> f)
|
|
|
|
- {
|
|
|
|
- CommandImplementations [command] = f;
|
|
|
|
- }
|
|
|
|
|
|
+ protected void AddCommand (Command command, Func<CommandContext, bool?> f) { CommandImplementations [command] = f; }
|
|
|
|
|
|
/// <summary>
|
|
/// <summary>
|
|
/// <para>
|
|
/// <para>
|
|
/// Sets the function that will be invoked for a <see cref="Command"/>. Views should call
|
|
/// Sets the function that will be invoked for a <see cref="Command"/>. Views should call
|
|
- /// AddCommand for each command they support.
|
|
|
|
|
|
+ /// AddCommand for each command they support.
|
|
/// </para>
|
|
/// </para>
|
|
/// <para>
|
|
/// <para>
|
|
/// If AddCommand has already been called for <paramref name="command"/> <paramref name="f"/> will
|
|
/// If AddCommand has already been called for <paramref name="command"/> <paramref name="f"/> will
|
|
@@ -844,17 +842,15 @@ public partial class View // Keyboard APIs
|
|
/// </para>
|
|
/// </para>
|
|
/// </summary>
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// <remarks>
|
|
- /// <para>
|
|
|
|
- /// This version of AddCommand is for commands that do not require a <see cref="CommandContext"/>.
|
|
|
|
- /// If the command requires context, use <see cref="AddCommand(Command,Func{CommandContext,System.Nullable{bool}})"/>
|
|
|
|
- /// </para>
|
|
|
|
|
|
+ /// <para>
|
|
|
|
+ /// This version of AddCommand is for commands that do not require a <see cref="CommandContext"/>.
|
|
|
|
+ /// If the command requires context, use
|
|
|
|
+ /// <see cref="AddCommand(Command,Func{CommandContext,System.Nullable{bool}})"/>
|
|
|
|
+ /// </para>
|
|
/// </remarks>
|
|
/// </remarks>
|
|
/// <param name="command">The command.</param>
|
|
/// <param name="command">The command.</param>
|
|
/// <param name="f">The function.</param>
|
|
/// <param name="f">The function.</param>
|
|
- protected void AddCommand (Command command, Func<bool?> f)
|
|
|
|
- {
|
|
|
|
- CommandImplementations [command] = ctx => f ();
|
|
|
|
- }
|
|
|
|
|
|
+ protected void AddCommand (Command command, Func<bool?> f) { CommandImplementations [command] = ctx => f (); }
|
|
|
|
|
|
/// <summary>Returns all commands that are supported by this <see cref="View"/>.</summary>
|
|
/// <summary>Returns all commands that are supported by this <see cref="View"/>.</summary>
|
|
/// <returns></returns>
|
|
/// <returns></returns>
|