v1.8.23: fix Ctrl+V/C/X/A/Z for non-Latin keyboard layouts, add Entry undo/redo

- Global keycode-based handler for Ctrl shortcuts (works with Russian, Chinese, any layout)
- Tkinter maps <<Paste>> to <Control-v> by keysym which fails on non-Latin layouts
- New handler intercepts <Control-Key> at 'all' level, checks keycodes and generates correct virtual events
- Added Undo/Redo support for Entry widgets (tk.Entry has no built-in undo)
- Tab switch focus management: terminal releases focus when switching away

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
chrome-storm-c442
2026-02-24 06:13:27 -05:00
parent a8f3bd04e1
commit 5cf856069b
5 changed files with 141 additions and 14 deletions

View File

@@ -251,6 +251,9 @@ class TerminalWidget(tk.Frame):
self._selecting = False
self._last_ctrl_c: float = 0.0
# ── Keyboard enable/disable (for modal dialogs) ──
self._keyboard_enabled = True
# ── Flash status state ──
self._flash_after_id = None
self._saved_status_text = ""
@@ -360,6 +363,14 @@ class TerminalWidget(tk.Frame):
def focus_terminal(self):
self._text.focus_set()
def disable_keyboard(self):
"""Disable keyboard processing (e.g. when a modal dialog is open)."""
self._keyboard_enabled = False
def enable_keyboard(self):
"""Re-enable keyboard processing."""
self._keyboard_enabled = True
def get_size(self) -> tuple[int, int]:
return self._cols, self._rows
@@ -581,6 +592,9 @@ class TerminalWidget(tk.Frame):
# ── Keyboard handling ──────────────────────────────────────────────────
def _on_key(self, event):
# Don't intercept keys when keyboard is disabled (modal dialog open)
if not self._keyboard_enabled:
return
# Ignore modifier-only keys
if event.keysym in ("Shift_L", "Shift_R", "Control_L", "Control_R",
"Alt_L", "Alt_R", "Meta_L", "Meta_R",
@@ -708,6 +722,8 @@ class TerminalWidget(tk.Frame):
def _on_ctrl_key(self, event):
"""Route Ctrl+key by physical keycode (layout-independent)."""
if not self._keyboard_enabled:
return
handler_name = self._CTRL_KEYCODE_MAP.get(event.keycode)
if handler_name:
# Check if Shift is also held