From 78bf62c80ea68e23cec6b9d95d0a3ec76b172612 Mon Sep 17 00:00:00 2001 From: Erik Date: Fri, 21 Aug 2026 08:00:43 +0200 Subject: [PATCH] fix(chat): the tell prefill leaves the caret after the prefix, not before it MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Clicking a name filled the entry with "@tell Name, " correctly but parked the caret at column 0, so the player had to click the chat bar to get behind their own prefix before typing — which defeats most of the point of the affordance. Self-inflicted in d32ef388. SetText already places the caret at the end, and I stacked an explicit "move to the end" on top of it. MoveCaret takes a DELTA, so int.MaxValue overflowed _caret + delta to negative and the clamp landed at column 0. The redundant call was not merely redundant; it was the bug. Removing it is the whole fix. The test now pins CaretPos as well as the text, and reintroducing the call reproduces the reported symptom exactly (expected 11, actual 0). Solution builds clean; full hermetic gate green. Co-Authored-By: Claude Opus 5 --- src/AcDream.App/UI/Layout/ChatWindowController.cs | 6 +++++- .../UI/Layout/ChatWindowControllerTests.cs | 6 ++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/AcDream.App/UI/Layout/ChatWindowController.cs b/src/AcDream.App/UI/Layout/ChatWindowController.cs index 657a6353..74c4682f 100644 --- a/src/AcDream.App/UI/Layout/ChatWindowController.cs +++ b/src/AcDream.App/UI/Layout/ChatWindowController.cs @@ -855,8 +855,12 @@ public sealed class ChatWindowController : IRetainedWindowStateController, IReta /// Aims the chat entry at and focuses it. internal void StartTell(string name) { + // SetText already places the caret at the end. An explicit "move to + // the end" on top of it is not merely redundant: MoveCaret takes a + // DELTA, so int.MaxValue overflows _caret + delta to negative and the + // clamp lands the caret at column 0 — the player then has to click the + // bar to get behind their own prefix. Input.SetText($"@tell {name}, "); - Input.MoveCaret(int.MaxValue); FindRootOf(Input)?.SetKeyboardFocus(Input); } diff --git a/tests/AcDream.App.Tests/UI/Layout/ChatWindowControllerTests.cs b/tests/AcDream.App.Tests/UI/Layout/ChatWindowControllerTests.cs index 05d43166..46f7d5c4 100644 --- a/tests/AcDream.App.Tests/UI/Layout/ChatWindowControllerTests.cs +++ b/tests/AcDream.App.Tests/UI/Layout/ChatWindowControllerTests.cs @@ -175,6 +175,12 @@ public class ChatWindowControllerTests ctrl!.StartTell("Dww"); Assert.Equal("@tell Dww, ", ctrl.Input.Text); + + // ...and the caret sits AFTER the prefix, ready to type into. It landed + // at column 0 in the first cut because an explicit MoveCaret(int.MaxValue) + // was stacked on top of SetText, which already ends there — MoveCaret + // takes a delta, so that overflowed negative and clamped to zero. + Assert.Equal("@tell Dww, ".Length, ctrl.Input.CaretPos); } // ── Talk-focus specials: "Tell to X" / "Squelch (ignore) X" ─────────────