- PointerTracker: per-finger gesture state machine (pure, unit-tested) - AlternatesPicker + AlternatesPopup.qml: long-press choices, finger selects - Space long-press trackpad moves the cursor with arrow keysyms - Slide from .?123 onto a symbol types it and switches back - New finger commits pending taps (iOS rollover) - Flick animation: secondary symbol slides down as the finger moves - Transparent popup margin with an input region that passes clicks through - tst_keyboardsurface: end-to-end gesture tests on the real QML Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
124 lines
2.9 KiB
C++
124 lines
2.9 KiB
C++
#include "input/PointerTracker.h"
|
|
|
|
#include <QTest>
|
|
|
|
using namespace Qt::StringLiterals;
|
|
using Gesture = PointerTracker::Gesture;
|
|
|
|
namespace {
|
|
|
|
KeyDef letter(const QString &flick = {}, const QStringList &alternates = {})
|
|
{
|
|
KeyDef k;
|
|
k.label = u"e"_s;
|
|
k.flick = flick;
|
|
k.alternates = alternates;
|
|
return k;
|
|
}
|
|
|
|
KeyDef ofType(KeyType type)
|
|
{
|
|
KeyDef k;
|
|
k.type = type;
|
|
return k;
|
|
}
|
|
|
|
PointerTracker::Config config()
|
|
{
|
|
PointerTracker::Config c;
|
|
c.slop = 10;
|
|
c.flickDistance = 30;
|
|
c.trackpadStep = 10;
|
|
c.trackpadRowStep = 40;
|
|
return c;
|
|
}
|
|
|
|
} // namespace
|
|
|
|
class TestPointerTracker : public QObject
|
|
{
|
|
Q_OBJECT
|
|
|
|
private Q_SLOTS:
|
|
void smallMovementStaysTap()
|
|
{
|
|
PointerTracker t(letter(u"3"_s), {0, 0}, config());
|
|
t.moveTo({5, 8});
|
|
QCOMPARE(t.gesture(), Gesture::Tap);
|
|
}
|
|
|
|
void downwardMovementFlicks()
|
|
{
|
|
PointerTracker t(letter(u"3"_s), {0, 0}, config());
|
|
t.moveTo({2, 15});
|
|
QCOMPARE(t.gesture(), Gesture::Flick);
|
|
QCOMPARE(t.flickProgress(), 0.5);
|
|
QVERIFY(!t.flickCommitted());
|
|
t.moveTo({2, 45});
|
|
QVERIFY(t.flickCommitted());
|
|
}
|
|
|
|
void flickBackUpUncommits()
|
|
{
|
|
PointerTracker t(letter(u"3"_s), {0, 0}, config());
|
|
t.moveTo({0, 40});
|
|
t.moveTo({0, 5});
|
|
QCOMPARE(t.gesture(), Gesture::Flick);
|
|
QVERIFY(!t.flickCommitted());
|
|
}
|
|
|
|
void sidewaysMovementDoesNotFlick()
|
|
{
|
|
PointerTracker t(letter(u"3"_s), {0, 0}, config());
|
|
t.moveTo({30, 15});
|
|
QCOMPARE(t.gesture(), Gesture::Tap);
|
|
}
|
|
|
|
void keysWithoutFlickNeverFlick()
|
|
{
|
|
PointerTracker t(letter(), {0, 0}, config());
|
|
t.moveTo({0, 40});
|
|
QCOMPARE(t.gesture(), Gesture::Tap);
|
|
}
|
|
|
|
void holdingStillOpensAlternates()
|
|
{
|
|
PointerTracker t(letter({}, {u"é"_s}), {0, 0}, config());
|
|
QVERIFY(t.wantsLongPress());
|
|
QVERIFY(t.longPressElapsed());
|
|
QCOMPARE(t.gesture(), Gesture::LongPress);
|
|
}
|
|
|
|
void movingCancelsLongPress()
|
|
{
|
|
PointerTracker t(letter({}, {u"é"_s}), {0, 0}, config());
|
|
t.moveTo({20, 0});
|
|
QVERIFY(!t.longPressElapsed());
|
|
QCOMPARE(t.gesture(), Gesture::Tap);
|
|
}
|
|
|
|
void spaceLongPressBecomesTrackpad()
|
|
{
|
|
PointerTracker t(ofType(KeyType::Space), {100, 0}, config());
|
|
QVERIFY(t.longPressElapsed());
|
|
QCOMPARE(t.gesture(), Gesture::Trackpad);
|
|
|
|
t.moveTo({125, 0});
|
|
QCOMPARE(t.takeTrackpadSteps(), QPoint(2, 0));
|
|
t.moveTo({131, 0});
|
|
QCOMPARE(t.takeTrackpadSteps(), QPoint(1, 0));
|
|
t.moveTo({95, -45});
|
|
QCOMPARE(t.takeTrackpadSteps(), QPoint(-3, -1));
|
|
}
|
|
|
|
void layerKeySlides()
|
|
{
|
|
PointerTracker t(ofType(KeyType::LayerSwitch), {0, 0}, config());
|
|
t.moveTo({40, -30});
|
|
QCOMPARE(t.gesture(), Gesture::Slide);
|
|
}
|
|
};
|
|
|
|
QTEST_GUILESS_MAIN(TestPointerTracker)
|
|
#include "tst_pointertracker.moc"
|