Chord: add Acme left+right = Paste
The paste chord (Acme 1-3) now works: with the left button held, a right tap pastes over the selection via edit_paste (standard KDE clipboard). This is conflict-free because the radial gesture is already suppressed while the left button is held — right alone opens the radial, right while left-held pastes. The paired right release is swallowed so it doesn't leak a context menu or other action. All 5 ctest suites green.
This commit is contained in:
parent
87f5587bd4
commit
3129662f31
26
docs/PLAN.md
26
docs/PLAN.md
|
|
@ -128,20 +128,18 @@ Therefore the palette is replaced, not extended, and the replacement is built on
|
||||||
- Not yet done: free-form stroke gestures (only button-press gesture so far);
|
- Not yet done: free-form stroke gestures (only button-press gesture so far);
|
||||||
user-file config loading (built-in default only); frecency.
|
user-file config loading (built-in default only); frecency.
|
||||||
|
|
||||||
### Mouse chording (Acme-style) — DONE (first increment)
|
### Mouse chording (Acme-style) — DONE
|
||||||
- Left+middle chord = **Cut**: with the left button held while selecting
|
- Left-button chords (button 1 held while selecting is the anchor):
|
||||||
(button 1 anchor), a tap of the middle button (button 2) cuts the current
|
**left + middle = Cut**, **left + right = Paste**. Both use `edit_cut` /
|
||||||
selection via `edit_cut`, which uses the **standard KDE clipboard**
|
`edit_paste` → the **standard KDE clipboard** (Klipper-backed), not the X11
|
||||||
(Klipper-backed), not the X11 primary selection.
|
primary selection.
|
||||||
- **Middle-click primary paste is suppressed** inside the editor. Kate pastes
|
- The right-button paste chord is free of conflict because the radial gesture is
|
||||||
the primary selection on the middle event; the filter consumes the middle
|
already suppressed while the left button is held: right alone = radial, right
|
||||||
button on **both press and release** (swallowing only the press let the paste
|
while left-held = paste.
|
||||||
leak through on release). So middle-click no longer pastes in the editor —
|
- **Middle-click primary paste is suppressed** inside the editor — the middle
|
||||||
paste is the normal `Ctrl+V` / palette paste from the KDE clipboard.
|
button is consumed on both press and release (the paste fires on release, so
|
||||||
- Right-button chords are intentionally **not** ported — the right button is the
|
swallowing only the press leaked it). Paste in the editor is the KDE-clipboard
|
||||||
radial gesture. (Revisit later.)
|
paste (`Ctrl+V`, palette, or the left+right chord).
|
||||||
- The radial gesture is suppressed while the left button is held, so an RMB tap
|
|
||||||
mid-selection (or during a left+middle chord) does not pop the radial.
|
|
||||||
|
|
||||||
### M5 — Command vocabulary + project model + switchers — NEXT
|
### M5 — Command vocabulary + project model + switchers — NEXT
|
||||||
- `:`-verb pack via `KTextEditor::Command`: `sort`, `align`, `json`, `b64`,
|
- `:`-verb pack via `KTextEditor::Command`: `sort`, `align`, `json`, `b64`,
|
||||||
|
|
|
||||||
|
|
@ -347,13 +347,14 @@ bool OllieView::eventFilter(QObject *obj, QEvent *event)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Acme-style left+middle chord = Cut, and suppression of X11 primary-
|
// Acme-style left-button chords, plus suppression of X11 primary-selection
|
||||||
// selection paste. Middle-button events inside the view are consumed on
|
// paste. Button 1 (left) held while selecting is the anchor:
|
||||||
// BOTH press and release (Kate pastes the primary selection on the middle
|
// left + middle tap = Cut, left + right tap = Paste.
|
||||||
// event; swallowing only the press lets the paste leak through on release).
|
// Both use edit_cut / edit_paste, which use the standard KDE clipboard
|
||||||
// When the left button is held, the middle tap cuts the current selection
|
// (Klipper-backed). The right-button chord is free because the radial
|
||||||
// via edit_cut, which uses the standard KDE clipboard (Klipper-backed).
|
// gesture is already suppressed while the left button is held. Middle-button
|
||||||
// Right-button chords are intentionally not ported (RMB is the radial).
|
// events in the view are consumed on BOTH press and release to kill the
|
||||||
|
// middle-click primary paste (it fires on release, not just press).
|
||||||
if (event->type() == QEvent::MouseButtonRelease) {
|
if (event->type() == QEvent::MouseButtonRelease) {
|
||||||
auto *mev = static_cast<QMouseEvent *>(event);
|
auto *mev = static_cast<QMouseEvent *>(event);
|
||||||
if (mev->button() == Qt::LeftButton) {
|
if (mev->button() == Qt::LeftButton) {
|
||||||
|
|
@ -363,12 +364,25 @@ bool OllieView::eventFilter(QObject *obj, QEvent *event)
|
||||||
m_swallowMiddleRelease = false;
|
m_swallowMiddleRelease = false;
|
||||||
return true; // suppress the primary paste that fires on release
|
return true; // suppress the primary paste that fires on release
|
||||||
}
|
}
|
||||||
|
if (mev->button() == Qt::RightButton && m_swallowRightRelease) {
|
||||||
|
m_swallowRightRelease = false;
|
||||||
|
return true; // paired release of a paste chord
|
||||||
|
}
|
||||||
} else if (event->type() == QEvent::MouseButtonPress) {
|
} else if (event->type() == QEvent::MouseButtonPress) {
|
||||||
auto *mev = static_cast<QMouseEvent *>(event);
|
auto *mev = static_cast<QMouseEvent *>(event);
|
||||||
KTextEditor::View *v = m_mainWindow->activeView();
|
KTextEditor::View *v = m_mainWindow->activeView();
|
||||||
auto *w = qobject_cast<QWidget *>(obj);
|
auto *w = qobject_cast<QWidget *>(obj);
|
||||||
const bool inView = v && w && v->isAncestorOf(w);
|
const bool inView = v && w && v->isAncestorOf(w);
|
||||||
|
|
||||||
|
// left + right tap = Paste over the selection.
|
||||||
|
if (mev->button() == Qt::RightButton && m_leftDownInView && inView) {
|
||||||
|
if (QAction *paste = findActionByName(QStringLiteral("edit_paste"))) {
|
||||||
|
paste->trigger();
|
||||||
|
}
|
||||||
|
m_swallowRightRelease = true;
|
||||||
|
return true; // consume: chord, not a radial / context menu
|
||||||
|
}
|
||||||
|
|
||||||
if (mev->button() == Qt::MiddleButton && inView) {
|
if (mev->button() == Qt::MiddleButton && inView) {
|
||||||
if (m_leftDownInView) {
|
if (m_leftDownInView) {
|
||||||
if (QAction *cut = findActionByName(QStringLiteral("edit_cut"))) {
|
if (QAction *cut = findActionByName(QStringLiteral("edit_cut"))) {
|
||||||
|
|
|
||||||
|
|
@ -91,6 +91,7 @@ private:
|
||||||
bool m_gestureActive = false; // an RMB drag gesture is in progress
|
bool m_gestureActive = false; // an RMB drag gesture is in progress
|
||||||
bool m_leftDownInView = false; // LMB held inside the view (Acme chord anchor)
|
bool m_leftDownInView = false; // LMB held inside the view (Acme chord anchor)
|
||||||
bool m_swallowMiddleRelease = false; // swallow the release paired with a consumed middle press
|
bool m_swallowMiddleRelease = false; // swallow the release paired with a consumed middle press
|
||||||
|
bool m_swallowRightRelease = false; // swallow the release paired with a left+right paste chord
|
||||||
QHash<QString, QPointer<QAction>> m_actionsById;
|
QHash<QString, QPointer<QAction>> m_actionsById;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue