From 441c1d615b7873ac5df8e648d222cc9325d81850 Mon Sep 17 00:00:00 2001 From: ericek111 Date: Sun, 25 Oct 2026 17:51:09 +0100 Subject: [PATCH] Slide sideways on space to move the cursor As on phone keyboards: a sideways move on space moves the cursor right away, along the line only, without blanking the keys. Long-press space still opens the full trackpad. Co-Authored-By: Claude Opus 5.5 --- README.md | 2 +- src/input/PointerTracker.cpp | 11 +++++++++-- src/input/PointerTracker.h | 4 +++- tests/tst_keyboardsurface.cpp | 11 +++++++++++ tests/tst_pointertracker.cpp | 27 +++++++++++++++++++++++++++ 5 files changed, 51 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index a54ab84..50f8c18 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ iPad-style floating on-screen keyboard for Plasma Wayland. Qt 6, C++ core, QML U - "Hold Keys" (⚙): keys stay down while touched, like a hardware keyboard (games, Shift+click, system key repeat); modifiers are plain keys, dead keys compose in the app; touch conveniences off - Letters follow the system keyboard layout; the globe key switches it - Auto-capitalization, double-space → ". " (both optional, ⚙ on the bottom bar), backspace repeat → word delete -- Long-press space = trackpad; slide from `.?123` onto a symbol and release +- Slide sideways on space to move the cursor; long-press space = trackpad (lines too); slide from `.?123` onto a symbol and release - Compact (iPad) or full (iPad Pro) keyboard: number row, punctuation, tab, caps lock, ctrl/alt/super, dead keys - Ctrl/Alt/Super stick like shift (tap, double-tap, hold) and turn keys into shortcuts; a tapped or held shift joins them (Shift+F5, Shift+Tab, Shift+arrows), auto-shift and caps lock don't - Optional PC key blocks: function row, navigation (ins/home/pg up, del/end/pg dn, arrows), numeric keypad; any mix, typing keys included (⚙) diff --git a/src/input/PointerTracker.cpp b/src/input/PointerTracker.cpp index 1b462ac..25f16f4 100644 --- a/src/input/PointerTracker.cpp +++ b/src/input/PointerTracker.cpp @@ -26,8 +26,14 @@ void PointerTracker::moveTo(QPointF pos) return; m_moved = true; - if (m_key.type == KeyType::LayerSwitch) + if (m_key.type == KeyType::LayerSwitch) { m_gesture = Gesture::Slide; + } else if (m_config.gestures && m_key.type == KeyType::Space && qAbs(delta.x()) > qAbs(delta.y())) { + // From the press point: the slop counts towards the first step. + m_gesture = Gesture::Trackpad; + m_trackpadOrigin = m_start; + m_trackpadLines = false; + } else if (m_config.gestures && !m_key.flick.isEmpty() && delta.y() > qAbs(delta.x())) m_gesture = Gesture::Flick; } @@ -63,7 +69,8 @@ QPoint PointerTracker::takeTrackpadSteps() const QPointF travel = m_position - m_trackpadOrigin; // Truncate towards zero so jitter around the origin doesn't step. - const QPoint total(int(travel.x() / m_config.trackpadStep), int(travel.y() / m_config.trackpadRowStep)); + const int rows = m_trackpadLines ? int(travel.y() / m_config.trackpadRowStep) : 0; + const QPoint total(int(travel.x() / m_config.trackpadStep), rows); const QPoint steps = total - m_trackpadStepsTaken; m_trackpadStepsTaken = total; return steps; diff --git a/src/input/PointerTracker.h b/src/input/PointerTracker.h index 94a3ae6..8e5f9a6 100644 --- a/src/input/PointerTracker.h +++ b/src/input/PointerTracker.h @@ -11,7 +11,8 @@ // Tap pressed, not (yet) anything else // Flick moved down on a key with a flick symbol // LongPress held still on a key with alternates -// Trackpad held still on space; movement moves the text cursor +// Trackpad held still on space; movement moves the text cursor. Sliding +// sideways on space moves it too, along the line only. // Slide moved off a layer key (type a symbol, then switch back) class PointerTracker { @@ -56,5 +57,6 @@ private: Gesture m_gesture = Gesture::Tap; bool m_moved = false; QPointF m_trackpadOrigin; + bool m_trackpadLines = true; // vertical travel moves between lines QPoint m_trackpadStepsTaken; }; diff --git a/tests/tst_keyboardsurface.cpp b/tests/tst_keyboardsurface.cpp index a692f03..b2d26a6 100644 --- a/tests/tst_keyboardsurface.cpp +++ b/tests/tst_keyboardsurface.cpp @@ -208,6 +208,17 @@ private Q_SLOTS: QCOMPARE(engine.output, QString()); QCOMPARE(engine.keysyms, (QList{XKB_KEY_Right, XKB_KEY_Right, XKB_KEY_Right})); } + + void spaceSlideMovesCursorAtOnce() + { + const QPoint space = keyCenter({}, u"space"_s); + QTest::touchEvent(&window, touchscreen).press(0, space); + QTest::touchEvent(&window, touchscreen).move(0, space - QPoint(30, 0)); + QVERIFY(!qobject_cast(keyboard)->isTrackpadActive()); // keys keep their labels + QTest::touchEvent(&window, touchscreen).release(0, space - QPoint(30, 0)); + QCOMPARE(engine.output, QString()); + QCOMPARE(engine.keysyms, (QList{XKB_KEY_Left, XKB_KEY_Left})); + } }; QTEST_MAIN(TestKeyboardSurface) diff --git a/tests/tst_pointertracker.cpp b/tests/tst_pointertracker.cpp index 583441c..8d5c62e 100644 --- a/tests/tst_pointertracker.cpp +++ b/tests/tst_pointertracker.cpp @@ -111,6 +111,33 @@ private Q_SLOTS: QCOMPARE(t.takeTrackpadSteps(), QPoint(-3, -1)); } + void spaceSlideSidewaysMovesAlongTheLine() + { + PointerTracker t(ofType(KeyType::Space), {100, 0}, config()); + t.moveTo({112, 5}); + QCOMPARE(t.gesture(), Gesture::Trackpad); + QCOMPARE(t.takeTrackpadSteps(), QPoint(1, 0)); // the slop counts + t.moveTo({75, -50}); + QCOMPARE(t.takeTrackpadSteps(), QPoint(-3, 0)); // no line changes + QVERIFY(!t.longPressElapsed()); + } + + void spaceSlideVerticallyStaysTap() + { + PointerTracker t(ofType(KeyType::Space), {100, 0}, config()); + t.moveTo({105, -20}); + QCOMPARE(t.gesture(), Gesture::Tap); + } + + void spaceSlideNeedsGestures() + { + PointerTracker::Config c = config(); + c.gestures = false; + PointerTracker t(ofType(KeyType::Space), {100, 0}, c); + t.moveTo({140, 0}); + QCOMPARE(t.gesture(), Gesture::Tap); + } + void layerKeySlides() { PointerTracker t(ofType(KeyType::LayerSwitch), {0, 0}, config());