mirror of
https://github.com/andrey271192/ssh-manage.git
synced 2026-09-21 12:02:01 +00:00
fix: nuclear paste fix — bind all macOS modifier variants for Cmd+V/C
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -493,8 +493,7 @@ def agent_search(query):
|
|||||||
|
|
||||||
|
|
||||||
def setup_entry_clipboard(entry):
|
def setup_entry_clipboard(entry):
|
||||||
"""Fix clipboard on macOS (Tk 8.6 maps <<Paste>> to Mod1 not Command)
|
"""Fix clipboard on all platforms. Covers every known Tk modifier mapping."""
|
||||||
and add right-click context menu."""
|
|
||||||
|
|
||||||
def _paste(e=None):
|
def _paste(e=None):
|
||||||
try:
|
try:
|
||||||
@@ -526,23 +525,43 @@ def setup_entry_clipboard(entry):
|
|||||||
def _context_menu(event):
|
def _context_menu(event):
|
||||||
menu = tk.Menu(entry, tearoff=0, bg="#313244", fg="#cdd6f4",
|
menu = tk.Menu(entry, tearoff=0, bg="#313244", fg="#cdd6f4",
|
||||||
activebackground="#45475a")
|
activebackground="#45475a")
|
||||||
menu.add_command(label="Вырезать", command=_cut)
|
menu.add_command(label="Cut", command=_cut)
|
||||||
menu.add_command(label="Копировать", command=_copy)
|
menu.add_command(label="Copy", command=_copy)
|
||||||
menu.add_command(label="Вставить", command=_paste)
|
menu.add_command(label="Paste", command=_paste)
|
||||||
menu.add_separator()
|
menu.add_separator()
|
||||||
menu.add_command(label="Выделить всё", command=_select_all)
|
menu.add_command(label="Select All", command=_select_all)
|
||||||
menu.tk_popup(event.x_root, event.y_root)
|
menu.tk_popup(event.x_root, event.y_root)
|
||||||
|
|
||||||
|
# Bind virtual events (works on all platforms)
|
||||||
|
entry.bind("<<Paste>>", _paste)
|
||||||
|
entry.bind("<<Copy>>", _copy)
|
||||||
|
entry.bind("<<Cut>>", _cut)
|
||||||
|
entry.bind("<<SelectAll>>", _select_all)
|
||||||
|
|
||||||
if sys.platform == "darwin":
|
if sys.platform == "darwin":
|
||||||
# macOS Tk 8.6 bug: <<Paste>> bound to Mod1 (Option) not Command
|
# macOS: physical Command key may map to Command, Mod1, Mod2, or Meta
|
||||||
# Manually bind Command+key for clipboard operations
|
# depending on Tk version and frozen/unfrozen state.
|
||||||
entry.bind("<Command-v>", _paste)
|
# Bind ALL possible modifiers to guarantee it works.
|
||||||
entry.bind("<Command-c>", _copy)
|
for mod in ("Command", "Mod1", "Meta", "Mod2"):
|
||||||
entry.bind("<Command-x>", _cut)
|
entry.bind(f"<{mod}-v>", _paste)
|
||||||
entry.bind("<Command-a>", _select_all)
|
entry.bind(f"<{mod}-c>", _copy)
|
||||||
|
entry.bind(f"<{mod}-x>", _cut)
|
||||||
|
entry.bind(f"<{mod}-a>", _select_all)
|
||||||
|
# Also register Command-v as trigger for <<Paste>> virtual event
|
||||||
|
for seq in ("<Command-v>", "<Mod1-v>", "<Meta-v>", "<Mod2-v>"):
|
||||||
|
try:
|
||||||
|
entry.event_add("<<Paste>>", seq)
|
||||||
|
except tk.TclError:
|
||||||
|
pass
|
||||||
# Right-click
|
# Right-click
|
||||||
entry.bind("<Button-2>", _context_menu)
|
entry.bind("<Button-2>", _context_menu)
|
||||||
entry.bind("<Control-Button-1>", _context_menu)
|
entry.bind("<Control-Button-1>", _context_menu)
|
||||||
|
else:
|
||||||
|
# Windows/Linux: Ctrl+V
|
||||||
|
entry.bind("<Control-v>", _paste)
|
||||||
|
entry.bind("<Control-c>", _copy)
|
||||||
|
entry.bind("<Control-x>", _cut)
|
||||||
|
entry.bind("<Control-a>", _select_all)
|
||||||
|
|
||||||
entry.bind("<Button-3>", _context_menu)
|
entry.bind("<Button-3>", _context_menu)
|
||||||
|
|
||||||
@@ -763,9 +782,25 @@ class TerminalWidget(tk.Frame):
|
|||||||
self.text.bind("<Control-l>", lambda e: self._send("\x0c"))
|
self.text.bind("<Control-l>", lambda e: self._send("\x0c"))
|
||||||
self.text.bind("<Control-z>", lambda e: self._send("\x1a"))
|
self.text.bind("<Control-z>", lambda e: self._send("\x1a"))
|
||||||
# Paste/Copy in terminal: send clipboard to SSH / copy selection
|
# Paste/Copy in terminal: send clipboard to SSH / copy selection
|
||||||
|
# Bind virtual events first
|
||||||
|
self.text.bind("<<Paste>>", self._term_paste)
|
||||||
|
self.text.bind("<<Copy>>", self._term_copy)
|
||||||
if sys.platform == "darwin":
|
if sys.platform == "darwin":
|
||||||
self.text.bind("<Command-v>", self._term_paste)
|
# Nuclear: bind ALL possible macOS modifier mappings
|
||||||
self.text.bind("<Command-c>", self._term_copy)
|
for mod in ("Command", "Mod1", "Meta", "Mod2"):
|
||||||
|
self.text.bind(f"<{mod}-v>", self._term_paste)
|
||||||
|
self.text.bind(f"<{mod}-c>", self._term_copy)
|
||||||
|
# Also register as virtual event triggers
|
||||||
|
for seq in ("<Command-v>", "<Mod1-v>", "<Meta-v>", "<Mod2-v>"):
|
||||||
|
try:
|
||||||
|
self.text.event_add("<<Paste>>", seq)
|
||||||
|
except tk.TclError:
|
||||||
|
pass
|
||||||
|
for seq in ("<Command-c>", "<Mod1-c>", "<Meta-c>", "<Mod2-c>"):
|
||||||
|
try:
|
||||||
|
self.text.event_add("<<Copy>>", seq)
|
||||||
|
except tk.TclError:
|
||||||
|
pass
|
||||||
else:
|
else:
|
||||||
# Windows/Linux: Ctrl+V paste, Ctrl+Shift+C copy
|
# Windows/Linux: Ctrl+V paste, Ctrl+Shift+C copy
|
||||||
self.text.bind("<Control-v>", self._term_paste)
|
self.text.bind("<Control-v>", self._term_paste)
|
||||||
@@ -887,6 +922,8 @@ class TerminalWidget(tk.Frame):
|
|||||||
return
|
return
|
||||||
if event.state & 8: # Mod1 / Command on macOS — let bindings handle it
|
if event.state & 8: # Mod1 / Command on macOS — let bindings handle it
|
||||||
return
|
return
|
||||||
|
if sys.platform == "darwin" and (event.state & 0x10): # Mod2 — Command on some Tk builds
|
||||||
|
return
|
||||||
if event.char and ord(event.char) >= 32:
|
if event.char and ord(event.char) >= 32:
|
||||||
self._send(event.char)
|
self._send(event.char)
|
||||||
return "break"
|
return "break"
|
||||||
|
|||||||
Reference in New Issue
Block a user