浏览代码

Merge pull request #3795 from tig/v2_3793-CollectionNavigator-Use-OnKeyDown

Fixes #3793.  Simplifies and makes correct `KeyDown/Up` API, Fixes: `CollectionNavigator` should be called on `KeyDown`
Tig 9 月之前
父节点
当前提交
23eb14c6e2
共有 58 个文件被更改,包括 1519 次插入1737 次删除
  1. 2 2
      Terminal.Gui/Application/Application.Initialization.cs
  2. 75 191
      Terminal.Gui/Application/Application.Keyboard.cs
  3. 79 0
      Terminal.Gui/Application/Application.Navigation.cs
  4. 35 0
      Terminal.Gui/Application/Application.Run.cs
  5. 0 173
      Terminal.Gui/Input/ShortcutHelper.cs
  6. 2 4
      Terminal.Gui/View/Orientation/OrientationHelper.cs
  7. 141 182
      Terminal.Gui/View/View.Keyboard.cs
  8. 0 1
      Terminal.Gui/View/View.Layout.cs
  9. 1 1
      Terminal.Gui/Views/DateField.cs
  10. 4 4
      Terminal.Gui/Views/FileDialog.cs
  11. 1 1
      Terminal.Gui/Views/HexView.cs
  12. 55 3
      Terminal.Gui/Views/ListView.cs
  13. 4 12
      Terminal.Gui/Views/Menu/Menu.cs
  14. 2 2
      Terminal.Gui/Views/ScrollView.cs
  15. 10 8
      Terminal.Gui/Views/TableView/TableView.cs
  16. 12 29
      Terminal.Gui/Views/TextField.cs
  17. 1 1
      Terminal.Gui/Views/TextValidateField.cs
  18. 80 84
      Terminal.Gui/Views/TextView.cs
  19. 2 2
      Terminal.Gui/Views/TileView.cs
  20. 1 1
      Terminal.Gui/Views/TimeField.cs
  21. 4 7
      Terminal.Gui/Views/TreeView/TreeView.cs
  22. 2 2
      Terminal.Gui/Views/Wizard/Wizard.cs
  23. 92 70
      UICatalog/Scenarios/Keys.cs
  24. 2 2
      UICatalog/Scenarios/LineDrawing.cs
  25. 5 5
      UICatalog/Scenarios/Snake.cs
  26. 3 3
      UICatalog/Scenarios/VkeyPacketSimulator.cs
  27. 22 22
      UICatalog/UICatalog.cs
  28. 45 45
      UnitTests/Application/KeyboardTests.cs
  29. 5 5
      UnitTests/Dialogs/MessageBoxTests.cs
  30. 6 4
      UnitTests/FileServices/FileDialogTests.cs
  31. 5 5
      UnitTests/Input/ResponderTests.cs
  32. 1 1
      UnitTests/UICatalog/ScenarioTests.cs
  33. 11 7
      UnitTests/View/Keyboard/HotKeyTests.cs
  34. 329 0
      UnitTests/View/Keyboard/KeyboardEventTests.cs
  35. 39 37
      UnitTests/View/Keyboard/ViewKeyBindingTests.cs
  36. 0 502
      UnitTests/View/KeyboardEventTests.cs
  37. 1 1
      UnitTests/View/Navigation/CanFocusTests.cs
  38. 11 11
      UnitTests/View/Navigation/NavigationTests.cs
  39. 4 4
      UnitTests/View/ViewTests.cs
  40. 6 6
      UnitTests/Views/ButtonTests.cs
  41. 23 23
      UnitTests/Views/ColorPickerTests.cs
  42. 44 44
      UnitTests/Views/ComboBoxTests.cs
  43. 41 41
      UnitTests/Views/ContextMenuTests.cs
  44. 1 1
      UnitTests/Views/DatePickerTests.cs
  45. 2 2
      UnitTests/Views/LabelTests.cs
  46. 6 10
      UnitTests/Views/ListViewTests.cs
  47. 3 3
      UnitTests/Views/MenuBarTests.cs
  48. 33 33
      UnitTests/Views/RadioGroupTests.cs
  49. 65 65
      UnitTests/Views/ScrollViewTests.cs
  50. 5 5
      UnitTests/Views/ShortcutTests.cs
  51. 1 1
      UnitTests/Views/StatusBarTests.cs
  52. 15 15
      UnitTests/Views/TabViewTests.cs
  53. 11 11
      UnitTests/Views/TableViewTests.cs
  54. 3 3
      UnitTests/Views/TextFieldTests.cs
  55. 20 20
      UnitTests/Views/ToplevelTests.cs
  56. 1 1
      UnitTests/Views/TreeTableSourceTests.cs
  57. 126 0
      docfx/docs/events.md
  58. 19 19
      docfx/docs/keyboard.md

+ 2 - 2
Terminal.Gui/Application/Application.Initialization.cs

@@ -178,8 +178,8 @@ public static partial class Application // Initialization (Init/Shutdown)
     }
 
     private static void Driver_SizeChanged (object? sender, SizeChangedEventArgs e) { OnSizeChanging (e); }
-    private static void Driver_KeyDown (object? sender, Key e) { OnKeyDown (e); }
-    private static void Driver_KeyUp (object? sender, Key e) { OnKeyUp (e); }
+    private static void Driver_KeyDown (object? sender, Key e) { RaiseKeyDownEvent (e); }
+    private static void Driver_KeyUp (object? sender, Key e) { RaiseKeyUpEvent (e); }
     private static void Driver_MouseEvent (object? sender, MouseEvent e) { OnMouseEvent (e); }
 
     /// <summary>Gets of list of <see cref="ConsoleDriver"/> types that are available.</summary>

+ 75 - 191
Terminal.Gui/Application/Application.Keyboard.cs

@@ -3,94 +3,19 @@ namespace Terminal.Gui;
 
 public static partial class Application // Keyboard handling
 {
-    private static Key _nextTabGroupKey = Key.F6; // Resources/config.json overrrides
-    private static Key _nextTabKey = Key.Tab; // Resources/config.json overrrides
-    private static Key _prevTabGroupKey = Key.F6.WithShift; // Resources/config.json overrrides
-    private static Key _prevTabKey = Key.Tab.WithShift; // Resources/config.json overrrides
-    private static Key _quitKey = Key.Esc; // Resources/config.json overrrides
-    private static Key _arrangeKey = Key.F5.WithCtrl; // Resources/config.json overrrides
-
-    static Application () { AddApplicationKeyBindings (); }
-
-    /// <summary>Gets the key bindings for this view.</summary>
-    public static KeyBindings KeyBindings { get; internal set; } = new ();
-
-    /// <summary>
-    ///     Event fired when the user presses a key. Fired by <see cref="OnKeyDown"/>.
-    ///     <para>
-    ///         Set <see cref="Key.Handled"/> to <see langword="true"/> to indicate the key was handled and to prevent
-    ///         additional processing.
-    ///     </para>
-    /// </summary>
-    /// <remarks>
-    ///     All drivers support firing the <see cref="KeyDown"/> event. Some drivers (Curses) do not support firing the
-    ///     <see cref="KeyDown"/> and <see cref="KeyUp"/> events.
-    ///     <para>Fired after <see cref="KeyDown"/> and before <see cref="KeyUp"/>.</para>
-    /// </remarks>
-    public static event EventHandler<Key>? KeyDown;
-
     /// <summary>
-    ///     Event fired when the user releases a key. Fired by <see cref="OnKeyUp"/>.
-    ///     <para>
-    ///         Set <see cref="Key.Handled"/> to <see langword="true"/> to indicate the key was handled and to prevent
-    ///         additional processing.
-    ///     </para>
-    /// </summary>
-    /// <remarks>
-    ///     All drivers support firing the <see cref="KeyDown"/> event. Some drivers (Curses) do not support firing the
-    ///     <see cref="KeyDown"/> and <see cref="KeyUp"/> events.
-    ///     <para>Fired after <see cref="KeyDown"/>.</para>
-    /// </remarks>
-    public static event EventHandler<Key>? KeyUp;
-
-    /// <summary>Alternative key to navigate forwards through views. Ctrl+Tab is the primary key.</summary>
-    [SerializableConfigurationProperty (Scope = typeof (SettingsScope))]
-    public static Key NextTabGroupKey
-    {
-        get => _nextTabGroupKey;
-        set
-        {
-            if (_nextTabGroupKey != value)
-            {
-                ReplaceKey (_nextTabGroupKey, value);
-                _nextTabGroupKey = value;
-            }
-        }
-    }
-
-    /// <summary>Alternative key to navigate forwards through views. Ctrl+Tab is the primary key.</summary>
-    [SerializableConfigurationProperty (Scope = typeof (SettingsScope))]
-    public static Key NextTabKey
-    {
-        get => _nextTabKey;
-        set
-        {
-            if (_nextTabKey != value)
-            {
-                ReplaceKey (_nextTabKey, value);
-                _nextTabKey = value;
-            }
-        }
-    }
-
-    /// <summary>
-    ///     Called by the <see cref="ConsoleDriver"/> when the user presses a key. Fires the <see cref="KeyDown"/> event
-    ///     then calls <see cref="View.NewKeyDownEvent"/> on all top level views. Called after <see cref="OnKeyDown"/> and
-    ///     before <see cref="OnKeyUp"/>.
+    ///     Called when the user presses a key (by the <see cref="ConsoleDriver"/>). Raises the cancelable
+    ///     <see cref="KeyDown"/> event, then calls <see cref="View.NewKeyDownEvent"/> on all top level views, and finally
+    ///     if the key was not handled, invokes any Application-scoped <see cref="KeyBindings"/>.
     /// </summary>
     /// <remarks>Can be used to simulate key press events.</remarks>
-    /// <param name="keyEvent"></param>
+    /// <param name="key"></param>
     /// <returns><see langword="true"/> if the key was handled.</returns>
-    public static bool OnKeyDown (Key keyEvent)
+    public static bool RaiseKeyDownEvent (Key key)
     {
-        //if (!IsInitialized)
-        //{
-        //    return true;
-        //}
+        KeyDown?.Invoke (null, key);
 
-        KeyDown?.Invoke (null, keyEvent);
-
-        if (keyEvent.Handled)
+        if (key.Handled)
         {
             return true;
         }
@@ -99,7 +24,7 @@ public static partial class Application // Keyboard handling
         {
             foreach (Toplevel topLevel in TopLevels.ToList ())
             {
-                if (topLevel.NewKeyDownEvent (keyEvent))
+                if (topLevel.NewKeyDownEvent (key))
                 {
                     return true;
                 }
@@ -112,7 +37,7 @@ public static partial class Application // Keyboard handling
         }
         else
         {
-            if (Top.NewKeyDownEvent (keyEvent))
+            if (Top.NewKeyDownEvent (key))
             {
                 return true;
             }
@@ -120,7 +45,7 @@ public static partial class Application // Keyboard handling
 
         // Invoke any Application-scoped KeyBindings.
         // The first view that handles the key will stop the loop.
-        foreach (KeyValuePair<Key, KeyBinding> binding in KeyBindings.Bindings.Where (b => b.Key == keyEvent.KeyCode))
+        foreach (KeyValuePair<Key, KeyBinding> binding in KeyBindings.Bindings.Where (b => b.Key == key.KeyCode))
         {
             if (binding.Value.BoundView is { })
             {
@@ -133,7 +58,7 @@ public static partial class Application // Keyboard handling
             }
             else
             {
-                if (!KeyBindings.TryGet (keyEvent, KeyBindingScope.Application, out KeyBinding appBinding))
+                if (!KeyBindings.TryGet (key, KeyBindingScope.Application, out KeyBinding appBinding))
                 {
                     continue;
                 }
@@ -142,7 +67,7 @@ public static partial class Application // Keyboard handling
 
                 foreach (Command command in appBinding.Commands)
                 {
-                    toReturn = InvokeCommand (command, keyEvent, appBinding);
+                    toReturn = InvokeCommand (command, key, appBinding);
                 }
 
                 return toReturn ?? true;
@@ -150,59 +75,66 @@ public static partial class Application // Keyboard handling
         }
 
         return false;
-    }
 
-    /// <summary>
-    ///     INTENRAL method to invoke one of the commands in <see cref="CommandImplementations"/>
-    /// </summary>
-    /// <param name="command"></param>
-    /// <param name="keyEvent"></param>
-    /// <param name="appBinding"></param>
-    /// <returns></returns>
-    /// <exception cref="NotSupportedException"></exception>
-    private static bool? InvokeCommand (Command command, Key keyEvent, KeyBinding appBinding)
-    {
-        if (!CommandImplementations!.ContainsKey (command))
+        static bool? InvokeCommand (Command command, Key key, KeyBinding appBinding)
         {
-            throw new NotSupportedException (
-                                             @$"A KeyBinding was set up for the command {command} ({keyEvent}) but that command is not supported by Application."
-                                            );
-        }
+            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))
-        {
-            var context = new CommandContext (command, keyEvent, appBinding); // Create the context here
+            if (CommandImplementations.TryGetValue (command, out View.CommandImplementation? implementation))
+            {
+                var context = new CommandContext (command, key, appBinding); // Create the context here
 
-            return implementation (context);
-        }
+                return implementation (context);
+            }
 
-        return false;
+            return false;
+        }
     }
 
     /// <summary>
-    ///     Called by the <see cref="ConsoleDriver"/> when the user releases a key. Fires the <see cref="KeyUp"/> event
-    ///     then calls <see cref="View.NewKeyUpEvent"/> on all top level views. Called after <see cref="OnKeyDown"/>.
+    ///     Raised when the user presses a key.
+    ///     <para>
+    ///         Set <see cref="Key.Handled"/> to <see langword="true"/> to indicate the key was handled and to prevent
+    ///         additional processing.
+    ///     </para>
     /// </summary>
-    /// <remarks>Can be used to simulate key press events.</remarks>
-    /// <param name="a"></param>
+    /// <remarks>
+    ///     All drivers support firing the <see cref="KeyDown"/> event. Some drivers (Curses) do not support firing the
+    ///     <see cref="KeyDown"/> and <see cref="KeyUp"/> events.
+    ///     <para>Fired after <see cref="KeyDown"/> and before <see cref="KeyUp"/>.</para>
+    /// </remarks>
+    public static event EventHandler<Key>? KeyDown;
+
+    /// <summary>
+    ///     Called when the user releases a key (by the <see cref="ConsoleDriver"/>). Raises the cancelable <see cref="KeyUp"/>
+    ///     event
+    ///     then calls <see cref="View.NewKeyUpEvent"/> on all top level views. Called after <see cref="RaiseKeyDownEvent"/>.
+    /// </summary>
+    /// <remarks>Can be used to simulate key release events.</remarks>
+    /// <param name="key"></param>
     /// <returns><see langword="true"/> if the key was handled.</returns>
-    public static bool OnKeyUp (Key a)
+    public static bool RaiseKeyUpEvent (Key key)
     {
         if (!IsInitialized)
         {
             return true;
         }
 
-        KeyUp?.Invoke (null, a);
+        KeyUp?.Invoke (null, key);
 
-        if (a.Handled)
+        if (key.Handled)
         {
             return true;
         }
 
         foreach (Toplevel topLevel in TopLevels.ToList ())
         {
-            if (topLevel.NewKeyUpEvent (a))
+            if (topLevel.NewKeyUpEvent (key))
             {
                 return true;
             }
@@ -216,65 +148,12 @@ public static partial class Application // Keyboard handling
         return false;
     }
 
-    /// <summary>Alternative key to navigate backwards through views. Shift+Ctrl+Tab is the primary key.</summary>
-    [SerializableConfigurationProperty (Scope = typeof (SettingsScope))]
-    public static Key PrevTabGroupKey
-    {
-        get => _prevTabGroupKey;
-        set
-        {
-            if (_prevTabGroupKey != value)
-            {
-                ReplaceKey (_prevTabGroupKey, value);
-                _prevTabGroupKey = value;
-            }
-        }
-    }
-
-    /// <summary>Alternative key to navigate backwards through views. Shift+Ctrl+Tab is the primary key.</summary>
-    [SerializableConfigurationProperty (Scope = typeof (SettingsScope))]
-    public static Key PrevTabKey
-    {
-        get => _prevTabKey;
-        set
-        {
-            if (_prevTabKey != value)
-            {
-                ReplaceKey (_prevTabKey, value);
-                _prevTabKey = value;
-            }
-        }
-    }
+    #region Application-scoped KeyBindings
 
-    /// <summary>Gets or sets the key to quit the application.</summary>
-    [SerializableConfigurationProperty (Scope = typeof (SettingsScope))]
-    public static Key QuitKey
-    {
-        get => _quitKey;
-        set
-        {
-            if (_quitKey != value)
-            {
-                ReplaceKey (_quitKey, value);
-                _quitKey = value;
-            }
-        }
-    }
+    static Application () { AddApplicationKeyBindings (); }
 
-    /// <summary>Gets or sets the key to activate arranging views using the keyboard.</summary>
-    [SerializableConfigurationProperty (Scope = typeof (SettingsScope))]
-    public static Key ArrangeKey
-    {
-        get => _arrangeKey;
-        set
-        {
-            if (_arrangeKey != value)
-            {
-                ReplaceKey (_arrangeKey, value);
-                _arrangeKey = value;
-            }
-        }
-    }
+    /// <summary>Gets the Application-scoped key bindings.</summary>
+    public static KeyBindings KeyBindings { get; internal set; } = new ();
 
     internal static void AddApplicationKeyBindings ()
     {
@@ -286,6 +165,7 @@ public static partial class Application // Keyboard handling
                     static () =>
                     {
                         RequestStop ();
+
                         return true;
                     }
                    );
@@ -348,7 +228,7 @@ public static partial class Application // Keyboard handling
 
         KeyBindings.Clear ();
 
-        // Resources/config.json overrrides
+        // Resources/config.json overrides
         NextTabKey = Key.Tab;
         PrevTabKey = Key.Tab.WithShift;
         NextTabGroupKey = Key.F6;
@@ -397,6 +277,26 @@ public static partial class Application // Keyboard handling
                           .ToList ();
     }
 
+    private static void ReplaceKey (Key oldKey, Key newKey)
+    {
+        if (KeyBindings.Bindings.Count == 0)
+        {
+            return;
+        }
+
+        if (newKey == Key.Empty)
+        {
+            KeyBindings.Remove (oldKey);
+        }
+        else
+        {
+            KeyBindings.ReplaceKey (oldKey, newKey);
+        }
+    }
+
+
+    #endregion Application-scoped KeyBindings
+
     /// <summary>
     ///     <para>
     ///         Sets the function that will be invoked for a <see cref="Command"/>.
@@ -420,20 +320,4 @@ public static partial class Application // Keyboard handling
     /// </summary>
     private static Dictionary<Command, View.CommandImplementation>? CommandImplementations { get; set; }
 
-    private static void ReplaceKey (Key oldKey, Key newKey)
-    {
-        if (KeyBindings.Bindings.Count == 0)
-        {
-            return;
-        }
-
-        if (newKey == Key.Empty)
-        {
-            KeyBindings.Remove (oldKey);
-        }
-        else
-        {
-            KeyBindings.ReplaceKey (oldKey, newKey);
-        }
-    }
 }

+ 79 - 0
Terminal.Gui/Application/Application.Navigation.cs

@@ -7,4 +7,83 @@ public static partial class Application // Navigation stuff
     ///     Gets the <see cref="ApplicationNavigation"/> instance for the current <see cref="Application"/>.
     /// </summary>
     public static ApplicationNavigation? Navigation { get; internal set; }
+
+    private static Key _nextTabGroupKey = Key.F6; // Resources/config.json overrides
+    private static Key _nextTabKey = Key.Tab; // Resources/config.json overrides
+    private static Key _prevTabGroupKey = Key.F6.WithShift; // Resources/config.json overrides
+    private static Key _prevTabKey = Key.Tab.WithShift; // Resources/config.json overrides
+
+    /// <summary>Alternative key to navigate forwards through views. Ctrl+Tab is the primary key.</summary>
+    [SerializableConfigurationProperty (Scope = typeof (SettingsScope))]
+    public static Key NextTabGroupKey
+    {
+        get => _nextTabGroupKey;
+        set
+        {
+            if (_nextTabGroupKey != value)
+            {
+                ReplaceKey (_nextTabGroupKey, value);
+                _nextTabGroupKey = value;
+            }
+        }
+    }
+
+    /// <summary>Alternative key to navigate forwards through views. Ctrl+Tab is the primary key.</summary>
+    [SerializableConfigurationProperty (Scope = typeof (SettingsScope))]
+    public static Key NextTabKey
+    {
+        get => _nextTabKey;
+        set
+        {
+            if (_nextTabKey != value)
+            {
+                ReplaceKey (_nextTabKey, value);
+                _nextTabKey = value;
+            }
+        }
+    }
+
+
+    /// <summary>
+    ///     Raised when the user releases a key.
+    ///     <para>
+    ///         Set <see cref="Key.Handled"/> to <see langword="true"/> to indicate the key was handled and to prevent
+    ///         additional processing.
+    ///     </para>
+    /// </summary>
+    /// <remarks>
+    ///     All drivers support firing the <see cref="KeyDown"/> event. Some drivers (Curses) do not support firing the
+    ///     <see cref="KeyDown"/> and <see cref="KeyUp"/> events.
+    ///     <para>Fired after <see cref="KeyDown"/>.</para>
+    /// </remarks>
+    public static event EventHandler<Key>? KeyUp;
+    /// <summary>Alternative key to navigate backwards through views. Shift+Ctrl+Tab is the primary key.</summary>
+    [SerializableConfigurationProperty (Scope = typeof (SettingsScope))]
+    public static Key PrevTabGroupKey
+    {
+        get => _prevTabGroupKey;
+        set
+        {
+            if (_prevTabGroupKey != value)
+            {
+                ReplaceKey (_prevTabGroupKey, value);
+                _prevTabGroupKey = value;
+            }
+        }
+    }
+
+    /// <summary>Alternative key to navigate backwards through views. Shift+Ctrl+Tab is the primary key.</summary>
+    [SerializableConfigurationProperty (Scope = typeof (SettingsScope))]
+    public static Key PrevTabKey
+    {
+        get => _prevTabKey;
+        set
+        {
+            if (_prevTabKey != value)
+            {
+                ReplaceKey (_prevTabKey, value);
+                _prevTabKey = value;
+            }
+        }
+    }
 }

+ 35 - 0
Terminal.Gui/Application/Application.Run.cs

@@ -6,6 +6,41 @@ namespace Terminal.Gui;
 
 public static partial class Application // Run (Begin, Run, End, Stop)
 {
+    private static Key _quitKey = Key.Esc; // Resources/config.json overrides
+
+    /// <summary>Gets or sets the key to quit the application.</summary>
+    [SerializableConfigurationProperty (Scope = typeof (SettingsScope))]
+    public static Key QuitKey
+    {
+        get => _quitKey;
+        set
+        {
+            if (_quitKey != value)
+            {
+                ReplaceKey (_quitKey, value);
+                _quitKey = value;
+            }
+        }
+    }
+
+    private static Key _arrangeKey = Key.F5.WithCtrl; // Resources/config.json overrides
+
+
+    /// <summary>Gets or sets the key to activate arranging views using the keyboard.</summary>
+    [SerializableConfigurationProperty (Scope = typeof (SettingsScope))]
+    public static Key ArrangeKey
+    {
+        get => _arrangeKey;
+        set
+        {
+            if (_arrangeKey != value)
+            {
+                ReplaceKey (_arrangeKey, value);
+                _arrangeKey = value;
+            }
+        }
+    }
+
     // When `End ()` is called, it is possible `RunState.Toplevel` is a different object than `Top`.
     // This variable is set in `End` in this case so that `Begin` correctly sets `Top`.
     private static Toplevel? _cachedRunStateToplevel;

+ 0 - 173
Terminal.Gui/Input/ShortcutHelper.cs

@@ -1,173 +0,0 @@
-using System.Diagnostics;
-
-namespace Terminal.Gui;
-
-// TODO: Nuke when #2975 is completed
-/// <summary>Represents a helper to manipulate shortcut keys used on views.</summary>
-public class ShortcutHelper
-{
-    // TODO: Update this to use Key, not KeyCode
-    private KeyCode shortcut;
-
-    /// <summary>This is the global setting that can be used as a global shortcut to invoke the action on the view.</summary>
-    public virtual KeyCode Shortcut
-    {
-        get => shortcut;
-        set
-        {
-            if (shortcut != value && (PostShortcutValidation (value) || value is KeyCode.Null))
-            {
-                shortcut = value;
-            }
-        }
-    }
-
-    /// <summary>The keystroke combination used in the <see cref="Shortcut"/> as string.</summary>
-    public virtual string ShortcutTag => Key.ToString (shortcut, Key.Separator);
-
-    /// <summary>Lookup for a <see cref="KeyCode"/> on range of keys.</summary>
-    /// <param name="key">The source key.</param>
-    /// <param name="first">First key in range.</param>
-    /// <param name="last">Last key in range.</param>
-    public static bool CheckKeysFlagRange (KeyCode key, KeyCode first, KeyCode last)
-    {
-        for (var i = (uint)first; i < (uint)last; i++)
-        {
-            if ((key | (KeyCode)i) == key)
-            {
-                return true;
-            }
-        }
-
-        return false;
-    }
-
-    /// <summary>Allows to retrieve a <see cref="KeyCode"/> from a <see cref="ShortcutTag"/></summary>
-    /// <param name="tag">The key as string.</param>
-    /// <param name="delimiter">The delimiter string.</param>
-    public static KeyCode GetShortcutFromTag (string tag, Rune delimiter = default)
-    {
-        string sCut = tag;
-
-        if (string.IsNullOrEmpty (sCut))
-        {
-            return default (KeyCode);
-        }
-
-        var key = KeyCode.Null;
-
-        //var hasCtrl = false;
-        if (delimiter == default (Rune))
-        {
-            delimiter = Key.Separator;
-        }
-
-        string [] keys = sCut.Split (delimiter.ToString ());
-
-        for (var i = 0; i < keys.Length; i++)
-        {
-            string k = keys [i];
-
-            if (k == "Ctrl")
-            {
-                //hasCtrl = true;
-                key |= KeyCode.CtrlMask;
-            }
-            else if (k == "Shift")
-            {
-                key |= KeyCode.ShiftMask;
-            }
-            else if (k == "Alt")
-            {
-                key |= KeyCode.AltMask;
-            }
-            else if (k.StartsWith ("F") && k.Length > 1)
-            {
-                int.TryParse (k.Substring (1), out int n);
-
-                for (var j = (uint)KeyCode.F1; j <= (uint)KeyCode.F12; j++)
-                {
-                    int.TryParse (((KeyCode)j).ToString ().Substring (1), out int f);
-
-                    if (f == n)
-                    {
-                        key |= (KeyCode)j;
-                    }
-                }
-            }
-            else
-            {
-                key |= (KeyCode)Enum.Parse (typeof (KeyCode), k);
-            }
-        }
-
-        return key;
-    }
-
-    /// <summary>Used at key up validation.</summary>
-    /// <param name="key">The key to validate.</param>
-    /// <returns><c>true</c> if is valid.<c>false</c>otherwise.</returns>
-    public static bool PostShortcutValidation (KeyCode key)
-    {
-        GetKeyToString (key, out KeyCode knm);
-
-        if (CheckKeysFlagRange (key, KeyCode.F1, KeyCode.F12) || ((key & (KeyCode.CtrlMask | KeyCode.ShiftMask | KeyCode.AltMask)) != 0 && knm != KeyCode.Null))
-        {
-            return true;
-        }
-
-        return false;
-    }
-
-    /// <summary>Used at key down or key press validation.</summary>
-    /// <param name="key">The key to validate.</param>
-    /// <returns><c>true</c> if is valid.<c>false</c>otherwise.</returns>
-    public static bool PreShortcutValidation (KeyCode key)
-    {
-        if ((key & (KeyCode.CtrlMask | KeyCode.ShiftMask | KeyCode.AltMask)) == 0
-            && !CheckKeysFlagRange (key, KeyCode.F1, KeyCode.F12))
-        {
-            return false;
-        }
-
-        return true;
-    }
-
-    /// <summary>Return key as string.</summary>
-    /// <param name="key">The key to extract.</param>
-    /// <param name="knm">Correspond to the non modifier key.</param>
-    private static string GetKeyToString (KeyCode key, out KeyCode knm)
-    {
-        if (key == KeyCode.Null)
-        {
-            knm = KeyCode.Null;
-
-            return "";
-        }
-
-        knm = key;
-        KeyCode mK = key & (KeyCode.AltMask | KeyCode.CtrlMask | KeyCode.ShiftMask);
-        knm &= ~mK;
-
-        for (var i = (uint)KeyCode.F1; i < (uint)KeyCode.F12; i++)
-        {
-            if (knm == (KeyCode)i)
-            {
-                mK |= (KeyCode)i;
-            }
-        }
-
-        knm &= ~mK;
-        uint.TryParse (knm.ToString (), out uint c);
-        string s = mK == KeyCode.Null ? "" : mK.ToString ();
-
-        if (s != "" && (knm != KeyCode.Null || c > 0))
-        {
-            s += ",";
-        }
-
-        s += c == 0 ? knm == KeyCode.Null ? "" : knm.ToString () : ((char)c).ToString ();
-
-        return s;
-    }
-}

+ 2 - 4
Terminal.Gui/View/Orientation/OrientationHelper.cs

@@ -69,7 +69,7 @@ public class OrientationHelper
                 return;
             }
 
-            // Best practice is to invoke the virtual method first.
+            // Best practice is to call the virtual method first.
             // This allows derived classes to handle the event and potentially cancel it.
             if (_owner?.OnOrientationChanging (value, _orientation) ?? false)
             {
@@ -98,10 +98,8 @@ public class OrientationHelper
                 }
             }
 
-            // Best practice is to invoke the virtual method first.
+            // Best practice is to call the virtual method first, then raise the event.
             _owner?.OnOrientationChanged (_orientation);
-
-            // Even though Changed is not cancelable, it is still a good practice to raise the event after.
             OrientationChanged?.Invoke (_owner, new (in _orientation));
         }
     }

+ 141 - 182
Terminal.Gui/View/View.Keyboard.cs

@@ -26,7 +26,7 @@ public partial class View // Keyboard APIs
 
     #region HotKey Support
 
-    /// <summary>Invoked when the <see cref="HotKey"/> is changed.</summary>
+    /// <summary>Raised when the <see cref="HotKey"/> is changed.</summary>
     public event EventHandler<KeyChangedEventArgs>? HotKeyChanged;
 
     private Key _hotKey = new ();
@@ -73,7 +73,7 @@ public partial class View // Keyboard APIs
     ///     <para>If the hot key is changed, the <see cref="HotKeyChanged"/> event is fired.</para>
     ///     <para>Set to <see cref="Key.Empty"/> to disable the hot key.</para>
     /// </remarks>
