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
+19
View File
@@ -37,6 +37,7 @@ void KeyboardController::keyDown(const KeyDef &key, qint64 timeMs)
m_engine.sendKeysym(XKB_KEY_BackSpace);
break;
case KeyType::LayerSwitch:
m_layerBeforeSwitch = m_model.layerName();
m_model.setLayer(key.target);
break;
default:
@@ -81,6 +82,24 @@ void KeyboardController::keyCancelled(const KeyDef &key)
changeShift([&] { m_shift.release(); });
}
void KeyboardController::slideReleased(const KeyDef &target, qint64 timeMs)
{
keyUp(target, KeyOutput::Primary, {}, timeMs);
m_model.setLayer(m_layerBeforeSwitch);
}
void KeyboardController::moveCursor(QPoint steps)
{
const auto repeat = [this](int count, quint32 keysym) {
for (int i = 0; i < count; ++i)
m_engine.sendKeysym(keysym);
};
repeat(qMax(0, steps.x()), XKB_KEY_Right);
repeat(qMax(0, -steps.x()), XKB_KEY_Left);
repeat(qMax(0, steps.y()), XKB_KEY_Down);
repeat(qMax(0, -steps.y()), XKB_KEY_Up);
}
void KeyboardController::nextLayout()
{
const auto &layouts = m_layouts.layouts();