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 <noreply@anthropic.com>
This commit is contained in:
@@ -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
|
- "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
|
- 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
|
- 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
|
- 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
|
- 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 (⚙)
|
- Optional PC key blocks: function row, navigation (ins/home/pg up, del/end/pg dn, arrows), numeric keypad; any mix, typing keys included (⚙)
|
||||||
|
|||||||
@@ -26,8 +26,14 @@ void PointerTracker::moveTo(QPointF pos)
|
|||||||
return;
|
return;
|
||||||
m_moved = true;
|
m_moved = true;
|
||||||
|
|
||||||
if (m_key.type == KeyType::LayerSwitch)
|
if (m_key.type == KeyType::LayerSwitch) {
|
||||||
m_gesture = Gesture::Slide;
|
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()))
|
else if (m_config.gestures && !m_key.flick.isEmpty() && delta.y() > qAbs(delta.x()))
|
||||||
m_gesture = Gesture::Flick;
|
m_gesture = Gesture::Flick;
|
||||||
}
|
}
|
||||||
@@ -63,7 +69,8 @@ QPoint PointerTracker::takeTrackpadSteps()
|
|||||||
|
|
||||||
const QPointF travel = m_position - m_trackpadOrigin;
|
const QPointF travel = m_position - m_trackpadOrigin;
|
||||||
// Truncate towards zero so jitter around the origin doesn't step.
|
// 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;
|
const QPoint steps = total - m_trackpadStepsTaken;
|
||||||
m_trackpadStepsTaken = total;
|
m_trackpadStepsTaken = total;
|
||||||
return steps;
|
return steps;
|
||||||
|
|||||||
@@ -11,7 +11,8 @@
|
|||||||
// Tap pressed, not (yet) anything else
|
// Tap pressed, not (yet) anything else
|
||||||
// Flick moved down on a key with a flick symbol
|
// Flick moved down on a key with a flick symbol
|
||||||
// LongPress held still on a key with alternates
|
// 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)
|
// Slide moved off a layer key (type a symbol, then switch back)
|
||||||
class PointerTracker
|
class PointerTracker
|
||||||
{
|
{
|
||||||
@@ -56,5 +57,6 @@ private:
|
|||||||
Gesture m_gesture = Gesture::Tap;
|
Gesture m_gesture = Gesture::Tap;
|
||||||
bool m_moved = false;
|
bool m_moved = false;
|
||||||
QPointF m_trackpadOrigin;
|
QPointF m_trackpadOrigin;
|
||||||
|
bool m_trackpadLines = true; // vertical travel moves between lines
|
||||||
QPoint m_trackpadStepsTaken;
|
QPoint m_trackpadStepsTaken;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -208,6 +208,17 @@ private Q_SLOTS:
|
|||||||
QCOMPARE(engine.output, QString());
|
QCOMPARE(engine.output, QString());
|
||||||
QCOMPARE(engine.keysyms, (QList<quint32>{XKB_KEY_Right, XKB_KEY_Right, XKB_KEY_Right}));
|
QCOMPARE(engine.keysyms, (QList<quint32>{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<KeyboardSurface *>(keyboard)->isTrackpadActive()); // keys keep their labels
|
||||||
|
QTest::touchEvent(&window, touchscreen).release(0, space - QPoint(30, 0));
|
||||||
|
QCOMPARE(engine.output, QString());
|
||||||
|
QCOMPARE(engine.keysyms, (QList<quint32>{XKB_KEY_Left, XKB_KEY_Left}));
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
QTEST_MAIN(TestKeyboardSurface)
|
QTEST_MAIN(TestKeyboardSurface)
|
||||||
|
|||||||
@@ -111,6 +111,33 @@ private Q_SLOTS:
|
|||||||
QCOMPARE(t.takeTrackpadSteps(), QPoint(-3, -1));
|
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()
|
void layerKeySlides()
|
||||||
{
|
{
|
||||||
PointerTracker t(ofType(KeyType::LayerSwitch), {0, 0}, config());
|
PointerTracker t(ofType(KeyType::LayerSwitch), {0, 0}, config());
|
||||||
|
|||||||
Reference in New Issue
Block a user