-    public virtual Key HotKey
+    public Key HotKey
     {
         get => _hotKey;
         set
@@ -218,7 +218,7 @@ public partial class View // Keyboard APIs
 
     private void SetHotKeyFromTitle ()
     {
-        if (TitleTextFormatter == null || HotKeySpecifier == new Rune ('\xFFFF'))
+        if (HotKeySpecifier == new Rune ('\xFFFF'))
         {
             return; // throw new InvalidOperationException ("Can't set HotKey unless a TextFormatter has been created");
         }
@@ -243,7 +243,8 @@ public partial class View // Keyboard APIs
     #region Key Down Event
 
     /// <summary>
-    ///     If the view is enabled, processes a new key down event and returns <see langword="true"/> if the event was
+    ///     If the view is enabled, raises the related key down events on the view, and returns <see langword="true"/> if the
+    ///     event was
     ///     handled.
     /// </summary>
     /// <remarks>
@@ -252,74 +253,95 @@ public partial class View // Keyboard APIs
     ///         first.
     ///     </para>
     ///     <para>
-    ///         If the focused sub view does not handle the key press, this method calls <see cref="OnKeyDown"/> to allow the
-    ///         view to pre-process the key press. If <see cref="OnKeyDown"/> returns <see langword="false"/>, this method then
-    ///         calls <see cref="OnInvokingKeyBindings"/> to invoke any key bindings. Then, only if no key bindings are
-    ///         handled, <see cref="OnProcessKeyDown"/> will be called allowing the view to process the key press.
+    ///         If a more focused subview does not handle the key press, this method raises <see cref="OnKeyDown"/>/
+    ///         <see cref="KeyDown"/> to allow the
+    ///         view to pre-process the key press. If <see cref="OnKeyDown"/>/<see cref="KeyDown"/> is not handled any commands bound to the key will be invoked.
+    ///         Then, only if no key bindings are
+    ///         handled, <see cref="OnKeyDownNotHandled"/>/<see cref="KeyDownNotHandled"/> will be raised allowing the view to
+    ///         process the key press.
+    ///     </para>
+    ///     <para>
+    ///         Calling this method for a key bound to the view via an Application-scoped keybinding will have no effect.
+    ///         Instead,
+    ///         use <see cref="Application.RaiseKeyDownEvent"/>.
     ///     </para>
     ///     <para>See <see href="../docs/keyboard.md">for an overview of Terminal.Gui keyboard APIs.</see></para>
     /// </remarks>
-    /// <param name="keyEvent"></param>
+    /// <param name="key"></param>
     /// <returns><see langword="true"/> if the event was handled.</returns>
-    public bool NewKeyDownEvent (Key keyEvent)
+    public bool NewKeyDownEvent (Key key)
     {
         if (!Enabled)
         {
             return false;
         }
 
-        // By default the KeyBindingScope is View
-
-        if (Focused?.NewKeyDownEvent (keyEvent) == true)
+        // If there's a Focused subview, give it a chance (this recurses down the hierarchy)
+        if (Focused?.NewKeyDownEvent (key) == true)
         {
             return true;
         }
 
         // Before (fire the cancellable event)
-        if (OnKeyDown (keyEvent))
+        if (RaiseKeyDown (key) || key.Handled)
         {
             return true;
         }
 
         // During (this is what can be cancelled)
-        InvokingKeyBindings?.Invoke (this, keyEvent);
 
-        if (keyEvent.Handled)
+        // TODO: NewKeyDownEvent returns bool. It should be bool? so state of InvokeCommands can be reflected up stack
+        if (InvokeCommandsBoundToKey (key) is true || key.Handled)
         {
             return true;
         }
 
-        // TODO: NewKeyDownEvent returns bool. It should be bool? so state of InvokeCommand can be reflected up stack
-
-        bool? handled = OnInvokingKeyBindings (keyEvent, KeyBindingScope.HotKey | KeyBindingScope.Focused);
-
-        if (handled is { } && (bool)handled)
+        // After
+        if (RaiseKeyDownNotHandled (key) || key.Handled)
         {
             return true;
         }
 
-        // TODO: The below is not right. OnXXX handlers are supposed to fire the events.
-        // TODO: But I've moved it outside of the v-function to test something.
-        // After (fire the cancellable event)
-        // fire event
-        ProcessKeyDown?.Invoke (this, keyEvent);
+        return key.Handled;
 
-        if (!keyEvent.Handled && OnProcessKeyDown (keyEvent))
+        bool RaiseKeyDown (Key k)
         {
-            return true;
+            // Before (fire the cancellable event)
+            if (OnKeyDown (k) || k.Handled)
+            {
+                return true;
+            }
+
+            // fire event
+            KeyDown?.Invoke (this, k);
+
+            return k.Handled;
         }
 
-        return keyEvent.Handled;
+        bool RaiseKeyDownNotHandled (Key k)
+        {
+            if (OnKeyDownNotHandled (k) || k.Handled)
+            {
+                return true;
+            }
+
+            KeyDownNotHandled?.Invoke (this, k);
+
+            return false;
+        }
     }
 
     /// <summary>
-    ///     Low-level API called when the user presses a key, allowing a view to pre-process the key down event. This is
-    ///     called from <see cref="NewKeyDownEvent"/> before <see cref="OnInvokingKeyBindings"/>.
+    ///     Called when the user presses a key, allowing subscribers to pre-process the key down event. Called
+    ///     before key bindings are invoked and <see cref="KeyDownNotHandled"/> is raised. Set
+    ///     <see cref="Key.Handled"/>
+    ///     to true to
+    ///     stop the key from being processed further.
     /// </summary>
-    /// <param name="keyEvent">Contains the details about the key that produced the event.</param>
+    /// <param name="key">The key that produced the event.</param>
     /// <returns>
-    ///     <see langword="false"/> if the key press was not handled. <see langword="true"/> if the keypress was handled
-    ///     and no other view should see it.
+    ///     <see langword="false"/> if the key down event was not handled. <see langword="true"/> if the event was handled
+    ///     and processing should stop.
     /// </returns>
     /// <remarks>
     ///     <para>
@@ -328,18 +350,14 @@ public partial class View // Keyboard APIs
     ///     </para>
     ///     <para>Fires the <see cref="KeyDown"/> event.</para>
     /// </remarks>
-    public virtual bool OnKeyDown (Key keyEvent)
-    {
-        // fire event
-        KeyDown?.Invoke (this, keyEvent);
-
-        return keyEvent.Handled;
-    }
+    protected virtual bool OnKeyDown (Key key) { return false; }
 
     /// <summary>
-    ///     Invoked when the user presses a key, allowing subscribers to pre-process the key down event. This is fired
-    ///     from <see cref="OnKeyDown"/> before <see cref="OnInvokingKeyBindings"/>. Set <see cref="Key.Handled"/> to true to
-    ///     stop the key from being processed by other views.
+    ///     Raised when the user presses a key, allowing subscribers to pre-process the key down event. Called
+    ///     before key bindings are invoked and <see cref="KeyDownNotHandled"/> is raised. Set
+    ///     <see cref="Key.Handled"/>
+    ///     to true to
+    ///     stop the key from being processed further.
     /// </summary>
     /// <remarks>
     ///     <para>
@@ -351,60 +369,49 @@ public partial class View // Keyboard APIs
     public event EventHandler<Key>? KeyDown;
 
     /// <summary>
-    ///     Low-level API called when the user presses a key, allowing views do things during key down events. This is
-    ///     called from <see cref="NewKeyDownEvent"/> after <see cref="OnInvokingKeyBindings"/>.
+    ///     Called when the user has pressed key it wasn't handled by <see cref="KeyDown"/> and was not bound to a key binding.
     /// </summary>
-    /// <param name="keyEvent">Contains the details about the key that produced the event.</param>
-    /// <returns>
-    ///     <see langword="false"/> if the key press was not handled. <see langword="true"/> if the keypress was handled
-    ///     and no other view should see it.
-    /// </returns>
     /// <remarks>
     ///     <para>
-    ///         Override <see cref="OnProcessKeyDown"/> to override the behavior of how the base class processes key down
-    ///         events.
-    ///     </para>
-    ///     <para>
     ///         For processing <see cref="HotKey"/>s and commands, use <see cref="Command"/> and
     ///         <see cref="KeyBindings.Add(Key, Command[])"/>instead.
     ///     </para>
-    ///     <para>Fires the <see cref="ProcessKeyDown"/> event.</para>
     ///     <para>
     ///         Not all terminals support distinct key up notifications; applications should avoid depending on distinct
     ///         KeyUp events.
     ///     </para>
     /// </remarks>
-    public virtual bool OnProcessKeyDown (Key keyEvent)
-    {
-        //ProcessKeyDown?.Invoke (this, keyEvent);
-        return keyEvent.Handled;
-    }
+    /// <param name="key">Contains the details about the key that produced the event.</param>
+    /// <returns>
+    ///     <see langword="false"/> if the key press was not handled. <see langword="true"/> if the keypress was handled
+    ///     and no other view should see it.
+    /// </returns>
+    protected virtual bool OnKeyDownNotHandled (Key key) { return key.Handled; }
 
     /// <summary>
-    ///     Invoked when the user presses a key, allowing subscribers to do things during key down events. Set
-    ///     <see cref="Key.Handled"/> to true to stop the key from being processed by other views. Invoked after
-    ///     <see cref="KeyDown"/> and before <see cref="InvokingKeyBindings"/>.
+    ///     Raised when the user has pressed key it wasn't handled by <see cref="KeyDown"/> and was not bound to a key binding.
     /// </summary>
     /// <remarks>
     ///     <para>
-    ///         SubViews can use the <see cref="ProcessKeyDown"/> of their super view override the default behavior of when
-    ///         key bindings are invoked.
+    ///         For processing <see cref="HotKey"/>s and commands, use <see cref="Command"/> and
+    ///         <see cref="KeyBindings.Add(Key, Command[])"/>instead.
     ///     </para>
     ///     <para>
-    ///         Not all terminals support distinct key up notifications; applications should avoid depending on distinct
-    ///         KeyUp events.
+    ///         SubViews can use the <see cref="KeyDownNotHandled"/> of their super view override the default behavior of when
+    ///         key bindings are invoked.
     ///     </para>
     ///     <para>See <see href="../docs/keyboard.md">for an overview of Terminal.Gui keyboard APIs.</see></para>
     /// </remarks>
-    public event EventHandler<Key>? ProcessKeyDown;
+    public event EventHandler<Key>? KeyDownNotHandled;
 
     #endregion KeyDown Event
 
     #region KeyUp Event
 
     /// <summary>
-    ///     If the view is enabled, processes a new key up event and returns <see langword="true"/> if the event was
-    ///     handled. Called before <see cref="NewKeyDownEvent"/>.
+    ///     If the view is enabled, raises the related key up events on the view, and returns <see langword="true"/> if the
+    ///     event was
+    ///     handled.
     /// </summary>
     /// <remarks>
     ///     <para>
@@ -416,44 +423,52 @@ public partial class View // Keyboard APIs
     ///         first.
     ///     </para>
     ///     <para>
-    ///         If the focused sub view does not handle the key press, this method calls <see cref="OnKeyUp"/>, which is
-    ///         cancellable.
+    ///         If the focused sub view does not handle the key press, this method raises <see cref="OnKeyUp"/>/
+    ///         <see cref="KeyUp"/> to allow the
+    ///         view to pre-process the key press.
     ///     </para>
     ///     <para>See <see href="../docs/keyboard.md">for an overview of Terminal.Gui keyboard APIs.</see></para>
     /// </remarks>
-    /// <param name="keyEvent"></param>
+    /// <param name="key"></param>
     /// <returns><see langword="true"/> if the event was handled.</returns>
-    public bool NewKeyUpEvent (Key keyEvent)
+    public bool NewKeyUpEvent (Key key)
     {
         if (!Enabled)
         {
             return false;
         }
 
-        if (Focused?.NewKeyUpEvent (keyEvent) == true)
+        // Before
+        if (RaiseKeyUp (key) || key.Handled)
         {
             return true;
         }
 
-        // Before (fire the cancellable event)
-        if (OnKeyUp (keyEvent))
-        {
-            return true;
-        }
-
-        // During (this is what can be cancelled)
-        // TODO: Until there's a clear use-case, we will not define 'during' event (e.g. OnDuringKeyUp). 
+        // During
 
-        // After (fire the cancellable event InvokingKeyBindings)
-        // TODO: Until there's a clear use-case, we will not define an 'after' event (e.g. OnAfterKeyUp). 
+        // After
 
         return false;
+
+        bool RaiseKeyUp (Key k)
+        {
+            // Before (fire the cancellable event)
+            if (OnKeyUp (k) || k.Handled)
+            {
+                return true;
+            }
+
+            // fire event
+            KeyUp?.Invoke (this, k);
+
+            return k.Handled;
+        }
     }
 
-    /// <summary>Method invoked when a key is released. This method is called from <see cref="NewKeyUpEvent"/>.</summary>
-    /// <param name="keyEvent">Contains the details about the key that produced the event.</param>
+    /// <summary>Called when a key is released. This method is called from <see cref="NewKeyUpEvent"/>.</summary>
+    /// <param name="key">Contains the details about the key that produced the event.</param>
     /// <returns>
-    ///     <see langword="false"/> if the key stroke was not handled. <see langword="true"/> if no other view should see
+    ///     <see langword="false"/> if the keys up event was not handled. <see langword="true"/> if no other view should see
     ///     it.
     /// </returns>
     /// <remarks>
@@ -465,21 +480,10 @@ public partial class View // Keyboard APIs
     ///     </para>
     ///     <para>See <see href="../docs/keyboard.md">for an overview of Terminal.Gui keyboard APIs.</see></para>
     /// </remarks>
-    public virtual bool OnKeyUp (Key keyEvent)
-    {
-        // fire event
-        KeyUp?.Invoke (this, keyEvent);
-
-        if (keyEvent.Handled)
-        {
-            return true;
-        }
-
-        return false;
-    }
+    public virtual bool OnKeyUp (Key key) { return false; }
 
     /// <summary>
-    ///     Invoked when a key is released. Set <see cref="Key.Handled"/> to true to stop the key up event from being processed
+    ///     Raised when a key is released. Set <see cref="Key.Handled"/> to true to stop the key up event from being processed
     ///     by other views.
     ///     <remarks>
     ///         Not all terminals support key distinct down/up notifications, Applications should avoid depending on
@@ -501,32 +505,20 @@ public partial class View // Keyboard APIs
     private Dictionary<Command, CommandImplementation> CommandImplementations { get; } = new ();
 
     /// <summary>
-    ///     Low-level API called when a user presses a key; invokes any key bindings set on the view. This is called
-    ///     during <see cref="NewKeyDownEvent"/> after <see cref="OnKeyDown"/> has returned.
+    ///     INTERNAL API: Invokes any commands bound to <paramref name="key"/> on this view, adornments, and subviews.
     /// </summary>
-    /// <remarks>
-    ///     <para>Fires the <see cref="InvokingKeyBindings"/> event.</para>
-    ///     <para>See <see href="../docs/keyboard.md">for an overview of Terminal.Gui keyboard APIs.</see></para>
-    /// </remarks>
-    /// <param name="keyEvent">Contains the details about the key that produced the event.</param>
-    /// <param name="scope">The scope.</param>
+    /// <param name="key"></param>
     /// <returns>
-    ///     <see langword="null"/> if no event was raised; input proessing should continue.
-    ///     <see langword="false"/> if the event was raised and was not handled (or cancelled); input proessing should continue.
-    ///     <see langword="true"/> if the event was raised and handled (or cancelled); input proessing should stop.
+    ///     <see langword="null"/> if no command was invoked or there was no matching key binding; input processing should
+    ///     continue.
+    ///     <see langword="false"/> if a 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>
-    public virtual bool? OnInvokingKeyBindings (Key keyEvent, KeyBindingScope scope)
+    internal bool? InvokeCommandsBoundToKey (Key key)
     {
-        // fire event only if there's a hotkey binding for the key
-        if (KeyBindings.TryGet (keyEvent, scope, out KeyBinding kb))
-        {
-            InvokingKeyBindings?.Invoke (this, keyEvent);
-
-            if (keyEvent.Handled)
-            {
-                return true;
-            }
-        }
+        KeyBindingScope scope = KeyBindingScope.Focused | KeyBindingScope.HotKey;
 
         // * If no key binding was found, `InvokeKeyBindings` returns `null`.
         //   Continue passing the event (return `false` from `OnInvokeKeyBindings`).
@@ -534,31 +526,31 @@ 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 = InvokeKeyBindings (keyEvent, scope);
+        bool?  handled = InvokeCommands (key, scope);
 
-        if (handled is { } && (bool)handled)
+        if (handled is true)
         {
             // Stop processing if any key binding handled the key.
             // DO NOT stop processing if there are no matching key bindings or none of the key bindings handled the key
-            return true;
+            return handled;
         }
 
-        if (Margin is { } && ProcessAdornmentKeyBindings (Margin, keyEvent, scope, ref handled))
+        if (Margin is { } && InvokeCommandsBoundToKeyOnAdornment (Margin, key, scope, ref handled))
         {
             return true;
         }
 
-        if (Padding is { } && ProcessAdornmentKeyBindings (Padding, keyEvent, scope, ref handled))
+        if (Padding is { } && InvokeCommandsBoundToKeyOnAdornment (Padding, key, scope, ref handled))
         {
             return true;
         }
 
-        if (Border is { } && ProcessAdornmentKeyBindings (Border, keyEvent, scope, ref handled))
+        if (Border is { } && InvokeCommandsBoundToKeyOnAdornment (Border, key, scope, ref handled))
         {
             return true;
         }
 
-        if (ProcessSubViewKeyBindings (keyEvent, scope, ref handled))
+        if (InvokeCommandsBoundToKeyOnSubviews (key, scope, ref handled))
         {
             return true;
         }
@@ -566,9 +558,9 @@ public partial class View // Keyboard APIs
         return handled;
     }
 
-    private bool ProcessAdornmentKeyBindings (Adornment adornment, Key keyEvent, KeyBindingScope scope, ref bool? handled)
+    private static bool InvokeCommandsBoundToKeyOnAdornment (Adornment adornment, Key key, KeyBindingScope scope, ref bool? handled)
     {
-        bool? adornmentHandled = adornment.OnInvokingKeyBindings (keyEvent, scope);
+        bool? adornmentHandled = adornment.InvokeCommandsBoundToKey (key);
 
         if (adornmentHandled is true)
         {
@@ -582,7 +574,7 @@ public partial class View // Keyboard APIs
 
         foreach (View subview in adornment.Subviews)
         {
-            bool? subViewHandled = subview.OnInvokingKeyBindings (keyEvent, scope);
+            bool? subViewHandled = subview.InvokeCommandsBoundToKey (key);
 
             if (subViewHandled is { })
             {
@@ -598,7 +590,7 @@ public partial class View // Keyboard APIs
         return false;
     }
 
-    private bool ProcessSubViewKeyBindings (Key keyEvent, KeyBindingScope scope, ref bool? handled, bool invoke = true)
+    private bool InvokeCommandsBoundToKeyOnSubviews (Key key, KeyBindingScope scope, ref bool? handled, bool invoke = true)
     {
         // Now, process any key bindings in the subviews that are tagged to KeyBindingScope.HotKey.
         foreach (View subview in Subviews)
@@ -608,7 +600,7 @@ public partial class View // Keyboard APIs
                 continue;
             }
 
-            if (subview.KeyBindings.TryGet (keyEvent, scope, out KeyBinding binding))
+            if (subview.KeyBindings.TryGet (key, scope, out KeyBinding binding))
             {
                 if (binding.Scope == KeyBindingScope.Focused && !subview.HasFocus)
                 {
@@ -620,7 +612,7 @@ public partial class View // Keyboard APIs
                     return true;
                 }
 
-                bool? subViewHandled = subview.OnInvokingKeyBindings (keyEvent, scope);
+                bool? subViewHandled = subview.InvokeCommandsBoundToKey (key);
 
                 if (subViewHandled is { })
                 {
@@ -633,7 +625,7 @@ public partial class View // Keyboard APIs
                 }
             }
 
-            bool recurse = subview.ProcessSubViewKeyBindings (keyEvent, scope, ref handled, invoke);
+            bool recurse = subview.InvokeCommandsBoundToKeyOnSubviews (key, scope, ref handled, invoke);
 
             if (recurse || (handled is { } && (bool)handled))
             {
@@ -653,7 +645,7 @@ public partial class View // Keyboard APIs
     /// <param name="key">The key to test.</param>
     /// <param name="boundView">Returns the view the key is bound to.</param>
     /// <returns></returns>
-    public bool IsHotKeyKeyBound (Key key, out View? boundView)
+    public bool IsHotKeyBound (Key key, out View? boundView)
     {
         // recurse through the subviews to find the views that has the key bound
         boundView = null;
@@ -667,7 +659,7 @@ public partial class View // Keyboard APIs
                 return true;
             }
 
-            if (subview.IsHotKeyKeyBound (key, out boundView))
+            if (subview.IsHotKeyBound (key, out boundView))
             {
                 return true;
             }
@@ -677,26 +669,20 @@ public partial class View // Keyboard APIs
     }
 
     /// <summary>
-    ///     Raised when a key is pressed that may be mapped to a key binding. Set <see cref="Key.Handled"/> to true to
-    ///     stop the key from being processed by other views.
-    /// </summary>
-    public event EventHandler<Key>? InvokingKeyBindings;
-
-    /// <summary>
-    ///     Invokes any binding that is registered on this <see cref="View"/> and matches the <paramref name="key"/>
+    ///     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>
     /// <param name="scope">The scope.</param>
     /// <returns>
-    ///     <see langword="null"/> if no command was invoked; input proessing should continue.
-    ///     <see langword="false"/> if at least one command was invoked and was not handled (or cancelled); input proessing should continue.
-    ///     <see langword="true"/> if at least one command was invoked and handled (or cancelled); input proessing should stop.
+    ///     <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? InvokeKeyBindings (Key key, KeyBindingScope scope)
+    protected bool? InvokeCommands (Key key, KeyBindingScope scope)
     {
-        bool? toReturn = null;
-
         if (!KeyBindings.TryGet (key, scope, out KeyBinding binding))
         {
             return null;
@@ -704,49 +690,22 @@ public partial class View // Keyboard APIs
 
 #if DEBUG
 
-        // TODO: Determine if App scope bindings should be fired first or last (currently last).
         if (Application.KeyBindings.TryGet (key, KeyBindingScope.Focused | KeyBindingScope.HotKey, out KeyBinding b))
         {
-            //var boundView = views [0];
-            //var commandBinding = boundView.KeyBindings.Get (key);
             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.");
         }
 
         // 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?.IsHotKeyKeyBound (key, out View? previouslyBoundView) ?? false)
+        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 (binding.Commands, key, binding);
-
-        foreach (Command command in binding.Commands)
-        {
-            if (!CommandImplementations.ContainsKey (command))
-            {
-                throw new NotSupportedException (
-                                                 @$"A KeyBinding was set up for the command {command} ({key}) but that command is not supported by this View ({GetType ().Name})"
-                                                );
-            }
-
-            // each command has its own return value
-            bool? thisReturn = InvokeCommand (command, key, binding);
-
-            // if we haven't got anything yet, the current command result should be used
-            toReturn ??= thisReturn;
-
-            // if ever see a true then that's what we will return
-            if (thisReturn ?? false)
-            {
-                toReturn = true;
-            }
-        }
-
-        return toReturn;
     }
 
     #endregion Key Bindings

+ 0 - 1
Terminal.Gui/View/View.Layout.cs

@@ -28,7 +28,6 @@ public partial class View // Layout APIs
     /// <param name="targetY">The target y location.</param>
     /// <param name="nx">The new x location that will ensure <paramref name="viewToMove"/> will be fully visible.</param>
     /// <param name="ny">The new y location that will ensure <paramref name="viewToMove"/> will be fully visible.</param>
-    /// <param name="statusBar">The new top most statusBar</param>
     /// <returns>
     ///     Either <see cref="Application.Top"/> (if <paramref name="viewToMove"/> does not have a Super View) or
     ///     <paramref name="viewToMove"/>'s SuperView. This can be used to ensure LayoutSubviews is called on the correct View.

+ 1 - 1
Terminal.Gui/Views/DateField.cs

@@ -131,7 +131,7 @@ public class DateField : TextField
     public virtual void OnDateChanged (DateTimeEventArgs<DateTime> args) { DateChanged?.Invoke (this, args); }
 
     /// <inheritdoc/>
-    public override bool OnProcessKeyDown (Key a)
+    protected override bool OnKeyDownNotHandled (Key a)
     {
         // Ignore non-numeric characters.
         if (a >= Key.D0 && a <= Key.D9)

+ 4 - 4
Terminal.Gui/Views/FileDialog.cs

@@ -233,7 +233,7 @@ public class FileDialog : Dialog
         _tbPath.TextChanged += (s, e) => PathChanged ();
 
         _tableView.CellActivated += CellActivate;
-        _tableView.KeyUp += (s, k) => k.Handled = TableView_KeyUp (k);
+        _tableView.KeyDown += (s, k) => k.Handled = TableView_KeyUp (k);
         _tableView.SelectedCellChanged += TableView_SelectedCellChanged;
 
         _tableView.KeyBindings.ReplaceCommands (Key.Home, Command.Start);
@@ -670,11 +670,11 @@ public class FileDialog : Dialog
         FinishAccept ();
     }
 
-    private void AcceptIf (Key keyEvent, KeyCode isKey)
+    private void AcceptIf (Key key, KeyCode isKey)
     {
-        if (!keyEvent.Handled && keyEvent.KeyCode == isKey)
+        if (!key.Handled && key.KeyCode == isKey)
         {
-            keyEvent.Handled = true;
+            key.Handled = true;
 
             // User hit Enter in text box so probably wants the
             // contents of the text box as their selection not

+ 1 - 1
Terminal.Gui/Views/HexView.cs

@@ -452,7 +452,7 @@ public class HexView : View, IDesignable
     public virtual void OnPositionChanged () { PositionChanged?.Invoke (this, new HexViewEventArgs (Position, CursorPosition, BytesPerLine)); }
 
     /// <inheritdoc/>
-    public override bool OnProcessKeyDown (Key keyEvent)
+    protected override bool OnKeyDownNotHandled (Key keyEvent)
     {
         if (!AllowEdits)
         {

+ 55 - 3
Terminal.Gui/Views/ListView.cs

@@ -147,7 +147,7 @@ public class ListView : View, IDesignable
 
                                         if (OnOpenSelectedItem ())
                                         {
-                                                return true;
+                                            return true;
                                         }
 
                                         return false;
@@ -189,6 +189,7 @@ public class ListView : View, IDesignable
                                         return !SetFocus ();
                                     });
 
+        AddCommand (Command.SelectAll, (ctx) => MarkAll((bool)ctx.KeyBinding?.Context!));
 
         // Default keybindings for all ListViews
         KeyBindings.Add (Key.CursorUp, Command.Up);
@@ -205,6 +206,13 @@ public class ListView : View, IDesignable
         KeyBindings.Add (Key.Home, Command.Start);
 
         KeyBindings.Add (Key.End, Command.End);
+
+        // Key.Space is already bound to Command.Select; this gives us select then move down
+        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));
     }
 
     /// <summary>Gets or sets whether this <see cref="ListView"/> allows items to be marked.</summary>
@@ -370,6 +378,31 @@ public class ListView : View, IDesignable
         }
     }
 
+    /// <summary>
+    ///     If <see cref="AllowsMarking"/> and <see cref="AllowsMultipleSelection"/> are both <see langword="true"/>,
+    ///     marks all items.
+    /// </summary>
+    /// <param name="mark"><see langword="true"/> marks all items; otherwise unmarks all items.</param>
+    /// <returns><see langword="true"/> if marking was successful.</returns>
+    public bool MarkAll (bool mark)
+    {
+        if (!_allowsMarking)
+        {
+            return false;
+        }
+
+        if (AllowsMultipleSelection)
+        {
+            for (var i = 0; i < Source.Count; i++)
+            {
+                Source.SetMark (i, mark);
+            }
+            return true;
+        }
+
+        return false;
+    }
+
     /// <summary>
     ///     If <see cref="AllowsMarking"/> and <see cref="AllowsMultipleSelection"/> are both <see langword="true"/>,
     ///     unmarks all marked items other than <see cref="SelectedItem"/>.
@@ -784,7 +817,6 @@ public class ListView : View, IDesignable
         }
     }
 
-    // TODO: This should be cancelable
     /// <summary>Invokes the <see cref="OpenSelectedItem"/> event if it is defined.</summary>
     /// <returns><see langword="true"/> if the <see cref="OpenSelectedItem"/> event was fired.</returns>
     public bool OnOpenSelectedItem ()
@@ -803,8 +835,28 @@ public class ListView : View, IDesignable
     }
 
     /// <inheritdoc/>
-    public override bool OnProcessKeyDown (Key a)
+    protected override bool OnKeyDown (Key a)
     {
+        // If marking is enabled and the user presses the space key don't let CollectionNavigator
+        // at it
+        if (AllowsMarking)
+        {
+            var keys = KeyBindings.GetKeysFromCommands (Command.Select);
+
+            if (keys.Contains (a))
+            {
+                return false;
+            }
+
+            keys = KeyBindings.GetKeysFromCommands ([Command.Select, Command.Down]);
+
+            if (keys.Contains (a))
+            {
+                return false;
+            }
+
+        }
+
         // Enable user to find & select an item by typing text
         if (CollectionNavigatorBase.IsCompatibleKey (a))
         {

+ 4 - 12
Terminal.Gui/Views/Menu/Menu.cs

@@ -305,19 +305,11 @@ internal sealed class Menu : View
         return true;
     }
 
-    /// <inheritdoc/>
-    public override bool? OnInvokingKeyBindings (Key keyEvent, KeyBindingScope scope)
+    /// <inheritdoc />
+    protected override bool OnKeyDownNotHandled (Key keyEvent)
     {
-        bool? handled = base.OnInvokingKeyBindings (keyEvent, scope);
-
-        if (handled is { } && (bool)handled)
-        {
-            return true;
-        }
-
-        // TODO: Determine if there's a cleaner way to handle this.
-        // This supports the case where the menu bar is a context menu
-        return _host.OnInvokingKeyBindings (keyEvent, scope);
+        // We didn't handle the key, pass it on to host
+        return _host.InvokeCommandsBoundToKey (keyEvent) == true;
     }
 
     private void Current_TerminalResized (object? sender, SizeChangedEventArgs e)

+ 2 - 2
Terminal.Gui/Views/ScrollView.cs

@@ -388,14 +388,14 @@ public class ScrollView : View
     }
 
     /// <inheritdoc/>
