Layouts, iPad-style rendering, taps, shift and layers

- JSON layouts (en-US, sv-SE inheriting number/symbol layers via base)
- LayoutModel + KeyGeometry: proportional rows, nearest-key hit testing
- KeyboardSurface: multi-pointer touch/mouse routing to the controller
- KeyboardController + ShiftState: iOS shift/caps-lock, layers, globe, dismiss
- QML view with light/dark iPad palette and drag handle
- DevHooks: SLOPOSK_AUTOTYPE, SLOPOSK_SCREENSHOT for headless checks
- Unit tests for shift, loader, geometry and controller

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-14 14:50:21 +02:00
co-authored by Claude Opus 5.5
parent cdef9b4ad0
commit be14bbcc62
35 changed files with 1970 additions and 65 deletions
+86
View File
@@ -0,0 +1,86 @@
#include "input/ShiftState.h"
#include <QTest>
using Mode = ShiftState::Mode;
class TestShiftState : public QObject
{
Q_OBJECT
private Q_SLOTS:
void tapShiftsOneCharacter()
{
ShiftState shift;
shift.press(0);
shift.release();
QCOMPARE(shift.mode(), Mode::Once);
shift.characterTyped();
QCOMPARE(shift.mode(), Mode::Off);
}
void doubleTapLocks()
{
ShiftState shift;
shift.press(0);
shift.release();
shift.press(200);
shift.release();
QCOMPARE(shift.mode(), Mode::Locked);
shift.characterTyped();
shift.characterTyped();
QCOMPARE(shift.mode(), Mode::Locked);
}
void tapUnlocks()
{
ShiftState shift;
shift.press(0);
shift.press(100);
shift.press(1000);
QCOMPARE(shift.mode(), Mode::Off);
}
void slowSecondTapTurnsOff()
{
ShiftState shift;
shift.press(0);
shift.release();
shift.press(ShiftState::DoubleTapMs + 1);
shift.release();
QCOMPARE(shift.mode(), Mode::Off);
}
void holdShiftsEveryCharacterUntilRelease()
{
ShiftState shift;
shift.press(0);
shift.characterTyped();
shift.characterTyped();
QCOMPARE(shift.mode(), Mode::Once);
shift.release();
QCOMPARE(shift.mode(), Mode::Off);
}
void automaticIgnoredWhileLocked()
{
ShiftState shift;
shift.press(0);
shift.press(100);
shift.release();
shift.setAutomatic(false);
QCOMPARE(shift.mode(), Mode::Locked);
}
void automaticCapitalizes()
{
ShiftState shift;
shift.setAutomatic(true);
QCOMPARE(shift.mode(), Mode::Once);
shift.characterTyped();
QCOMPARE(shift.mode(), Mode::Off);
}
};
QTEST_GUILESS_MAIN(TestShiftState)
#include "tst_shiftstate.moc"