Copier-coller a la souris comme dans un terminal Unix
Selectionner copie aussitot au relachement du bouton, et le clic droit colle directement. Plus de menu contextuel ni de raccourci a connaitre : c'est le comportement des terminaux Unix et de PuTTY. - selection relachee, et double-clic sur un mot, copient dans la foulee - clic droit et clic molette collent immediatement - un simple clic sans deplacement se contente d'annuler la selection, sans toucher au presse-papiers : sinon il ecraserait ce qu'on s'apprete a coller - le menu contextuel est supprime, le clic droit etant desormais un collage - "Tout selectionner" passe sur Ctrl+Maj+A, Ctrl+A restant "debut de ligne" pour le shell Les raccourcis clavier restent disponibles pour qui les prefere. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -5,9 +5,10 @@ Client SSH/SFTP personnel (type MobaXterm/Termius/Bitvise), 100% local, sans com
|
||||
## Fonctionnalites
|
||||
|
||||
- Sessions SSH multiples dans des onglets, avec terminal ANSI colore et trois themes
|
||||
- Copier-coller dans le terminal : selection a la souris, double-clic pour selectionner un mot,
|
||||
`Ctrl+Shift+C` / `Ctrl+Shift+V`, `Maj+Inser`, clic molette, et menu au clic droit.
|
||||
`Ctrl+C` reste l'interruption, comme dans tout terminal
|
||||
- Copier-coller **a la souris, comme dans un terminal Unix** : selectionner copie aussitot
|
||||
(double-clic pour un mot), et le clic droit colle directement — ni menu, ni raccourci.
|
||||
Le clic molette colle aussi. `Ctrl+Shift+C` / `Ctrl+Shift+V` / `Maj+Inser` restent
|
||||
disponibles au clavier, et `Ctrl+C` reste l'interruption comme dans tout terminal
|
||||
- Confort d'affichage : zoom `Ctrl+molette` ou `Ctrl+ +/-` (`Ctrl+0` remet a zero, la taille est
|
||||
memorisee), barre de defilement de l'historique, `Maj+PagePrec/Suiv`, `Ctrl+Fin` pour revenir
|
||||
en direct, et recherche dans l'historique avec `Ctrl+F`
|
||||
|
||||
@@ -11,9 +11,9 @@ from __future__ import annotations
|
||||
import pyte
|
||||
from PySide6.QtCore import QRect, Qt, Signal
|
||||
from PySide6.QtGui import (
|
||||
QColor, QFont, QFontMetrics, QPainter, QKeyEvent, QWheelEvent, QKeySequence,
|
||||
QColor, QFont, QFontMetrics, QPainter, QKeyEvent, QWheelEvent,
|
||||
)
|
||||
from PySide6.QtWidgets import QWidget, QMenu, QApplication, QScrollBar
|
||||
from PySide6.QtWidgets import QWidget, QApplication, QScrollBar
|
||||
|
||||
from app import theme as app_theme
|
||||
|
||||
@@ -478,6 +478,10 @@ class TerminalWidget(QWidget):
|
||||
if key == Qt.Key_V:
|
||||
self.paste_clipboard()
|
||||
return
|
||||
if key == Qt.Key_A:
|
||||
# Ctrl+A seul reste "debut de ligne" pour le shell
|
||||
self.select_all()
|
||||
return
|
||||
if key == Qt.Key_Insert and (modifiers & Qt.ShiftModifier):
|
||||
self.paste_clipboard()
|
||||
return
|
||||
@@ -551,8 +555,10 @@ class TerminalWidget(QWidget):
|
||||
self._sel_anchor = self._sel_focus = self._cell_at(event.position().toPoint())
|
||||
self._selecting = True
|
||||
self.update()
|
||||
elif event.button() == Qt.MiddleButton:
|
||||
self.paste_clipboard() # habitude Unix : clic molette = coller
|
||||
elif event.button() in (Qt.RightButton, Qt.MiddleButton):
|
||||
# Comportement des terminaux Unix (et de PuTTY) : le clic droit colle
|
||||
# directement, sans passer par un menu.
|
||||
self.paste_clipboard()
|
||||
super().mousePressEvent(event)
|
||||
|
||||
def mouseMoveEvent(self, event) -> None:
|
||||
@@ -564,9 +570,14 @@ class TerminalWidget(QWidget):
|
||||
def mouseReleaseEvent(self, event) -> None:
|
||||
if event.button() == Qt.LeftButton:
|
||||
self._selecting = False
|
||||
# un simple clic (sans deplacement) annule la selection
|
||||
if self._sel_anchor == self._sel_focus:
|
||||
# simple clic sans deplacement : on annule la selection sans toucher
|
||||
# au presse-papiers, qui contient peut-etre ce qu'on s'apprete a coller
|
||||
self.clear_selection()
|
||||
else:
|
||||
# Comportement des terminaux Unix : relacher la souris apres une
|
||||
# selection copie immediatement, sans raccourci ni menu.
|
||||
self.copy_selection()
|
||||
super().mouseReleaseEvent(event)
|
||||
|
||||
def mouseDoubleClickEvent(self, event) -> None:
|
||||
@@ -584,22 +595,9 @@ class TerminalWidget(QWidget):
|
||||
end += 1
|
||||
self._sel_anchor, self._sel_focus = (start, row), (end, row)
|
||||
self.update()
|
||||
self.copy_selection() # comme la selection a la souris : copie immediate
|
||||
|
||||
def contextMenuEvent(self, event) -> None:
|
||||
menu = QMenu(self)
|
||||
copy_action = menu.addAction("Copier")
|
||||
copy_action.setShortcut(QKeySequence("Ctrl+Shift+C"))
|
||||
copy_action.setEnabled(self.has_selection())
|
||||
paste_action = menu.addAction("Coller")
|
||||
paste_action.setShortcut(QKeySequence("Ctrl+Shift+V"))
|
||||
paste_action.setEnabled(bool(QApplication.clipboard().text()))
|
||||
menu.addSeparator()
|
||||
select_all_action = menu.addAction("Tout selectionner")
|
||||
|
||||
action = menu.exec(event.globalPos())
|
||||
if action == copy_action:
|
||||
self.copy_selection()
|
||||
elif action == paste_action:
|
||||
self.paste_clipboard()
|
||||
elif action == select_all_action:
|
||||
self.select_all()
|
||||
# Pas de menu contextuel : dans un terminal Unix le clic droit colle,
|
||||
# et il est traite dans mousePressEvent.
|
||||
event.ignore()
|
||||
|
||||
@@ -88,5 +88,39 @@ t.clear_selection()
|
||||
assert not t.has_selection()
|
||||
print(" OK")
|
||||
|
||||
print()
|
||||
print("=== 9. Souris : selection = copie, clic droit = collage (comme sous Unix) ===")
|
||||
from PySide6.QtGui import QMouseEvent, QContextMenuEvent
|
||||
from PySide6.QtCore import QPointF
|
||||
|
||||
|
||||
def clic(bouton, col, row, type_evt=QEvent.MouseButtonPress):
|
||||
pos = QPointF(col * t.char_w + 1, row * t.char_h + 1)
|
||||
return QMouseEvent(type_evt, pos, pos, bouton, bouton, Qt.NoModifier)
|
||||
|
||||
|
||||
QApplication.clipboard().setText("")
|
||||
t.mousePressEvent(clic(Qt.LeftButton, 0, 1))
|
||||
t._sel_focus = (14, 1)
|
||||
t.mouseReleaseEvent(clic(Qt.LeftButton, 14, 1, QEvent.MouseButtonRelease))
|
||||
print(" selection relachee -> presse-papiers :", repr(QApplication.clipboard().text()))
|
||||
assert QApplication.clipboard().text() == "serveur-test-01", "la selection doit copier sans raccourci"
|
||||
|
||||
envoye.clear()
|
||||
t.mousePressEvent(clic(Qt.RightButton, 5, 0))
|
||||
print(" clic droit -> envoye au shell :", envoye)
|
||||
assert envoye == [b"serveur-test-01"], "le clic droit doit coller directement"
|
||||
|
||||
QApplication.clipboard().setText("a-conserver")
|
||||
t.mousePressEvent(clic(Qt.LeftButton, 3, 0))
|
||||
t.mouseReleaseEvent(clic(Qt.LeftButton, 3, 0, QEvent.MouseButtonRelease))
|
||||
assert QApplication.clipboard().text() == "a-conserver", "un simple clic ne doit rien ecraser"
|
||||
print(" simple clic -> presse-papiers intact")
|
||||
|
||||
ev = QContextMenuEvent(QContextMenuEvent.Mouse, QPoint(10, 10), QPoint(10, 10))
|
||||
t.contextMenuEvent(ev)
|
||||
assert not ev.isAccepted(), "aucun menu contextuel ne doit s'ouvrir"
|
||||
print(" clic droit -> aucun menu contextuel")
|
||||
|
||||
print()
|
||||
print("COPIER/COLLER : TOUS LES TESTS OK")
|
||||
|
||||
Reference in New Issue
Block a user