-    public override bool OnKeyDown (Key a)
+    protected override bool OnKeyDown (Key a)
     {
         if (base.OnKeyDown (a))
         {
             return true;
         }
 
-        bool? result = InvokeKeyBindings (a, KeyBindingScope.HotKey | KeyBindingScope.Focused);
+        bool? result = InvokeCommands (a, KeyBindingScope.HotKey | KeyBindingScope.Focused);
 
         if (result is { })
         {

+ 10 - 8
Terminal.Gui/Views/TableView/TableView.cs

@@ -988,7 +988,7 @@ public class TableView : View
     }
 
     /// <inheritdoc/>
-    public override bool OnProcessKeyDown (Key keyEvent)
+    protected override bool OnKeyDown (Key key)
     {
         if (TableIsNullOrInvisible ())
         {
@@ -998,12 +998,14 @@ public class TableView : View
         if (CollectionNavigator != null
             && HasFocus
             && Table.Rows != 0
-            && CollectionNavigatorBase.IsCompatibleKey (keyEvent)
-            && !keyEvent.KeyCode.HasFlag (KeyCode.CtrlMask)
-            && !keyEvent.KeyCode.HasFlag (KeyCode.AltMask)
-            && Rune.IsLetterOrDigit ((Rune)keyEvent))
+            && key != KeyBindings.GetKeyFromCommands (Command.Accept)
+            && key != CellActivationKey
+            && CollectionNavigatorBase.IsCompatibleKey (key)
+            && !key.KeyCode.HasFlag (KeyCode.CtrlMask)
+            && !key.KeyCode.HasFlag (KeyCode.AltMask)
+            && Rune.IsLetterOrDigit ((Rune)key))
         {
-            return CycleToNextTableEntryBeginningWith (keyEvent);
+            return CycleToNextTableEntryBeginningWith (key);
         }
 
         return false;
@@ -1561,7 +1563,7 @@ public class TableView : View
     /// <returns></returns>
     private TableSelection CreateTableSelection (int x, int y) { return CreateTableSelection (x, y, x, y); }
 
-    private bool CycleToNextTableEntryBeginningWith (Key keyEvent)
+    private bool CycleToNextTableEntryBeginningWith (Key key)
     {
         int row = SelectedRow;
 
@@ -1571,7 +1573,7 @@ public class TableView : View
             return false;
         }
 
-        int match = CollectionNavigator.GetNextMatchingItem (row, (char)keyEvent);
+        int match = CollectionNavigator.GetNextMatchingItem (row, (char)key);
 
         if (match != -1)
         {

+ 12 - 29
Terminal.Gui/Views/TextField.cs

@@ -1014,48 +1014,31 @@ public class TextField : View
     }
 
     /// <inheritdoc/>
-    public override bool? OnInvokingKeyBindings (Key a, KeyBindingScope scope)
+    protected override void OnHasFocusChanged (bool newHasFocus, View previousFocusedView, View view)
     {
-        // Give autocomplete first opportunity to respond to key presses
-        if (SelectedLength == 0 && Autocomplete.Suggestions.Count > 0 && Autocomplete.ProcessKey (a))
+        if (Application.MouseGrabView is { } && Application.MouseGrabView == this)
         {
-            return true;
+            Application.UngrabMouse ();
         }
 
-        return base.OnInvokingKeyBindings (a, scope);
+        //if (SelectedLength != 0 && !(Application.MouseGrabView is MenuBar))
+        //	ClearAllSelection ();
     }
 
     /// <inheritdoc/>
-    protected override void OnHasFocusChanged (bool newHasFocus, View previousFocusedView, View view)
+    protected override bool OnKeyDown (Key key)
     {
-        if (Application.MouseGrabView is { } && Application.MouseGrabView == this)
+        // Give autocomplete first opportunity to respond to key presses
+        if (SelectedLength == 0 && Autocomplete.Suggestions.Count > 0 && Autocomplete.ProcessKey (key))
         {
-            Application.UngrabMouse ();
+            return true;
         }
 
-        //if (SelectedLength != 0 && !(Application.MouseGrabView is MenuBar))
-        //	ClearAllSelection ();
+        return false;
     }
 
-    /// TODO: Flush out these docs
-    /// <summary>
-    ///     Processes key presses for the <see cref="TextField"/>.
-    ///     <remarks>
-    ///         The <see cref="TextField"/> control responds to the following keys:
-    ///         <list type="table">
-    ///             <listheader>
-    ///                 <term>Keys</term> <description>Function</description>
-    ///             </listheader>
-    ///             <item>
-    ///                 <term><see cref="Key.Delete"/>, <see cref="Key.Backspace"/></term>
-    ///                 <description>Deletes the character before cursor.</description>
-    ///             </item>
-    ///         </list>
-    ///     </remarks>
-    /// </summary>
-    /// <param name="a"></param>
-    /// <returns></returns>
-    public override bool OnProcessKeyDown (Key a)
+    /// <inheritdoc />
+    protected override bool OnKeyDownNotHandled (Key a)
     {
         // Remember the cursor position because the new calculated cursor position is needed
         // to be set BEFORE the TextChanged event is triggered.

+ 1 - 1
Terminal.Gui/Views/TextValidateField.cs

@@ -597,7 +597,7 @@ namespace Terminal.Gui
         }
 
         /// <inheritdoc/>
-        public override bool OnProcessKeyDown (Key a)
+        protected override bool OnKeyDownNotHandled (Key a)
         {
             if (_provider is null)
             {

+ 80 - 84
Terminal.Gui/Views/TextView.cs

@@ -1,10 +1,8 @@
 #nullable enable
 
 // TextView.cs: multi-line text editing
-using System.Diagnostics;
 using System.Globalization;
 using System.Runtime.CompilerServices;
-using System.Text.Json.Serialization;
 using Terminal.Gui.Resources;
 
 namespace Terminal.Gui;
@@ -106,7 +104,7 @@ internal class TextModel
 
     public void LoadCells (List<Cell> cells, Attribute? attribute)
     {
-        _lines = Cell.ToCells ((List<Cell>)cells);
+        _lines = Cell.ToCells (cells);
         SetAttributes (attribute);
         OnLinesLoaded ();
     }
@@ -180,7 +178,7 @@ internal class TextModel
     {
         if (_lines.Count > 0 && pos < _lines.Count)
         {
-            _lines [pos] = [..runes];
+            _lines [pos] = [.. runes];
         }
         else if (_lines.Count == 0 || (_lines.Count > 0 && pos >= _lines.Count))
         {
@@ -188,8 +186,6 @@ internal class TextModel
         }
     }
 
-
-
     public override string ToString ()
     {
         var sb = new StringBuilder ();
@@ -608,8 +604,7 @@ internal class TextModel
 
     internal Size GetDisplaySize ()
     {
-        Size size = Size.Empty;
-
+        var size = Size.Empty;
 
         return size;
     }
@@ -799,7 +794,7 @@ internal class TextModel
 
         string GetText (List<Cell> x)
         {
-            string txt = Cell.ToString (x);
+            var txt = Cell.ToString (x);
 
             if (!matchCase)
             {
@@ -872,7 +867,7 @@ internal class TextModel
         for (int i = start.Y; i < linesCount; i++)
         {
             List<Cell> x = _lines [i];
-            string txt = Cell.ToString (x);
+            var txt = Cell.ToString (x);
 
             if (!matchCase)
             {
@@ -912,7 +907,7 @@ internal class TextModel
         for (int i = linesCount; i >= 0; i--)
         {
             List<Cell> x = _lines [i];
-            string txt = Cell.ToString (x);
+            var txt = Cell.ToString (x);
 
             if (!matchCase)
             {
@@ -1075,7 +1070,7 @@ internal class TextModel
 
     private string ReplaceText (List<Cell> source, string textToReplace, string matchText, int col)
     {
-        string origTxt = Cell.ToString (source);
+        var origTxt = Cell.ToString (source);
         (_, int len) = DisplaySize (source, 0, col, false);
         (_, int len2) = DisplaySize (source, col, col + matchText.Length, false);
         (_, int len3) = DisplaySize (source, col + matchText.Length, origTxt.GetRuneCount (), false);
@@ -1171,10 +1166,11 @@ internal partial class HistoryText
         _historyTextItems.Clear ();
         _idxHistoryText = -1;
         _originalCellsList.Clear ();
+
         // Save a copy of the original, not the reference
         foreach (List<Cell> cells in cellsList)
         {
-            _originalCellsList.Add ([..cells]);
+            _originalCellsList.Add ([.. cells]);
         }
 
         OnChangeText (null);
@@ -1678,15 +1674,15 @@ internal class WordWrapManager
             List<Cell> line = Model.GetLine (i);
 
             List<List<Cell>> wrappedLines = ToListRune (
-                                                            TextFormatter.Format (
-                                                                                  Cell.ToString (line),
-                                                                                  width,
-                                                                                  Alignment.Start,
-                                                                                  true,
-                                                                                  preserveTrailingSpaces,
-                                                                                  tabWidth
-                                                                                 )
-                                                           );
+                                                        TextFormatter.Format (
+                                                                              Cell.ToString (line),
+                                                                              width,
+                                                                              Alignment.Start,
+                                                                              true,
+                                                                              preserveTrailingSpaces,
+                                                                              tabWidth
+                                                                             )
+                                                       );
             var sumColWidth = 0;
 
             for (var j = 0; j < wrappedLines.Count; j++)
@@ -1885,7 +1881,6 @@ public class TextView : View
     private WordWrapManager? _wrapManager;
     private bool _wrapNeeded;
 
-
     /// <summary>
     ///     Initializes a <see cref="TextView"/> on the specified area, with dimensions controlled with the X, Y, Width
     ///     and Height properties.
@@ -1911,7 +1906,7 @@ public class TextView : View
         // Things this view knows how to do
 
         // Note - NewLine is only bound to Enter if Multiline is true
-        AddCommand (Command.NewLine, (ctx) => ProcessEnterKey (ctx));
+        AddCommand (Command.NewLine, ctx => ProcessEnterKey (ctx));
 
         AddCommand (
                     Command.PageDown,
@@ -2376,7 +2371,7 @@ public class TextView : View
         KeyBindings.Add (Key.C.WithCtrl, Command.Copy);
 
         KeyBindings.Add (Key.W.WithCtrl, Command.Cut); // Move to Unix?
-        KeyBindings.Add (Key.X.WithCtrl, Command.Cut); 
+        KeyBindings.Add (Key.X.WithCtrl, Command.Cut);
 
         KeyBindings.Add (Key.CursorLeft.WithCtrl, Command.WordLeft);
 
@@ -2422,10 +2417,7 @@ public class TextView : View
         KeyBindings.Add ((KeyCode)ContextMenu.Key, KeyBindingScope.HotKey, Command.Context);
     }
 
-    private void TextView_Added1 (object? sender, SuperViewChangedEventArgs e)
-    {
-        throw new NotImplementedException ();
-    }
+    private void TextView_Added1 (object? sender, SuperViewChangedEventArgs e) { throw new NotImplementedException (); }
 
     // BUGBUG: AllowsReturn is mis-named. It should be EnterKeyAccepts.
     /// <summary>
@@ -2435,11 +2427,13 @@ public class TextView : View
     /// <remarks>
     ///     <para>
     ///         Setting this property alters <see cref="Multiline"/>.
-    ///         If <see cref="AllowsReturn"/> is set to <see langword="true"/>, then <see cref="Multiline"/> is also set to `true` and
+    ///         If <see cref="AllowsReturn"/> is set to <see langword="true"/>, then <see cref="Multiline"/> is also set to
+    ///         `true` and
     ///         vice-versa.
     ///     </para>
     ///     <para>
-    ///         If <see cref="AllowsReturn"/> is set to <see langword="false"/>, then <see cref="AllowsTab"/> gets set to <see langword="false"/>.
+    ///         If <see cref="AllowsReturn"/> is set to <see langword="false"/>, then <see cref="AllowsTab"/> gets set to
+    ///         <see langword="false"/>.
     ///     </para>
     /// </remarks>
     public bool AllowsReturn
@@ -2458,6 +2452,7 @@ public class TextView : View
             if (!_allowsReturn && _multiline)
             {
                 Multiline = false;
+
                 // BUGBUG: Setting properties should not have side-effects like this. Multiline and AllowsTab should be independent.
                 AllowsTab = false;
             }
@@ -2532,7 +2527,6 @@ public class TextView : View
         }
     }
 
-
     /// <summary>
     ///     Indicates whatever the text has history changes or not. <see langword="true"/> if the text has history changes
     ///     <see langword="false"/> otherwise.
@@ -2604,7 +2598,7 @@ public class TextView : View
                 CurrentRow = 0;
                 _savedHeight = Height;
 
-                Height = Dim.Auto (DimAutoStyle.Text, minimumContentDim: 1);
+                Height = Dim.Auto (DimAutoStyle.Text, 1);
 
                 if (!IsInitialized)
                 {
@@ -2805,7 +2799,6 @@ public class TextView : View
         }
     }
 
-
     /// <summary>Allows clearing the <see cref="HistoryText.HistoryTextItemEventArgs"/> items updating the original text.</summary>
     public void ClearHistoryChanges () { _historyText?.Clear (_model.GetAllLines ()); }
 
@@ -2855,7 +2848,7 @@ public class TextView : View
                     line [c] = cell; // Assign the modified copy back
                 }
 
-                selectedCellsChanged.Add ([..GetLine (r)]);
+                selectedCellsChanged.Add ([.. GetLine (r)]);
             }
 
             GetSelectedRegion ();
@@ -2906,10 +2899,10 @@ public class TextView : View
     public void PromptForColors ()
     {
         if (!ColorPicker.Prompt (
-                                     "Colors",
-                                     GetSelectedCellAttribute (),
-                                     out Attribute newAttribute
-                                    ))
+                                 "Colors",
+                                 GetSelectedCellAttribute (),
+                                 out Attribute newAttribute
+                                ))
         {
             return;
         }
@@ -3177,10 +3170,7 @@ public class TextView : View
     public List<Cell> GetLine (int line) { return _model.GetLine (line); }
 
     /// <inheritdoc/>
-    public override Attribute GetNormalColor ()
-    {
-        return GetFocusColor ();
-    }
+    public override Attribute GetNormalColor () { return GetFocusColor (); }
 
     /// <summary>
     ///     Inserts the given <paramref name="toAdd"/> text at the current cursor position exactly as if the user had just
@@ -3563,7 +3553,6 @@ public class TextView : View
 
         ProcessInheritsPreviousColorScheme (CurrentRow, CurrentColumn);
         ProcessAutocomplete ();
-
     }
 
     /// <inheritdoc/>
@@ -3628,6 +3617,7 @@ public class TextView : View
                 else
                 {
                     AddRune (col, row, rune);
+
                     // Ensures that cols less than 0 to be 1 because it will be converted to a printable rune
                     cols = Math.Max (cols, 1);
                 }
@@ -3664,46 +3654,33 @@ public class TextView : View
     }
 
     /// <inheritdoc/>
-    public override bool? OnInvokingKeyBindings (Key a, KeyBindingScope scope)
+    protected override void OnHasFocusChanged (bool newHasFocus, View? previousFocusedView, View? view)
     {
-        if (!a.IsValid)
-        {
-            return false;
-        }
-
-        // Give autocomplete first opportunity to respond to key presses
-        if (SelectedLength == 0 && Autocomplete.Suggestions.Count > 0 && Autocomplete.ProcessKey (a))
+        if (Application.MouseGrabView is { } && Application.MouseGrabView == this)
         {
-            return true;
+            Application.UngrabMouse ();
         }
-
-        return base.OnInvokingKeyBindings (a, scope);
     }
 
     /// <inheritdoc/>
-    public override bool OnKeyUp (Key key)
+    protected override bool OnKeyDown (Key key)
     {
-        if (key == Key.Space.WithCtrl)
+        if (!key.IsValid)
         {
-            return true;
+            return false;
         }
 
-        return base.OnKeyUp (key);
-    }
-
-    /// <inheritdoc/>
-    protected override void OnHasFocusChanged (bool newHasFocus, View? previousFocusedView, View? view)
-    {
-        if (Application.MouseGrabView is { } && Application.MouseGrabView == this)
+        // Give autocomplete first opportunity to respond to key presses
+        if (SelectedLength == 0 && Autocomplete.Suggestions.Count > 0 && Autocomplete.ProcessKey (key))
         {
-            Application.UngrabMouse ();
+            return true;
         }
 
-        return;
+        return false;
     }
 
     /// <inheritdoc/>
-    public override bool OnProcessKeyDown (Key a)
+    protected override bool OnKeyDownNotHandled (Key a)
     {
         if (!CanFocus)
         {
@@ -3724,6 +3701,17 @@ public class TextView : View
         return true;
     }
 
+    /// <inheritdoc/>
+    public override bool OnKeyUp (Key key)
+    {
+        if (key == Key.Space.WithCtrl)
+        {
+            return true;
+        }
+
+        return false;
+    }
+
     /// <summary>Invoke the <see cref="UnwrappedCursorPosition"/> event with the unwrapped <see cref="CursorPosition"/>.</summary>
     public virtual void OnUnwrappedCursorPosition (int? cRow = null, int? cCol = null)
     {
@@ -3760,7 +3748,7 @@ public class TextView : View
             List<List<Cell>> addedLine = [new (currentLine), runeList];
 
             _historyText.Add (
-                              [..addedLine],
+                              [.. addedLine],
                               CursorPosition,
                               HistoryText.LineStatus.Added
                              );
@@ -3862,6 +3850,7 @@ public class TextView : View
         if (posX > -1 && col >= posX && posX < Viewport.Width && _topRow <= CurrentRow && posY < Viewport.Height)
         {
             Move (col, CurrentRow - _topRow);
+
             return new (col, CurrentRow - _topRow);
         }
 
@@ -4481,12 +4470,12 @@ public class TextView : View
         }
         else
         {
-            _historyText.Add ([ [.. currentLine]], CursorPosition);
+            _historyText.Add ([[.. currentLine]], CursorPosition);
 
             currentLine.RemoveAt (CurrentColumn);
 
             _historyText.Add (
-                              [ [.. currentLine]],
+                              [[.. currentLine]],
                               CursorPosition,
                               HistoryText.LineStatus.Replaced
                              );
@@ -4656,6 +4645,7 @@ public class TextView : View
         {
             cells = line.GetRange (startCol, endCol - startCol);
             cellsList.Add (cells);
+
             return StringFromRunes (cells);
         }
 
@@ -4668,6 +4658,7 @@ public class TextView : View
             cellsList.AddRange ([]);
             cells = model == null ? _model.GetLine (row) : model.GetLine (row);
             cellsList.Add (cells);
+
             res = res
                   + Environment.NewLine
                   + StringFromRunes (cells);
@@ -4703,7 +4694,7 @@ public class TextView : View
 
         OnUnwrappedCursorPosition (cRow, cCol);
 
-        return GetRegion (out _, sRow: startRow, sCol: startCol, cRow: cRow, cCol: cCol, model: model);
+        return GetRegion (out _, startRow, startCol, cRow, cCol, model);
     }
 
     private (int Row, int Col) GetUnwrappedPosition (int line, int col)
@@ -4897,7 +4888,7 @@ public class TextView : View
         {
             _model.AddLine (CurrentRow + i, lines [i]);
 
-            addedLines.Add ([..lines [i]]);
+            addedLines.Add ([.. lines [i]]);
         }
 
         if (rest is { })
@@ -5071,7 +5062,7 @@ public class TextView : View
         }
 
         _historyText.Add (
-                          [ [.. GetCurrentLine ()]],
+                          [[.. GetCurrentLine ()]],
                           CursorPosition,
                           HistoryText.LineStatus.Replaced
                          );
@@ -5111,7 +5102,7 @@ public class TextView : View
             return;
         }
 
-        _historyText.Add ([ [.. currentLine]], CursorPosition);
+        _historyText.Add ([[.. currentLine]], CursorPosition);
 
         if (currentLine.Count == 0)
         {
@@ -5178,7 +5169,7 @@ public class TextView : View
         }
 
         _historyText.Add (
-                          [ [.. GetCurrentLine ()]],
+                          [[.. GetCurrentLine ()]],
                           CursorPosition,
                           HistoryText.LineStatus.Replaced
                          );
@@ -5202,14 +5193,14 @@ public class TextView : View
 
         List<Cell> currentLine = GetCurrentLine ();
 
-        _historyText.Add ([ [.. GetCurrentLine ()]], CursorPosition);
+        _historyText.Add ([[.. GetCurrentLine ()]], CursorPosition);
 
         if (CurrentColumn == 0)
         {
             DeleteTextBackwards ();
 
             _historyText.ReplaceLast (
-                                      [ [.. GetCurrentLine ()]],
+                                      [[.. GetCurrentLine ()]],
                                       CursorPosition,
                                       HistoryText.LineStatus.Replaced
                                      );
@@ -5248,7 +5239,7 @@ public class TextView : View
         }
 
         _historyText.Add (
-                          [ [.. GetCurrentLine ()]],
+                          [[.. GetCurrentLine ()]],
                           CursorPosition,
                           HistoryText.LineStatus.Replaced
                          );
@@ -5270,14 +5261,14 @@ public class TextView : View
 
         List<Cell> currentLine = GetCurrentLine ();
 
-        _historyText.Add ([ [.. GetCurrentLine ()]], CursorPosition);
+        _historyText.Add ([[.. GetCurrentLine ()]], CursorPosition);
 
         if (currentLine.Count == 0 || CurrentColumn == currentLine.Count)
         {
             DeleteTextForwards ();
 
             _historyText.ReplaceLast (
-                                      [ [.. GetCurrentLine ()]],
+                                      [[.. GetCurrentLine ()]],
                                       CursorPosition,
                                       HistoryText.LineStatus.Replaced
                                      );
@@ -5307,7 +5298,7 @@ public class TextView : View
         }
 
         _historyText.Add (
-                          [ [.. GetCurrentLine ()]],
+                          [[.. GetCurrentLine ()]],
                           CursorPosition,
                           HistoryText.LineStatus.Replaced
                          );
@@ -5579,6 +5570,7 @@ public class TextView : View
         }
 
         DoNeededAction ();
+
         return true;
     }
 
@@ -5919,6 +5911,7 @@ public class TextView : View
     private bool ProcessMoveDown ()
     {
         ResetContinuousFindTrack ();
+
         if (_shiftSelecting && IsSelecting)
         {
             StopSelecting ();
@@ -5961,8 +5954,10 @@ public class TextView : View
             if (IsSelecting)
             {
                 StopSelecting ();
+
                 return true;
             }
+
             // do not respond (this lets the key press fall through to navigation system - which usually changes focus backward)
             return false;
         }
@@ -6001,8 +5996,10 @@ public class TextView : View
             {
                 // In which case clear
                 StopSelecting ();
+
                 return true;
             }
+
             return false;
         }
 
@@ -6296,7 +6293,6 @@ public class TextView : View
         _continuousFind = false;
     }
 
-
     private void ResetPosition ()
     {
         _topRow = _leftColumn = CurrentRow = CurrentColumn = 0;
@@ -6461,13 +6457,13 @@ public class TextView : View
         }
     }
 
-
     private void TextView_Initialized (object sender, EventArgs e)
     {
         if (Autocomplete.HostControl is null)
         {
             Autocomplete.HostControl = this;
         }
+
         OnContentsChanged ();
     }
 

+ 2 - 2
Terminal.Gui/Views/TileView.cs

@@ -286,11 +286,11 @@ public class TileView : View
 
     //// BUGBUG: Why is this not handled by a key binding???
     /// <inheritdoc/>
