#include "engine/InputEngine.h" #include "input/KeyboardController.h" #include "layout/LayoutModel.h" #include "layout/LayoutRepository.h" #include #include using namespace Qt::StringLiterals; namespace { class FakeEngine : public InputEngine { public: void commitText(const QString &text) override { output += text; } void sendKeysym(quint32 keysym) override { keysyms.append(keysym); } QString output; QList keysyms; }; KeyDef makeKey(KeyType type, const QString &label = {}) { KeyDef k; k.type = type; k.label = label; return k; } } // namespace class TestController : public QObject { Q_OBJECT private: FakeEngine engine; LayoutRepository repo; LayoutModel model; std::unique_ptr controller; qint64 now = 0; void tap(const KeyDef &key, KeyOutput output = KeyOutput::Primary, const QString &alternate = {}) { now += 1000; // far apart: never a double tap controller->keyDown(key, now); controller->keyUp(key, output, alternate, now + 50); } private Q_SLOTS: void init() { engine = {}; repo = {}; Q_INIT_RESOURCE(layouts); repo.loadDirectory(u":/layouts"_s); repo.finalize(u"en_US"_s); controller = std::make_unique(engine, model, repo); } void typesLowercase() { tap(makeKey(KeyType::Character, u"a"_s)); QCOMPARE(engine.output, u"a"); } void shiftCapitalizesOneCharacter() { const KeyDef a = makeKey(KeyType::Character, u"a"_s); tap(makeKey(KeyType::Shift)); QCOMPARE(controller->shiftMode(), KeyboardController::ShiftMode::Once); tap(a); tap(a); QCOMPARE(engine.output, u"Aa"); QCOMPARE(controller->shiftMode(), KeyboardController::ShiftMode::Off); } void flickAndAlternateOutputs() { KeyDef e = makeKey(KeyType::Character, u"e"_s); e.flick = u"3"_s; tap(e, KeyOutput::Flick); tap(e, KeyOutput::Alternate, u"é"_s); QCOMPARE(engine.output, u"3é"); } void backspaceActsOnPress() { controller->keyDown(makeKey(KeyType::Backspace), 0); QCOMPARE(engine.keysyms, QList{XKB_KEY_BackSpace}); } void enterSendsReturn() { tap(makeKey(KeyType::Enter)); QCOMPARE(engine.keysyms, QList{XKB_KEY_Return}); } void layerSwitchChangesModelLayer() { KeyDef layer = makeKey(KeyType::LayerSwitch); layer.target = u"numbers"_s; controller->keyDown(layer, 0); QCOMPARE(model.layerName(), u"numbers"); } void slideTypesSymbolAndSwitchesBack() { KeyDef layer = makeKey(KeyType::LayerSwitch); layer.target = u"numbers"_s; controller->keyDown(layer, 0); controller->slideReleased(makeKey(KeyType::Character, u"5"_s), 100); QCOMPARE(engine.output, u"5"); QCOMPARE(model.layerName(), u"letters"); } void trackpadMovesCursor() { controller->moveCursor({2, -1}); QCOMPARE(engine.keysyms, (QList{XKB_KEY_Right, XKB_KEY_Right, XKB_KEY_Up})); } void globeCyclesLayouts() { QCOMPARE(model.layoutName(), u"English (US)"); tap(makeKey(KeyType::Globe)); QCOMPARE(model.layoutName(), u"Svenska"); tap(makeKey(KeyType::Globe)); QCOMPARE(model.layoutName(), u"English (US)"); } void dismissEmitsSignal() { int dismissed = 0; connect(controller.get(), &KeyboardController::dismissRequested, this, [&] { ++dismissed; }); tap(makeKey(KeyType::Dismiss)); QCOMPARE(dismissed, 1); } }; QTEST_GUILESS_MAIN(TestController) #include "tst_controller.moc"