Gestures: flick, long-press alternates, trackpad, layer slide, rollover

- 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>
This commit is contained in:
2026-10-14 14:55:49 +02:00
co-authored by Claude Opus 5.5
parent be14bbcc62
commit 2b5edeb365
23 changed files with 901 additions and 35 deletions
+11
View File
@@ -50,6 +50,7 @@ QVariant LayoutModel::data(const QModelIndex &index, int role) const
case KeyWidthRole: return rect.width();
case KeyHeightRole: return rect.height();
case PressedRole: return m_pressCount.at(index.row()) > 0;
case FlickProgressRole: return m_flickProgress.at(index.row());
}
return {};
}
@@ -65,6 +66,7 @@ QHash<int, QByteArray> LayoutModel::roleNames() const
{KeyWidthRole, "keyWidth"},
{KeyHeightRole, "keyHeight"},
{PressedRole, "pressed"},
{FlickProgressRole, "flickProgress"},
};
}
@@ -115,6 +117,14 @@ void LayoutModel::setPressed(int row, bool pressed)
Q_EMIT dataChanged(index(row), index(row), {PressedRole});
}
void LayoutModel::setFlickProgress(int row, qreal progress)
{
if (row < 0 || row >= m_flickProgress.size() || qFuzzyCompare(m_flickProgress[row], progress))
return;
m_flickProgress[row] = progress;
Q_EMIT dataChanged(index(row), index(row), {FlickProgressRole});
}
int LayoutModel::keyAt(QPointF pos) const
{
int nearest = -1;
@@ -142,6 +152,7 @@ void LayoutModel::rebuild()
}
}
m_pressCount = QList<int>(m_keys.size(), 0);
m_flickProgress = QList<qreal>(m_keys.size(), 0.0);
relayout();
endResetModel();
}