Ver código fonte

Thinking through Adornments (again)

Tig 10 meses atrás
pai
commit
1e19e9572d

+ 34 - 19
Terminal.Gui/Application/Application.Mouse.cs

@@ -6,6 +6,13 @@ namespace Terminal.Gui;
 
 public static partial class Application // Mouse handling
 {
+    internal static Point _lastMousePosition = Point.Empty;
+
+    /// <summary>
+    ///     Gets the most recent position of the mouse.
+    /// </summary>
+    public static Point GetLastMousePosition () => _lastMousePosition;
+
     /// <summary>Disable or enable the mouse. The mouse is enabled by default.</summary>
     [SerializableConfigurationProperty (Scope = typeof (SettingsScope))]
     public static bool IsMouseDisabled { get; set; }
@@ -132,12 +139,17 @@ public static partial class Application // Mouse handling
     /// <param name="mouseEvent">The mouse event with coordinates relative to the screen.</param>
     internal static void OnMouseEvent (MouseEvent mouseEvent)
     {
+        _lastMousePosition = mouseEvent.ScreenPosition;
+
         if (IsMouseDisabled)
         {
             return;
         }
 
-        List<View?> currentViewsUnderMouse = View.GetViewsUnderMouse (mouseEvent.Position);
+        // The position of the mouse is the same as the screen position at the application level.
+        mouseEvent.Position = mouseEvent.ScreenPosition;
+
+        List<View?> currentViewsUnderMouse = View.GetViewsUnderMouse (mouseEvent.ScreenPosition);
 
         View? deepestViewUnderMouse = currentViewsUnderMouse.LastOrDefault ();
 
@@ -180,44 +192,45 @@ public static partial class Application // Mouse handling
             return;
         }
 
-        // TODO: Move this after call to RaiseMouseEnterLeaveEvents once MouseEnter/Leave don't use MouseEvent anymore.
-        MouseEvent? me;
+        // Create a view-relative mouse event to send to the view that is under the mouse.
+        MouseEvent? viewMouseEvent;
 
         if (deepestViewUnderMouse is Adornment adornment)
         {
-            Point frameLoc = adornment.ScreenToFrame (mouseEvent.Position);
+            Point frameLoc = adornment.ScreenToFrame (mouseEvent.ScreenPosition);
 
-            me = new ()
+            viewMouseEvent = new ()
             {
                 Position = frameLoc,
                 Flags = mouseEvent.Flags,
-                ScreenPosition = mouseEvent.Position,
+                ScreenPosition = mouseEvent.ScreenPosition,
                 View = deepestViewUnderMouse
             };
         }
         else if (deepestViewUnderMouse.ViewportToScreen (Rectangle.Empty with { Size = deepestViewUnderMouse.Viewport.Size }).Contains (mouseEvent.Position))
         {
-            Point viewportLocation = deepestViewUnderMouse.ScreenToViewport (mouseEvent.Position);
+            Point viewportLocation = deepestViewUnderMouse.ScreenToViewport (mouseEvent.ScreenPosition);
 
-            me = new ()
+            viewMouseEvent = new ()
             {
                 Position = viewportLocation,
                 Flags = mouseEvent.Flags,
-                ScreenPosition = mouseEvent.Position,
+                ScreenPosition = mouseEvent.ScreenPosition,
                 View = deepestViewUnderMouse
             };
         }
         else
         {
-            Debug.Fail ("This should never happen");
+            // The mouse was outside any View's Viewport.
+
             return;
         }
 
-        RaiseMouseEnterLeaveEvents (me.ScreenPosition, currentViewsUnderMouse);
+        RaiseMouseEnterLeaveEvents (viewMouseEvent.ScreenPosition, currentViewsUnderMouse);
 
         WantContinuousButtonPressedView = deepestViewUnderMouse.WantContinuousButtonPressed ? deepestViewUnderMouse : null;
 
-        while (deepestViewUnderMouse.NewMouseEvent (me) is not true && MouseGrabView is not { })
+        while (deepestViewUnderMouse.NewMouseEvent (viewMouseEvent) is not true && MouseGrabView is not { })
         {
             if (deepestViewUnderMouse is Adornment adornmentView)
             {
@@ -233,13 +246,13 @@ public static partial class Application // Mouse handling
                 break;
             }
 
-            Point boundsPoint = deepestViewUnderMouse.ScreenToViewport (mouseEvent.Position);
+            Point boundsPoint = deepestViewUnderMouse.ScreenToViewport (mouseEvent.ScreenPosition);
 
-            me = new ()
+            viewMouseEvent = new ()
             {
                 Position = boundsPoint,
                 Flags = mouseEvent.Flags,
-                ScreenPosition = mouseEvent.Position,
+                ScreenPosition = mouseEvent.ScreenPosition,
                 View = deepestViewUnderMouse
             };
         }
@@ -249,22 +262,22 @@ public static partial class Application // Mouse handling
     {
         if (MouseGrabView is { })
         {
-
 #if DEBUG_IDISPOSABLE
             if (MouseGrabView.WasDisposed)
             {
                 throw new ObjectDisposedException (MouseGrabView.GetType ().FullName);
             }
 #endif
+
             // If the mouse is grabbed, send the event to the view that grabbed it.
             // The coordinates are relative to the Bounds of the view that grabbed the mouse.
-            Point frameLoc = MouseGrabView.ScreenToViewport (mouseEvent.Position);
+            Point frameLoc = MouseGrabView.ScreenToViewport (mouseEvent.ScreenPosition);
 
             var viewRelativeMouseEvent = new MouseEvent
             {
                 Position = frameLoc,
                 Flags = mouseEvent.Flags,
-                ScreenPosition = mouseEvent.Position,
+                ScreenPosition = mouseEvent.ScreenPosition,
                 View = deepestViewUnderMouse ?? MouseGrabView
             };
 
@@ -297,6 +310,7 @@ public static partial class Application // Mouse handling
     {
         // Tell any views that are no longer under the mouse that the mouse has left
         List<View?> viewsToLeave = _cachedViewsUnderMouse.Where (v => v is { } && !currentViewsUnderMouse.Contains (v)).ToList ();
+
         foreach (View? view in viewsToLeave)
         {
             if (view is null)
@@ -322,7 +336,8 @@ public static partial class Application // Mouse handling
             }
 
             _cachedViewsUnderMouse.Add (view);
-            bool raise = false;
+            var raise = false;
+
             if (view is Adornment { Parent: { } } adornmentView)
             {
                 Point superViewLoc = adornmentView.Parent.SuperView?.ScreenToViewport (screenPosition) ?? screenPosition;

+ 7 - 5
Terminal.Gui/Input/KeyBindings.cs

@@ -284,12 +284,14 @@ public class KeyBindings
         return Array.Empty<Command> ();
     }
 
-    /// <summary>Gets the Key used by a set of commands.</summary>
-    /// <remarks></remarks>
+    // TODO: Consider having this return all keys bound to the commands
+    /// <summary>Gets the first Key bound to the set of commands specified by <paramref name="commands"/>.</summary>
     /// <param name="commands">The set of commands to search.</param>
-    /// <returns>The <see cref="Key"/> used by a <see cref="Command"/></returns>
-    /// <exception cref="InvalidOperationException">If no matching set of commands was found.</exception>
-    public Key GetKeyFromCommands (params Command [] commands) { return Bindings.First (a => a.Value.Commands.SequenceEqual (commands)).Key; }
+    /// <returns>The first <see cref="Key"/> bound to the set of commands specified by <paramref name="commands"/>. <see langword="null"/> if the set of caommands was not found.</returns>
+    public Key? GetKeyFromCommands (params Command [] commands)
+    {
+        return Bindings.FirstOrDefault (a => a.Value.Commands.SequenceEqual (commands)).Key;
+    }
 
     /// <summary>Removes a <see cref="KeyBinding"/> from the collection.</summary>
     /// <param name="key"></param>

+ 3 - 3
Terminal.Gui/View/Adornment/Adornment.cs

@@ -223,10 +223,10 @@ public class Adornment : View
             return false;
         }
 
-        Rectangle frame = Frame;
-        frame.Offset (Parent.Frame.Location);
+        Rectangle outside = Parent.Frame;
+        //outside.Offset (Parent.Frame.Location);
 
-        return Thickness.Contains (frame, location);
+        return Thickness.Contains (outside, location);
     }
 
     ///// <inheritdoc/>

+ 1 - 1
Terminal.Gui/View/View.Mouse.cs

@@ -351,7 +351,7 @@ public partial class View // Mouse APIs
         // BUGBUG: This should be named NewMouseClickEvent. Fix this in https://github.com/gui-cs/Terminal.Gui/issues/3029
 
         // Pre-conditions
-        if (!Enabled || !CanFocus)
+        if (!Enabled)
         {
             // QUESTION: Is this right? Should a disabled view eat mouse clicks?
             return args.Handled = false;

+ 4 - 27
Terminal.Gui/Views/CheckBox.cs

@@ -23,13 +23,13 @@ public class CheckBox : View
         CanFocus = true;
 
         // Select (Space key and single-click) - Advance state and raise Select event
-        AddCommand (Command.Select, AdvanceCheckState);
+        AddCommand (Command.Select, () => AdvanceCheckState () is false);
 
         // Accept (Enter key and double-click) - Raise Accept event - DO NOT advance state
         AddCommand (Command.Accept, () => RaiseAcceptEvent ());
 
         // Hotkey - Advance state and raise Select event - DO NOT raise Accept
-        AddCommand (Command.HotKey, AdvanceCheckState);
+        AddCommand (Command.HotKey, () => AdvanceCheckState () is false);
 
         TitleChanged += Checkbox_TitleChanged;
 
@@ -39,34 +39,11 @@ public class CheckBox : View
 
     private void CheckBox_MouseClick (object? sender, MouseEventEventArgs e)
     {
-#if CHECKBOX_SUPPORTS_DOUBLE_CLICK_ACCEPT
-        CheckState savedCheckState = CheckedState;
-#endif
-
         if (e.MouseEvent.Flags.HasFlag (MouseFlags.Button1Clicked))
         {
-            AdvanceCheckState ();
-            ;
-            //           e.Handled = AdvanceCheckState () == true;
-        }
-
-#if CHECKBOX_SUPPORTS_DOUBLE_CLICK_ACCEPT
-        if (e.MouseEvent.Flags.HasFlag (MouseFlags.Button1DoubleClicked))
-        {
-            if (RaiseAcceptEvent () == true)
-            {
-                e.Handled = false;
-                _checkedState = savedCheckState;
-            }
-
-            // TODO: This needs to be made consistent with how Button.IsDefault works
-            if (SuperView is { })
-            {
-                // TODO: This should pass context
-                SuperView.InvokeCommand (Command.Accept);
-            }
+            // AdvanceCheckState returns false if the state was changed
+            e.Handled = AdvanceCheckState () is false;
         }
-#endif
     }
 
     private void Checkbox_TitleChanged (object? sender, EventArgs<string> e)

+ 11 - 13
Terminal.Gui/Views/Shortcut.cs

@@ -518,8 +518,8 @@ public class Shortcut : View, IOrientation, IDesignable
 
             void CommandViewOnAccept (object sender, HandledEventArgs e)
             {
-                KeyBinding binding = new ([Command.Select], KeyBindingScope.Focused, _commandView, null);
-                e.Handled = DispatchAcceptCommand (new CommandContext (Command.Select, null, binding)) == true;
+                // Always eat CommandView.Accept
+                e.Handled = true;
             }
 
             _commandView.Select += CommandViewOnSelect;
@@ -537,10 +537,11 @@ public class Shortcut : View, IOrientation, IDesignable
 
             void CommandViewOnSelect (object sender, HandledEventArgs e)
             {
-                //e.Handled = true;
-                RaiseAcceptEvent ();
+                // Always eat CommandView.Select
+                e.Handled = true;
 
-                // SetFocus ();
+                // AND raise our Accept event
+                RaiseAcceptEvent ();
             }
 
             SetCommandViewDefaultLayout ();
@@ -781,15 +782,12 @@ public class Shortcut : View, IOrientation, IDesignable
     {
         var cancel = false;
 
-        // We don't care if CommandView handles the command or not
-        CommandView.InvokeCommand (Command.Select, ctx.Key, ctx.KeyBinding);
-
-        cancel = RaiseAcceptEvent () == true;
+        bool? handled = CommandView.InvokeCommand (Command.Select, ctx.Key, ctx.KeyBinding);
 
-        //if (!cancel && ctx.KeyBinding?.BoundView != CommandView)
-        //{
-        //   // CommandView.InvokeCommand (Command.Select, ctx.Key, ctx.KeyBinding);
-        //}
+        if (handled is null or false)
+        {
+            cancel = RaiseAcceptEvent () == true;
+        }
 
         if (Action is { })
         {

+ 21 - 0
UnitTests/Drawing/ThicknessTests.cs

@@ -735,6 +735,27 @@ public class ThicknessTests (ITestOutputHelper output)
         Assert.Equal (expected, result);
     }
 
+
+    [Theory]
+    [InlineData (0, 0, 0, 0, 0, 0, false)]
+    [InlineData (0, 0, 0, 1, 0, 0, false)]
+    [InlineData (0, 0, 1, 0, 0, 0, false)]
+    [InlineData (0, 0, 1, 1, 0, 0, true)]
+
+    [InlineData (1, 1, 0, 0, 0, 0, false)]
+    [InlineData (1, 1, 0, 1, 0, 0, false)]
+    [InlineData (1, 1, 1, 0, 0, 0, false)]
+    [InlineData (1, 1, 1, 0, 0, 1, false)]
+    [InlineData (1, 1, 1, 1, 1, 0, false)]
+    [InlineData (1, 1, 1, 1, 1, 1, true)]
+    public void TestContains_Left_Only (int x, int y, int width, int height, int pointX, int pointY, bool expected)
+    {
+        var outside = new Rectangle (x, y, width, height);
+        var thickness = new Thickness (1, 0, 0, 0);
+        bool result = thickness.Contains (outside, new (pointX, pointY));
+        Assert.Equal (expected, result);
+    }
+
     [Fact]
     public void ToStringTest ()
     {

+ 26 - 0
UnitTests/View/Adornment/AdornmentTests.cs

@@ -381,4 +381,30 @@ public class AdornmentTests (ITestOutputHelper output)
         view.Padding.Thickness = new (2, 2, 2, 2);
         Assert.Throws<InvalidOperationException> (() => view.Padding.Viewport = view.Padding.Viewport with { Location = new (1, 1) });
     }
+
+    // Contains tests
+
+    [Theory]
+    [InlineData (0, 0, 0, 0, 0, 0, false)]
+    [InlineData (0, 0, 0, 1, 0, 0, false)]
+    [InlineData (0, 0, 1, 0, 0, 0, false)]
+    [InlineData (0, 0, 1, 1, 0, 0, true)]
+
+    [InlineData (1, 1, 0, 0, 0, 0, false)]
+    [InlineData (1, 1, 0, 1, 0, 0, false)]
+    [InlineData (1, 1, 1, 0, 0, 0, false)]
+    [InlineData (1, 1, 1, 0, 0, 1, false)]
+    [InlineData (1, 1, 1, 1, 1, 0, false)]
+    [InlineData (1, 1, 1, 1, 1, 1, true)]
+    public void Contains_Left_Only (int x, int y, int width, int height, int pointX, int pointY, bool expected)
+    {
+        Adornment adornment = new () { Id = "adornment" };
+        adornment.Parent = new View () { Id = "parent" };
+        adornment.Parent.Frame = new Rectangle (x, y, width, height);
+        adornment.Thickness = new (1, 0, 0, 0);
+
+
+        bool result = adornment.Contains (new (pointX, pointY));
+        Assert.Equal (expected, result);
+    }
 }

+ 8 - 3
UnitTests/Views/CheckBoxTests.cs

@@ -148,8 +148,12 @@ public class CheckBoxTests (ITestOutputHelper output)
         checkBox.HasFocus = true;
         Assert.True (checkBox.HasFocus);
         Assert.Equal (CheckState.UnChecked, checkBox.CheckedState);
+
+        // Select with keyboard
         Assert.True (checkBox.NewKeyDownEvent (Key.Space));
         Assert.Equal (CheckState.Checked, checkBox.CheckedState);
+
+        // Select with mouse
         Assert.True (checkBox.NewMouseEvent (new () { Position = new (0, 0), Flags = MouseFlags.Button1Clicked }));
         Assert.Equal (CheckState.UnChecked, checkBox.CheckedState);
 
@@ -576,7 +580,7 @@ public class CheckBoxTests (ITestOutputHelper output)
     [InlineData (CheckState.Checked)]
     [InlineData (CheckState.UnChecked)]
     [InlineData (CheckState.None)]
-    public void Select_Handle_Event_Prevents_Change (CheckState initialState)
+    public void Select_Handle_Event_Does_Not_Prevent_Change (CheckState initialState)
     {
         var ckb = new CheckBox { AllowCheckStateNone = true };
         var checkedInvoked = false;
@@ -589,7 +593,7 @@ public class CheckBoxTests (ITestOutputHelper output)
         bool? ret = ckb.InvokeCommand (Command.Select);
         Assert.False (ret);
         Assert.True (checkedInvoked);
-        Assert.Equal (initialState, ckb.CheckedState);
+        Assert.NotEqual (initialState, ckb.CheckedState);
 
         return;
 
@@ -614,8 +618,9 @@ public class CheckBoxTests (ITestOutputHelper output)
         ckb.CheckedStateChanging += OnCheckedStateChanging;
 
         Assert.Equal (initialState, ckb.CheckedState);
+        // AdvanceCheckState returns false if the state was changed, true if it was cancelled, null if it was not changed
         bool? ret = ckb.AdvanceCheckState ();
-        Assert.False (ret);
+        Assert.True (ret);
         Assert.True (checkedInvoked);
         Assert.Equal (initialState, ckb.CheckedState);
 

+ 158 - 26
UnitTests/Views/ShortcutTests.cs

@@ -15,9 +15,74 @@ public class ShortcutTests
         Assert.IsType<DimAuto> (shortcut.Width);
         Assert.IsType<DimAuto> (shortcut.Height);
 
-        // TOOD: more
     }
 
+    [Fact]
+    public void Size_Defaults ()
+    {
+        var shortcut = new Shortcut ();
+
+        shortcut.SetRelativeLayout (new (100, 100));
+        Assert.Equal (2, shortcut.Frame.Width);
+        Assert.Equal (1, shortcut.Frame.Height);
+        Assert.Equal (2, shortcut.Viewport.Width);
+        Assert.Equal (1, shortcut.Viewport.Height);
+
+        Assert.Equal (0, shortcut.CommandView.Viewport.Width);
+        Assert.Equal (1, shortcut.CommandView.Viewport.Height);
+
+        Assert.Equal (0, shortcut.HelpView.Viewport.Width);
+        Assert.Equal (1, shortcut.HelpView.Viewport.Height);
+
+        Assert.Equal (0, shortcut.KeyView.Viewport.Width);
+        Assert.Equal (1, shortcut.KeyView.Viewport.Height);
+
+        //  0123456789
+        // "   0  A "
+        shortcut = new Shortcut ()
+        {
+            Key = Key.A,
+            HelpText = "0"
+        };
+        shortcut.SetRelativeLayout (new (100, 100));
+        Assert.Equal (8, shortcut.Frame.Width);
+        Assert.Equal (1, shortcut.Frame.Height);
+        Assert.Equal (8, shortcut.Viewport.Width);
+        Assert.Equal (1, shortcut.Viewport.Height);
+
+        Assert.Equal (0, shortcut.CommandView.Viewport.Width);
+        Assert.Equal (1, shortcut.CommandView.Viewport.Height);
+
+        Assert.Equal (1, shortcut.HelpView.Viewport.Width);
+        Assert.Equal (1, shortcut.HelpView.Viewport.Height);
+
+        Assert.Equal (1, shortcut.KeyView.Viewport.Width);
+        Assert.Equal (1, shortcut.KeyView.Viewport.Height);
+
+        //  0123456789
+        // " C  0  A "
+        shortcut = new Shortcut ()
+        {
+            Title = "C",
+            Key = Key.A,
+            HelpText = "0"
+        };
+        shortcut.SetRelativeLayout (new (100, 100));
+        Assert.Equal (9, shortcut.Frame.Width);
+        Assert.Equal (1, shortcut.Frame.Height);
+        Assert.Equal (9, shortcut.Viewport.Width);
+        Assert.Equal (1, shortcut.Viewport.Height);
+
+        Assert.Equal (1, shortcut.CommandView.Viewport.Width);
+        Assert.Equal (1, shortcut.CommandView.Viewport.Height);
+
+        Assert.Equal (1, shortcut.HelpView.Viewport.Width);
+        Assert.Equal (1, shortcut.HelpView.Viewport.Height);
+
+        Assert.Equal (1, shortcut.KeyView.Viewport.Width);
+        Assert.Equal (1, shortcut.KeyView.Viewport.Height);
+
+    }
     [Theory]
     [InlineData ("", "", KeyCode.Null, 2)]
     [InlineData ("C", "", KeyCode.Null, 3)]
@@ -365,7 +430,7 @@ public class ShortcutTests
         Application.OnMouseEvent (
                                   new ()
                                   {
-                                      Position = new (x, 0),
+                                      ScreenPosition = new (x, 0),
                                       Flags = MouseFlags.Button1Clicked
                                   });
 
@@ -374,6 +439,75 @@ public class ShortcutTests
         current.Dispose ();
     }
 
+
+    [Theory]
+
+    //  0123456789
+    // " C  0  A "
+    [InlineData (-1, 0, 0, 0, 0)]
+    [InlineData (0, 1, 0, 1, 1)]
+    //[InlineData (1, 1, 1)]
+    //[InlineData (2, 1, 0)]
+    //[InlineData (3, 1, 0)]
+    //[InlineData (4, 1, 0)]
+    //[InlineData (5, 1, 0)]
+    //[InlineData (6, 1, 0)]
+    //[InlineData (7, 1, 0)]
+    //[InlineData (8, 1, 0)]
+    //[InlineData (9, 0, 0)]
+    public void MouseClick_Default_CommandView_Raises_Accept_Select_Correctly (int mouseX, int expectedCommandViewAccept, int expectedCommandViewSelect, int expectedShortcutAccept, int expectedShortcutSelect)
+    {
+        Application.Top = new Toplevel ();
+
+        var shortcut = new Shortcut
+        {
+            Title = "C",
+            Key = Key.A,
+            HelpText = "0"
+        };
+
+        var commandViewAcceptCount = 0;
+        shortcut.CommandView.Accept += (s, e) =>
+        {
+            commandViewAcceptCount++;
+        };
+        var commandViewSelectCount = 0;
+        shortcut.CommandView.Select += (s, e) =>
+        {
+            commandViewSelectCount++;
+        };
+
+        var shortcutAcceptCount = 0;
+        shortcut.Accept += (s, e) =>
+        {
+            shortcutAcceptCount++;
+        };
+        var shortcutSelectCount = 0;
+        shortcut.Select += (s, e) =>
+        {
+            shortcutSelectCount++;
+        };
+
+
+        Application.Top.Add (shortcut);
+        Application.Top.SetRelativeLayout (new (100, 100));
+
+        Application.OnMouseEvent (
+                                  new ()
+                                  {
+                                      ScreenPosition = new (mouseX, 0),
+                                      Flags = MouseFlags.Button1Clicked
+                                  });
+
+        Assert.Equal (expectedShortcutAccept, shortcutAcceptCount);
+        Assert.Equal (expectedCommandViewAccept, commandViewAcceptCount);
+        Assert.Equal (expectedShortcutSelect, shortcutSelectCount);
+        Assert.Equal (expectedCommandViewSelect, commandViewSelectCount);
+
+        Application.Top.Dispose ();
+        Application.ResetState (true);
+    }
+
     [Theory]
 
     //  0123456789
@@ -389,10 +523,9 @@ public class ShortcutTests
     [InlineData (7, 1, 0)]
     [InlineData (8, 1, 0)]
     [InlineData (9, 0, 0)]
-    [AutoInitShutdown]
     public void MouseClick_Button_CommandView_Fires_Shortcut_Accept (int mouseX, int expectedAccept, int expectedButtonAccept)
     {
-        var current = new Toplevel ();
+        Application.Top = new Toplevel ();
 
         var shortcut = new Shortcut
         {
@@ -408,14 +541,13 @@ public class ShortcutTests
             CanFocus = false
         };
         var buttonAccepted = 0;
-        shortcut.CommandView.Accept += (s, e) => {
-                                           buttonAccepted++;
-                                           // Must indicate handled
-                                           e.Handled = true;
-                                       };
-        current.Add (shortcut);
-
-        Application.Begin (current);
+        shortcut.CommandView.Accept += (s, e) =>
+        {
+            buttonAccepted++;
+            // Must indicate handled
+            e.Handled = true;
+        };
+        Application.Top.Add (shortcut);
 
         var accepted = 0;
         shortcut.Accept += (s, e) => accepted++;
@@ -425,14 +557,15 @@ public class ShortcutTests
         Application.OnMouseEvent (
                                   new ()
                                   {
-                                      Position = new (mouseX, 0),
+                                      ScreenPosition = new (mouseX, 0),
                                       Flags = MouseFlags.Button1Clicked
                                   });
 
         Assert.Equal (expectedButtonAccept, buttonAccepted);
         Assert.Equal (expectedAccept, accepted);
 
-        current.Dispose ();
+        Application.Top.Dispose ();
+        Application.ResetState (true);
     }
 
     [Theory]
@@ -482,10 +615,9 @@ public class ShortcutTests
     [InlineData (KeyCode.Enter, 1)]
     [InlineData (KeyCode.Space, 0)]
     [InlineData (KeyCode.F1, 0)]
-    [AutoInitShutdown]
     public void KeyDown_App_Scope_Invokes_Accept (KeyCode key, int expectedAccept)
     {
-        var current = new Toplevel ();
+        Application.Top = new Toplevel ();
 
         var shortcut = new Shortcut
         {
@@ -494,9 +626,8 @@ public class ShortcutTests
             Text = "0",
             Title = "_C"
         };
-        current.Add (shortcut);
-
-        Application.Begin (current);
+        Application.Top.Add (shortcut);
+        Application.Top.SetFocus ();
 
         var accepted = 0;
         shortcut.Accept += (s, e) => accepted++;
@@ -505,7 +636,8 @@ public class ShortcutTests
 
         Assert.Equal (expectedAccept, accepted);
 
-        current.Dispose ();
+        Application.Top.Dispose ();
+        Application.ResetState (true);
     }
 
     [Theory]
@@ -564,7 +696,7 @@ public class ShortcutTests
     [AutoInitShutdown]
     public void KeyDown_App_Scope_Invokes_Action (bool canFocus, KeyCode key, int expectedAction)
     {
-        var current = new Toplevel ();
+        Application.Top = new Toplevel ();
 
         var shortcut = new Shortcut
         {
@@ -574,10 +706,9 @@ public class ShortcutTests
             Title = "_C",
             CanFocus = canFocus
         };
-        current.Add (shortcut);
 
-        Application.Begin (current);
-        Assert.Equal (canFocus, shortcut.HasFocus);
+        Application.Top.Add (shortcut);
+        Application.Top.SetFocus ();
 
         var action = 0;
         shortcut.Action += () => action++;
@@ -585,9 +716,10 @@ public class ShortcutTests
         Application.OnKeyDown (key);
 
         Assert.Equal (expectedAction, action);
-        current.Dispose ();
-    }
 
+        Application.Top.Dispose ();
+        Application.ResetState (true);
+    }
 
     [Fact]
     public void ColorScheme_SetsAndGetsCorrectly ()