diff --git a/src/ETTerms/App/AboutView.cs b/src/ETTerms/App/AboutView.cs index e1fd0a7..4a2ade1 100644 --- a/src/ETTerms/App/AboutView.cs +++ b/src/ETTerms/App/AboutView.cs @@ -177,6 +177,11 @@ public sealed class AboutView : UserControl private static readonly ChangelogEntry[] Changelog = [ + new("0.2.2", new DateOnly(2026, 6, 5), "Bugfix — terminal stability", + [ + "Fixed: the terminal no longer freezes after minimizing or switching tabs (notably in PowerShell / Kiro).", + "Added: Shift+Enter inserts a newline in the shell, so you can type multi-line commands.", + ]), new("0.2.1", new DateOnly(2026, 6, 4), "AI MCP one-click setup", [ "New Settings → AI MCP tab: register the Serial MCP server into Claude Code or Kiro with one click.", diff --git a/src/ETTerms/ETTerms.csproj b/src/ETTerms/ETTerms.csproj index ed4c1c7..a776bd3 100644 --- a/src/ETTerms/ETTerms.csproj +++ b/src/ETTerms/ETTerms.csproj @@ -10,7 +10,7 @@ ETTerms - 0.2.1 + 0.2.2 ETTerms ETTerms Project diff --git a/src/ETTerms/Terminal/ScreenBuffer.cs b/src/ETTerms/Terminal/ScreenBuffer.cs index ad1b4ba..5550564 100644 --- a/src/ETTerms/Terminal/ScreenBuffer.cs +++ b/src/ETTerms/Terminal/ScreenBuffer.cs @@ -270,20 +270,29 @@ public sealed class ScreenBuffer { cols = Math.Max(1, cols); rows = Math.Max(1, rows); if (cols == Cols && rows == Rows) return; - var ng = new Cell[rows][]; - for (int r = 0; r < rows; r++) - { - ng[r] = new Cell[cols]; - for (int c = 0; c < cols; c++) - ng[r][c] = (r < Rows && c < Cols) ? _screen[r][c] : BlankDefault(); - } - _screen = ng; + _screen = Reflow(_screen, rows, cols); + // alt screen 啟用中也要一併 reflow 保存的主畫面,否則 resize 後 ExitAlt 會還原失敗、 + // 畫面殘留 TUI 內容。不可把 _mainScreen 丟掉。 + if (_mainScreen != null) _mainScreen = Reflow(_mainScreen, rows, cols); Rows = rows; Cols = cols; _top = 0; _bottom = Rows - 1; CursorRow = Math.Clamp(CursorRow, 0, Rows - 1); CursorCol = Math.Clamp(CursorCol, 0, Cols - 1); _wrapPending = false; - _mainScreen = null; - if (AltActive) { /* alt 下 resize:重建 alt 畫面 */ } + } + + /// 把字格陣列重排到新尺寸,保留左上重疊區,其餘填預設空白。 + private Cell[][] Reflow(Cell[][] src, int rows, int cols) + { + int oldRows = src.Length; + var ng = new Cell[rows][]; + for (int r = 0; r < rows; r++) + { + ng[r] = new Cell[cols]; + int oldCols = r < oldRows ? src[r].Length : 0; + for (int c = 0; c < cols; c++) + ng[r][c] = (c < oldCols) ? src[r][c] : BlankDefault(); + } + return ng; } } diff --git a/src/ETTerms/Terminal/TerminalInput.cs b/src/ETTerms/Terminal/TerminalInput.cs index 081eeaf..038f21c 100644 --- a/src/ETTerms/Terminal/TerminalInput.cs +++ b/src/ETTerms/Terminal/TerminalInput.cs @@ -9,6 +9,11 @@ public static class TerminalInput { public static byte[]? Map(KeyEventArgs e, bool appCursor) { + // Enter:一般送 CR(\r) 視為「送出」;Shift+Enter 送 LF(\n),讓 PSReadLine / Kiro 等 + // 視為「插入換行」以便輸入多行指令,而不是直接送出。 + if (e.KeyCode == Keys.Enter) + return new[] { (byte)(e.Shift ? '\n' : '\r') }; + string? seq = e.KeyCode switch { Keys.Up => appCursor ? "\x1bOA" : "\x1b[A", @@ -21,7 +26,6 @@ public static class TerminalInput Keys.Delete => "\x1b[3~", Keys.PageUp => "\x1b[5~", Keys.PageDown => "\x1b[6~", - Keys.Enter => "\r", Keys.Tab => "\t", Keys.Escape => "\x1b", Keys.Back => "\x7f", diff --git a/src/ETTerms/Terminal/TerminalView.cs b/src/ETTerms/Terminal/TerminalView.cs index 87c7b64..4ff3759 100644 --- a/src/ETTerms/Terminal/TerminalView.cs +++ b/src/ETTerms/Terminal/TerminalView.cs @@ -59,6 +59,13 @@ public sealed class TerminalView : UserControl protected override void OnSizeChanged(EventArgs e) { base.OnSizeChanged(e); + + // 視窗最小化、或分頁/分割切換的瞬間,ClientSize 會變成 0/極小。此時若把退化尺寸 + // (會被算成 1×1)送給 PTY,ConPTY 下的全螢幕 TUI(如 Kiro CLI)會誤以為終端機只剩 + // 1×1 而停止重繪、輸入也像「卡住」。直接忽略這種尺寸,還原後再以正常尺寸重繪即可。 + if (ClientSize.Width < _cellW || ClientSize.Height < _cellH) return; + if (FindForm() is { WindowState: FormWindowState.Minimized }) return; + int cols = VisibleCols, rows = VisibleRows; if (cols == _lastCols && rows == _lastRows) return; _lastCols = cols; _lastRows = rows;