From 6601950521f262a57a2ae1e35f1c2ea6f8560b3b Mon Sep 17 00:00:00 2001 From: YourRobotOverlord <47068588+YourRobotOverlord@users.noreply.github.com> Date: Fri, 8 May 2026 21:58:02 -0600 Subject: [PATCH] Fixes #5272. Ctrl+Click on link in Markdown no longer shows context menu Remove the base class Ctrl+LeftButtonReleased -> Command.Context mouse binding from Markdown.SetupBindingsAndCommands(). The base View registers this binding so Ctrl+Click can open a context menu, but the Markdown view already handles right-click directly in OnMouseEvent and uses Ctrl+Click for link following. Without this removal, Ctrl+Click would fire Command.Context -> ShowContextMenu() via the LeftButtonReleased event, showing the Select All/Copy popover at the upper-left corner (because no selection is active, GetContextMenuScreenPosition falls back to Point(0,0)). Add two regression tests: - MouseBindings_CtrlLeftButtonReleased_IsNotBoundTo_Context: verifies the binding is absent on a fresh Markdown instance - CtrlClick_On_Link_Opens_Link_And_Does_Not_Show_Context_Menu: end-to-end verification that Ctrl+Click fires LinkClicked without making the context menu visible Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../Views/Markdown/MarkdownView.Mouse.cs | 3 ++ .../Markdown/MarkdownViewSelectionTests.cs | 43 +++++++++++++++++++ 2 files changed, 46 insertions(+) diff --git a/Terminal.Gui/Views/Markdown/MarkdownView.Mouse.cs b/Terminal.Gui/Views/Markdown/MarkdownView.Mouse.cs index 62e68ba58f..694a5d3253 100644 --- a/Terminal.Gui/Views/Markdown/MarkdownView.Mouse.cs +++ b/Terminal.Gui/Views/Markdown/MarkdownView.Mouse.cs @@ -59,7 +59,10 @@ private void SetupBindingsAndCommands () // The base class binds LeftButtonReleased → Activate; remove that so Activate // fires only on LeftButtonClicked (not twice per click which would clear selection). + // Also remove the base class Ctrl+LeftButtonReleased → Context binding so that + // Ctrl+Click can follow links without triggering the context menu popover. MouseBindings.Remove (MouseFlags.LeftButtonReleased); + MouseBindings.Remove (MouseFlags.LeftButtonReleased | MouseFlags.Ctrl); MouseBindings.ReplaceCommands (MouseFlags.LeftButtonClicked, Command.Activate); // Right-click is handled directly in OnMouseEvent so that the view can be focused diff --git a/Tests/UnitTestsParallelizable/Views/Markdown/MarkdownViewSelectionTests.cs b/Tests/UnitTestsParallelizable/Views/Markdown/MarkdownViewSelectionTests.cs index 156bba53c3..5aa297745e 100644 --- a/Tests/UnitTestsParallelizable/Views/Markdown/MarkdownViewSelectionTests.cs +++ b/Tests/UnitTestsParallelizable/Views/Markdown/MarkdownViewSelectionTests.cs @@ -250,6 +250,49 @@ public void MouseBindings_LeftButtonPressedPositionReport_IsBoundTo_Activate () mv.Dispose (); } + // Copilot - Regression: #5272 — Ctrl+LeftButtonReleased must NOT be bound to Context + // The base View class adds this binding; Markdown must remove it so Ctrl+Click can follow + // links without triggering the context menu popover. + [Fact] + public void MouseBindings_CtrlLeftButtonReleased_IsNotBoundTo_Context () + { + Terminal.Gui.Views.Markdown mv = new (); + + bool found = mv.MouseBindings.TryGet (MouseFlags.LeftButtonReleased | MouseFlags.Ctrl, out _); + + Assert.False (found); + + mv.Dispose (); + } + + // Copilot - Regression: #5272 — Ctrl+Click on a link opens the link and does NOT show context menu + [Fact] + public void CtrlClick_On_Link_Opens_Link_And_Does_Not_Show_Context_Menu () + { + (IApplication app, Runnable window, Terminal.Gui.Views.Markdown mv) = CreateMv ("[Click](https://example.com)"); + + mv.SetFocus (); + + var linkClicked = false; + + mv.LinkClicked += (_, e) => + { + linkClicked = true; + e.Handled = true; + }; + + // Simulate Ctrl+Click: press, Ctrl+release, Ctrl+clicked + mv.NewMouseEvent (new Mouse { Position = new Point (0, 0), Flags = MouseFlags.LeftButtonPressed }); + mv.NewMouseEvent (new Mouse { Position = new Point (0, 0), Flags = MouseFlags.LeftButtonReleased | MouseFlags.Ctrl }); + mv.NewMouseEvent (new Mouse { Position = new Point (0, 0), Flags = MouseFlags.LeftButtonClicked }); + + Assert.True (linkClicked); + Assert.True (mv.ContextMenu is null || !mv.ContextMenu.Visible); + + window.Dispose (); + app.Dispose (); + } + // Copilot - verifies that a drag (press + position-report) activates the selection [Fact] public void Drag_Mouse_Creates_Selection ()