forked from qt-creator/qt-creator
Terminal: Improve keyboard shortcuts and mouse copy/paste
Change-Id: I7e032a48cc55143dd8fb038d74eb71c4ad8badac Reviewed-by: Marcus Tillmanns <marcus.tillmanns@qt.io>
This commit is contained in:
@@ -60,6 +60,7 @@ TerminalWidget::TerminalWidget(QWidget *parent, const OpenTerminalParameters &op
|
|||||||
setupVTerm();
|
setupVTerm();
|
||||||
setupFont();
|
setupFont();
|
||||||
setupColors();
|
setupColors();
|
||||||
|
setupActions();
|
||||||
|
|
||||||
setAttribute(Qt::WA_InputMethodEnabled);
|
setAttribute(Qt::WA_InputMethodEnabled);
|
||||||
setAttribute(Qt::WA_MouseTracking);
|
setAttribute(Qt::WA_MouseTracking);
|
||||||
@@ -223,6 +224,23 @@ void TerminalWidget::setupColors()
|
|||||||
clearContents();
|
clearContents();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TerminalWidget::setupActions()
|
||||||
|
{
|
||||||
|
m_copyAction.setShortcuts(
|
||||||
|
{QKeySequence(HostOsInfo::isMacHost() ? QLatin1String("Ctrl+C")
|
||||||
|
: QLatin1String("Ctrl+Shift+C")),
|
||||||
|
QKeySequence(Qt::Key_Return)});
|
||||||
|
m_pasteAction.setShortcut(QKeySequence(
|
||||||
|
HostOsInfo::isMacHost() ? QLatin1String("Ctrl+V") : QLatin1String("Ctrl+Shift+V")));
|
||||||
|
|
||||||
|
m_clearSelectionAction.setShortcut(QKeySequence("Esc"));
|
||||||
|
|
||||||
|
m_zoomInAction.setShortcuts({QKeySequence("Ctrl++"), QKeySequence("Ctrl+Shift++")});
|
||||||
|
m_zoomOutAction.setShortcut(QKeySequence("Ctrl+-"));
|
||||||
|
|
||||||
|
addActions({&m_copyAction, &m_pasteAction, &m_clearSelectionAction, &m_zoomInAction, &m_zoomOutAction});
|
||||||
|
}
|
||||||
|
|
||||||
void TerminalWidget::writeToPty(const QByteArray &data)
|
void TerminalWidget::writeToPty(const QByteArray &data)
|
||||||
{
|
{
|
||||||
if (m_process)
|
if (m_process)
|
||||||
@@ -392,8 +410,9 @@ void TerminalWidget::pasteFromClipboard()
|
|||||||
|
|
||||||
void TerminalWidget::clearSelection()
|
void TerminalWidget::clearSelection()
|
||||||
{
|
{
|
||||||
m_selection.reset();
|
setSelection(std::nullopt);
|
||||||
update();
|
viewport()->update();
|
||||||
|
vterm_keyboard_key(m_vterm.get(), VTERM_KEY_ESCAPE, VTERM_MOD_NONE);
|
||||||
}
|
}
|
||||||
void TerminalWidget::zoomIn()
|
void TerminalWidget::zoomIn()
|
||||||
{
|
{
|
||||||
@@ -438,6 +457,12 @@ void TerminalWidget::flushVTerm(bool force)
|
|||||||
m_flushDelayTimer.start();
|
m_flushDelayTimer.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TerminalWidget::setSelection(const std::optional<Selection> &selection)
|
||||||
|
{
|
||||||
|
m_copyAction.setEnabled(selection.has_value());
|
||||||
|
m_selection = selection;
|
||||||
|
}
|
||||||
|
|
||||||
const VTermScreenCell *TerminalWidget::fetchCell(int x, int y) const
|
const VTermScreenCell *TerminalWidget::fetchCell(int x, int y) const
|
||||||
{
|
{
|
||||||
QTC_ASSERT(y >= 0, return nullptr);
|
QTC_ASSERT(y >= 0, return nullptr);
|
||||||
@@ -647,33 +672,32 @@ void TerminalWidget::paintEvent(QPaintEvent *event)
|
|||||||
|
|
||||||
void TerminalWidget::keyPressEvent(QKeyEvent *event)
|
void TerminalWidget::keyPressEvent(QKeyEvent *event)
|
||||||
{
|
{
|
||||||
|
bool actionTriggered = false;
|
||||||
|
for (const auto &action : actions()) {
|
||||||
|
if (!action->isEnabled())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for (const auto &shortcut : action->shortcuts()) {
|
||||||
|
const auto result = shortcut.matches(QKeySequence(event->keyCombination()));
|
||||||
|
if (result == QKeySequence::ExactMatch) {
|
||||||
|
action->trigger();
|
||||||
|
actionTriggered = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (actionTriggered)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (actionTriggered) {
|
||||||
|
setSelection(std::nullopt);
|
||||||
|
viewport()->update();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
event->accept();
|
event->accept();
|
||||||
|
|
||||||
if (event->modifiers() == Qt::NoModifier && event->key() == Qt::Key_Escape && m_selection) {
|
|
||||||
clearSelectionAction().trigger();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (event->modifiers() == Qt::ControlModifier && event->key() == Qt::Key_Plus) {
|
|
||||||
zoomInAction().trigger();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (event->modifiers() == Qt::ControlModifier && event->key() == Qt::Key_Minus) {
|
|
||||||
zoomOutAction().trigger();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (event->modifiers() == Qt::ControlModifier && event->key() == Qt::Key_C) {
|
|
||||||
copyAction().trigger();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (event->modifiers() == Qt::ControlModifier && event->key() == Qt::Key_V) {
|
|
||||||
pasteAction().trigger();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool keypad = event->modifiers() & Qt::KeypadModifier;
|
bool keypad = event->modifiers() & Qt::KeypadModifier;
|
||||||
VTermModifier mod = Internal::qtModifierToVTerm(event->modifiers());
|
VTermModifier mod = Internal::qtModifierToVTerm(event->modifiers());
|
||||||
VTermKey key = Internal::qtKeyToVTerm(Qt::Key(event->key()), keypad);
|
VTermKey key = Internal::qtKeyToVTerm(Qt::Key(event->key()), keypad);
|
||||||
@@ -702,6 +726,8 @@ void TerminalWidget::keyPressEvent(QKeyEvent *event)
|
|||||||
vterm_keyboard_unichar(m_vterm.get(),
|
vterm_keyboard_unichar(m_vterm.get(),
|
||||||
event->text().toUcs4()[0],
|
event->text().toUcs4()[0],
|
||||||
static_cast<VTermModifier>(mod & ~VTERM_MOD_CTRL));
|
static_cast<VTermModifier>(mod & ~VTERM_MOD_CTRL));
|
||||||
|
|
||||||
|
setSelection(std::nullopt);
|
||||||
} else if (mod != VTERM_MOD_NONE && event->key() == Qt::Key_C) {
|
} else if (mod != VTERM_MOD_NONE && event->key() == Qt::Key_C) {
|
||||||
vterm_keyboard_unichar(m_vterm.get(), 'c', mod);
|
vterm_keyboard_unichar(m_vterm.get(), 'c', mod);
|
||||||
}
|
}
|
||||||
@@ -745,7 +771,7 @@ void TerminalWidget::resizeEvent(QResizeEvent *event)
|
|||||||
|
|
||||||
applySizeChange();
|
applySizeChange();
|
||||||
|
|
||||||
m_selection.reset();
|
setSelection(std::nullopt);
|
||||||
m_ignoreScroll = false;
|
m_ignoreScroll = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -826,10 +852,18 @@ void TerminalWidget::mousePressEvent(QMouseEvent *event)
|
|||||||
} else {
|
} else {
|
||||||
m_selectLineMode = false;
|
m_selectLineMode = false;
|
||||||
QPoint pos = viewportToGlobal(event->pos());
|
QPoint pos = viewportToGlobal(event->pos());
|
||||||
m_selection = Selection{pos, pos};
|
setSelection(Selection{pos, pos});
|
||||||
}
|
}
|
||||||
|
|
||||||
viewport()->update();
|
viewport()->update();
|
||||||
|
} else if (event->button() == Qt::RightButton) {
|
||||||
|
if (m_selection) {
|
||||||
|
m_copyAction.trigger();
|
||||||
|
setSelection(std::nullopt);
|
||||||
|
viewport()->update();
|
||||||
|
} else {
|
||||||
|
m_pasteAction.trigger();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void TerminalWidget::mouseMoveEvent(QMouseEvent *event)
|
void TerminalWidget::mouseMoveEvent(QMouseEvent *event)
|
||||||
@@ -863,7 +897,7 @@ void TerminalWidget::mouseReleaseEvent(QMouseEvent *event)
|
|||||||
{
|
{
|
||||||
if (m_selection && event->button() != Qt::LeftButton) {
|
if (m_selection && event->button() != Qt::LeftButton) {
|
||||||
if ((m_selectionStartPos - event->pos()).manhattanLength() < 2) {
|
if ((m_selectionStartPos - event->pos()).manhattanLength() < 2) {
|
||||||
m_selection.reset();
|
setSelection(std::nullopt);
|
||||||
viewport()->update();
|
viewport()->update();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -904,7 +938,7 @@ void TerminalWidget::mouseDoubleClickEvent(QMouseEvent *event)
|
|||||||
(rightEnd / m_vtermSize.width()) * m_cellSize.height()
|
(rightEnd / m_vtermSize.width()) * m_cellSize.height()
|
||||||
+ m_cellSize.height());
|
+ m_cellSize.height());
|
||||||
|
|
||||||
m_selection = Selection{selectionStart, selectionEnd};
|
setSelection(Selection{selectionStart, selectionEnd});
|
||||||
|
|
||||||
m_lastDoubleClick = QDateTime::currentDateTime();
|
m_lastDoubleClick = QDateTime::currentDateTime();
|
||||||
|
|
||||||
@@ -992,7 +1026,7 @@ int TerminalWidget::setTerminalProperties(VTermProp prop, VTermValue *val)
|
|||||||
break;
|
break;
|
||||||
case VTERM_PROP_ALTSCREEN:
|
case VTERM_PROP_ALTSCREEN:
|
||||||
m_altscreen = val->boolean;
|
m_altscreen = val->boolean;
|
||||||
m_selection.reset();
|
setSelection(std::nullopt);
|
||||||
break;
|
break;
|
||||||
case VTERM_PROP_MOUSE:
|
case VTERM_PROP_MOUSE:
|
||||||
qCDebug(terminalLog) << "Ignoring VTERM_PROP_MOUSE" << val->number;
|
qCDebug(terminalLog) << "Ignoring VTERM_PROP_MOUSE" << val->number;
|
||||||
|
@@ -81,6 +81,7 @@ protected:
|
|||||||
void setupFont();
|
void setupFont();
|
||||||
void setupPty();
|
void setupPty();
|
||||||
void setupColors();
|
void setupColors();
|
||||||
|
void setupActions();
|
||||||
|
|
||||||
void writeToPty(const QByteArray &data);
|
void writeToPty(const QByteArray &data);
|
||||||
|
|
||||||
@@ -113,6 +114,8 @@ protected:
|
|||||||
|
|
||||||
void flushVTerm(bool force);
|
void flushVTerm(bool force);
|
||||||
|
|
||||||
|
void setSelection(const std::optional<Selection> &selection);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<Utils::QtcProcess> m_process;
|
std::unique_ptr<Utils::QtcProcess> m_process;
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user