-    public override bool OnProcessKeyDown (Key keyEvent)
+    protected override bool OnKeyDownNotHandled (Key key)
     {
         var focusMoved = false;
 
-        if (keyEvent.KeyCode == ToggleResizable)
+        if (key.KeyCode == ToggleResizable)
         {
             foreach (TileViewLineView l in _splitterLines)
             {

+ 1 - 1
Terminal.Gui/Views/TimeField.cs

@@ -177,7 +177,7 @@ public class TimeField : TextField
     }
 
     /// <inheritdoc/>
-    public override bool OnProcessKeyDown (Key a)
+    protected override bool OnKeyDownNotHandled (Key a)
     {
         // Ignore non-numeric characters.
         if (a.KeyCode is >= (KeyCode)(int)KeyCode.D0 and <= (KeyCode)(int)KeyCode.D9)

+ 4 - 7
Terminal.Gui/Views/TreeView/TreeView.cs

@@ -1182,26 +1182,23 @@ public class TreeView<T> : View, ITreeView where T : class
     }
 
     /// <inheritdoc/>
-    public override bool OnProcessKeyDown (Key keyEvent)
+    protected override bool OnKeyDown (Key key)
     {
         if (!Enabled)
         {
             return false;
         }
 
-        // BUGBUG: this should move to OnInvokingKeyBindings
         // If not a keybinding, is the key a searchable key press?
-        if (CollectionNavigatorBase.IsCompatibleKey (keyEvent) && AllowLetterBasedNavigation)
+        if (CollectionNavigatorBase.IsCompatibleKey (key) && AllowLetterBasedNavigation)
         {
-            IReadOnlyCollection<Branch<T>> map;
-
             // If there has been a call to InvalidateMap since the last time
             // we need a new one to reflect the new exposed tree state
-            map = BuildLineMap ();
+            IReadOnlyCollection<Branch<T>> map = BuildLineMap ();
 
             // Find the current selected object within the tree
             int current = map.IndexOf (b => b.Model == SelectedObject);
-            int? newIndex = KeystrokeNavigator?.GetNextMatchingItem (current, (char)keyEvent);
+            int? newIndex = KeystrokeNavigator?.GetNextMatchingItem (current, (char)key);
 
             if (newIndex is int && newIndex != -1)
             {

+ 2 - 2
Terminal.Gui/Views/Wizard/Wizard.cs

@@ -381,12 +381,12 @@ public class Wizard : Dialog
     /// <summary>
     ///     <see cref="Wizard"/> is derived from <see cref="Dialog"/> and Dialog causes <c>Esc</c> to call
     ///     <see cref="Application.RequestStop(Toplevel)"/>, closing the Dialog. Wizard overrides
-    ///     <see cref="OnProcessKeyDown"/> to instead fire the <see cref="Cancelled"/> event when Wizard is being used as a
+    ///     <see cref="OnKeyDownNotHandled"/> to instead fire the <see cref="Cancelled"/> event when Wizard is being used as a
     ///     non-modal (see <see cref="Wizard.Modal"/>).
     /// </summary>
     /// <param name="key"></param>
     /// <returns></returns>
-    public override bool OnProcessKeyDown (Key key)
+    protected override bool OnKeyDownNotHandled (Key key)
     {
         //// BUGBUG: Why is this not handled by a key binding???
         if (!Modal)

+ 92 - 70
UICatalog/Scenarios/Keys.cs

@@ -10,120 +10,142 @@ public class Keys : Scenario
     public override void Main ()
     {
         Application.Init ();
-        ObservableCollection<string> keyPressedList = [];
-        ObservableCollection<string> invokingKeyBindingsList = new ();
+        ObservableCollection<string> keyDownList = [];
+        ObservableCollection<string> keyDownNotHandledList = new ();
 
         var win = new Window { Title = GetQuitKeyAndName () };
-        var editLabel = new Label { X = 0, Y = 0, Text = "Type text here:" };
-        win.Add (editLabel);
 
-        var edit = new TextField { X = Pos.Right (editLabel) + 1, Y = Pos.Top (editLabel), Width = Dim.Fill (2) };
+        var label = new Label
+        {
+            X = 0,
+            Y = 0,
+            Text = "_Type text here:"
+        };
+        win.Add (label);
+
+        var edit = new TextField
+        {
+            X = Pos.Right (label) + 1,
+            Y = Pos.Top (label),
+            Width = Dim.Fill (2),
+            Height = 1,
+        };
         win.Add (edit);
 
-        edit.KeyDown += (s, a) => { keyPressedList.Add (a.ToString ()); };
+        label = new Label
+        {
+            X = 0,
+            Y = Pos.Bottom (label),
+            Text = "Last _Application.KeyDown:"
+        };
+        win.Add (label);
+        var labelAppKeypress = new Label
+        {
+            X = Pos.Right (label) + 1,
+            Y = Pos.Top (label)
+        };
+        win.Add (labelAppKeypress);
 
-        edit.InvokingKeyBindings += (s, a) =>
-                                    {
-                                        if (edit.KeyBindings.TryGet (a, out KeyBinding binding))
-                                        {
-                                            invokingKeyBindingsList.Add ($"{a}: {string.Join (",", binding.Commands)}");
-                                        }
-                                    };
+        Application.KeyDown += (s, e) => labelAppKeypress.Text = e.ToString ();
 
-        // Last KeyPress: ______
-        var keyPressedLabel = new Label
+        label = new ()
         {
-            X = Pos.Left (editLabel), Y = Pos.Top (editLabel) + 1, Text = "Last TextView.KeyPressed:"
+            X = 0,
+            Y = Pos.Bottom (label),
+            Text = "_Last TextField.KeyDown:"
         };
-        win.Add (keyPressedLabel);
-        var labelTextViewKeypress = new Label { X = Pos.Right (keyPressedLabel) + 1, Y = Pos.Top (keyPressedLabel) };
-        win.Add (labelTextViewKeypress);
-
-        edit.KeyDown += (s, e) => labelTextViewKeypress.Text = e.ToString ();
+        win.Add (label);
 
-        keyPressedLabel = new Label
+        var lastTextFieldKeyDownLabel = new Label
         {
-            X = Pos.Left (keyPressedLabel), Y = Pos.Bottom (keyPressedLabel), Text = "Last Application.KeyDown:"
+            X = Pos.Right (label) + 1,
+            Y = Pos.Top (label),
+            Height = 1,
         };
-        win.Add (keyPressedLabel);
-        var labelAppKeypress = new Label { X = Pos.Right (keyPressedLabel) + 1, Y = Pos.Top (keyPressedLabel) };
-        win.Add (labelAppKeypress);
+        win.Add (lastTextFieldKeyDownLabel);
 
-        Application.KeyDown += (s, e) => labelAppKeypress.Text = e.ToString ();
+        edit.KeyDown += (s, e) => lastTextFieldKeyDownLabel.Text = e.ToString ();
 
-        // Key stroke log:
-        var keyLogLabel = new Label
+        // Application key event log:
+        label = new Label
         {
-            X = Pos.Left (editLabel), Y = Pos.Top (editLabel) + 4, Text = "Application Key Events:"
+            X = 0,
+            Y = Pos.Bottom (label) + 1,
+            Text = "Application Key Events:"
         };
-        win.Add (keyLogLabel);
+        win.Add (label);
         int maxKeyString = Key.CursorRight.WithAlt.WithCtrl.WithShift.ToString ().Length;
-        var yOffset = 1;
-        ObservableCollection<string> keyEventlist = new ();
 
-        var keyEventListView = new ListView
+        ObservableCollection<string> keyList = new ();
+
+        var appKeyListView = new ListView
         {
             X = 0,
-            Y = Pos.Top (keyLogLabel) + yOffset,
-            Width = "Key Down:".Length + maxKeyString,
+            Y = Pos.Bottom (label),
+            Width = "KeyDown:".Length + maxKeyString,
             Height = Dim.Fill (),
-            Source = new ListWrapper<string> (keyEventlist)
+            Source = new ListWrapper<string> (keyList)
         };
-        keyEventListView.ColorScheme = Colors.ColorSchemes ["TopLevel"];
-        win.Add (keyEventListView);
+        appKeyListView.ColorScheme = Colors.ColorSchemes ["TopLevel"];
+        win.Add (appKeyListView);
+
+        // View key events...
+        edit.KeyDown += (s, a) => { keyDownList.Add (a.ToString ()); };
+
+        edit.KeyDownNotHandled += (s, a) =>
+                                  {
+                                      keyDownNotHandledList.Add ($"{a}");
+                                  };
 
-        // OnKeyPressed
-        var onKeyPressedLabel = new Label
+        // KeyDown
+        label = new Label
         {
-            X = Pos.Right (keyEventListView) + 1, Y = Pos.Top (editLabel) + 4, Text = "TextView KeyDown:"
+            X = Pos.Right (appKeyListView) + 1,
+            Y = Pos.Top (label),
+            Text = "TextView Key Down:"
         };
-        win.Add (onKeyPressedLabel);
+        win.Add (label);
 
-        yOffset = 1;
-
-        var onKeyPressedListView = new ListView
+        var onKeyDownListView = new ListView
         {
-            X = Pos.Left (onKeyPressedLabel),
-            Y = Pos.Top (onKeyPressedLabel) + yOffset,
+            X = Pos.Left (label),
+            Y = Pos.Bottom (label),
             Width = maxKeyString,
             Height = Dim.Fill (),
-            Source = new ListWrapper<string> (keyPressedList)
+            Source = new ListWrapper<string> (keyDownList)
         };
-        onKeyPressedListView.ColorScheme = Colors.ColorSchemes ["TopLevel"];
-        win.Add (onKeyPressedListView);
+        onKeyDownListView.ColorScheme = Colors.ColorSchemes ["TopLevel"];
+        win.Add (onKeyDownListView);
 
-        // OnInvokeKeyBindings
-        var onInvokingKeyBindingsLabel = new Label
+        // KeyDownNotHandled
+        label = new Label
         {
-            X = Pos.Right (onKeyPressedListView) + 1,
-            Y = Pos.Top (editLabel) + 4,
-            Text = "TextView InvokingKeyBindings:"
+            X = Pos.Right (onKeyDownListView) + 1,
+            Y = Pos.Top (label),
+            Text = "TextView KeyDownNotHandled:"
         };
-        win.Add (onInvokingKeyBindingsLabel);
+        win.Add (label);
 
-        var onInvokingKeyBindingsListView = new ListView
+        var onKeyDownNotHandledListView = new ListView
         {
-            X = Pos.Left (onInvokingKeyBindingsLabel),
-            Y = Pos.Top (onInvokingKeyBindingsLabel) + yOffset,
-            Width = Dim.Fill (1),
+            X = Pos.Left (label),
+            Y = Pos.Bottom (label),
+            Width = maxKeyString,
             Height = Dim.Fill (),
-            Source = new ListWrapper<string> (invokingKeyBindingsList)
+            Source = new ListWrapper<string> (keyDownNotHandledList)
         };
-        onInvokingKeyBindingsListView.ColorScheme = Colors.ColorSchemes ["TopLevel"];
-        win.Add (onInvokingKeyBindingsListView);
+        onKeyDownNotHandledListView.ColorScheme = Colors.ColorSchemes ["TopLevel"];
+        win.Add (onKeyDownNotHandledListView);
 
-        //Application.KeyDown += (s, a) => KeyDownPressUp (a, "Down");
         Application.KeyDown += (s, a) => KeyDownPressUp (a, "Down");
         Application.KeyUp += (s, a) => KeyDownPressUp (a, "Up");
 
         void KeyDownPressUp (Key args, string updown)
         {
-            // BUGBUG: KeyEvent.ToString is badly broken
             var msg = $"Key{updown,-7}: {args}";
-            keyEventlist.Add (msg);
-            keyEventListView.MoveDown ();
-            onKeyPressedListView.MoveDown ();
-            onInvokingKeyBindingsListView.MoveDown ();
+            keyList.Add (msg);
+            appKeyListView.MoveDown ();
+            onKeyDownNotHandledListView.MoveDown ();
         }
 
         Application.Run (win);

+ 2 - 2
UICatalog/Scenarios/LineDrawing.cs

@@ -121,7 +121,7 @@ public class LineDrawing : Scenario
         tools.CurrentColor = canvas.GetNormalColor ();
         canvas.CurrentAttribute = tools.CurrentColor;
 
-        win.KeyDown += (s, e) => { e.Handled = canvas.OnKeyDown (e); };
+        win.KeyDown += (s, e) => { e.Handled = canvas.NewKeyDownEvent (e); };
 
         Application.Run (win);
         win.Dispose ();
@@ -290,7 +290,7 @@ public class DrawingArea : View
     }
 
     //// BUGBUG: Why is this not handled by a key binding???
-    public override bool OnKeyDown (Key e)
+    protected override bool OnKeyDown (Key e)
     {
         // BUGBUG: These should be implemented with key bindings
         if (e.KeyCode == (KeyCode.Z | KeyCode.CtrlMask))

+ 5 - 5
UICatalog/Scenarios/Snake.cs

@@ -357,30 +357,30 @@ public class Snake : Scenario
         }
 
         // BUGBUG: Should (can) this use key bindings instead.
-        public override bool OnKeyDown (Key keyEvent)
+        protected override bool OnKeyDown (Key key)
         {
-            if (keyEvent.KeyCode == KeyCode.CursorUp)
+            if (key.KeyCode == KeyCode.CursorUp)
             {
                 State.PlannedDirection = Direction.Up;
 
                 return true;
             }
 
-            if (keyEvent.KeyCode == KeyCode.CursorDown)
+            if (key.KeyCode == KeyCode.CursorDown)
             {
                 State.PlannedDirection = Direction.Down;
 
                 return true;
             }
 
-            if (keyEvent.KeyCode == KeyCode.CursorLeft)
+            if (key.KeyCode == KeyCode.CursorLeft)
             {
                 State.PlannedDirection = Direction.Left;
 
                 return true;
             }
 
-            if (keyEvent.KeyCode == KeyCode.CursorRight)
+            if (key.KeyCode == KeyCode.CursorRight)
             {
                 State.PlannedDirection = Direction.Right;
 

+ 3 - 3
UICatalog/Scenarios/VkeyPacketSimulator.cs

@@ -108,11 +108,11 @@ public class VkeyPacketSimulator : Scenario
                                 if (_outputStarted)
                                 {
                                     // If the key wasn't handled by the TextView will popup a Dialog with the keys pressed.
-                                    bool? handled = tvOutput.OnInvokingKeyBindings (e, KeyBindingScope.HotKey | KeyBindingScope.Focused);
+                                    bool? handled = tvOutput.NewKeyDownEvent (e);
 
                                     if (handled == null || handled == false)
                                     {
-                                        if (!tvOutput.OnProcessKeyDown (e))
+                                        if (!tvOutput.NewKeyDownEvent (e))
                                         {
                                             Application.Invoke (
                                                                 () => MessageBox.Query (
@@ -148,7 +148,7 @@ public class VkeyPacketSimulator : Scenario
                                }
                            };
 
-        tvInput.InvokingKeyBindings += (s, e) =>
+        tvInput.KeyDownNotHandled += (s, e) =>
                                        {
                                            Key ev = e;
 

+ 22 - 22
UICatalog/UICatalog.cs

@@ -620,28 +620,28 @@ public class UICatalogApp
                                                 );
             ScenarioList.Style.ColumnStyles.Add (1, new () { MaxWidth = 1 });
 
-            // Enable user to find & select a scenario by typing text
-            // TableView does not (currently) have built-in CollectionNavigator support (the ability for the 
-            // user to type and the items that match get selected). We implement it in the app instead. 
-            ScenarioList.KeyDown += (s, a) =>
-                                    {
-                                        if (CollectionNavigatorBase.IsCompatibleKey (a))
-                                        {
-                                            int? newItem =
-                                                _scenarioCollectionNav?.GetNextMatchingItem (
-                                                                                             ScenarioList.SelectedRow,
-                                                                                             (char)a
-                                                                                            );
-
-                                            if (newItem is int v && newItem != -1)
-                                            {
-                                                ScenarioList.SelectedRow = v;
-                                                ScenarioList.EnsureSelectedCellIsVisible ();
-                                                ScenarioList.SetNeedsDisplay ();
-                                                a.Handled = true;
-                                            }
-                                        }
-                                    };
+            //// Enable user to find & select a scenario by typing text
+            //// TableView does not (currently) have built-in CollectionNavigator support (the ability for the 
+            //// user to type and the items that match get selected). We implement it in the app instead. 
+            //ScenarioList.KeyDown += (s, a) =>
+            //                        {
+            //                            if (CollectionNavigatorBase.IsCompatibleKey (a))
+            //                            {
+            //                                int? newItem =
+            //                                    _scenarioCollectionNav?.GetNextMatchingItem (
+            //                                                                                 ScenarioList.SelectedRow,
+            //                                                                                 (char)a
+            //                                                                                );
+
+            //                                if (newItem is int v && newItem != -1)
+            //                                {
+            //                                    ScenarioList.SelectedRow = v;
+            //                                    ScenarioList.EnsureSelectedCellIsVisible ();
+            //                                    ScenarioList.SetNeedsDisplay ();
+            //                                    a.Handled = true;
+            //                                }
+            //                            }
+            //                        };
             ScenarioList.CellActivated += ScenarioView_OpenSelectedItem;
 
             // TableView typically is a grid where nav keys are biased for moving left/right.

+ 45 - 45
UnitTests/Application/KeyboardTests.cs

@@ -64,14 +64,14 @@ public class KeyboardTests
         Assert.True (win2.HasFocus);
         Assert.Equal ("win2", ((Window)top.Subviews [^1]).Title);
 
-        Application.OnKeyDown (Key.F6);
+        Application.RaiseKeyDownEvent (Key.F6);
         Assert.True (win2.CanFocus);
         Assert.False (win.HasFocus);
         Assert.True (win2.CanFocus);
         Assert.True (win2.HasFocus);
         Assert.Equal ("win2", ((Window)top.Subviews [^1]).Title);
 
-        Application.OnKeyDown (Key.F6);
+        Application.RaiseKeyDownEvent (Key.F6);
         Assert.False (win.CanFocus);
         Assert.False (win.HasFocus);
         Assert.True (win2.CanFocus);
@@ -117,14 +117,14 @@ public class KeyboardTests
         Assert.False (win2.HasFocus);
         Assert.Equal ("win", ((Window)top.Subviews [^1]).Title);
 
-        Application.OnKeyDown (Key.F6);
+        Application.RaiseKeyDownEvent (Key.F6);
         Assert.True (win.CanFocus);
         Assert.False (win.HasFocus);
         Assert.True (win2.CanFocus);
         Assert.True (win2.HasFocus);
         Assert.Equal ("win2", ((Window)top.Subviews [^1]).Title);
 
-        Application.OnKeyDown (Key.F6);
+        Application.RaiseKeyDownEvent (Key.F6);
         Assert.True (win.CanFocus);
         Assert.True (win.HasFocus);
         Assert.True (win2.CanFocus);
@@ -163,39 +163,39 @@ public class KeyboardTests
     public void KeyBinding_OnKeyDown ()
     {
         var view = new ScopedKeyBindingView ();
-        var invoked = false;
-        view.InvokingKeyBindings += (s, e) => invoked = true;
+        var keyWasHandled = false;
+        view.KeyDownNotHandled += (s, e) => keyWasHandled = true;
 
         var top = new Toplevel ();
         top.Add (view);
         Application.Begin (top);
 
-        Application.OnKeyDown (Key.A);
-        Assert.False (invoked);
+        Application.RaiseKeyDownEvent (Key.A);
+        Assert.False (keyWasHandled);
         Assert.True (view.ApplicationCommand);
 
-        invoked = false;
+        keyWasHandled = false;
         view.ApplicationCommand = false;
         Application.KeyBindings.Remove (KeyCode.A);
-        Application.OnKeyDown (Key.A); // old
-        Assert.False (invoked);
+        Application.RaiseKeyDownEvent (Key.A); // old
+        Assert.False (keyWasHandled);
         Assert.False (view.ApplicationCommand);
         Application.KeyBindings.Add (Key.A.WithCtrl, view, Command.Save);
-        Application.OnKeyDown (Key.A); // old
-        Assert.False (invoked);
+        Application.RaiseKeyDownEvent (Key.A); // old
+        Assert.False (keyWasHandled);
         Assert.False (view.ApplicationCommand);
-        Application.OnKeyDown (Key.A.WithCtrl); // new
-        Assert.False (invoked);
+        Application.RaiseKeyDownEvent (Key.A.WithCtrl); // new
+        Assert.False (keyWasHandled);
         Assert.True (view.ApplicationCommand);
 
-        invoked = false;
-        Application.OnKeyDown (Key.H);
-        Assert.True (invoked);
+        keyWasHandled = false;
+        Application.RaiseKeyDownEvent (Key.H);
+        Assert.False (keyWasHandled);
 
-        invoked = false;
+        keyWasHandled = false;
         Assert.False (view.HasFocus);
-        Application.OnKeyDown (Key.F);
-        Assert.False (invoked);
+        Application.RaiseKeyDownEvent (Key.F);
+        Assert.False (keyWasHandled);
 
         Assert.True (view.ApplicationCommand);
         Assert.True (view.HotKeyCommand);
@@ -208,23 +208,23 @@ public class KeyboardTests
     public void KeyBinding_OnKeyDown_Negative ()
     {
         var view = new ScopedKeyBindingView ();
-        var invoked = false;
-        view.InvokingKeyBindings += (s, e) => invoked = true;
+        var keyWasHandled = false;
+        view.KeyDownNotHandled += (s, e) => keyWasHandled = true;
 
         var top = new Toplevel ();
         top.Add (view);
         Application.Begin (top);
 
-        Application.OnKeyDown (Key.A.WithCtrl);
-        Assert.False (invoked);
+        Application.RaiseKeyDownEvent (Key.A.WithCtrl);
+        Assert.False (keyWasHandled);
         Assert.False (view.ApplicationCommand);
         Assert.False (view.HotKeyCommand);
         Assert.False (view.FocusedCommand);
 
-        invoked = false;
+        keyWasHandled = false;
         Assert.False (view.HasFocus);
-        Application.OnKeyDown (Key.Z);
-        Assert.False (invoked);
+        Application.RaiseKeyDownEvent (Key.Z);
+        Assert.False (keyWasHandled);
         Assert.False (view.ApplicationCommand);
         Assert.False (view.HotKeyCommand);
         Assert.False (view.FocusedCommand);
@@ -399,7 +399,7 @@ public class KeyboardTests
         Assert.True (subView1.HasFocus);
 
         // Act
-        Application.OnKeyDown (Application.NextTabGroupKey);
+        Application.RaiseKeyDownEvent (Application.NextTabGroupKey);
 
         // Assert
         Assert.True (view2.HasFocus);
@@ -432,24 +432,24 @@ public class KeyboardTests
                                      Assert.True (v1.HasFocus);
 
                                      // Across TabGroups
-                                     Application.OnKeyDown (Key.F6);
+                                     Application.RaiseKeyDownEvent (Key.F6);
                                      Assert.True (v3.HasFocus);
-                                     Application.OnKeyDown (Key.F6);
+                                     Application.RaiseKeyDownEvent (Key.F6);
                                      Assert.True (v1.HasFocus);
 
-                                     Application.OnKeyDown (Key.F6.WithShift);
+                                     Application.RaiseKeyDownEvent (Key.F6.WithShift);
                                      Assert.True (v3.HasFocus);
-                                     Application.OnKeyDown (Key.F6.WithShift);
+                                     Application.RaiseKeyDownEvent (Key.F6.WithShift);
                                      Assert.True (v1.HasFocus);
 
                                      // Restore?
-                                     Application.OnKeyDown (Key.Tab);
+                                     Application.RaiseKeyDownEvent (Key.Tab);
                                      Assert.True (v2.HasFocus);
 
-                                     Application.OnKeyDown (Key.F6);
+                                     Application.RaiseKeyDownEvent (Key.F6);
                                      Assert.True (v3.HasFocus);
 
-                                     Application.OnKeyDown (Key.F6);
+                                     Application.RaiseKeyDownEvent (Key.F6);
                                      Assert.True (v1.HasFocus);
 
                                      Application.RequestStop ();
@@ -485,7 +485,7 @@ public class KeyboardTests
         view1.SetFocus ();
 
         // Act
-        Application.OnKeyDown (Application.NextTabKey);
+        Application.RaiseKeyDownEvent (Application.NextTabKey);
 
         // Assert
         Assert.True (view2.HasFocus);
@@ -539,7 +539,7 @@ public class KeyboardTests
         Assert.True (subView1.HasFocus);
 
         // Act
-        Application.OnKeyDown (Application.PrevTabGroupKey);
+        Application.RaiseKeyDownEvent (Application.PrevTabGroupKey);
 
         // Assert
         Assert.True (view2.HasFocus);
@@ -562,7 +562,7 @@ public class KeyboardTests
         view1.SetFocus ();
 
         // Act
-        Application.OnKeyDown (Application.NextTabKey);
+        Application.RaiseKeyDownEvent (Application.NextTabKey);
 
         // Assert
         Assert.True (view2.HasFocus);
@@ -605,21 +605,21 @@ public class KeyboardTests
 
         Key prevKey = Application.QuitKey;
 
-        Application.OnKeyDown (Application.QuitKey);
+        Application.RaiseKeyDownEvent (Application.QuitKey);
         Assert.True (isQuiting);
 
         isQuiting = false;
-        Application.OnKeyDown (Application.QuitKey);
+        Application.RaiseKeyDownEvent (Application.QuitKey);
         Assert.True (isQuiting);
 
         isQuiting = false;
         Application.QuitKey = Key.C.WithCtrl;
-        Application.OnKeyDown (prevKey); // Should not quit
+        Application.RaiseKeyDownEvent (prevKey); // Should not quit
         Assert.False (isQuiting);
-        Application.OnKeyDown (Key.Q.WithCtrl); // Should not quit
+        Application.RaiseKeyDownEvent (Key.Q.WithCtrl); // Should not quit
         Assert.False (isQuiting);
 
-        Application.OnKeyDown (Application.QuitKey);
+        Application.RaiseKeyDownEvent (Application.QuitKey);
         Assert.True (isQuiting);
 
         // Reset the QuitKey to avoid throws errors on another tests
@@ -728,7 +728,7 @@ public class KeyboardTests
             if (Application.IsInitialized)
             {
                 _output.WriteLine ("  Pressing QuitKey");
-                Application.OnKeyDown (Application.QuitKey);
+                Application.RaiseKeyDownEvent (Application.QuitKey);
             }
         }
     }

+ 5 - 5
UnitTests/Dialogs/MessageBoxTests.cs

@@ -33,14 +33,14 @@ public class MessageBoxTests
 
                                          case 2:
                                              // Tab to btn2
-                                             Application.OnKeyDown (Key.Tab);
+                                             Application.RaiseKeyDownEvent (Key.Tab);
 
                                              Button btn = Application.Navigation!.GetFocused () as Button;
 
                                              btn.Accepting += (sender, e) => { btnAcceptCount++; };
 
                                              // Click
-                                             Application.OnKeyDown (Key.Enter);
+                                             Application.RaiseKeyDownEvent (Key.Enter);
 
                                              break;
 
@@ -77,7 +77,7 @@ public class MessageBoxTests
                                              break;
 
                                          case 2:
-                                             Application.OnKeyDown (Key.Esc);
+                                             Application.RaiseKeyDownEvent (Key.Esc);
 
                                              break;
 
@@ -116,13 +116,13 @@ public class MessageBoxTests
 
                                          case 2:
                                              // Tab to btn2
-                                             Application.OnKeyDown (Key.Tab);
+                                             Application.RaiseKeyDownEvent (Key.Tab);
 
                                              Button btn = Application.Navigation!.GetFocused () as Button;
 
                                              btn.Accepting += (sender, e) => { btnAcceptCount++; };
 
-                                             Application.OnKeyDown (Key.Space);
+                                             Application.RaiseKeyDownEvent (Key.Space);
 
                                              break;
 

+ 6 - 4
UnitTests/FileServices/FileDialogTests.cs

@@ -140,7 +140,7 @@ public class FileDialogTests ()
         AssertIsTheStartingDirectory (dlg.Path);
 
         Assert.IsType<TextField> (dlg.MostFocused);
-        Send ('v', ConsoleKey.DownArrow);
+        Application.RaiseKeyDownEvent (Key.CursorDown);
 
         var tv = GetTableView(dlg);
         tv.SetFocus ();
@@ -152,15 +152,17 @@ public class FileDialogTests ()
         AssertIsTheStartingDirectory (dlg.Path);
 
         // Accept navigation up a directory
-        Send ('\n', ConsoleKey.Enter);
+        Application.RaiseKeyDownEvent (Key.Enter);
 
         AssertIsTheRootDirectory (dlg.Path);
 
         Assert.True (dlg.Canceled);
         Assert.False (selected);
 
-        // Now press the back button (in table view)
-        Send ('<', ConsoleKey.Backspace);
+        Assert.IsType<TableView> (dlg.MostFocused);
+
+        // Now press Backspace (in table view)
+        Application.RaiseKeyDownEvent (Key.Backspace);
 
         // Should move us back to the root
         AssertIsTheStartingDirectory (dlg.Path);

+ 5 - 5
UnitTests/Input/ResponderTests.cs

@@ -205,11 +205,11 @@ public class ResponderTests
         var r = new View ();
         var args = new Key { KeyCode = KeyCode.Null };
 
-        Assert.False (r.OnKeyDown (args));
+        Assert.False (r.NewKeyDownEvent (args));
         Assert.False (args.Handled);
 
         r.KeyDown += (s, a) => a.Handled = true;
-        Assert.True (r.OnKeyDown (args));
+        Assert.True (r.NewKeyDownEvent (args));
         Assert.True (args.Handled);
 
         r.Dispose ();
@@ -232,8 +232,8 @@ public class ResponderTests
         var r = new View ();
 
         //Assert.False (r.OnKeyDown (new KeyEventArgs () { Key = Key.Unknown }));
-        Assert.False (r.OnKeyDown (new Key { KeyCode = KeyCode.Null }));
-        Assert.False (r.OnKeyUp (new Key { KeyCode = KeyCode.Null }));
+        Assert.False (r.NewKeyDownEvent (new Key { KeyCode = KeyCode.Null }));
+        Assert.False (r.NewKeyDownEvent (new Key { KeyCode = KeyCode.Null }));
         Assert.False (r.NewMouseEvent (new MouseEvent { Flags = MouseFlags.AllEvents }));
 
         var v = new View ();
@@ -293,6 +293,6 @@ public class ResponderTests
 
     public class DerivedView : View
     {
-        public override bool OnKeyDown (Key keyEvent) { return true; }
+        protected override bool OnKeyDown (Key keyEvent) { return true; }
     }
 }

+ 1 - 1
UnitTests/UICatalog/ScenarioTests.cs

@@ -132,7 +132,7 @@ public class ScenarioTests : TestsAllViews
             {
                 // Press QuitKey 
                 //_output.WriteLine ($"Forcing Quit with {Application.QuitKey}");
-                Application.OnKeyDown (Application.QuitKey);
+                Application.RaiseKeyDownEvent (Application.QuitKey);
             }
         }
     }

+ 11 - 7
UnitTests/View/HotKeyTests.cs → UnitTests/View/Keyboard/HotKeyTests.cs

@@ -95,7 +95,7 @@ public class HotKeyTests
     {
         var view = new View ();
         view.KeyBindings.Add (Key.A, Command.HotKey); // implies KeyBindingScope.Focused - so this should not be invoked
-        view.InvokingKeyBindings += (s, e) => { Assert.Fail (); };
+        view.KeyDownNotHandled += (s, e) => { Assert.Fail (); };
 
         var superView = new View ();
         superView.Add (view);
@@ -109,8 +109,11 @@ public class HotKeyTests
     {
         var view = new View ();
         view.KeyBindings.Add (Key.A, KeyBindingScope.HotKey, Command.HotKey);
-        bool invoked = false;
-        view.InvokingKeyBindings += (s, e) => { invoked = true; };
+        bool hotKeyInvoked = false;
+        view.HandlingHotKey += (s, e) => { hotKeyInvoked = true; };
+
+        bool notHandled = false;
+        view.KeyDownNotHandled += (s, e) => { notHandled = true; };
 
         var superView = new View ();
         superView.Add (view);
@@ -118,7 +121,8 @@ public class HotKeyTests
         var ke = Key.A;
         superView.NewKeyDownEvent (ke);
 
-        Assert.True (invoked);
+        Assert.False (notHandled);
+        Assert.True (hotKeyInvoked);
     }
 
 
@@ -362,20 +366,20 @@ public class HotKeyTests
         view.Selecting += (s, e) => selectRaised = true;
 
         Assert.Equal (KeyCode.T, view.HotKey);
-        Assert.True (Application.OnKeyDown (Key.T)); 
+        Assert.True (Application.RaiseKeyDownEvent (Key.T)); 
         Assert.True (hotKeyRaised);
         Assert.False (acceptRaised);
         Assert.False (selectRaised);
 
         hotKeyRaised = false;
-        Assert.True (Application.OnKeyDown (Key.T.WithAlt));
+        Assert.True (Application.RaiseKeyDownEvent (Key.T.WithAlt));
         Assert.True (hotKeyRaised);
         Assert.False (acceptRaised);
         Assert.False (selectRaised);
 
         hotKeyRaised = false;
         view.HotKey = KeyCode.E;
-        Assert.True (Application.OnKeyDown (Key.E.WithAlt));
+        Assert.True (Application.RaiseKeyDownEvent (Key.E.WithAlt));
         Assert.True (hotKeyRaised);
         Assert.False (acceptRaised);
         Assert.False (selectRaised);

+ 329 - 0
UnitTests/View/Keyboard/KeyboardEventTests.cs

@@ -0,0 +1,329 @@
+using Xunit.Abstractions;
+
+// Alias Console to MockConsole so we don't accidentally use Console
+
+namespace Terminal.Gui.ViewTests;
+
+public class KeyboardEventTests (ITestOutputHelper output) : TestsAllViews
+{
+    /// <summary>
+    ///     This tests that when a new key down event is sent to the view  will fire the key-down related
+    ///     events: KeyDown and KeyDownNotHandled. Note that KeyUp is independent.
+    /// </summary>
+    [Theory]
+    [MemberData (nameof (AllViewTypes))]
+    public void AllViews_NewKeyDownEvent_All_EventsFire (Type viewType)
+    {
+        var view = CreateInstanceIfNotGeneric (viewType);
+
+        if (view == null)
+        {
+            output.WriteLine ($"ERROR: Skipping generic view: {viewType}");
+
+            return;
+        }
+
+        output.WriteLine ($"Testing {viewType}");
+
+        var keyDown = false;
+
+        view.KeyDown += (s, a) =>
+                        {
+                            a.Handled = false; // don't handle it so the other events are called
+                            keyDown = true;
+                        };
+
+        var keyDownNotHandled = false;
+
+        view.KeyDownNotHandled += (s, a) =>
+                               {
+                                   a.Handled = true;
+                                   keyDownNotHandled = true;
+                               };
+
+        // Key.Empty is invalid, but it's used here to test that the event is fired
+        Assert.True (view.NewKeyDownEvent (Key.Empty)); // this will be true because the ProcessKeyDown event handled it
+        Assert.True (keyDown);
+        Assert.True (keyDownNotHandled);
+        view.Dispose ();
+    }
+
+    /// <summary>
+    ///     This tests that when a new key up event is sent to the view the view will fire the 1 key-up related event:
+    ///     KeyUp
+    /// </summary>
+    [Theory]
+    [MemberData (nameof (AllViewTypes))]
+    public void AllViews_NewKeyUpEvent_All_EventsFire (Type viewType)
+    {
+        var view = CreateInstanceIfNotGeneric (viewType);
+
+        if (view == null)
+        {
+            output.WriteLine ($"ERROR: Generic view {viewType}");
+
+            return;
+        }
+
+        output.WriteLine ($"Testing {view.GetType ().Name}");
+
+        var keyUp = false;
+
+        view.KeyUp += (s, a) =>
+                      {
+                          a.Handled = true;
+                          keyUp = true;
+                      };
+
+        Assert.True (view.NewKeyUpEvent (Key.A)); // this will be true because the KeyUp event handled it
+        Assert.True (keyUp);
+        view.Dispose ();
+    }
+
+    [Theory]
+    [InlineData (true, false, false)]
+    [InlineData (true, true, false)]
+    [InlineData (true, true, true)]
+    public void NewKeyDownUpEvents_Events_Are_Raised_With_Only_Key_Modifiers (bool shift, bool alt, bool control)
+    {
+        var keyDown = false;
+        var keyDownNotHandled = false;
+        var keyUp = false;
+
+        var view = new OnNewKeyTestView ();
+        view.CancelVirtualMethods = false;
+
+        view.KeyDown += (s, e) =>
+                        {
+                            Assert.Equal (KeyCode.Null, e.KeyCode & ~KeyCode.CtrlMask & ~KeyCode.AltMask & ~KeyCode.ShiftMask);
+                            Assert.Equal (shift, e.IsShift);
+                            Assert.Equal (alt, e.IsAlt);
+                            Assert.Equal (control, e.IsCtrl);
+                            Assert.False (keyDown);
+                            Assert.True (view.OnKeyDownCalled);
+                            keyDown = true;
+                        };
+        view.KeyDownNotHandled += (s, e) => { keyDownNotHandled = true; };
+
+        view.KeyUp += (s, e) =>
+                      {
+                          Assert.Equal (KeyCode.Null, e.KeyCode & ~KeyCode.CtrlMask & ~KeyCode.AltMask & ~KeyCode.ShiftMask);
+                          Assert.Equal (shift, e.IsShift);
+                          Assert.Equal (alt, e.IsAlt);
+                          Assert.Equal (control, e.IsCtrl);
+                          Assert.False (keyUp);
+                          Assert.True (view.OnKeyUpCalled);
+                          keyUp = true;
+                      };
+
+        view.NewKeyDownEvent (
+                              new (
+                                   KeyCode.Null
+                                   | (shift ? KeyCode.ShiftMask : 0)
+                                   | (alt ? KeyCode.AltMask : 0)
+                                   | (control ? KeyCode.CtrlMask : 0)
+                                  )
+                             );
+        Assert.True (keyDownNotHandled);
+        Assert.True (view.OnKeyDownCalled);
+        Assert.True (view.OnProcessKeyDownCalled);
+
+        view.NewKeyUpEvent (
+                            new (
+                                 KeyCode.Null
+                                 | (shift ? KeyCode.ShiftMask : 0)
+                                 | (alt ? KeyCode.AltMask : 0)
+                                 | (control ? KeyCode.CtrlMask : 0)
+                                )
+                           );
+        Assert.True (keyUp);
+        Assert.True (view.OnKeyUpCalled);
+    }
+
+    [Fact]
+    public void NewKeyDownEvent_Handled_True_Stops_Processing ()
+    {
+        var keyDown = false;
+        var keyDownNotHandled = false;
+
+        var view = new OnNewKeyTestView ();
+        Assert.True (view.CanFocus);
+        view.CancelVirtualMethods = false;
+
+        view.KeyDown += (s, e) =>
+                        {
+                            Assert.Equal (KeyCode.A, e.KeyCode);
+                            Assert.False (keyDown);
+                            Assert.True (view.OnKeyDownCalled);
+                            e.Handled = true;
+                            keyDown = true;
+                        };
+
+
+        view.KeyDownNotHandled += (s, e) =>
+                               {
+                                   Assert.Equal (KeyCode.A, e.KeyCode);
+                                   Assert.False (keyDownNotHandled);
+                                   Assert.False (view.OnProcessKeyDownCalled);
+                                   e.Handled = true;
+                                   keyDownNotHandled = true;
+                               };
+
+        view.NewKeyDownEvent (Key.A);
+        Assert.True (keyDown);
+        Assert.False (keyDownNotHandled);
+
+        Assert.True (view.OnKeyDownCalled);
+        Assert.False (view.OnProcessKeyDownCalled);
+    }
+
+    [Fact]
+    public void NewKeyDownEvent_KeyDown_Handled_Stops_Processing ()
+    {
+        var view = new View ();
+        var keyDownNotHandled = false;
+        var setHandledTo = false;
+
+        view.KeyDown += (s, e) =>
+                        {
+                            e.Handled = setHandledTo;
+                            Assert.Equal (setHandledTo, e.Handled);
+                            Assert.Equal (KeyCode.N, e.KeyCode);
+                        };
+
+        view.KeyDownNotHandled += (s, e) =>
+                               {
+                                   keyDownNotHandled = true;
+                                   Assert.False (e.Handled);
+                                   Assert.Equal (KeyCode.N, e.KeyCode);
+                               };
+
+        view.NewKeyDownEvent (Key.N);
+        Assert.True (keyDownNotHandled);
+
+        keyDownNotHandled = false;
+        setHandledTo = true;
+        view.NewKeyDownEvent (Key.N);
+        Assert.False (keyDownNotHandled);
+    }
+
+    [Fact]
+    public void NewKeyDownEvent_ProcessKeyDown_Handled_Stops_Processing ()
+    {
+        var keyDown = false;
+        var keyDownNotHandled = false;
+
+        var view = new OnNewKeyTestView ();
+        Assert.True (view.CanFocus);
+        view.CancelVirtualMethods = false;
+
+        view.KeyDown += (s, e) =>
+                        {
+                            Assert.Equal (KeyCode.A, e.KeyCode);
+                            Assert.False (keyDown);
+                            Assert.True (view.OnKeyDownCalled);
+                            e.Handled = false;
+                            keyDown = true;
+                        };
+
+        view.KeyDownNotHandled += (s, e) =>
+                               {
+                                   Assert.Equal (KeyCode.A, e.KeyCode);
+                                   Assert.False (keyDownNotHandled);
+                                   Assert.True (view.OnProcessKeyDownCalled);
+                                   e.Handled = true;
+                                   keyDownNotHandled = true;
+                               };
+
+        view.NewKeyDownEvent (Key.A);
+        Assert.True (keyDown);
+        Assert.True (keyDownNotHandled);
+
+        Assert.True (view.OnKeyDownCalled);
+        Assert.True (view.OnProcessKeyDownCalled);
+    }
+
+    [Fact]
+    public void NewKeyUpEvent_KeyUp_Handled_True_Stops_Processing ()
+    {
+        var keyUp = false;
+
+        var view = new OnNewKeyTestView ();
+        Assert.True (view.CanFocus);
+        view.CancelVirtualMethods = false;
+
+        view.KeyUp += (s, e) =>
+                      {
+                          Assert.Equal (KeyCode.A, e.KeyCode);
+                          Assert.False (keyUp);
+                          Assert.False (view.OnProcessKeyDownCalled);
+                          e.Handled = true;
+                          keyUp = true;
+                      };
+
+        view.NewKeyUpEvent (Key.A);
+        Assert.True (keyUp);
+
+        Assert.True (view.OnKeyUpCalled);
+        Assert.False (view.OnKeyDownCalled);
+        Assert.False (view.OnProcessKeyDownCalled);
+    }
+
+    [Theory]
+    [InlineData (null, null)]
+    [InlineData (true, true)]
+    [InlineData (false, false)]
+    public void InvokeCommandsBoundToKey_Returns_Nullable_Properly (bool? toReturn, bool? expected)
+    {
+        var view = new KeyBindingsTestView ();
+        view.CommandReturns = toReturn;
+
+        bool? result = view.InvokeCommandsBoundToKey (Key.A);
+        Assert.Equal (expected, result);
+    }
+
+    /// <summary>A view that overrides the OnKey* methods so we can test that they are called.</summary>
+    public class KeyBindingsTestView : View
+    {
+        public KeyBindingsTestView ()
+        {
+            CanFocus = true;
+            AddCommand (Command.HotKey, () => CommandReturns);
+            KeyBindings.Add (Key.A, Command.HotKey);
+        }
+
+        public bool? CommandReturns { get; set; }
+    }
+
+    /// <summary>A view that overrides the OnKey* methods so we can test that they are called.</summary>
+    public class OnNewKeyTestView : View
+    {
+        public OnNewKeyTestView () { CanFocus = true; }
+        public bool CancelVirtualMethods { set; private get; }
+        public bool OnKeyDownCalled { get; set; }
+        public bool OnProcessKeyDownCalled { get; set; }
+        public bool OnKeyUpCalled { get; set; }
+        public override string Text { get; set; }
+
+        protected override bool OnKeyDown (Key keyEvent)
+        {
+            OnKeyDownCalled = true;
+
+            return CancelVirtualMethods;
+        }
+
+        public override bool OnKeyUp (Key keyEvent)
+        {
+            OnKeyUpCalled = true;
+
+            return CancelVirtualMethods;
+        }
+
+        protected override bool OnKeyDownNotHandled (Key keyEvent)
+        {
+            OnProcessKeyDownCalled = true;
+
+            return CancelVirtualMethods;
+        }
+    }
+}

+ 39 - 37
UnitTests/View/ViewKeyBindingTests.cs → UnitTests/View/Keyboard/ViewKeyBindingTests.cs

@@ -11,37 +11,38 @@ public class ViewKeyBindingTests (ITestOutputHelper output)
     public void Focus_KeyBinding ()
     {
         var view = new ScopedKeyBindingView ();
-        var invoked = false;
-        view.InvokingKeyBindings += (s, e) => invoked = true;
+        var keyWasHandled = false;
+        view.KeyDownNotHandled += (s, e) => keyWasHandled = true;
 
         var top = new Toplevel ();
         top.Add (view);
         Application.Begin (top);
 
-        Application.OnKeyDown (Key.A);
-        Assert.False (invoked);
+        Application.RaiseKeyDownEvent (Key.A);
+        Assert.False (keyWasHandled);
         Assert.True (view.ApplicationCommand);
 
-        invoked = false;
-        Application.OnKeyDown (Key.H);
-        Assert.True (invoked);
+        keyWasHandled = false;
+        Application.RaiseKeyDownEvent (Key.H);
+        Assert.True (view.HotKeyCommand);
+        Assert.False (keyWasHandled);
 
-        invoked = false;
+        keyWasHandled = false;
         Assert.False (view.HasFocus);
-        Application.OnKeyDown (Key.F);
-        Assert.False (invoked);
+        Application.RaiseKeyDownEvent (Key.F);
+        Assert.False (keyWasHandled);
         Assert.False (view.FocusedCommand);
 
-        invoked = false;
+        keyWasHandled = false;
         view.CanFocus = true;
         view.SetFocus ();
         Assert.True (view.HasFocus);
-        Application.OnKeyDown (Key.F);
-        Assert.True (invoked);
+        Application.RaiseKeyDownEvent (Key.F);
+        Assert.True (view.FocusedCommand);
+        Assert.False (keyWasHandled); // Command was invoked, but wasn't handled
 
         Assert.True (view.ApplicationCommand);
         Assert.True (view.HotKeyCommand);
-        Assert.True (view.FocusedCommand);
         top.Dispose ();
     }
 
@@ -50,23 +51,23 @@ public class ViewKeyBindingTests (ITestOutputHelper output)
     public void Focus_KeyBinding_Negative ()
     {
         var view = new ScopedKeyBindingView ();
-        var invoked = false;
-        view.InvokingKeyBindings += (s, e) => invoked = true;
+        var keyWasHandled = false;
+        view.KeyDownNotHandled += (s, e) => keyWasHandled = true;
 
         var top = new Toplevel ();
         top.Add (view);
         Application.Begin (top);
 
-        Application.OnKeyDown (Key.Z);
-        Assert.False (invoked);
+        Application.RaiseKeyDownEvent (Key.Z);
+        Assert.False (keyWasHandled);
         Assert.False (view.ApplicationCommand);
         Assert.False (view.HotKeyCommand);
         Assert.False (view.FocusedCommand);
 
-        invoked = false;
+        keyWasHandled = false;
         Assert.False (view.HasFocus);
-        Application.OnKeyDown (Key.F);
-        Assert.False (invoked);
+        Application.RaiseKeyDownEvent (Key.F);
+        Assert.False (keyWasHandled);
         Assert.False (view.ApplicationCommand);
         Assert.False (view.HotKeyCommand);
         Assert.False (view.FocusedCommand);
@@ -78,28 +79,29 @@ public class ViewKeyBindingTests (ITestOutputHelper output)
     public void HotKey_KeyBinding ()
     {
         var view = new ScopedKeyBindingView ();
-        var invoked = false;
-        view.InvokingKeyBindings += (s, e) => invoked = true;
+        var keyWasHandled = false;
+        view.KeyDownNotHandled += (s, e) => keyWasHandled = true;
 
         var top = new Toplevel ();
         top.Add (view);
         Application.Begin (top);
 
-        invoked = false;
-        Application.OnKeyDown (Key.H);
-        Assert.True (invoked);
+        keyWasHandled = false;
+        Application.RaiseKeyDownEvent (Key.H);
         Assert.True (view.HotKeyCommand);
+        Assert.False (keyWasHandled);
 
         view.HotKey = KeyCode.Z;
-        invoked = false;
+        keyWasHandled = false;
         view.HotKeyCommand = false;
-        Application.OnKeyDown (Key.H); // old hot key
-        Assert.False (invoked);
+        Application.RaiseKeyDownEvent (Key.H); // old hot key
+        Assert.False (keyWasHandled);
         Assert.False (view.HotKeyCommand);
 
-        Application.OnKeyDown (Key.Z); // new hot key
-        Assert.True (invoked);
+        Application.RaiseKeyDownEvent (Key.Z); // new hot key
         Assert.True (view.HotKeyCommand);
+        Assert.False (keyWasHandled);
+
         top.Dispose ();
     }
 
@@ -108,19 +110,19 @@ public class ViewKeyBindingTests (ITestOutputHelper output)
     public void HotKey_KeyBinding_Negative ()
     {
         var view = new ScopedKeyBindingView ();
-        var invoked = false;
-        view.InvokingKeyBindings += (s, e) => invoked = true;
+        var keyWasHandled = false;
+        view.KeyDownNotHandled += (s, e) => keyWasHandled = true;
 
         var top = new Toplevel ();
         top.Add (view);
         Application.Begin (top);
 
-        Application.OnKeyDown (Key.Z);
-        Assert.False (invoked);
+        Application.RaiseKeyDownEvent (Key.Z);
+        Assert.False (keyWasHandled);
         Assert.False (view.HotKeyCommand);
 
-        invoked = false;
-        Application.OnKeyDown (Key.F);
+        keyWasHandled = false;
+        Application.RaiseKeyDownEvent (Key.F);
         Assert.False (view.HotKeyCommand);
         top.Dispose ();
     }

+ 0 - 502
UnitTests/View/KeyboardEventTests.cs

@@ -1,502 +0,0 @@
-using Xunit.Abstractions;
-
-// Alias Console to MockConsole so we don't accidentally use Console
-
-namespace Terminal.Gui.ViewTests;
-
-public class KeyboardEventTests (ITestOutputHelper output) : TestsAllViews
-{
-    /// <summary>
-    ///     This tests that when a new key down event is sent to the view  will fire the 3 key-down related
-    ///     events: KeyDown, InvokingKeyBindings, and ProcessKeyDown. Note that KeyUp is independent.
-    /// </summary>
-    [Theory]
-    [MemberData (nameof (AllViewTypes))]
-    public void AllViews_KeyDown_All_EventsFire (Type viewType)
-    {
-        var view = CreateInstanceIfNotGeneric (viewType);
-
-        if (view == null)
-        {
-            output.WriteLine ($"ERROR: Skipping generic view: {viewType}");
-
-            return;
-        }
-
-        output.WriteLine ($"Testing {viewType}");
-
-        var keyDown = false;
-
-        view.KeyDown += (s, a) =>
-                        {
-                            a.Handled = false; // don't handle it so the other events are called
-                            keyDown = true;
-                        };
-
-        var invokingKeyBindings = false;
-
-        view.InvokingKeyBindings += (s, a) =>
-                                    {
-                                        a.Handled = false; // don't handle it so the other events are called
-                                        invokingKeyBindings = true;
-                                    };
-
-        var keyDownProcessed = false;
-
-        view.ProcessKeyDown += (s, a) =>
-                               {
-                                   a.Handled = true;
-                                   keyDownProcessed = true;
-                               };
-
-        Assert.True (view.NewKeyDownEvent (Key.A)); // this will be true because the ProcessKeyDown event handled it
-        Assert.True (keyDown);
-        Assert.True (invokingKeyBindings);
-        Assert.True (keyDownProcessed);
-        view.Dispose ();
-    }
-
-    /// <summary>
-    ///     This tests that when a new key up event is sent to the view the view will fire the 1 key-up related event:
-    ///     KeyUp
-    /// </summary>
-    [Theory]
-    [MemberData (nameof (AllViewTypes))]
-    public void AllViews_KeyUp_All_EventsFire (Type viewType)
-    {
-        var view = CreateInstanceIfNotGeneric (viewType);
-
-        if (view == null)
-        {
-            output.WriteLine ($"ERROR: Generic view {viewType}");
-
-            return;
-        }
-
-        output.WriteLine ($"Testing {view.GetType ().Name}");
-
-        var keyUp = false;
-
-        view.KeyUp += (s, a) =>
-                      {
-                          a.Handled = true;
-                          keyUp = true;
-                      };
-
-        Assert.True (view.NewKeyUpEvent (Key.A)); // this will be true because the KeyUp event handled it
-        Assert.True (keyUp);
-        view.Dispose ();
-    }
-
-    [Theory]
-    [InlineData (true, false, false)]
-    [InlineData (true, true, false)]
-    [InlineData (true, true, true)]
-    public void Events_Are_Called_With_Only_Key_Modifiers (bool shift, bool alt, bool control)
-    {
-        var keyDown = false;
-        var keyPressed = false;
-        var keyUp = false;
-
-        var view = new OnKeyTestView ();
-        view.CancelVirtualMethods = false;
-
-        view.KeyDown += (s, e) =>
-                        {
-                            Assert.Equal (KeyCode.Null, e.KeyCode & ~KeyCode.CtrlMask & ~KeyCode.AltMask & ~KeyCode.ShiftMask);
-                            Assert.Equal (shift, e.IsShift);
-                            Assert.Equal (alt, e.IsAlt);
-                            Assert.Equal (control, e.IsCtrl);
-                            Assert.False (keyDown);
-                            Assert.False (view.OnKeyDownContinued);
-                            keyDown = true;
-                        };
-        view.ProcessKeyDown += (s, e) => { keyPressed = true; };
-
-        view.KeyUp += (s, e) =>
-                      {
-                          Assert.Equal (KeyCode.Null, e.KeyCode & ~KeyCode.CtrlMask & ~KeyCode.AltMask & ~KeyCode.ShiftMask);
-                          Assert.Equal (shift, e.IsShift);
-                          Assert.Equal (alt, e.IsAlt);
-                          Assert.Equal (control, e.IsCtrl);
-                          Assert.False (keyUp);
-                          Assert.False (view.OnKeyUpContinued);
-                          keyUp = true;
-                      };
-
-        //view.ProcessKeyDownEvent (new (Key.Null | (shift ? Key.ShiftMask : 0) | (alt ? Key.AltMask : 0) | (control ? Key.CtrlMask : 0)));
-        //Assert.True (keyDown);
-        //Assert.True (view.OnKeyDownWasCalled);
-        //Assert.True (view.OnProcessKeyDownWasCalled);
-
-        view.NewKeyDownEvent (
-                              new (
-                                   KeyCode.Null
-                                   | (shift ? KeyCode.ShiftMask : 0)
-                                   | (alt ? KeyCode.AltMask : 0)
-                                   | (control ? KeyCode.CtrlMask : 0)
-                                  )
-                             );
-        Assert.True (keyPressed);
-        Assert.True (view.OnKeyDownContinued);
-        Assert.True (view.OnKeyPressedContinued);
-
-        view.NewKeyUpEvent (
-                            new (
-                                 KeyCode.Null
-                                 | (shift ? KeyCode.ShiftMask : 0)
-                                 | (alt ? KeyCode.AltMask : 0)
-                                 | (control ? KeyCode.CtrlMask : 0)
-                                )
-                           );
-        Assert.True (keyUp);
-        Assert.True (view.OnKeyUpContinued);
-    }
-
-    [Fact]
-    public void InvokingKeyBindings_Handled_Cancels ()
-    {
-        var view = new View ();
-        var keyPressInvoked = false;
-        var invokingKeyBindingsInvoked = false;
-        var processKeyPressInvoked = false;
-        var setHandledTo = false;
-
-        view.KeyDown += (s, e) =>
-                        {
-                            keyPressInvoked = true;
-                            Assert.False (e.Handled);
-                            Assert.Equal (KeyCode.N, e.KeyCode);
-                        };
-
-        view.InvokingKeyBindings += (s, e) =>
-                                    {
-                                        invokingKeyBindingsInvoked = true;
-                                        e.Handled = setHandledTo;
-                                        Assert.Equal (setHandledTo, e.Handled);
-                                        Assert.Equal (KeyCode.N, e.KeyCode);
-                                    };
-
-        view.ProcessKeyDown += (s, e) =>
-                               {
-                                   processKeyPressInvoked = true;
-                                   processKeyPressInvoked = true;
-                                   Assert.False (e.Handled);
-                                   Assert.Equal (KeyCode.N, e.KeyCode);
-                               };
-
-        view.NewKeyDownEvent (Key.N);
-        Assert.True (keyPressInvoked);
-        Assert.True (invokingKeyBindingsInvoked);
-        Assert.True (processKeyPressInvoked);
-
-        keyPressInvoked = false;
-        invokingKeyBindingsInvoked = false;
-        processKeyPressInvoked = false;
-        setHandledTo = true;
-        view.NewKeyDownEvent (Key.N);
-        Assert.True (keyPressInvoked);
-        Assert.True (invokingKeyBindingsInvoked);
-        Assert.False (processKeyPressInvoked);
-    }
-
-    [Fact]
-    public void InvokingKeyBindings_Handled_True_Stops_Processing ()
-    {
-        var keyDown = false;
-        var invokingKeyBindings = false;
-        var keyPressed = false;
-
-        var view = new OnKeyTestView ();
-        Assert.True (view.CanFocus);
-        view.CancelVirtualMethods = false;
-
-        view.KeyDown += (s, e) =>
-                        {
-                            Assert.Equal (KeyCode.A, e.KeyCode);
-                            Assert.False (keyDown);
-                            Assert.False (view.OnKeyDownContinued);
-                            e.Handled = false;
-                            keyDown = true;
-                        };
-
-        view.InvokingKeyBindings += (s, e) =>
-                                    {
-                                        Assert.Equal (KeyCode.A, e.KeyCode);
-                                        Assert.False (keyPressed);
-                                        Assert.False (view.OnInvokingKeyBindingsContinued);
-                                        e.Handled = true;
-                                        invokingKeyBindings = true;
-                                    };
-
-        view.ProcessKeyDown += (s, e) =>
-                               {
-                                   Assert.Equal (KeyCode.A, e.KeyCode);
-                                   Assert.False (keyPressed);
-                                   Assert.False (view.OnKeyPressedContinued);
-                                   e.Handled = true;
-                                   keyPressed = true;
-                               };
-
-        view.NewKeyDownEvent (Key.A);
-        Assert.True (keyDown);
-        Assert.True (invokingKeyBindings);
-        Assert.False (keyPressed);
-
-        Assert.True (view.OnKeyDownContinued);
-        Assert.False (view.OnInvokingKeyBindingsContinued);
-        Assert.False (view.OnKeyPressedContinued);
-    }
-
-    [Fact]
-    public void KeyDown_Handled_True_Stops_Processing ()
-    {
-        var keyDown = false;
-        var invokingKeyBindings = false;
-        var keyPressed = false;
-
-        var view = new OnKeyTestView ();
-        Assert.True (view.CanFocus);
-        view.CancelVirtualMethods = false;
-
-        view.KeyDown += (s, e) =>
-                        {
-                            Assert.Equal (KeyCode.A, e.KeyCode);
-                            Assert.False (keyDown);
-                            Assert.False (view.OnKeyDownContinued);
-                            e.Handled = true;
-                            keyDown = true;
-                        };
-
-        view.InvokingKeyBindings += (s, e) =>
-                                    {
-                                        Assert.Equal (KeyCode.A, e.KeyCode);
-                                        Assert.False (keyPressed);
-                                        Assert.False (view.OnInvokingKeyBindingsContinued);
-                                        e.Handled = true;
-                                        invokingKeyBindings = true;
-                                    };
-
-        view.ProcessKeyDown += (s, e) =>
-                               {
-                                   Assert.Equal (KeyCode.A, e.KeyCode);
-                                   Assert.False (keyPressed);
-                                   Assert.False (view.OnKeyPressedContinued);
-                                   e.Handled = true;
-                                   keyPressed = true;
-                               };
-
-        view.NewKeyDownEvent (Key.A);
-        Assert.True (keyDown);
-        Assert.False (invokingKeyBindings);
-        Assert.False (keyPressed);
-
-        Assert.False (view.OnKeyDownContinued);
-        Assert.False (view.OnInvokingKeyBindingsContinued);
-        Assert.False (view.OnKeyPressedContinued);
-    }
-
-    [Fact]
-    public void KeyPress_Handled_Cancels ()
-    {
-        var view = new View ();
-        var invokingKeyBindingsInvoked = false;
-        var processKeyPressInvoked = false;
-        var setHandledTo = false;
-
-        view.KeyDown += (s, e) =>
-                        {
-                            e.Handled = setHandledTo;
-                            Assert.Equal (setHandledTo, e.Handled);
-                            Assert.Equal (KeyCode.N, e.KeyCode);
-                        };
-
-        view.InvokingKeyBindings += (s, e) =>
-                                    {
-                                        invokingKeyBindingsInvoked = true;
-                                        Assert.False (e.Handled);
-                                        Assert.Equal (KeyCode.N, e.KeyCode);
-                                    };
-
-        view.ProcessKeyDown += (s, e) =>
-                               {
-                                   processKeyPressInvoked = true;
-                                   Assert.False (e.Handled);
-                                   Assert.Equal (KeyCode.N, e.KeyCode);
-                               };
-
-        view.NewKeyDownEvent (Key.N);
-        Assert.True (invokingKeyBindingsInvoked);
-        Assert.True (processKeyPressInvoked);
-
-        invokingKeyBindingsInvoked = false;
-        processKeyPressInvoked = false;
-        setHandledTo = true;
-        view.NewKeyDownEvent (Key.N);
-        Assert.False (invokingKeyBindingsInvoked);
-        Assert.False (processKeyPressInvoked);
-    }
-
-    [Fact]
-    public void KeyPressed_Handled_True_Stops_Processing ()
-    {
-        var keyDown = false;
-        var invokingKeyBindings = false;
-        var keyPressed = false;
-
-        var view = new OnKeyTestView ();
-        Assert.True (view.CanFocus);
-        view.CancelVirtualMethods = false;
-
-        view.KeyDown += (s, e) =>
-                        {
-                            Assert.Equal (KeyCode.A, e.KeyCode);
-                            Assert.False (keyDown);
-                            Assert.False (view.OnKeyDownContinued);
-                            e.Handled = false;
-                            keyDown = true;
-                        };
-
-        view.InvokingKeyBindings += (s, e) =>
-                                    {
-                                        Assert.Equal (KeyCode.A, e.KeyCode);
-                                        Assert.False (keyPressed);
-                                        Assert.False (view.OnInvokingKeyBindingsContinued);
-                                        e.Handled = false;
-                                        invokingKeyBindings = true;
-                                    };
-
-        view.ProcessKeyDown += (s, e) =>
-                               {
-                                   Assert.Equal (KeyCode.A, e.KeyCode);
-                                   Assert.False (keyPressed);
-                                   Assert.False (view.OnKeyPressedContinued);
-                                   e.Handled = true;
-                                   keyPressed = true;
-                               };
-
-        view.NewKeyDownEvent (Key.A);
-        Assert.True (keyDown);
-        Assert.True (invokingKeyBindings);
-        Assert.True (keyPressed);
-
-        Assert.True (view.OnKeyDownContinued);
-        Assert.True (view.OnInvokingKeyBindingsContinued);
-        Assert.False (view.OnKeyPressedContinued);
-    }
-
-    [Fact]
-    public void KeyUp_Handled_True_Stops_Processing ()
-    {
-        var keyUp = false;
-
-        var view = new OnKeyTestView ();
-        Assert.True (view.CanFocus);
-        view.CancelVirtualMethods = false;
-
-        view.KeyUp += (s, e) =>
-                      {
-                          Assert.Equal (KeyCode.A, e.KeyCode);
-                          Assert.False (keyUp);
-                          Assert.False (view.OnKeyPressedContinued);
-                          e.Handled = true;
-                          keyUp = true;
-                      };
-
-        view.NewKeyUpEvent (Key.A);
-        Assert.True (keyUp);
-
-        Assert.False (view.OnKeyUpContinued);
-        Assert.False (view.OnKeyDownContinued);
-        Assert.False (view.OnInvokingKeyBindingsContinued);
-        Assert.False (view.OnKeyPressedContinued);
-    }
-
-    [Theory]
-    [InlineData (null, null)]
-    [InlineData (true, true)]
-    [InlineData (false, false)]
-    public void OnInvokingKeyBindings_Returns_Nullable_Properly (bool? toReturn, bool? expected)
-    {
-        var view = new KeyBindingsTestView ();
-        view.CommandReturns = toReturn;
-
-        bool? result = view.OnInvokingKeyBindings (Key.A, KeyBindingScope.HotKey | KeyBindingScope.Focused);
-        Assert.Equal (expected, result);
-    }
-
-    /// <summary>A view that overrides the OnKey* methods so we can test that they are called.</summary>
-    public class KeyBindingsTestView : View
-    {
-        public KeyBindingsTestView ()
-        {
-            CanFocus = true;
-            AddCommand (Command.HotKey, () => CommandReturns);
-            KeyBindings.Add (Key.A, Command.HotKey);
-        }
-
-        public bool? CommandReturns { get; set; }
-    }
-
-    /// <summary>A view that overrides the OnKey* methods so we can test that they are called.</summary>
-    public class OnKeyTestView : View
-    {
-        public OnKeyTestView () { CanFocus = true; }
-        public bool CancelVirtualMethods { set; private get; }
-        public bool OnInvokingKeyBindingsContinued { get; set; }
-        public bool OnKeyDownContinued { get; set; }
-        public bool OnKeyPressedContinued { get; set; }
-        public bool OnKeyUpContinued { get; set; }
-        public override string Text { get; set; }
-
-        public override bool? OnInvokingKeyBindings (Key keyEvent, KeyBindingScope scope)
-        {
-            bool? handled = base.OnInvokingKeyBindings (keyEvent, scope);
-
-            if (handled != null && (bool)handled)
-            {
-                return true;
-            }
-
-            OnInvokingKeyBindingsContinued = true;
-
-            return CancelVirtualMethods;
-        }
-
-        public override bool OnKeyDown (Key keyEvent)
-        {
-            if (base.OnKeyDown (keyEvent))
-            {
-                return true;
-            }
-
-            OnKeyDownContinued = true;
-
-            return CancelVirtualMethods;
-        }
-
-        public override bool OnKeyUp (Key keyEvent)
-        {
-            if (base.OnKeyUp (keyEvent))
-            {
-                return true;
-            }
-
-            OnKeyUpContinued = true;
-
-            return CancelVirtualMethods;
-        }
-
-        public override bool OnProcessKeyDown (Key keyEvent)
-        {
-            if (base.OnProcessKeyDown (keyEvent))
-            {
-                return true;
-            }
-
-            OnKeyPressedContinued = true;
-
-            return CancelVirtualMethods;
-        }
-    }
-}

+ 1 - 1
UnitTests/View/Navigation/CanFocusTests.cs

@@ -354,7 +354,7 @@ public class CanFocusTests () : TestsAllViews
         Assert.False (label.HasFocus);
         Assert.True (view.HasFocus);
 
-        Assert.True (Application.OnKeyDown (Key.Tab));
+        Assert.True (Application.RaiseKeyDownEvent (Key.Tab));
         Assert.True (label.HasFocus);
         Assert.False (view.HasFocus);
 

+ 11 - 11
UnitTests/View/Navigation/NavigationTests.cs

@@ -59,17 +59,17 @@ public class NavigationTests (ITestOutputHelper _output) : TestsAllViews
                 case TabBehavior.TabStop:
                 case TabBehavior.NoStop:
                 case TabBehavior.TabGroup:
-                    Application.OnKeyDown (key);
+                    Application.RaiseKeyDownEvent (key);
 
                     if (view.HasFocus)
                     {
                         // Try once more (HexView)
-                        Application.OnKeyDown (key);
+                        Application.RaiseKeyDownEvent (key);
                     }
 
                     break;
                 default:
-                    Application.OnKeyDown (Key.Tab);
+                    Application.RaiseKeyDownEvent (Key.Tab);
 
                     break;
             }
@@ -178,18 +178,18 @@ public class NavigationTests (ITestOutputHelper _output) : TestsAllViews
                 case null:
                 case TabBehavior.NoStop:
                 case TabBehavior.TabStop:
-                    if (Application.OnKeyDown (Key.Tab))
+                    if (Application.RaiseKeyDownEvent (Key.Tab))
                     {
                         if (view.HasFocus)
                         {
                             // Try another nav key (e.g. for TextView that eats Tab)
-                            Application.OnKeyDown (Key.CursorDown);
+                            Application.RaiseKeyDownEvent (Key.CursorDown);
                         }
                     };
                     break;
 
                 case TabBehavior.TabGroup:
-                    Application.OnKeyDown (Key.F6);
+                    Application.RaiseKeyDownEvent (Key.F6);
 
                     break;
                 default:
@@ -211,18 +211,18 @@ public class NavigationTests (ITestOutputHelper _output) : TestsAllViews
 
                 break;
             case TabBehavior.TabStop:
-                Application.OnKeyDown (Key.Tab);
+                Application.RaiseKeyDownEvent (Key.Tab);
 
                 break;
             case TabBehavior.TabGroup:
-                if (!Application.OnKeyDown (Key.F6))
+                if (!Application.RaiseKeyDownEvent (Key.F6))
                 {
                     view.SetFocus ();
                 }
 
                 break;
             case null:
-                Application.OnKeyDown (Key.Tab);
+                Application.RaiseKeyDownEvent (Key.Tab);
 
                 break;
             default:
@@ -308,12 +308,12 @@ public class NavigationTests (ITestOutputHelper _output) : TestsAllViews
         Assert.Equal (0, hasFocusChangingCount);
         Assert.Equal (0, hasFocusChangedCount);
 
-        Application.OnKeyDown (Key.Tab);
+        Application.RaiseKeyDownEvent (Key.Tab);
 
         Assert.Equal (0, hasFocusChangingCount);
         Assert.Equal (0, hasFocusChangedCount);
 
-        Application.OnKeyDown (Key.F6);
+        Application.RaiseKeyDownEvent (Key.F6);
 
         Assert.Equal (0, hasFocusChangingCount);
         Assert.Equal (0, hasFocusChangedCount);

+ 4 - 4
UnitTests/View/ViewTests.cs

@@ -870,10 +870,10 @@ At 0,0
     {
         var r = new View ();
 
-        Assert.False (r.OnKeyDown (new () { KeyCode = KeyCode.Null }));
+        Assert.False (r.NewKeyDownEvent (Key.Empty));
 
         //Assert.False (r.OnKeyDown (new KeyEventArgs () { Key = Key.Unknown }));
-        Assert.False (r.OnKeyUp (new () { KeyCode = KeyCode.Null }));
+        Assert.False (r.NewKeyUpEvent (Key.Empty));
         Assert.False (r.NewMouseEvent (new () { Flags = MouseFlags.AllEvents }));
 
         r.Dispose ();
@@ -1132,7 +1132,7 @@ At 0,0
             ClearNeedsDisplay ();
         }
 
-        public override bool OnKeyDown (Key keyEvent)
+        protected override bool OnKeyDown (Key keyEvent)
         {
             IsKeyDown = true;
 
@@ -1146,7 +1146,7 @@ At 0,0
             return true;
         }
 
-        public override bool OnProcessKeyDown (Key keyEvent)
+        protected override bool OnKeyDownNotHandled (Key keyEvent)
         {
             IsKeyPress = true;
 

+ 6 - 6
UnitTests/Views/ButtonTests.cs

@@ -376,7 +376,7 @@ public class ButtonTests (ITestOutputHelper output)
         Assert.True (btn.HasFocus);
 
         // default keybinding is Space which results in Command.Accept (when focused)
-        Application.OnKeyDown (new ((KeyCode)' '));
+        Application.RaiseKeyDownEvent (new ((KeyCode)' '));
         Assert.Equal (1, pressed);
 
         // remove the default keybinding (Space)
@@ -384,26 +384,26 @@ public class ButtonTests (ITestOutputHelper output)
         btn.KeyBindings.Clear (Command.Accept);
 
         // After clearing the default keystroke the Space button no longer does anything for the Button
-        Application.OnKeyDown (new ((KeyCode)' '));
+        Application.RaiseKeyDownEvent (new ((KeyCode)' '));
         Assert.Equal (1, pressed);
 
         // Set a new binding of b for the click (Accept) event
         btn.KeyBindings.Add (Key.B, Command.HotKey); // b will now trigger the Accept command (when focused or not)
 
         // now pressing B should call the button click event
-        Application.OnKeyDown (Key.B);
+        Application.RaiseKeyDownEvent (Key.B);
         Assert.Equal (2, pressed);
 
         // now pressing Shift-B should NOT call the button click event
-        Application.OnKeyDown (Key.B.WithShift);
+        Application.RaiseKeyDownEvent (Key.B.WithShift);
         Assert.Equal (2, pressed);
 
         // now pressing Alt-B should NOT call the button click event
-        Application.OnKeyDown (Key.B.WithAlt);
+        Application.RaiseKeyDownEvent (Key.B.WithAlt);
         Assert.Equal (2, pressed);
 
         // now pressing Shift-Alt-B should NOT call the button click event
-        Application.OnKeyDown (Key.B.WithAlt.WithShift);
+        Application.RaiseKeyDownEvent (Key.B.WithAlt.WithShift);
         Assert.Equal (2, pressed);
         top.Dispose ();
     }

+ 23 - 23
UnitTests/Views/ColorPickerTests.cs

@@ -64,14 +64,14 @@ public class ColorPickerTests
 
         cp.Draw ();
 
-        Application.OnKeyDown (Key.CursorRight);
+        Application.RaiseKeyDownEvent (Key.CursorRight);
 
         cp.Draw ();
 
         Assert.Equal (3, r.TrianglePosition);
         Assert.Equal ("#0F0000", hex.Text);
 
-        Application.OnKeyDown (Key.CursorRight);
+        Application.RaiseKeyDownEvent (Key.CursorRight);
 
         cp.Draw ();
 
@@ -81,7 +81,7 @@ public class ColorPickerTests
         // Use cursor to move the triangle all the way to the right
         for (int i = 0; i < 1000; i++)
         {
-            Application.OnKeyDown (Key.CursorRight);
+            Application.RaiseKeyDownEvent (Key.CursorRight);
         }
 
         cp.Draw ();
@@ -713,19 +713,19 @@ public class ColorPickerTests
         name.Text = "";
         Assert.Empty (name.Text);
 
-        Application.OnKeyDown (Key.A);
-        Application.OnKeyDown (Key.Q);
+        Application.RaiseKeyDownEvent (Key.A);
+        Application.RaiseKeyDownEvent (Key.Q);
 
         Assert.Equal ("aq", name.Text);
 
 
         // Auto complete the color name
-        Application.OnKeyDown (Key.Tab);
+        Application.RaiseKeyDownEvent (Key.Tab);
 
         Assert.Equal ("Aquamarine", name.Text);
 
         // Tab out of the text field
-        Application.OnKeyDown (Key.Tab);
+        Application.RaiseKeyDownEvent (Key.Tab);
 
         Assert.False (name.HasFocus);
         Assert.NotSame (name, cp.Focused);
@@ -761,24 +761,24 @@ public class ColorPickerTests
         Assert.Empty (hex.Text);
         Assert.Empty (name.Text);
 
-        Application.OnKeyDown ('#');
+        Application.RaiseKeyDownEvent ('#');
         Assert.Empty (name.Text);
         //7FFFD4
 
         Assert.Equal ("#", hex.Text);
-        Application.OnKeyDown ('7');
-        Application.OnKeyDown ('F');
-        Application.OnKeyDown ('F');
-        Application.OnKeyDown ('F');
-        Application.OnKeyDown ('D');
+        Application.RaiseKeyDownEvent ('7');
+        Application.RaiseKeyDownEvent ('F');
+        Application.RaiseKeyDownEvent ('F');
+        Application.RaiseKeyDownEvent ('F');
+        Application.RaiseKeyDownEvent ('D');
         Assert.Empty (name.Text);
 
-        Application.OnKeyDown ('4');
+        Application.RaiseKeyDownEvent ('4');
 
         Assert.True (hex.HasFocus);
 
         // Tab out of the hex field - should wrap to first focusable subview 
-        Application.OnKeyDown (Key.Tab);
+        Application.RaiseKeyDownEvent (Key.Tab);
         Assert.False (hex.HasFocus);
         Assert.NotSame (hex, cp.Focused);
 
@@ -819,24 +819,24 @@ public class ColorPickerTests
         Assert.Empty (hex.Text);
         Assert.Empty (name.Text);
 
-        Application.OnKeyDown ('#');
+        Application.RaiseKeyDownEvent ('#');
         Assert.Empty (name.Text);
         //7FFFD4
 
         Assert.Equal ("#", hex.Text);
-        Application.OnKeyDown ('7');
-        Application.OnKeyDown ('F');
-        Application.OnKeyDown ('F');
-        Application.OnKeyDown ('F');
-        Application.OnKeyDown ('D');
+        Application.RaiseKeyDownEvent ('7');
+        Application.RaiseKeyDownEvent ('F');
+        Application.RaiseKeyDownEvent ('F');
+        Application.RaiseKeyDownEvent ('F');
+        Application.RaiseKeyDownEvent ('D');
         Assert.Empty (name.Text);
 
-        Application.OnKeyDown ('4');
+        Application.RaiseKeyDownEvent ('4');
 
         Assert.True (hex.HasFocus);
 
         // Should stay in the hex field (because accept not tab)
-        Application.OnKeyDown (Key.Enter);
+        Application.RaiseKeyDownEvent (Key.Enter);
         Assert.True (hex.HasFocus);
         Assert.Same (hex, cp.Focused);
 

+ 44 - 44
UnitTests/Views/ComboBoxTests.cs

@@ -105,13 +105,13 @@ public class ComboBoxTests (ITestOutputHelper output)
         Assert.Equal (-1, cb.SelectedItem);
         Assert.Equal ("", cb.Text);
 
-        Assert.True (Application.OnKeyDown (Key.F4));
+        Assert.True (Application.RaiseKeyDownEvent (Key.F4));
         Assert.NotNull (cb.Source);
         Assert.True (cb.IsShow);
         Assert.Equal (-1, cb.SelectedItem);
         Assert.Equal ("", cb.Text);
 
-        Assert.True (Application.OnKeyDown (Key.F4));
+        Assert.True (Application.RaiseKeyDownEvent (Key.F4));
         Assert.Null (cb.Source);
         Assert.False (cb.IsShow);
         Assert.Equal (-1, cb.SelectedItem);
@@ -155,7 +155,7 @@ public class ComboBoxTests (ITestOutputHelper output)
         Assert.Equal (1, cb.SelectedItem);
         Assert.Equal ("Two", cb.Text);
 
-        Assert.True (Application.OnKeyDown (Key.F4));
+        Assert.True (Application.RaiseKeyDownEvent (Key.F4));
         Assert.Equal ("Two", selected);
         Assert.True (cb.IsShow);
         Assert.Equal (1, cb.SelectedItem);
@@ -166,7 +166,7 @@ public class ComboBoxTests (ITestOutputHelper output)
         Assert.Equal (2, cb.SelectedItem);
         Assert.Equal ("Three", cb.Text);
 
-        Assert.True (Application.OnKeyDown (Key.Esc));
+        Assert.True (Application.RaiseKeyDownEvent (Key.Esc));
         Assert.Equal ("Two", selected);
         Assert.False (cb.IsShow);
         Assert.Equal (1, cb.SelectedItem);
@@ -202,7 +202,7 @@ public class ComboBoxTests (ITestOutputHelper output)
         Assert.Equal ("One", cb.Text);
 
         Assert.True (cb.Subviews [1].NewKeyDownEvent (Key.CursorDown));
-        Assert.True (Application.OnKeyDown (Key.F4));
+        Assert.True (Application.RaiseKeyDownEvent (Key.F4));
         Assert.Equal ("Two", selected);
         Assert.False (cb.IsShow);
         Assert.Equal (1, cb.SelectedItem);
@@ -251,7 +251,7 @@ public class ComboBoxTests (ITestOutputHelper output)
         Assert.Equal (1, cb.SelectedItem);
         Assert.Equal ("Two", cb.Text);
 
-        Assert.True (Application.OnKeyDown (Key.F4));
+        Assert.True (Application.RaiseKeyDownEvent (Key.F4));
         Assert.Equal ("Two", selected);
         Assert.True (cb.IsShow);
         Assert.Equal (1, cb.SelectedItem);
@@ -262,7 +262,7 @@ public class ComboBoxTests (ITestOutputHelper output)
         Assert.Equal (2, cb.SelectedItem);
         Assert.Equal ("Three", cb.Text);
 
-        Assert.True (Application.OnKeyDown (Key.Esc));
+        Assert.True (Application.RaiseKeyDownEvent (Key.Esc));
         Assert.Equal ("Two", selected);
         Assert.False (cb.IsShow);
         Assert.Equal (1, cb.SelectedItem);
@@ -417,7 +417,7 @@ public class ComboBoxTests (ITestOutputHelper output)
         Assert.Equal (-1, cb.SelectedItem);
         Assert.Equal ("", cb.Text);
 
-        Assert.True (Application.OnKeyDown (Key.F4));
+        Assert.True (Application.RaiseKeyDownEvent (Key.F4));
 
         Assert.True (
                      cb.Subviews [1]
@@ -441,7 +441,7 @@ public class ComboBoxTests (ITestOutputHelper output)
         Assert.Equal (-1, cb.SelectedItem);
         Assert.Equal ("", cb.Text);
 
-        Assert.True (Application.OnKeyDown (Key.F4));
+        Assert.True (Application.RaiseKeyDownEvent (Key.F4));
 
         Assert.True (
                      cb.Subviews [1]
@@ -465,7 +465,7 @@ public class ComboBoxTests (ITestOutputHelper output)
         Assert.Equal (-1, cb.SelectedItem);
         Assert.Equal ("", cb.Text);
 
-        Assert.True (Application.OnKeyDown (Key.F4));
+        Assert.True (Application.RaiseKeyDownEvent (Key.F4));
 
         Assert.True (
                      cb.Subviews [1]
@@ -595,7 +595,7 @@ Three ",
         Assert.Equal (2, cb.SelectedItem);
         Assert.Equal ("Three", cb.Text);
 
-        Assert.True (Application.OnKeyDown (Key.F4));
+        Assert.True (Application.RaiseKeyDownEvent (Key.F4));
         Assert.Equal ("Three", selected);
         Assert.True (cb.IsShow);
         Assert.Equal (2, cb.SelectedItem);
@@ -646,7 +646,7 @@ Three ",
                                                attributes
                                               );
 
-        Assert.True (Application.OnKeyDown (Key.F4));
+        Assert.True (Application.RaiseKeyDownEvent (Key.F4));
         Assert.Equal ("Three", selected);
         Assert.False (cb.IsShow);
         Assert.Equal (2, cb.SelectedItem);
@@ -756,7 +756,7 @@ Three ",
         Assert.Equal (1, cb.SelectedItem);
         Assert.Equal ("Two", cb.Text);
 
-        Assert.True (Application.OnKeyDown (Key.F4));
+        Assert.True (Application.RaiseKeyDownEvent (Key.F4));
         Assert.Equal ("Two", selected);
         Assert.True (cb.IsShow);
         Assert.Equal (1, cb.SelectedItem);
@@ -767,7 +767,7 @@ Three ",
         Assert.Equal (1, cb.SelectedItem);
         Assert.Equal ("Two", cb.Text);
 
-        Assert.True (Application.OnKeyDown (Key.Esc));
+        Assert.True (Application.RaiseKeyDownEvent (Key.Esc));
         Assert.Equal ("Two", selected);
         Assert.False (cb.IsShow);
         Assert.Equal (1, cb.SelectedItem);
@@ -803,7 +803,7 @@ Three ",
         Assert.Equal ("", cb.Text);
 
         Assert.True (cb.Subviews [1].NewKeyDownEvent (Key.CursorDown));
-        Assert.True (Application.OnKeyDown (Key.F4));
+        Assert.True (Application.RaiseKeyDownEvent (Key.F4));
         Assert.Equal ("", selected);
         Assert.False (cb.IsShow);
         Assert.Equal (-1, cb.SelectedItem);
@@ -834,32 +834,32 @@ Three ",
 
         cb.OpenSelectedItem += (s, _) => opened = true;
 
-        Assert.False (Application.OnKeyDown (Key.Enter));
+        Assert.False (Application.RaiseKeyDownEvent (Key.Enter));
         Assert.False (opened);
 
         cb.Text = "Tw";
-        Assert.False (Application.OnKeyDown (Key.Enter));
+        Assert.False (Application.RaiseKeyDownEvent (Key.Enter));
         Assert.True (opened);
         Assert.Equal ("Tw", cb.Text);
         Assert.False (cb.IsShow);
 
         cb.SetSource<string> (null);
         Assert.False (cb.IsShow);
-        Assert.False (Application.OnKeyDown (Key.Enter));
-        Assert.True (Application.OnKeyDown (Key.F4)); // with no source also expand empty
+        Assert.False (Application.RaiseKeyDownEvent (Key.Enter));
+        Assert.True (Application.RaiseKeyDownEvent (Key.F4)); // with no source also expand empty
         Assert.True (cb.IsShow);
 
         Assert.Equal (-1, cb.SelectedItem);
         cb.SetSource (source);
         cb.Text = "";
-        Assert.True (Application.OnKeyDown (Key.F4)); // collapse
+        Assert.True (Application.RaiseKeyDownEvent (Key.F4)); // collapse
         Assert.False (cb.IsShow);
-        Assert.True (Application.OnKeyDown (Key.F4)); // expand
+        Assert.True (Application.RaiseKeyDownEvent (Key.F4)); // expand
         Assert.True (cb.IsShow);
         cb.Collapse ();
         Assert.False (cb.IsShow);
         Assert.True (cb.HasFocus);
-        Assert.True (Application.OnKeyDown (Key.CursorDown)); // losing focus
+        Assert.True (Application.RaiseKeyDownEvent (Key.CursorDown)); // losing focus
         Assert.False (cb.IsShow);
         Assert.False (cb.HasFocus);
         cb.SetFocus ();
@@ -870,27 +870,27 @@ Three ",
         Assert.True (cb.IsShow);
         Assert.Equal (0, cb.SelectedItem);
         Assert.Equal ("One", cb.Text);
-        Assert.True (Application.OnKeyDown (Key.CursorDown));
+        Assert.True (Application.RaiseKeyDownEvent (Key.CursorDown));
         Assert.True (cb.IsShow);
         Assert.Equal (1, cb.SelectedItem);
         Assert.Equal ("Two", cb.Text);
-        Assert.True (Application.OnKeyDown (Key.CursorDown));
+        Assert.True (Application.RaiseKeyDownEvent (Key.CursorDown));
         Assert.True (cb.IsShow);
         Assert.Equal (2, cb.SelectedItem);
         Assert.Equal ("Three", cb.Text);
-        Assert.True (Application.OnKeyDown (Key.CursorDown));
+        Assert.True (Application.RaiseKeyDownEvent (Key.CursorDown));
         Assert.True (cb.IsShow);
         Assert.Equal (2, cb.SelectedItem);
         Assert.Equal ("Three", cb.Text);
-        Assert.True (Application.OnKeyDown (Key.CursorUp));
+        Assert.True (Application.RaiseKeyDownEvent (Key.CursorUp));
         Assert.True (cb.IsShow);
         Assert.Equal (1, cb.SelectedItem);
         Assert.Equal ("Two", cb.Text);
-        Assert.True (Application.OnKeyDown (Key.CursorUp));
+        Assert.True (Application.RaiseKeyDownEvent (Key.CursorUp));
         Assert.True (cb.IsShow);
         Assert.Equal (0, cb.SelectedItem);
         Assert.Equal ("One", cb.Text);
-        Assert.True (Application.OnKeyDown (Key.CursorUp));
+        Assert.True (Application.RaiseKeyDownEvent (Key.CursorUp));
         Assert.True (cb.IsShow);
         Assert.Equal (0, cb.SelectedItem);
         Assert.Equal ("One", cb.Text);
@@ -904,7 +904,7 @@ One
                                                       output
                                                      );
 
-        Assert.True (Application.OnKeyDown (Key.PageDown));
+        Assert.True (Application.RaiseKeyDownEvent (Key.PageDown));
         Assert.True (cb.IsShow);
         Assert.Equal (1, cb.SelectedItem);
         Assert.Equal ("Two", cb.Text);
@@ -919,7 +919,7 @@ Two
                                                       output
                                                      );
 
-        Assert.True (Application.OnKeyDown (Key.PageDown));
+        Assert.True (Application.RaiseKeyDownEvent (Key.PageDown));
         Assert.True (cb.IsShow);
         Assert.Equal (2, cb.SelectedItem);
         Assert.Equal ("Three", cb.Text);
@@ -933,43 +933,43 @@ Three
 ",
                                                       output
                                                      );
-        Assert.True (Application.OnKeyDown (Key.PageUp));
+        Assert.True (Application.RaiseKeyDownEvent (Key.PageUp));
         Assert.True (cb.IsShow);
         Assert.Equal (1, cb.SelectedItem);
         Assert.Equal ("Two", cb.Text);
-        Assert.True (Application.OnKeyDown (Key.PageUp));
+        Assert.True (Application.RaiseKeyDownEvent (Key.PageUp));
         Assert.True (cb.IsShow);
         Assert.Equal (0, cb.SelectedItem);
         Assert.Equal ("One", cb.Text);
-        Assert.True (Application.OnKeyDown (Key.F4));
+        Assert.True (Application.RaiseKeyDownEvent (Key.F4));
         Assert.False (cb.IsShow);
         Assert.Equal (0, cb.SelectedItem);
         Assert.Equal ("One", cb.Text);
-        Assert.True (Application.OnKeyDown (Key.End));
+        Assert.True (Application.RaiseKeyDownEvent (Key.End));
         Assert.False (cb.IsShow);
         Assert.Equal (0, cb.SelectedItem);
         Assert.Equal ("One", cb.Text);
-        Assert.True (Application.OnKeyDown (Key.Home));
+        Assert.True (Application.RaiseKeyDownEvent (Key.Home));
         Assert.False (cb.IsShow);
         Assert.Equal (0, cb.SelectedItem);
         Assert.Equal ("One", cb.Text);
-        Assert.True (Application.OnKeyDown (Key.F4));
+        Assert.True (Application.RaiseKeyDownEvent (Key.F4));
         Assert.True (cb.IsShow);
         Assert.Equal (0, cb.SelectedItem);
         Assert.Equal ("One", cb.Text);
-        Assert.True (Application.OnKeyDown (Key.End));
+        Assert.True (Application.RaiseKeyDownEvent (Key.End));
         Assert.True (cb.IsShow);
         Assert.Equal (2, cb.SelectedItem);
         Assert.Equal ("Three", cb.Text);
-        Assert.True (Application.OnKeyDown (Key.Home));
+        Assert.True (Application.RaiseKeyDownEvent (Key.Home));
         Assert.True (cb.IsShow);
         Assert.Equal (0, cb.SelectedItem);
         Assert.Equal ("One", cb.Text);
-        Assert.True (Application.OnKeyDown (Key.Esc));
+        Assert.True (Application.RaiseKeyDownEvent (Key.Esc));
         Assert.False (cb.IsShow);
         Assert.Equal (0, cb.SelectedItem);
         Assert.Equal ("", cb.Text);
-        Assert.True (Application.OnKeyDown (Key.CursorDown)); // losing focus
+        Assert.True (Application.RaiseKeyDownEvent (Key.CursorDown)); // losing focus
         Assert.False (cb.HasFocus);
         Assert.False (cb.IsShow);
         Assert.Equal (-1, cb.SelectedItem);
@@ -980,7 +980,7 @@ Three
         Assert.False (cb.IsShow);
         Assert.Equal (-1, cb.SelectedItem);
         Assert.Equal ("One", cb.Text);
-        Assert.True (Application.OnKeyDown (Key.U.WithCtrl));
+        Assert.True (Application.RaiseKeyDownEvent (Key.U.WithCtrl));
         Assert.True (cb.HasFocus);
         Assert.True (cb.IsShow);
         Assert.Equal (-1, cb.SelectedItem);
@@ -1009,7 +1009,7 @@ Three
         source.Add ("One");
         Assert.Equal (1, cb.Source.Count);
         Assert.Equal (-1, cb.SelectedItem);
-        Assert.True (Application.OnKeyDown (Key.F4));
+        Assert.True (Application.RaiseKeyDownEvent (Key.F4));
         Assert.True (cb.IsShow);
         Assert.Equal (0, cb.SelectedItem);
         Assert.Equal ("One", cb.Text);
@@ -1020,12 +1020,12 @@ Three
         Assert.True (cb.IsShow);
         Assert.Equal (-1, cb.SelectedItem);
         Assert.Equal ("T", cb.Text);
-        Assert.True (Application.OnKeyDown (Key.Enter));
+        Assert.True (Application.RaiseKeyDownEvent (Key.Enter));
         Assert.False (cb.IsShow);
         Assert.Equal (2, cb.Source.Count);
         Assert.Equal (-1, cb.SelectedItem);
         Assert.Equal ("T", cb.Text);
-        Assert.True (Application.OnKeyDown (Key.Esc));
+        Assert.True (Application.RaiseKeyDownEvent (Key.Esc));
         Assert.False (cb.IsShow);
         Assert.Equal (-1, cb.SelectedItem); // retains last accept selected item
         Assert.Equal ("", cb.Text); // clear text

+ 41 - 41
UnitTests/Views/ContextMenuTests.cs

@@ -400,9 +400,9 @@ public class ContextMenuTests (ITestOutputHelper output)
         top.Add (tf);
         Application.Begin (top);
 
-        Assert.True (Application.OnKeyDown (ContextMenu.DefaultKey));
+        Assert.True (Application.RaiseKeyDownEvent (ContextMenu.DefaultKey));
         Assert.True (tf.ContextMenu.MenuBar!.IsMenuOpen);
-        Assert.True (Application.OnKeyDown (ContextMenu.DefaultKey));
+        Assert.True (Application.RaiseKeyDownEvent (ContextMenu.DefaultKey));
 
         // The last context menu bar opened is always preserved
         Assert.NotNull (tf.ContextMenu.MenuBar);
@@ -1473,9 +1473,9 @@ public class ContextMenuTests (ITestOutputHelper output)
         Application.Begin (top);
 
         Assert.Null (cm.MenuBar);
-        Assert.False (Application.OnKeyDown (Key.N.WithCtrl));
-        Assert.False (Application.OnKeyDown (Key.R.WithCtrl));
-        Assert.False (Application.OnKeyDown (Key.D.WithCtrl));
+        Assert.False (Application.RaiseKeyDownEvent (Key.N.WithCtrl));
+        Assert.False (Application.RaiseKeyDownEvent (Key.R.WithCtrl));
+        Assert.False (Application.RaiseKeyDownEvent (Key.D.WithCtrl));
         Assert.False (newFile);
         Assert.False (renameFile);
         Assert.False (deleteFile);
@@ -1485,17 +1485,17 @@ public class ContextMenuTests (ITestOutputHelper output)
         Assert.True (cm.MenuBar.KeyBindings.Bindings.ContainsKey (Key.R.WithCtrl));
         Assert.True (cm.MenuBar.KeyBindings.Bindings.ContainsKey (Key.D.WithCtrl));
 
-        Assert.True (Application.OnKeyDown (Key.N.WithCtrl));
+        Assert.True (Application.RaiseKeyDownEvent (Key.N.WithCtrl));
         Application.MainLoop!.RunIteration ();
         Assert.True (newFile);
         Assert.False (cm.MenuBar!.IsMenuOpen);
         cm.Show (menuItems);
-        Assert.True (Application.OnKeyDown (Key.R.WithCtrl));
+        Assert.True (Application.RaiseKeyDownEvent (Key.R.WithCtrl));
         Application.MainLoop!.RunIteration ();
         Assert.True (renameFile);
         Assert.False (cm.MenuBar.IsMenuOpen);
         cm.Show (menuItems);
-        Assert.True (Application.OnKeyDown (Key.D.WithCtrl));
+        Assert.True (Application.RaiseKeyDownEvent (Key.D.WithCtrl));
         Application.MainLoop!.RunIteration ();
         Assert.True (deleteFile);
         Assert.False (cm.MenuBar.IsMenuOpen);
@@ -1507,9 +1507,9 @@ public class ContextMenuTests (ITestOutputHelper output)
         newFile = false;
         renameFile = false;
         deleteFile = false;
-        Assert.False (Application.OnKeyDown (Key.N.WithCtrl));
-        Assert.False (Application.OnKeyDown (Key.R.WithCtrl));
-        Assert.False (Application.OnKeyDown (Key.D.WithCtrl));
+        Assert.False (Application.RaiseKeyDownEvent (Key.N.WithCtrl));
+        Assert.False (Application.RaiseKeyDownEvent (Key.R.WithCtrl));
+        Assert.False (Application.RaiseKeyDownEvent (Key.D.WithCtrl));
         Assert.False (newFile);
         Assert.False (renameFile);
         Assert.False (deleteFile);
@@ -1557,8 +1557,8 @@ public class ContextMenuTests (ITestOutputHelper output)
         Assert.False (menuBar.KeyBindings.Bindings.ContainsKey (Key.R.WithCtrl));
         Assert.Null (cm.MenuBar);
 
-        Assert.True (Application.OnKeyDown (Key.N.WithCtrl));
-        Assert.False (Application.OnKeyDown (Key.R.WithCtrl));
+        Assert.True (Application.RaiseKeyDownEvent (Key.N.WithCtrl));
+        Assert.False (Application.RaiseKeyDownEvent (Key.R.WithCtrl));
         Application.MainLoop!.RunIteration ();
         Assert.True (newFile);
         Assert.False (renameFile);
@@ -1572,12 +1572,12 @@ public class ContextMenuTests (ITestOutputHelper output)
         Assert.True (cm.MenuBar.KeyBindings.Bindings.ContainsKey (Key.R.WithCtrl));
 
         Assert.True (cm.MenuBar.IsMenuOpen);
-        Assert.True (Application.OnKeyDown (Key.N.WithCtrl));
+        Assert.True (Application.RaiseKeyDownEvent (Key.N.WithCtrl));
         Application.MainLoop!.RunIteration ();
         Assert.True (newFile);
         Assert.False (cm.MenuBar!.IsMenuOpen);
         cm.Show (menuItems);
-        Assert.True (Application.OnKeyDown (Key.R.WithCtrl));
+        Assert.True (Application.RaiseKeyDownEvent (Key.R.WithCtrl));
         Application.MainLoop!.RunIteration ();
         Assert.True (renameFile);
         Assert.False (cm.MenuBar.IsMenuOpen);
@@ -1589,8 +1589,8 @@ public class ContextMenuTests (ITestOutputHelper output)
 
         newFile = false;
         renameFile = false;
-        Assert.True (Application.OnKeyDown (Key.N.WithCtrl));
-        Assert.False (Application.OnKeyDown (Key.R.WithCtrl));
+        Assert.True (Application.RaiseKeyDownEvent (Key.N.WithCtrl));
+        Assert.False (Application.RaiseKeyDownEvent (Key.R.WithCtrl));
         Application.MainLoop!.RunIteration ();
         Assert.True (newFile);
         Assert.False (renameFile);
@@ -1635,7 +1635,7 @@ public class ContextMenuTests (ITestOutputHelper output)
         Assert.True (menuBar.KeyBindings.Bindings.ContainsKey (Key.N.WithCtrl));
         Assert.Null (cm.MenuBar);
 
-        Assert.True (Application.OnKeyDown (Key.N.WithCtrl));
+        Assert.True (Application.RaiseKeyDownEvent (Key.N.WithCtrl));
         Application.MainLoop!.RunIteration ();
         Assert.True (newMenuBar);
         Assert.False (newContextMenu);
@@ -1647,7 +1647,7 @@ public class ContextMenuTests (ITestOutputHelper output)
         Assert.True (cm.MenuBar!.KeyBindings.Bindings.ContainsKey (Key.N.WithCtrl));
 
         Assert.True (cm.MenuBar.IsMenuOpen);
-        Assert.True (Application.OnKeyDown (Key.N.WithCtrl));
+        Assert.True (Application.RaiseKeyDownEvent (Key.N.WithCtrl));
         Application.MainLoop!.RunIteration ();
         Assert.False (newMenuBar);
 
@@ -1660,7 +1660,7 @@ public class ContextMenuTests (ITestOutputHelper output)
 
         newMenuBar = false;
         newContextMenu = false;
-        Assert.True (Application.OnKeyDown (Key.N.WithCtrl));
+        Assert.True (Application.RaiseKeyDownEvent (Key.N.WithCtrl));
         Application.MainLoop!.RunIteration ();
         Assert.True (newMenuBar);
         Assert.False (newContextMenu);
@@ -1693,9 +1693,9 @@ public class ContextMenuTests (ITestOutputHelper output)
         Application.Begin (top);
 
         Assert.Null (cm.MenuBar);
-        Assert.False (Application.OnKeyDown (Key.N.WithAlt));
-        Assert.False (Application.OnKeyDown (Key.R.WithAlt));
-        Assert.False (Application.OnKeyDown (Key.D.WithAlt));
+        Assert.False (Application.RaiseKeyDownEvent (Key.N.WithAlt));
+        Assert.False (Application.RaiseKeyDownEvent (Key.R.WithAlt));
+        Assert.False (Application.RaiseKeyDownEvent (Key.D.WithAlt));
         Assert.False (newFile);
         Assert.False (renameFile);
         Assert.False (deleteFile);
@@ -1717,17 +1717,17 @@ public class ContextMenuTests (ITestOutputHelper output)
         Assert.True (menus [0].KeyBindings.Bindings.ContainsKey (Key.D.WithAlt));
         Assert.True (menus [0].KeyBindings.Bindings.ContainsKey (Key.D.NoShift));
 
-        Assert.True (Application.OnKeyDown (Key.N.WithAlt));
+        Assert.True (Application.RaiseKeyDownEvent (Key.N.WithAlt));
         Assert.False (cm.MenuBar!.IsMenuOpen);
         Application.MainLoop!.RunIteration ();
         Assert.True (newFile);
         cm.Show (menuItems);
-        Assert.True (Application.OnKeyDown (Key.R.WithAlt));
+        Assert.True (Application.RaiseKeyDownEvent (Key.R.WithAlt));
         Assert.False (cm.MenuBar.IsMenuOpen);
         Application.MainLoop!.RunIteration ();
         Assert.True (renameFile);
         cm.Show (menuItems);
-        Assert.True (Application.OnKeyDown (Key.D.WithAlt));
+        Assert.True (Application.RaiseKeyDownEvent (Key.D.WithAlt));
         Assert.False (cm.MenuBar.IsMenuOpen);
         Application.MainLoop!.RunIteration ();
         Assert.True (deleteFile);
@@ -1742,9 +1742,9 @@ public class ContextMenuTests (ITestOutputHelper output)
         newFile = false;
         renameFile = false;
         deleteFile = false;
-        Assert.False (Application.OnKeyDown (Key.N.WithAlt));
-        Assert.False (Application.OnKeyDown (Key.R.WithAlt));
-        Assert.False (Application.OnKeyDown (Key.D.WithAlt));
+        Assert.False (Application.RaiseKeyDownEvent (Key.N.WithAlt));
+        Assert.False (Application.RaiseKeyDownEvent (Key.R.WithAlt));
+        Assert.False (Application.RaiseKeyDownEvent (Key.D.WithAlt));
         Assert.False (newFile);
         Assert.False (renameFile);
         Assert.False (deleteFile);
@@ -1801,14 +1801,14 @@ public class ContextMenuTests (ITestOutputHelper output)
         Assert.Empty (menus);
         Assert.Null (cm.MenuBar);
 
-        Assert.True (Application.OnKeyDown (Key.F.WithAlt));
+        Assert.True (Application.RaiseKeyDownEvent (Key.F.WithAlt));
         Assert.True (menuBar.IsMenuOpen);
         Assert.Equal (2, Application.Top!.Subviews.Count);
         menus = Application.Top!.Subviews.Where (v => v is Menu m && m.Host == menuBar).ToArray ();
         Assert.True (menus [0].KeyBindings.Bindings.ContainsKey (Key.N.WithAlt));
-        Assert.True (Application.OnKeyDown (Key.N.WithAlt));
+        Assert.True (Application.RaiseKeyDownEvent (Key.N.WithAlt));
         Assert.False (menuBar.IsMenuOpen);
-        Assert.False (Application.OnKeyDown (Key.R.WithAlt));
+        Assert.False (Application.RaiseKeyDownEvent (Key.R.WithAlt));
         Application.MainLoop!.RunIteration ();
         Assert.True (newFile);
         Assert.False (renameFile);
@@ -1840,9 +1840,9 @@ public class ContextMenuTests (ITestOutputHelper output)
         Assert.True (menus [1].KeyBindings.Bindings.ContainsKey (Key.R.WithAlt));
         Assert.True (menus [1].KeyBindings.Bindings.ContainsKey (Key.R.NoShift));
         Assert.True (cm.MenuBar.IsMenuOpen);
-        Assert.True (Application.OnKeyDown (Key.F.WithAlt));
+        Assert.True (Application.RaiseKeyDownEvent (Key.F.WithAlt));
         Assert.False (cm.MenuBar.IsMenuOpen);
-        Assert.True (Application.OnKeyDown (Key.N.WithAlt));
+        Assert.True (Application.RaiseKeyDownEvent (Key.N.WithAlt));
         Application.MainLoop!.RunIteration ();
         Assert.True (newFile);
 
@@ -1858,8 +1858,8 @@ public class ContextMenuTests (ITestOutputHelper output)
         Assert.False (menus [1].KeyBindings.Bindings.ContainsKey (Key.E.NoShift));
         Assert.True (menus [1].KeyBindings.Bindings.ContainsKey (Key.R.WithAlt));
         Assert.True (menus [1].KeyBindings.Bindings.ContainsKey (Key.R.NoShift));
-        Assert.True (Application.OnKeyDown (Key.E.NoShift));
-        Assert.True (Application.OnKeyDown (Key.R.WithAlt));
+        Assert.True (Application.RaiseKeyDownEvent (Key.E.NoShift));
+        Assert.True (Application.RaiseKeyDownEvent (Key.R.WithAlt));
         Assert.False (cm.MenuBar.IsMenuOpen);
         Application.MainLoop!.RunIteration ();
         Assert.True (renameFile);
@@ -1876,9 +1876,9 @@ public class ContextMenuTests (ITestOutputHelper output)
 
         newFile = false;
         renameFile = false;
-        Assert.True (Application.OnKeyDown (Key.F.WithAlt));
-        Assert.True (Application.OnKeyDown (Key.N.WithAlt));
-        Assert.False (Application.OnKeyDown (Key.R.WithAlt));
+        Assert.True (Application.RaiseKeyDownEvent (Key.F.WithAlt));
+        Assert.True (Application.RaiseKeyDownEvent (Key.N.WithAlt));
+        Assert.False (Application.RaiseKeyDownEvent (Key.R.WithAlt));
         Application.MainLoop!.RunIteration ();
         Assert.True (newFile);
         Assert.False (renameFile);
@@ -1923,14 +1923,14 @@ public class ContextMenuTests (ITestOutputHelper output)
         top.Add (menuBar);
         Application.Begin (top);
 
-        Assert.True (Application.OnKeyDown (Key.F.WithAlt));
+        Assert.True (Application.RaiseKeyDownEvent (Key.F.WithAlt));
         Assert.True (menuBar.IsMenuOpen);
 
         cm.Show (menuItems);
         Assert.False (menuBar.IsMenuOpen);
         Assert.True (cm.MenuBar!.IsMenuOpen);
 
-        Assert.True (Application.OnKeyDown (Key.F.WithAlt));
+        Assert.True (Application.RaiseKeyDownEvent (Key.F.WithAlt));
         Assert.True (menuBar.IsMenuOpen);
         Assert.False (cm.MenuBar!.IsMenuOpen);
 

+ 1 - 1
UnitTests/Views/DatePickerTests.cs

@@ -82,7 +82,7 @@ public class DatePickerTests
         Assert.Equal (datePicker.Subviews.First (v => v.Id == "_nextMonthButton"), datePicker.Focused);
 
         // Change month to December
-        Assert.False (Application.OnKeyDown (Key.Enter));
+        Assert.False (Application.RaiseKeyDownEvent (Key.Enter));
         Assert.Equal (12, datePicker.Date.Month);
 
         // Next month button is disabled, so focus advanced to edit field

+ 2 - 2
UnitTests/Views/LabelTests.cs

@@ -1341,7 +1341,7 @@ e
         Application.Top.SetFocus ();
         Assert.True (otherView.HasFocus);
 
-        Assert.True (Application.OnKeyDown (label.HotKey));
+        Assert.True (Application.RaiseKeyDownEvent (label.HotKey));
         Assert.False (otherView.HasFocus);
         Assert.False (label.HasFocus);
         Assert.True (nextView.HasFocus);
@@ -1396,7 +1396,7 @@ e
         Assert.True (view.HasFocus);
 
         // No focused view accepts Tab, and there's no other view to focus, so OnKeyDown returns false
-        Assert.True (Application.OnKeyDown (label.HotKey));
+        Assert.True (Application.RaiseKeyDownEvent (label.HotKey));
         Assert.True (label.HasFocus);
         Assert.False (view.HasFocus);
 

+ 6 - 10
UnitTests/Views/ListViewTests.cs

@@ -522,7 +522,7 @@ Item 6",
     }
 
     [Fact]
-    public void ListViewSelectThenDown ()
+    public void AllowsMarking_True_SpaceWithShift_SelectsThenDown ()
     {
         var lv = new ListView { Source = new ListWrapper<string> (["One", "Two", "Three"]) };
         lv.AllowsMarking = true;
@@ -537,12 +537,8 @@ Item 6",
         Assert.False (lv.Source.IsMarked (1));
         Assert.False (lv.Source.IsMarked (2));
 
-        lv.KeyBindings.Add (Key.Space.WithShift, Command.Select, Command.Down);
-
-        Key ev = Key.Space.WithShift;
-
         // view should indicate that it has accepted and consumed the event
-        Assert.True (lv.NewKeyDownEvent (ev));
+        Assert.True (lv.NewKeyDownEvent (Key.Space.WithShift));
 
         // first item should now be selected
         Assert.Equal (0, lv.SelectedItem);
@@ -553,7 +549,7 @@ Item 6",
         Assert.False (lv.Source.IsMarked (2));
 
         // Press key combo again
-        Assert.True (lv.NewKeyDownEvent (ev));
+        Assert.True (lv.NewKeyDownEvent (Key.Space.WithShift));
 
         // second item should now be selected
         Assert.Equal (1, lv.SelectedItem);
@@ -564,21 +560,21 @@ Item 6",
         Assert.False (lv.Source.IsMarked (2));
 
         // Press key combo again
-        Assert.True (lv.NewKeyDownEvent (ev));
+        Assert.True (lv.NewKeyDownEvent (Key.Space.WithShift));
         Assert.Equal (2, lv.SelectedItem);
         Assert.True (lv.Source.IsMarked (0));
         Assert.True (lv.Source.IsMarked (1));
         Assert.False (lv.Source.IsMarked (2));
 
         // Press key combo again
-        Assert.True (lv.NewKeyDownEvent (ev));
+        Assert.True (lv.NewKeyDownEvent (Key.Space.WithShift));
         Assert.Equal (2, lv.SelectedItem); // cannot move down any further
         Assert.True (lv.Source.IsMarked (0));
         Assert.True (lv.Source.IsMarked (1));
         Assert.True (lv.Source.IsMarked (2)); // but can toggle marked
 
         // Press key combo again 
-        Assert.True (lv.NewKeyDownEvent (ev));
+        Assert.True (lv.NewKeyDownEvent (Key.Space.WithShift));
         Assert.Equal (2, lv.SelectedItem); // cannot move down any further
         Assert.True (lv.Source.IsMarked (0));
         Assert.True (lv.Source.IsMarked (1));

+ 3 - 3
UnitTests/Views/MenuBarTests.cs

@@ -1384,7 +1384,7 @@ wo
 
         foreach (Key key in keys)
         {
-            top.NewKeyDownEvent (new (key));
+            top.NewKeyDownEvent (key);
             Application.MainLoop.RunIteration ();
         }
 
@@ -2666,7 +2666,7 @@ Edit
         top.Draw ();
         TestHelpers.AssertDriverContentsAre (expectedMenu.ExpectedSubMenuOpen (0), output);
 
-        Assert.True (Application.OnKeyDown (menu.Key));
+        Assert.True (Application.RaiseKeyDownEvent (menu.Key));
         Assert.False (menu.IsMenuOpen);
         Assert.True (tf.HasFocus);
         top.Draw ();
@@ -2949,7 +2949,7 @@ Edit
         top.Add (menu);
         Application.Begin (top);
 
-        Application.OnKeyDown (Key.S.WithCtrl);
+        Application.RaiseKeyDownEvent (Key.S.WithCtrl);
         Application.MainLoop.RunIteration ();
 
         Assert.True (saveAction);

+ 33 - 33
UnitTests/Views/RadioGroupTests.cs

@@ -57,7 +57,7 @@ public class RadioGroupTests (ITestOutputHelper output)
         rg.SetFocus ();
 
         Assert.Equal (-1, rg.SelectedItem);
-        Application.OnKeyDown (Key.Space);
+        Application.RaiseKeyDownEvent (Key.Space);
         Assert.Equal (0, rg.SelectedItem);
 
         Application.Top.Dispose ();
@@ -105,21 +105,21 @@ public class RadioGroupTests (ITestOutputHelper output)
 
         // With HasFocus
         // Test up/down without Select
-        Assert.False (Application.OnKeyDown (Key.CursorUp)); // Should not change (should focus prev view if there was one, which there isn't)
+        Assert.False (Application.RaiseKeyDownEvent (Key.CursorUp)); // Should not change (should focus prev view if there was one, which there isn't)
         Assert.Equal (0, rg.SelectedItem);
         Assert.Equal (0, rg.Cursor);
         Assert.Equal (0, selectedItemChangedCount);
         Assert.Equal (0, selectingCount);
         Assert.Equal (0, acceptedCount);
 
-        Assert.True (Application.OnKeyDown (Key.CursorDown));
+        Assert.True (Application.RaiseKeyDownEvent (Key.CursorDown));
         Assert.Equal (0, rg.SelectedItem); // Cursor changed, but selection didnt
         Assert.Equal (1, rg.Cursor);
         Assert.Equal (0, selectedItemChangedCount);
         Assert.Equal (0, selectingCount);
         Assert.Equal (0, acceptedCount);
 
-        Assert.False (Application.OnKeyDown (Key.CursorDown)); // Should not change selection (should focus next view if there was one, which there isn't)
+        Assert.False (Application.RaiseKeyDownEvent (Key.CursorDown)); // Should not change selection (should focus next view if there was one, which there isn't)
         Assert.Equal (0, rg.SelectedItem);
         Assert.Equal (1, rg.Cursor);
         Assert.Equal (0, selectedItemChangedCount);
@@ -127,7 +127,7 @@ public class RadioGroupTests (ITestOutputHelper output)
         Assert.Equal (0, acceptedCount);
 
         // Test Select (Space) when Cursor != SelectedItem - Should select cursor
-        Assert.True (Application.OnKeyDown (Key.Space));
+        Assert.True (Application.RaiseKeyDownEvent (Key.Space));
         Assert.Equal (1, rg.SelectedItem);
         Assert.Equal (1, rg.Cursor);
         Assert.Equal (1, selectedItemChangedCount);
@@ -135,34 +135,34 @@ public class RadioGroupTests (ITestOutputHelper output)
         Assert.Equal (0, acceptedCount);
 
         // Test Select (Space) when Cursor == SelectedItem - Should cycle
-        Assert.True (Application.OnKeyDown (Key.Space));
+        Assert.True (Application.RaiseKeyDownEvent (Key.Space));
         Assert.Equal (0, rg.SelectedItem);
         Assert.Equal (0, rg.Cursor);
         Assert.Equal (2, selectedItemChangedCount);
         Assert.Equal (2, selectingCount);
         Assert.Equal (0, acceptedCount);
 
-        Assert.True (Application.OnKeyDown (Key.Space));
+        Assert.True (Application.RaiseKeyDownEvent (Key.Space));
         Assert.Equal (1, rg.SelectedItem);
         Assert.Equal (1, rg.Cursor);
-        Assert.True (Application.OnKeyDown (Key.Space));
+        Assert.True (Application.RaiseKeyDownEvent (Key.Space));
         Assert.Equal (0, rg.SelectedItem);
         Assert.Equal (0, rg.Cursor);
-        Assert.True (Application.OnKeyDown (Key.Space));
+        Assert.True (Application.RaiseKeyDownEvent (Key.Space));
         Assert.Equal (1, rg.SelectedItem);
         Assert.Equal (1, rg.Cursor);
 
-        Assert.True (Application.OnKeyDown (Key.Home));
+        Assert.True (Application.RaiseKeyDownEvent (Key.Home));
         Assert.Equal (1, rg.SelectedItem);
         Assert.Equal (0, rg.Cursor);
-        Assert.True (Application.OnKeyDown (Key.Space));
+        Assert.True (Application.RaiseKeyDownEvent (Key.Space));
         Assert.Equal (0, rg.SelectedItem);
         Assert.Equal (0, rg.Cursor);
 
-        Assert.True (Application.OnKeyDown (Key.End));
+        Assert.True (Application.RaiseKeyDownEvent (Key.End));
         Assert.Equal (0, rg.SelectedItem);
         Assert.Equal (1, rg.Cursor);
-        Assert.True (Application.OnKeyDown (Key.Space));
+        Assert.True (Application.RaiseKeyDownEvent (Key.Space));
         Assert.Equal (1, rg.SelectedItem);
         Assert.Equal (1, rg.Cursor);
         Assert.Equal (7, selectedItemChangedCount);
@@ -174,7 +174,7 @@ public class RadioGroupTests (ITestOutputHelper output)
 
         rg.HotKey = Key.L;
         Assert.Equal (Key.L, rg.HotKey);
-        Assert.True (Application.OnKeyDown (rg.HotKey));
+        Assert.True (Application.RaiseKeyDownEvent (rg.HotKey));
         Assert.Equal (0, rg.SelectedItem);
         Assert.Equal (0, rg.Cursor);
         Assert.Equal (8, selectedItemChangedCount);
@@ -182,12 +182,12 @@ public class RadioGroupTests (ITestOutputHelper output)
         Assert.Equal (0, acceptedCount);
 
         //     Make Selected != Cursor
-        Assert.True (Application.OnKeyDown (Key.CursorDown));
+        Assert.True (Application.RaiseKeyDownEvent (Key.CursorDown));
         Assert.Equal (0, rg.SelectedItem);
         Assert.Equal (1, rg.Cursor);
 
         //    Selected != Cursor - Raise HotKey event - Since we're focused, this should just advance
-        Assert.True (Application.OnKeyDown (rg.HotKey));
+        Assert.True (Application.RaiseKeyDownEvent (rg.HotKey));
         Assert.Equal (1, rg.SelectedItem);
         Assert.Equal (1, rg.Cursor);
         Assert.Equal (9, selectedItemChangedCount);
@@ -239,7 +239,7 @@ public class RadioGroupTests (ITestOutputHelper output)
         //    Selected (0) == Cursor (0) - SetFocus
         rg.HotKey = Key.L;
         Assert.Equal (Key.L, rg.HotKey);
-        Assert.True (Application.OnKeyDown (rg.HotKey));
+        Assert.True (Application.RaiseKeyDownEvent (rg.HotKey));
         Assert.True (rg.HasFocus);
         Assert.Equal (0, rg.SelectedItem);
         Assert.Equal (0, rg.Cursor);
@@ -248,14 +248,14 @@ public class RadioGroupTests (ITestOutputHelper output)
         Assert.Equal (0, acceptCount);
 
         //     Make Selected != Cursor
-        Assert.True (Application.OnKeyDown (Key.CursorDown));
+        Assert.True (Application.RaiseKeyDownEvent (Key.CursorDown));
         Assert.Equal (0, rg.SelectedItem);
         Assert.Equal (1, rg.Cursor);
 
         otherView.SetFocus ();
 
         //    Selected != Cursor - SetFocus
-        Assert.True (Application.OnKeyDown (rg.HotKey));
+        Assert.True (Application.RaiseKeyDownEvent (rg.HotKey));
         Assert.True (rg.HasFocus);
         Assert.Equal (0, rg.SelectedItem);
         Assert.Equal (1, rg.Cursor);
@@ -263,7 +263,7 @@ public class RadioGroupTests (ITestOutputHelper output)
         Assert.Equal (0, selectCount);
         Assert.Equal (0, acceptCount);
 
-        Assert.True (Application.OnKeyDown (rg.HotKey));
+        Assert.True (Application.RaiseKeyDownEvent (rg.HotKey));
         Assert.True (rg.HasFocus);
         Assert.Equal (1, rg.SelectedItem);
         Assert.Equal (1, rg.Cursor);
@@ -314,7 +314,7 @@ public class RadioGroupTests (ITestOutputHelper output)
 
         // Test RadioTitem.HotKey - Should never SetFocus
         //    Selected (0) == Cursor (0) 
-        Assert.True (Application.OnKeyDown (Key.A));
+        Assert.True (Application.RaiseKeyDownEvent (Key.A));
         Assert.False (rg.HasFocus);
         Assert.Equal (0, rg.SelectedItem);
         Assert.Equal (0, rg.Cursor);
@@ -325,14 +325,14 @@ public class RadioGroupTests (ITestOutputHelper output)
         rg.SetFocus ();
 
         //     Make Selected != Cursor
-        Assert.True (Application.OnKeyDown (Key.CursorDown));
+        Assert.True (Application.RaiseKeyDownEvent (Key.CursorDown));
         Assert.Equal (0, rg.SelectedItem);
         Assert.Equal (1, rg.Cursor);
 
         otherView.SetFocus ();
 
         //    Selected != Cursor
-        Assert.True (Application.OnKeyDown (Key.A));
+        Assert.True (Application.RaiseKeyDownEvent (Key.A));
         Assert.False (rg.HasFocus);
         Assert.Equal (0, rg.SelectedItem);
         Assert.Equal (1, rg.Cursor);
@@ -341,7 +341,7 @@ public class RadioGroupTests (ITestOutputHelper output)
         Assert.Equal (0, acceptCount);
 
         //    Selected != Cursor - Should not set focus
-        Assert.True (Application.OnKeyDown (Key.B));
+        Assert.True (Application.RaiseKeyDownEvent (Key.B));
         Assert.False (rg.HasFocus);
         Assert.Equal (1, rg.SelectedItem);
         Assert.Equal (1, rg.Cursor);
@@ -349,7 +349,7 @@ public class RadioGroupTests (ITestOutputHelper output)
         Assert.Equal (1, selectCount);
         Assert.Equal (0, acceptCount);
 
-        Assert.True (Application.OnKeyDown (Key.B));
+        Assert.True (Application.RaiseKeyDownEvent (Key.B));
         Assert.False (rg.HasFocus);
         Assert.Equal (1, rg.SelectedItem);
         Assert.Equal (1, rg.Cursor);
@@ -372,22 +372,22 @@ public class RadioGroupTests (ITestOutputHelper output)
         Assert.NotEmpty (rg.KeyBindings.GetCommands (KeyCode.L | KeyCode.ShiftMask));
         Assert.NotEmpty (rg.KeyBindings.GetCommands (KeyCode.L | KeyCode.AltMask));
 
-        Assert.True (Application.OnKeyDown (Key.T));
+        Assert.True (Application.RaiseKeyDownEvent (Key.T));
         Assert.Equal (2, rg.SelectedItem);
-        Assert.True (Application.OnKeyDown (Key.L));
+        Assert.True (Application.RaiseKeyDownEvent (Key.L));
         Assert.Equal (0, rg.SelectedItem);
-        Assert.True (Application.OnKeyDown (Key.J));
+        Assert.True (Application.RaiseKeyDownEvent (Key.J));
         Assert.Equal (3, rg.SelectedItem);
-        Assert.True (Application.OnKeyDown (Key.R));
+        Assert.True (Application.RaiseKeyDownEvent (Key.R));
         Assert.Equal (1, rg.SelectedItem);
 
-        Assert.True (Application.OnKeyDown (Key.T.WithAlt));
+        Assert.True (Application.RaiseKeyDownEvent (Key.T.WithAlt));
         Assert.Equal (2, rg.SelectedItem);
-        Assert.True (Application.OnKeyDown (Key.L.WithAlt));
+        Assert.True (Application.RaiseKeyDownEvent (Key.L.WithAlt));
         Assert.Equal (0, rg.SelectedItem);
-        Assert.True (Application.OnKeyDown (Key.J.WithAlt));
+        Assert.True (Application.RaiseKeyDownEvent (Key.J.WithAlt));
         Assert.Equal (3, rg.SelectedItem);
-        Assert.True (Application.OnKeyDown (Key.R.WithAlt));
+        Assert.True (Application.RaiseKeyDownEvent (Key.R.WithAlt));
         Assert.Equal (1, rg.SelectedItem);
 
         var superView = new View ();

+ 65 - 65
UnitTests/Views/ScrollViewTests.cs

@@ -579,7 +579,7 @@ public class ScrollViewTests (ITestOutputHelper output)
         Rectangle pos = TestHelpers.AssertDriverContentsWithFrameAre (expected, output);
         Assert.Equal (new (1, 1, 21, 14), pos);
 
-        Assert.True (scrollView.OnKeyDown (Key.CursorRight));
+        Assert.True (scrollView.NewKeyDownEvent (Key.CursorRight));
         top.Draw ();
 
         expected = @"
@@ -603,7 +603,7 @@ public class ScrollViewTests (ITestOutputHelper output)
         pos = TestHelpers.AssertDriverContentsWithFrameAre (expected, output);
         Assert.Equal (new (1, 1, 21, 14), pos);
 
-        Assert.True (scrollView.OnKeyDown (Key.CursorRight));
+        Assert.True (scrollView.NewKeyDownEvent (Key.CursorRight));
         top.Draw ();
 
         expected = @"
@@ -627,7 +627,7 @@ public class ScrollViewTests (ITestOutputHelper output)
         pos = TestHelpers.AssertDriverContentsWithFrameAre (expected, output);
         Assert.Equal (new (1, 1, 21, 14), pos);
 
-        Assert.True (scrollView.OnKeyDown (Key.CursorRight));
+        Assert.True (scrollView.NewKeyDownEvent (Key.CursorRight));
         top.Draw ();
 
         expected = @"
@@ -651,7 +651,7 @@ public class ScrollViewTests (ITestOutputHelper output)
         pos = TestHelpers.AssertDriverContentsWithFrameAre (expected, output);
         Assert.Equal (new (1, 1, 21, 14), pos);
 
-        Assert.True (scrollView.OnKeyDown (Key.CursorRight));
+        Assert.True (scrollView.NewKeyDownEvent (Key.CursorRight));
         top.Draw ();
 
         expected = @"
@@ -675,7 +675,7 @@ public class ScrollViewTests (ITestOutputHelper output)
         pos = TestHelpers.AssertDriverContentsWithFrameAre (expected, output);
         Assert.Equal (new (1, 1, 21, 14), pos);
 
-        Assert.True (scrollView.OnKeyDown (Key.CursorRight));
+        Assert.True (scrollView.NewKeyDownEvent (Key.CursorRight));
         top.Draw ();
 
         expected = @"
@@ -699,7 +699,7 @@ public class ScrollViewTests (ITestOutputHelper output)
         pos = TestHelpers.AssertDriverContentsWithFrameAre (expected, output);
         Assert.Equal (new (1, 1, 21, 14), pos);
 
-        Assert.True (scrollView.OnKeyDown (Key.CursorRight));
+        Assert.True (scrollView.NewKeyDownEvent (Key.CursorRight));
         top.Draw ();
 
         expected = @"
@@ -723,7 +723,7 @@ public class ScrollViewTests (ITestOutputHelper output)
         pos = TestHelpers.AssertDriverContentsWithFrameAre (expected, output);
         Assert.Equal (new (1, 1, 21, 14), pos);
 
-        Assert.True (scrollView.OnKeyDown (Key.CursorRight));
+        Assert.True (scrollView.NewKeyDownEvent (Key.CursorRight));
         top.Draw ();
 
         expected = @"
@@ -746,7 +746,7 @@ public class ScrollViewTests (ITestOutputHelper output)
         pos = TestHelpers.AssertDriverContentsWithFrameAre (expected, output);
         Assert.Equal (new (1, 1, 21, 14), pos);
 
-        Assert.True (scrollView.OnKeyDown (Key.End.WithCtrl));
+        Assert.True (scrollView.NewKeyDownEvent (Key.End.WithCtrl));
         top.Draw ();
 
         expected = @"
@@ -769,8 +769,8 @@ public class ScrollViewTests (ITestOutputHelper output)
         pos = TestHelpers.AssertDriverContentsWithFrameAre (expected, output);
         Assert.Equal (new (1, 1, 21, 14), pos);
 
-        Assert.True (scrollView.OnKeyDown (Key.Home.WithCtrl));
-        Assert.True (scrollView.OnKeyDown (Key.CursorDown));
+        Assert.True (scrollView.NewKeyDownEvent (Key.Home.WithCtrl));
+        Assert.True (scrollView.NewKeyDownEvent (Key.CursorDown));
         top.Draw ();
 
         expected = @"
@@ -793,7 +793,7 @@ public class ScrollViewTests (ITestOutputHelper output)
         pos = TestHelpers.AssertDriverContentsWithFrameAre (expected, output);
         Assert.Equal (new (1, 1, 21, 14), pos);
 
-        Assert.True (scrollView.OnKeyDown (Key.CursorDown));
+        Assert.True (scrollView.NewKeyDownEvent (Key.CursorDown));
         top.Draw ();
 
         expected = @"
@@ -816,7 +816,7 @@ public class ScrollViewTests (ITestOutputHelper output)
         pos = TestHelpers.AssertDriverContentsWithFrameAre (expected, output);
         Assert.Equal (new (1, 1, 21, 14), pos);
 
-        Assert.True (scrollView.OnKeyDown (Key.CursorDown));
+        Assert.True (scrollView.NewKeyDownEvent (Key.CursorDown));
         top.Draw ();
 
         expected = @"
@@ -839,7 +839,7 @@ public class ScrollViewTests (ITestOutputHelper output)
         pos = TestHelpers.AssertDriverContentsWithFrameAre (expected, output);
         Assert.Equal (new (1, 1, 21, 14), pos);
 
-        Assert.True (scrollView.OnKeyDown (Key.End));
+        Assert.True (scrollView.NewKeyDownEvent (Key.End));
         top.Draw ();
 
         expected = @"
@@ -940,120 +940,120 @@ public class ScrollViewTests (ITestOutputHelper output)
         Assert.True (sv.KeepContentAlwaysInViewport);
         Assert.True (sv.AutoHideScrollBars);
         Assert.Equal (Point.Empty, sv.ContentOffset);
-        Assert.False (sv.OnKeyDown (Key.CursorUp));
+        Assert.False (sv.NewKeyDownEvent (Key.CursorUp));
         Assert.Equal (Point.Empty, sv.ContentOffset);
-        Assert.True (sv.OnKeyDown (Key.CursorDown));
+        Assert.True (sv.NewKeyDownEvent (Key.CursorDown));
         Assert.Equal (new (0, -1), sv.ContentOffset);
-        Assert.True (sv.OnKeyDown (Key.CursorUp));
+        Assert.True (sv.NewKeyDownEvent (Key.CursorUp));
         Assert.Equal (Point.Empty, sv.ContentOffset);
-        Assert.False (sv.OnKeyDown (Key.PageUp));
+        Assert.False (sv.NewKeyDownEvent (Key.PageUp));
         Assert.Equal (Point.Empty, sv.ContentOffset);
-        Assert.True (sv.OnKeyDown (Key.PageDown));
+        Assert.True (sv.NewKeyDownEvent (Key.PageDown));
         Point point0xMinus10 = new (0, -10);
         Assert.Equal (point0xMinus10, sv.ContentOffset);
-        Assert.False (sv.OnKeyDown (Key.PageDown));
+        Assert.False (sv.NewKeyDownEvent (Key.PageDown));
         Assert.Equal (point0xMinus10, sv.ContentOffset);
-        Assert.False (sv.OnKeyDown (Key.CursorDown));
+        Assert.False (sv.NewKeyDownEvent (Key.CursorDown));
         Assert.Equal (point0xMinus10, sv.ContentOffset);
-        Assert.True (sv.OnKeyDown (Key.V.WithAlt));
+        Assert.True (sv.NewKeyDownEvent (Key.V.WithAlt));
         Assert.Equal (Point.Empty, sv.ContentOffset);
-        Assert.True (sv.OnKeyDown (Key.V.WithCtrl));
+        Assert.True (sv.NewKeyDownEvent (Key.V.WithCtrl));
         Assert.Equal (point0xMinus10, sv.ContentOffset);
-        Assert.False (sv.OnKeyDown (Key.CursorLeft));
+        Assert.False (sv.NewKeyDownEvent (Key.CursorLeft));
         Assert.Equal (point0xMinus10, sv.ContentOffset);
-        Assert.True (sv.OnKeyDown (Key.CursorRight));
+        Assert.True (sv.NewKeyDownEvent (Key.CursorRight));
         Assert.Equal (new (-1, -10), sv.ContentOffset);
-        Assert.True (sv.OnKeyDown (Key.CursorLeft));
+        Assert.True (sv.NewKeyDownEvent (Key.CursorLeft));
         Assert.Equal (point0xMinus10, sv.ContentOffset);
-        Assert.False (sv.OnKeyDown (Key.PageUp.WithCtrl));
+        Assert.False (sv.NewKeyDownEvent (Key.PageUp.WithCtrl));
         Assert.Equal (point0xMinus10, sv.ContentOffset);
-        Assert.True (sv.OnKeyDown (Key.PageDown.WithCtrl));
+        Assert.True (sv.NewKeyDownEvent (Key.PageDown.WithCtrl));
         Point pointMinus20xMinus10 = new (-20, -10);
         Assert.Equal (pointMinus20xMinus10, sv.ContentOffset);
-        Assert.False (sv.OnKeyDown (Key.CursorRight));
+        Assert.False (sv.NewKeyDownEvent (Key.CursorRight));
         Assert.Equal (pointMinus20xMinus10, sv.ContentOffset);
-        Assert.True (sv.OnKeyDown (Key.Home));
+        Assert.True (sv.NewKeyDownEvent (Key.Home));
         Point pointMinus20x0 = new (-20, 0);
         Assert.Equal (pointMinus20x0, sv.ContentOffset);
-        Assert.False (sv.OnKeyDown (Key.Home));
+        Assert.False (sv.NewKeyDownEvent (Key.Home));
         Assert.Equal (pointMinus20x0, sv.ContentOffset);
-        Assert.True (sv.OnKeyDown (Key.End));
+        Assert.True (sv.NewKeyDownEvent (Key.End));
         Assert.Equal (pointMinus20xMinus10, sv.ContentOffset);
-        Assert.False (sv.OnKeyDown (Key.End));
+        Assert.False (sv.NewKeyDownEvent (Key.End));
         Assert.Equal (pointMinus20xMinus10, sv.ContentOffset);
-        Assert.True (sv.OnKeyDown (Key.Home.WithCtrl));
+        Assert.True (sv.NewKeyDownEvent (Key.Home.WithCtrl));
         Assert.Equal (point0xMinus10, sv.ContentOffset);
-        Assert.False (sv.OnKeyDown (Key.Home.WithCtrl));
+        Assert.False (sv.NewKeyDownEvent (Key.Home.WithCtrl));
         Assert.Equal (point0xMinus10, sv.ContentOffset);
-        Assert.True (sv.OnKeyDown (Key.End.WithCtrl));
+        Assert.True (sv.NewKeyDownEvent (Key.End.WithCtrl));
         Assert.Equal (pointMinus20xMinus10, sv.ContentOffset);
-        Assert.False (sv.OnKeyDown (Key.End.WithCtrl));
+        Assert.False (sv.NewKeyDownEvent (Key.End.WithCtrl));
         Assert.Equal (pointMinus20xMinus10, sv.ContentOffset);
-        Assert.True (sv.OnKeyDown (Key.Home));
+        Assert.True (sv.NewKeyDownEvent (Key.Home));
         Assert.Equal (pointMinus20x0, sv.ContentOffset);
-        Assert.True (sv.OnKeyDown (Key.Home.WithCtrl));
+        Assert.True (sv.NewKeyDownEvent (Key.Home.WithCtrl));
         Assert.Equal (Point.Empty, sv.ContentOffset);
 
         sv.KeepContentAlwaysInViewport = false;
         Assert.False (sv.KeepContentAlwaysInViewport);
         Assert.True (sv.AutoHideScrollBars);
         Assert.Equal (Point.Empty, sv.ContentOffset);
-        Assert.False (sv.OnKeyDown (Key.CursorUp));
+        Assert.False (sv.NewKeyDownEvent (Key.CursorUp));
         Assert.Equal (Point.Empty, sv.ContentOffset);
-        Assert.True (sv.OnKeyDown (Key.CursorDown));
+        Assert.True (sv.NewKeyDownEvent (Key.CursorDown));
         Assert.Equal (new (0, -1), sv.ContentOffset);
-        Assert.True (sv.OnKeyDown (Key.CursorUp));
+        Assert.True (sv.NewKeyDownEvent (Key.CursorUp));
         Assert.Equal (Point.Empty, sv.ContentOffset);
-        Assert.False (sv.OnKeyDown (Key.PageUp));
+        Assert.False (sv.NewKeyDownEvent (Key.PageUp));
         Assert.Equal (Point.Empty, sv.ContentOffset);
-        Assert.True (sv.OnKeyDown (Key.PageDown));
+        Assert.True (sv.NewKeyDownEvent (Key.PageDown));
         Assert.Equal (point0xMinus10, sv.ContentOffset);
-        Assert.True (sv.OnKeyDown (Key.PageDown));
+        Assert.True (sv.NewKeyDownEvent (Key.PageDown));
         Point point0xMinus19 = new (0, -19);
         Assert.Equal (point0xMinus19, sv.ContentOffset);
-        Assert.False (sv.OnKeyDown (Key.PageDown));
+        Assert.False (sv.NewKeyDownEvent (Key.PageDown));
         Assert.Equal (point0xMinus19, sv.ContentOffset);
-        Assert.False (sv.OnKeyDown (Key.CursorDown));
+        Assert.False (sv.NewKeyDownEvent (Key.CursorDown));
         Assert.Equal (point0xMinus19, sv.ContentOffset);
-        Assert.True (sv.OnKeyDown (Key.V.WithAlt));
+        Assert.True (sv.NewKeyDownEvent (Key.V.WithAlt));
         Assert.Equal (new (0, -9), sv.ContentOffset);
-        Assert.True (sv.OnKeyDown (Key.V.WithCtrl));
+        Assert.True (sv.NewKeyDownEvent (Key.V.WithCtrl));
         Assert.Equal (point0xMinus19, sv.ContentOffset);
-        Assert.False (sv.OnKeyDown (Key.CursorLeft));
+        Assert.False (sv.NewKeyDownEvent (Key.CursorLeft));
         Assert.Equal (point0xMinus19, sv.ContentOffset);
-        Assert.True (sv.OnKeyDown (Key.CursorRight));
+        Assert.True (sv.NewKeyDownEvent (Key.CursorRight));
         Assert.Equal (new (-1, -19), sv.ContentOffset);
-        Assert.True (sv.OnKeyDown (Key.CursorLeft));
+        Assert.True (sv.NewKeyDownEvent (Key.CursorLeft));
         Assert.Equal (point0xMinus19, sv.ContentOffset);
-        Assert.False (sv.OnKeyDown (Key.PageUp.WithCtrl));
+        Assert.False (sv.NewKeyDownEvent (Key.PageUp.WithCtrl));
         Assert.Equal (point0xMinus19, sv.ContentOffset);
-        Assert.True (sv.OnKeyDown (Key.PageDown.WithCtrl));
+        Assert.True (sv.NewKeyDownEvent (Key.PageDown.WithCtrl));
         Assert.Equal (new (-20, -19), sv.ContentOffset);
-        Assert.True (sv.OnKeyDown (Key.PageDown.WithCtrl));
+        Assert.True (sv.NewKeyDownEvent (Key.PageDown.WithCtrl));
         Point pointMinus39xMinus19 = new (-39, -19);
         Assert.Equal (pointMinus39xMinus19, sv.ContentOffset);
-        Assert.False (sv.OnKeyDown (Key.PageDown.WithCtrl));
+        Assert.False (sv.NewKeyDownEvent (Key.PageDown.WithCtrl));
         Assert.Equal (pointMinus39xMinus19, sv.ContentOffset);
-        Assert.False (sv.OnKeyDown (Key.CursorRight));
+        Assert.False (sv.NewKeyDownEvent (Key.CursorRight));
         Assert.Equal (pointMinus39xMinus19, sv.ContentOffset);
-        Assert.True (sv.OnKeyDown (Key.PageUp.WithCtrl));
+        Assert.True (sv.NewKeyDownEvent (Key.PageUp.WithCtrl));
         var pointMinus19xMinus19 = new Point (-19, -19);
         Assert.Equal (pointMinus19xMinus19, sv.ContentOffset);
-        Assert.True (sv.OnKeyDown (Key.Home));
+        Assert.True (sv.NewKeyDownEvent (Key.Home));
         Assert.Equal (new (-19, 0), sv.ContentOffset);
-        Assert.False (sv.OnKeyDown (Key.Home));
+        Assert.False (sv.NewKeyDownEvent (Key.Home));
         Assert.Equal (new (-19, 0), sv.ContentOffset);
-        Assert.True (sv.OnKeyDown (Key.End));
+        Assert.True (sv.NewKeyDownEvent (Key.End));
         Assert.Equal (pointMinus19xMinus19, sv.ContentOffset);
-        Assert.False (sv.OnKeyDown (Key.End));
+        Assert.False (sv.NewKeyDownEvent (Key.End));
         Assert.Equal (pointMinus19xMinus19, sv.ContentOffset);
-        Assert.True (sv.OnKeyDown (Key.Home.WithCtrl));
+        Assert.True (sv.NewKeyDownEvent (Key.Home.WithCtrl));
         Assert.Equal (point0xMinus19, sv.ContentOffset);
-        Assert.False (sv.OnKeyDown (Key.Home.WithCtrl));
+        Assert.False (sv.NewKeyDownEvent (Key.Home.WithCtrl));
         Assert.Equal (point0xMinus19, sv.ContentOffset);
-        Assert.True (sv.OnKeyDown (Key.End.WithCtrl));
+        Assert.True (sv.NewKeyDownEvent (Key.End.WithCtrl));
         Assert.Equal (pointMinus39xMinus19, sv.ContentOffset);
-        Assert.False (sv.OnKeyDown (Key.End.WithCtrl));
+        Assert.False (sv.NewKeyDownEvent (Key.End.WithCtrl));
         Assert.Equal (pointMinus39xMinus19, sv.ContentOffset);
     }
 

+ 5 - 5
UnitTests/Views/ShortcutTests.cs

@@ -667,7 +667,7 @@ public class ShortcutTests
         var selected = 0;
         shortcut.Selecting += (s, e) => selected++;
 
-        Application.OnKeyDown (key);
+        Application.RaiseKeyDownEvent (key);
 
         Assert.Equal (expectedAccept, accepted);
         Assert.Equal (expectedSelect, selected);
@@ -719,7 +719,7 @@ public class ShortcutTests
         var selected = 0;
         shortcut.Selecting += (s, e) => selected++;
 
-        Application.OnKeyDown (key);
+        Application.RaiseKeyDownEvent (key);
 
         Assert.Equal (expectedAccept, accepted);
         Assert.Equal (expectedSelect, selected);
@@ -751,7 +751,7 @@ public class ShortcutTests
         var accepted = 0;
         shortcut.Accepting += (s, e) => accepted++;
 
-        Application.OnKeyDown (key);
+        Application.RaiseKeyDownEvent (key);
 
         Assert.Equal (expectedAccept, accepted);
 
@@ -792,7 +792,7 @@ public class ShortcutTests
         var action = 0;
         shortcut.Action += () => action++;
 
-        Application.OnKeyDown (key);
+        Application.RaiseKeyDownEvent (key);
 
         Assert.Equal (expectedAction, action);
 
@@ -831,7 +831,7 @@ public class ShortcutTests
         var action = 0;
         shortcut.Action += () => action++;
 
-        Application.OnKeyDown (key);
+        Application.RaiseKeyDownEvent (key);
 
         Assert.Equal (expectedAction, action);
 

+ 1 - 1
UnitTests/Views/StatusBarTests.cs

@@ -104,7 +104,7 @@ public class StatusBarTests
                                      if (iteration == 0)
                                      {
                                          Assert.Equal ("", msg);
-                                         Application.OnKeyDown (Application.QuitKey);
+                                         Application.RaiseKeyDownEvent (Application.QuitKey);
                                      }
                                      else if (iteration == 1)
                                      {

+ 15 - 15
UnitTests/Views/TabViewTests.cs

@@ -398,7 +398,7 @@ public class TabViewTests (ITestOutputHelper output)
         Assert.Equal (tv.SelectedTab.View, top.Focused.MostFocused);
 
         // Press the cursor up key to focus the selected tab
-        Application.OnKeyDown (Key.CursorUp);
+        Application.RaiseKeyDownEvent (Key.CursorUp);
         Application.Refresh ();
 
         // Is the selected tab focused
@@ -416,7 +416,7 @@ public class TabViewTests (ITestOutputHelper output)
                                  };
 
         // Press the cursor right key to select the next tab
-        Application.OnKeyDown (Key.CursorRight);
+        Application.RaiseKeyDownEvent (Key.CursorRight);
         Application.Refresh ();
         Assert.Equal (tab1, oldChanged);
         Assert.Equal (tab2, newChanged);
@@ -425,7 +425,7 @@ public class TabViewTests (ITestOutputHelper output)
         Assert.Equal (tv.MostFocused, top.Focused.MostFocused);
 
         // Press the cursor down key. Since the selected tab has no focusable views, the focus should move to the next view in the toplevel
-        Application.OnKeyDown (Key.CursorDown);
+        Application.RaiseKeyDownEvent (Key.CursorDown);
         Assert.Equal (tab2, tv.SelectedTab);
         Assert.Equal (btn, top.MostFocused);
 
@@ -439,31 +439,31 @@ public class TabViewTests (ITestOutputHelper output)
         tv.SelectedTab.View.Add (btnSubView);
 
         // Press cursor up. Should focus the subview in the selected tab.
-        Application.OnKeyDown (Key.CursorUp);
+        Application.RaiseKeyDownEvent (Key.CursorUp);
         Assert.Equal (tab2, tv.SelectedTab);
         Assert.Equal (btnSubView, top.MostFocused);
 
-        Application.OnKeyDown (Key.CursorUp);
+        Application.RaiseKeyDownEvent (Key.CursorUp);
         Assert.Equal (tab2, top.MostFocused);
 
         // Press the cursor down key twice.
-        Application.OnKeyDown (Key.CursorDown);
-        Application.OnKeyDown (Key.CursorDown);
+        Application.RaiseKeyDownEvent (Key.CursorDown);
+        Application.RaiseKeyDownEvent (Key.CursorDown);
         Assert.Equal (btn, top.MostFocused);
 
         // Press the cursor down key again will focus next view in the toplevel, whic is the TabView
-        Application.OnKeyDown (Key.CursorDown);
+        Application.RaiseKeyDownEvent (Key.CursorDown);
         Assert.Equal (tab2, tv.SelectedTab);
         Assert.Equal (tv, top.Focused);
         Assert.Equal (tab1, tv.MostFocused);
 
         // Press the cursor down key to focus the selected tab view hosting again
-        Application.OnKeyDown (Key.CursorDown);
+        Application.RaiseKeyDownEvent (Key.CursorDown);
         Assert.Equal (tab2, tv.SelectedTab);
         Assert.Equal (btnSubView, top.MostFocused);
 
         // Press the cursor up key to focus the selected tab
-        Application.OnKeyDown (Key.CursorUp);
+        Application.RaiseKeyDownEvent (Key.CursorUp);
         Application.Refresh ();
 
         // Is the selected tab focused
@@ -472,7 +472,7 @@ public class TabViewTests (ITestOutputHelper output)
         Assert.Equal (tv.MostFocused, top.Focused.MostFocused);
 
         // Press the cursor left key to select the previous tab
-        Application.OnKeyDown (Key.CursorLeft);
+        Application.RaiseKeyDownEvent (Key.CursorLeft);
         Application.Refresh ();
         Assert.Equal (tab2, oldChanged);
         Assert.Equal (tab1, newChanged);
@@ -481,7 +481,7 @@ public class TabViewTests (ITestOutputHelper output)
         Assert.Equal (tv.MostFocused, top.Focused.MostFocused);
 
         // Press the end key to select the last tab
-        Application.OnKeyDown (Key.End);
+        Application.RaiseKeyDownEvent (Key.End);
         Application.Refresh ();
         Assert.Equal (tab1, oldChanged);
         Assert.Equal (tab2, newChanged);
@@ -490,7 +490,7 @@ public class TabViewTests (ITestOutputHelper output)
         Assert.Equal (tv.MostFocused, top.Focused.MostFocused);
 
         // Press the home key to select the first tab
-        Application.OnKeyDown (Key.Home);
+        Application.RaiseKeyDownEvent (Key.Home);
         Application.Refresh ();
         Assert.Equal (tab2, oldChanged);
         Assert.Equal (tab1, newChanged);
@@ -499,7 +499,7 @@ public class TabViewTests (ITestOutputHelper output)
         Assert.Equal (tv.MostFocused, top.Focused.MostFocused);
 
         // Press the page down key to select the next set of tabs
-        Application.OnKeyDown (Key.PageDown);
+        Application.RaiseKeyDownEvent (Key.PageDown);
         Application.Refresh ();
         Assert.Equal (tab1, oldChanged);
         Assert.Equal (tab2, newChanged);
@@ -508,7 +508,7 @@ public class TabViewTests (ITestOutputHelper output)
         Assert.Equal (tv.MostFocused, top.Focused.MostFocused);
 
         // Press the page up key to select the previous set of tabs
-        Application.OnKeyDown (Key.PageUp);
+        Application.RaiseKeyDownEvent (Key.PageUp);
         Application.Refresh ();
         Assert.Equal (tab2, oldChanged);
         Assert.Equal (tab1, newChanged);

+ 11 - 11
UnitTests/Views/TableViewTests.cs

@@ -3215,12 +3215,12 @@ A B C
         tableView.SelectedColumn = 1;
 
         // Pressing left should move us to the first column without changing focus
-        Application.OnKeyDown (Key.CursorLeft);
+        Application.RaiseKeyDownEvent (Key.CursorLeft);
         Assert.Same (tableView, Application.Top!.MostFocused);
         Assert.True (tableView.HasFocus);
 
         // Because we are now on the leftmost cell a further left press should move focus
-        Application.OnKeyDown (Key.CursorLeft);
+        Application.RaiseKeyDownEvent (Key.CursorLeft);
 
         Assert.NotSame (tableView, Application.Top.MostFocused);
         Assert.False (tableView.HasFocus);
@@ -3240,12 +3240,12 @@ A B C
         tableView.SelectedRow = 1;
 
         // First press should move us up
-        Application.OnKeyDown (Key.CursorUp);
+        Application.RaiseKeyDownEvent (Key.CursorUp);
         Assert.Same (tableView, Application.Top!.MostFocused);
         Assert.True (tableView.HasFocus);
 
         // Because we are now on the top row a further press should move focus
-        Application.OnKeyDown (Key.CursorUp);
+        Application.RaiseKeyDownEvent (Key.CursorUp);
 
         Assert.NotSame (tableView, Application.Top.MostFocused);
         Assert.False (tableView.HasFocus);
@@ -3264,12 +3264,12 @@ A B C
         tableView.SelectedColumn = tableView.Table.Columns - 2;
 
         // First press should move us to the rightmost column without changing focus
-        Application.OnKeyDown (Key.CursorRight);
+        Application.RaiseKeyDownEvent (Key.CursorRight);
         Assert.Same (tableView, Application.Top!.MostFocused);
         Assert.True (tableView.HasFocus);
 
         // Because we are now on the rightmost cell, a further right press should move focus
-        Application.OnKeyDown (Key.CursorRight);
+        Application.RaiseKeyDownEvent (Key.CursorRight);
 
         Assert.NotSame (tableView, Application.Top.MostFocused);
         Assert.False (tableView.HasFocus);
@@ -3289,12 +3289,12 @@ A B C
         tableView.SelectedRow = tableView.Table.Rows - 2;
 
         // First press should move us to the bottommost row without changing focus
-        Application.OnKeyDown (Key.CursorDown);
+        Application.RaiseKeyDownEvent (Key.CursorDown);
         Assert.Same (tableView, Application.Top!.MostFocused);
         Assert.True (tableView.HasFocus);
 
         // Because we are now on the bottommost cell, a further down press should move focus
-        Application.OnKeyDown (Key.CursorDown);
+        Application.RaiseKeyDownEvent (Key.CursorDown);
 
         Assert.NotSame (tableView, Application.Top.MostFocused);
         Assert.False (tableView.HasFocus);
@@ -3315,7 +3315,7 @@ A B C
         tableView.SelectedColumn = 1;
 
         // Pressing shift-left should give us a multi selection
-        Application.OnKeyDown (Key.CursorLeft.WithShift);
+        Application.RaiseKeyDownEvent (Key.CursorLeft.WithShift);
         Assert.Same (tableView, Application.Top!.MostFocused);
         Assert.True (tableView.HasFocus);
         Assert.Equal (2, tableView.GetAllSelectedCells ().Count ());
@@ -3323,7 +3323,7 @@ A B C
         // Because we are now on the leftmost cell a further left press would normally move focus
         // However there is an ongoing selection so instead the operation clears the selection and
         // gets swallowed (not resulting in a focus change)
-        Application.OnKeyDown (Key.CursorLeft);
+        Application.RaiseKeyDownEvent (Key.CursorLeft);
 
         // Selection 'clears' just to the single cell and we remain focused
         Assert.Single (tableView.GetAllSelectedCells ());
@@ -3331,7 +3331,7 @@ A B C
         Assert.True (tableView.HasFocus);
 
         // A further left will switch focus
-        Application.OnKeyDown (Key.CursorLeft);
+        Application.RaiseKeyDownEvent (Key.CursorLeft);
 
         Assert.NotSame (tableView, Application.Top.MostFocused);
         Assert.False (tableView.HasFocus);

+ 3 - 3
UnitTests/Views/TextFieldTests.cs

@@ -524,7 +524,7 @@ public class TextFieldTests (ITestOutputHelper output)
         Application.Top = new ();
         Application.Top.Add (tf);
         tf.SetFocus ();
-        Application.OnKeyDown (Key.Space);
+        Application.RaiseKeyDownEvent (Key.Space);
 
         Application.Top.Dispose ();
         Application.ResetState (true);
@@ -541,7 +541,7 @@ public class TextFieldTests (ITestOutputHelper output)
         Application.Top = new ();
         Application.Top.Add (tf);
         tf.SetFocus ();
-        Application.OnKeyDown (Key.Enter);
+        Application.RaiseKeyDownEvent (Key.Enter);
 
         Assert.Equal (0, selectingCount);
 
@@ -560,7 +560,7 @@ public class TextFieldTests (ITestOutputHelper output)
         Application.Top = new ();
         Application.Top.Add (tf);
         tf.SetFocus ();
-        Application.OnKeyDown (Key.Enter);
+        Application.RaiseKeyDownEvent (Key.Enter);
 
         Assert.Equal (1, acceptedCount);
 

+ 20 - 20
UnitTests/Views/ToplevelTests.cs

@@ -299,26 +299,26 @@ public partial class ToplevelTests (ITestOutputHelper output)
         Assert.Equal (tf1W1, top.MostFocused);
 
         Assert.True (isRunning);
-        Assert.True (Application.OnKeyDown (Application.QuitKey));
+        Assert.True (Application.RaiseKeyDownEvent (Application.QuitKey));
         Assert.False (isRunning);
-        Assert.True (Application.OnKeyDown (Key.Z.WithCtrl));
+        Assert.True (Application.RaiseKeyDownEvent (Key.Z.WithCtrl));
 
-        Assert.True (Application.OnKeyDown (Key.F5)); // refresh
+        Assert.True (Application.RaiseKeyDownEvent (Key.F5)); // refresh
 
-        Assert.True (Application.OnKeyDown (Key.Tab));
+        Assert.True (Application.RaiseKeyDownEvent (Key.Tab));
         Assert.Equal (win1, top.Focused);
         Assert.Equal (tvW1, top.MostFocused);
-        Assert.True (Application.OnKeyDown (Key.Tab));
+        Assert.True (Application.RaiseKeyDownEvent (Key.Tab));
         Assert.Equal ($"\tFirst line Win1{Environment.NewLine}Second line Win1", tvW1.Text);
-        Assert.True (Application.OnKeyDown (Key.Tab.WithShift));
+        Assert.True (Application.RaiseKeyDownEvent (Key.Tab.WithShift));
         Assert.Equal ($"First line Win1{Environment.NewLine}Second line Win1", tvW1.Text);
 
         var prevMostFocusedSubview = top.MostFocused;
 
-        Assert.True (Application.OnKeyDown (Key.F6)); // move to next TabGroup (win2)
+        Assert.True (Application.RaiseKeyDownEvent (Key.F6)); // move to next TabGroup (win2)
         Assert.Equal (win2, top.Focused);
 
-        Assert.True (Application.OnKeyDown (Key.F6.WithShift)); // move to prev TabGroup (win1)
+        Assert.True (Application.RaiseKeyDownEvent (Key.F6.WithShift)); // move to prev TabGroup (win1)
         Assert.Equal (win1, top.Focused);
         Assert.Equal (tf2W1, top.MostFocused);  // BUGBUG: Should be prevMostFocusedSubview - We need to cache the last focused view in the TabGroup somehow
 
@@ -327,13 +327,13 @@ public partial class ToplevelTests (ITestOutputHelper output)
         Assert.Equal (tvW1, top.MostFocused);
 
         tf2W1.SetFocus ();
-        Assert.True (Application.OnKeyDown (Key.Tab)); // tf2W1 is last subview in win1 - tabbing should take us to first subview of win1
+        Assert.True (Application.RaiseKeyDownEvent (Key.Tab)); // tf2W1 is last subview in win1 - tabbing should take us to first subview of win1
         Assert.Equal (win1, top.Focused);
         Assert.Equal (tf1W1, top.MostFocused);
-        Assert.True (Application.OnKeyDown (Key.CursorRight)); // move char to right in tf1W1. We're at last char so nav to next view
+        Assert.True (Application.RaiseKeyDownEvent (Key.CursorRight)); // move char to right in tf1W1. We're at last char so nav to next view
         Assert.Equal (win1, top.Focused);
         Assert.Equal (tvW1, top.MostFocused);
-        Assert.True (Application.OnKeyDown (Key.CursorDown)); // move down to next view (tvW1)
+        Assert.True (Application.RaiseKeyDownEvent (Key.CursorDown)); // move down to next view (tvW1)
         Assert.Equal (win1, top.Focused);
         Assert.Equal (tvW1, top.MostFocused);
 #if UNIX_KEY_BINDINGS
@@ -341,34 +341,34 @@ public partial class ToplevelTests (ITestOutputHelper output)
         Assert.Equal (win1, top.GetFocused ());
         Assert.Equal (tf2W1, top.MostFocused);
 #endif
-        Assert.True (Application.OnKeyDown (Key.Tab.WithShift)); // Ignored. TextView eats shift-tab by default
+        Assert.True (Application.RaiseKeyDownEvent (Key.Tab.WithShift)); // Ignored. TextView eats shift-tab by default
         Assert.Equal (win1, top.Focused);
         Assert.Equal (tvW1, top.MostFocused);
         tvW1.AllowsTab = false;
-        Assert.True (Application.OnKeyDown (Key.Tab.WithShift));
+        Assert.True (Application.RaiseKeyDownEvent (Key.Tab.WithShift));
         Assert.Equal (win1, top.Focused);
         Assert.Equal (tf1W1, top.MostFocused);
-        Assert.True (Application.OnKeyDown (Key.CursorLeft));
+        Assert.True (Application.RaiseKeyDownEvent (Key.CursorLeft));
         Assert.Equal (win1, top.Focused);
         Assert.Equal (tf2W1, top.MostFocused);
-        Assert.True (Application.OnKeyDown (Key.CursorUp));
+        Assert.True (Application.RaiseKeyDownEvent (Key.CursorUp));
         Assert.Equal (win1, top.Focused);
         Assert.Equal (tvW1, top.MostFocused);
 
         // nav to win2
-        Assert.True (Application.OnKeyDown (Key.F6));
+        Assert.True (Application.RaiseKeyDownEvent (Key.F6));
         Assert.Equal (win2, top.Focused);
         Assert.Equal (tf1W2, top.MostFocused);
-        Assert.True (Application.OnKeyDown (Key.F6.WithShift));
+        Assert.True (Application.RaiseKeyDownEvent (Key.F6.WithShift));
         Assert.Equal (win1, top.Focused);
         Assert.Equal (tf2W1, top.MostFocused);
-        Assert.True (Application.OnKeyDown (Application.NextTabGroupKey));
+        Assert.True (Application.RaiseKeyDownEvent (Application.NextTabGroupKey));
         Assert.Equal (win2, top.Focused);
         Assert.Equal (tf1W2, top.MostFocused);
-        Assert.True (Application.OnKeyDown (Application.PrevTabGroupKey));
+        Assert.True (Application.RaiseKeyDownEvent (Application.PrevTabGroupKey));
         Assert.Equal (win1, top.Focused);
         Assert.Equal (tf2W1, top.MostFocused);
-        Assert.True (Application.OnKeyDown (Key.CursorUp));
+        Assert.True (Application.RaiseKeyDownEvent (Key.CursorUp));
         Assert.Equal (win1, top.Focused);
         Assert.Equal (tvW1, top.MostFocused);
 

+ 1 - 1
UnitTests/Views/TreeTableSourceTests.cs

@@ -187,7 +187,7 @@ public class TreeTableSourceTests : IDisposable
         Assert.Equal (0, tv.SelectedRow);
         Assert.Equal (1, tv.SelectedColumn);
 
-        Application.OnKeyDown (Key.CursorRight);
+        Application.RaiseKeyDownEvent (Key.CursorRight);
 
         tv.Draw ();
 

+ 126 - 0
docfx/docs/events.md

@@ -0,0 +1,126 @@
+# Terminal.Gui Event Deep Dive
+
+Terminal.Gui exposes and uses events in many places. This deep dive covers the patterns used, where they are used, and notes any exceptions.
+
+## Tenets for Terminal.Gui Events (Unless you know better ones...)
+
+Tenets higher in the list have precedence over tenets lower in the list.
+
+* **UI Interaction and Live Data Are Different Beasts** - TG distinguishes between events used for human interaction and events for live data. We don't believe in a one-size-fits-all eventing model. For UI interactions we use `EventHandler`. For data binding we think `INotifyPropertyChanged` is groovy. For some callbacks we use `Action<T>`.
+
+## Lexicon and Taxonomy
+
+* *Action*
+* *Event*
+* *Command*
+* *Invoke*
+* *Raise*
+* *Listen*
+* *Handle/Handling/Handled* - Applies to scenarios where an event can either be handled by an event listener (or override) vs not handled. Events that originate from a user action like mouse moves and key presses are examples. 
+* *Cancel/Cancelling/Cancelled* - Applies to scenarios where something can be cancelled. Changing the `Orientation` of a `Slider` is cancelable.
+
+## Useful External Documentation
+
+* [.NET Naming Guidelines - Names of Events](https://learn.microsoft.com/en-us/dotnet/standard/design-guidelines/names-of-type-members?redirectedfrom=MSDN#names-of-events)
+* [.NET Design for Extensibility - Events and Callbacks](https://learn.microsoft.com/en-us/dotnet/standard/design-guidelines/events-and-callbacks)
+* [C# Event Implementation Fundamentals, Best Practices and Conventions](https://www.codeproject.com/Articles/20550/C-Event-Implementation-Fundamentals-Best-Practices)
+
+## Naming
+
+TG follows the *naming* advice provided in [.NET Naming Guidelines - Names of Events](https://learn.microsoft.com/en-us/dotnet/standard/design-guidelines/names-of-type-members?redirectedfrom=MSDN#names-of-events).
+
+## `EventHandler` style event best-practices
+
+* Implement a helper method for raising the event: `RaisexxxEvent`.
+  * If the event is cancelable, the return type should be either `bool` or `bool?`.
+  * Can be `private`, `internal`, or `public` depending on the situation. `internal` should only be used to enable unit tests.
+* Raising an event involves FIRST calling the `protected virtual` method, THEN invoking the `EventHandler.
+
+## `Action<T>` style callback best-practices
+
+- tbd
+
+## `INotifyPropertyChanged` style notification best practices
+
+- tbd
+
+## Common Patterns
+
+The primary pattern for events is the `event/EventHandler` idiom. We use the `Action<T>` idiom sparingly. We support `INotifyPropertyChanged` in cases where data binding is relevant.
+
+
+
+## Cancellable Event Pattern
+
+A cancellable event is really two events and some activity that takes place between those events. The "pre-event" happens before the activity. The activity then takes place (or not). If the activity takes place, then the "post-event" is typically raised. So, to be precise, no event is being cancelled even though we say we have a cancellable event. Rather, the activity that takes place between the two events is what is cancelled — and likely prevented from starting at all.
+
+### **Before** - If any pre-conditions are met raise the "pre-event", typically named in the form of "xxxChanging". e.g.
+
+  - A `protected virtual` method is called. This method is named `OnxxxChanging` and the base implementation simply does `return false`.
+  - If the `OnxxxChanging` method returns `true` it means a derived class canceled the event. Processing should stop.
+  - Otherwise, the `xxxChanging` event is invoked via `xxxChanging?.Invoke(args)`. If `args.Cancel/Handled == true` it means a subscriber has cancelled the event. Processing should stop.
+
+
+### **During** - Do work.
+
+### **After** - Raise the "post-event", typically named in the form of "xxxChanged"
+
+  - A `protected virtual` method is called. This method is named `OnxxxChanged` has a return type of `void`.
+  - The `xxxChanged` event is invoked via `xxxChanging?.Invoke(args)`. 
+
+The `OrientationHelper` class supporting `IOrientation` and a `View` having an `Orientation` property illustrates the preferred TG pattern for cancelable events.
+
+```cs
+   /// <summary>
+   ///     Gets or sets the orientation of the View.
+   /// </summary>
+   public Orientation Orientation
+   {
+       get => _orientation;
+       set
+       {
+           if (_orientation == value)
+           {
+               return;
+           }
+
+           // Best practice is to call the virtual method first.
+           // This allows derived classes to handle the event and potentially cancel it.
+           if (_owner?.OnOrientationChanging (value, _orientation) ?? false)
+           {
+               return;
+           }
+
+           // If the event is not canceled by the virtual method, raise the event to notify any external subscribers.
+           CancelEventArgs<Orientation> args = new (in _orientation, ref value);
+           OrientationChanging?.Invoke (_owner, args);
+
+           if (args.Cancel)
+           {
+               return;
+           }
+
+           // If the event is not canceled, update the value.
+           Orientation old = _orientation;
+
+           if (_orientation != value)
+           {
+               _orientation = value;
+
+               if (_owner is { })
+               {
+                   _owner.Orientation = value;
+               }
+           }
+
+           // Best practice is to call the virtual method first, then raise the event.
+           _owner?.OnOrientationChanged (_orientation);
+           OrientationChanged?.Invoke (_owner, new (in _orientation));
+       }
+   }
+```
+
+ ## `bool` or `bool?` 
+
+ 
+

+ 19 - 19
docfx/docs/keyboard.md

@@ -59,22 +59,25 @@ The Command can be invoked even if the `View` that defines them is not focused o
 
 ### **Handling Keyboard Events**
 
-Keyboard events are retrieved from [Console Drivers](drivers.md) and passed on 
-to the [Application](~/api/Terminal.Gui.Application.yml) class by the [Main Loop](mainloop.md). 
+Keyboard events are retrieved from [Console Drivers](drivers.md) each iteration of the [Application](~/api/Terminal.Gui.Application.yml) [Main Loop](mainloop.md). The console driver raises the @Terminal.Gui.ConsoleDriver.KeyDown and @Terminal.Gui.ConsoleDriver.KeyUp events which invoke @Terminal.Gui.Application.RaiseKeyDown(Terminal.Gui.Key) and @Terminal.Gui.Application.RaiseKeyUp(Terminal.Gui.Key) respectively.
 
-[Application](~/api/Terminal.Gui.Application.yml) then determines the current [Toplevel](~/api/Terminal.Gui.Toplevel.yml) view
-(either the default created by calling @Terminal.Gui.Application.Init(Terminal.Gui.ConsoleDriver,System.String), or the one set by calling `Application.Run`). The mouse event, using [Viewport-relative coordinates](xref:Terminal.Gui.View.Viewport) is then passed to the @Terminal.Gui.View.NewKeyDownEvent(Terminal.Gui.Key) method of the current [Toplevel](~/api/Terminal.Gui.Toplevel.yml) view. 
+    NOTE: Not all drivers/platforms support sensing distinct KeyUp events. These drivers will simulate KeyUp events by raising @Terminal.Gui.ConsoleDriver.KeyUp after @Terminal.Gui.ConsoleDriver.KeyDown.
 
-If the view is enabled, the @Terminal.Gui.View.NewKeyDownEvent(Terminal.Gui.Key) method will do the following: 
+@Terminal.Gui.Application.RaiseKeyDown(Terminal.Gui.Key) raises @Terminal.Gui.Application.KeyDown and then calls @Terminal.Gui.View.NewKeyDownEvent(Terminal.Gui.Key) on all toplevel Views. If no View handles the key event, any Application-scoped key bindings will be invoked.
 
-1) If the view has a subview that has focus, 'ProcessKeyDown' on the focused view will be called. If the focused view handles the key press, processing stops.
-2) If there is no focused sub-view, or the focused sub-view does not handle the key press, @Terminal.Gui.View.OnKeyDown(Terminal.Gui.Key) will be called. If the view handles the key press, processing stops.
-3) If the view does not handle the key press, @Terminal.Gui.TextField.OnInvokingKeyBindings(Terminal.Gui.Key,Terminal.Gui.KeyBindingScope) will be called. This method calls @Terminal.Gui.View.InvokeKeyBindings(Terminal.Gui.Key,Terminal.Gui.KeyBindingScope) to invoke any keys bound to commands. If the key is bound and any of it's command handlers return true, processing stops.
-4) If the key is not bound, or the bound command handlers do not return true, @Terminal.Gui.View.OnProcessKeyDown(Terminal.Gui.Key) is called. If the view handles the key press, processing stops.
[email protected](Terminal.Gui.Key) raises @Terminal.Gui.Application.KeyDown and then calls @Terminal.Gui.View.NewKeyUpEvent(Terminal.Gui.Key) on all toplevel Views.
+
+If a view is enabled, the @Terminal.Gui.View.NewKeyDownEvent(Terminal.Gui.Key) method will do the following: 
+
+1) If the view has a subview that has focus, 'NewKeyDown' on the focused view will be called. This is recursive. If the most-focused view handles the key press, processing stops.
+2) If there is no most-focused sub-view, or a most-focused sub-view does not handle the key press, @Terminal.Gui.View.OnKeyDown(Terminal.Gui.Key) will be called. If the view handles the key press, processing stops.
+3) If @Terminal.Gui.View.OnKeyDown(Terminal.Gui.Key) does not handle the event. @Terminal.Gui.View.KeyDown will be raised.
+4) If the view does not handle the key down event, any bindings for the key will be invoked (see @Terminal.Gui.View.KeyBindings). If the key is bound and any of it's command handlers return true, processing stops.
+5) If the key is not bound, or the bound command handlers do not return true, @Terminal.Gui.View.OnKeyDownNotHandled(Terminal.Gui.Key) is called. 
 
 ## **Application Key Handling**
 
-To define application key handling logic for an entire application in cases where the methods listed above are not suitable, use the `Application.OnKeyDown` event. 
+To define application key handling logic for an entire application in cases where the methods listed above are not suitable, use the @Terminal.Gui.Application.KeyDown event. 
 
 ## **Key Down/Up Events**
 
@@ -90,17 +93,14 @@ To define application key handling logic for an entire application in cases wher
     - `NewKeyDownEvent` is called on the most-focused SubView (if any) that has focus. If that call returns true, the method returns.
     - Calls `OnKeyDown`.
   - **During**
-    - Assuming `OnKeyDown` call returns false (indicating the key wasn't handled)
-       - `OnInvokingKeyBindings` is called to invoke any bound commands.
-       - `OnInvokingKeyBindings` fires the `InvokingKeyBindings` event
+    - Assuming `OnKeyDown` call returns false (indicating the key wasn't handled) any commands bound to the key will be invoked.
   - **After**
-    - Assuming `OnInvokingKeyBindings` returns false (indicating the key wasn't handled)
-       - `OnProcessKeyDown` is called to process the key.
-       - `OnProcessKeyDown` fires the `ProcessKeyDown` event
+    - Assuming no keybinding was found or all invoked commands were not handled:
+       - `OnKeyDownNotHandled` is called to process the key.
+       - `KeyDownNotHandled` is raised.
 
-- Subclasses of `View` can (rarely) override `OnKeyDown` to see keys before they are processed by `OnInvokingKeyBindings` and `OnProcessKeyDown
-- Subclasses of `View` can (rarely) override `OnInvokingKeyBindings` to see keys before they are processed by `OnProcessKeyDown`
-- Subclasses of `View` can (often) override `OnProcessKeyDown` to do normal key processing.
+- Subclasses of `View` can (rarely) override `OnKeyDown` (or subscribe to `KeyDown`) to see keys before they are processed 
+- Subclasses of `View` can (often) override `OnKeyDownNotHandled` to do key processing for keys that were not previously handled. `TextField` and `TextView` are examples.
 
 ## ConsoleDriver