Text rules: auto-capitalization, double-space period, backspace repeat
- TextContext: field purpose/hints and text before the cursor, reported by the backend (KWin content_type + surrounding_text) - TextRules: sentence-start and double-space heuristics, deletion helpers - KeyRepeater: held backspace repeats, then deletes whole words (Ctrl+BS) - Controller keeps a best-guess of the text before the cursor so rules work instantly and in fields that don't report surrounding text - No auto-capitalization or smart punctuation in password/URL/email fields Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -14,10 +14,15 @@ class FakeEngine : public InputEngine
|
||||
{
|
||||
public:
|
||||
void commitText(const QString &text) override { output += text; }
|
||||
void sendKeysym(quint32 keysym) override { keysyms.append(keysym); }
|
||||
void sendKeysym(quint32 keysym, Qt::KeyboardModifiers modifiers) override
|
||||
{
|
||||
keysyms.append(keysym);
|
||||
lastModifiers = modifiers;
|
||||
}
|
||||
|
||||
QString output;
|
||||
QList<quint32> keysyms;
|
||||
Qt::KeyboardModifiers lastModifiers;
|
||||
};
|
||||
|
||||
KeyDef makeKey(KeyType type, const QString &label = {})
|
||||
@@ -105,6 +110,57 @@ private Q_SLOTS:
|
||||
QCOMPARE(model.layerName(), u"numbers");
|
||||
}
|
||||
|
||||
void backspaceStopsOnRelease()
|
||||
{
|
||||
const KeyDef backspace = makeKey(KeyType::Backspace);
|
||||
controller->keyDown(backspace, 0);
|
||||
controller->keyUp(backspace, KeyOutput::Primary, {}, 50);
|
||||
QTest::qWait(700); // past the repeat delay
|
||||
QCOMPARE(engine.keysyms.size(), 1);
|
||||
}
|
||||
|
||||
void capitalizesAtSentenceStart()
|
||||
{
|
||||
controller->resetContext();
|
||||
QCOMPARE(controller->shiftMode(), KeyboardController::ShiftMode::Once);
|
||||
for (const char *c : {"h", "i", ".", " "})
|
||||
tap(makeKey(KeyType::Character, QString::fromLatin1(c)));
|
||||
QCOMPARE(controller->shiftMode(), KeyboardController::ShiftMode::Once);
|
||||
tap(makeKey(KeyType::Character, u"o"_s));
|
||||
QCOMPARE(engine.output, u"Hi. O");
|
||||
}
|
||||
|
||||
void noCapitalizationInPasswordFields()
|
||||
{
|
||||
TextContext context;
|
||||
context.purpose = TextContext::Purpose::Password;
|
||||
controller->setContext(context);
|
||||
QCOMPARE(controller->shiftMode(), KeyboardController::ShiftMode::Off);
|
||||
}
|
||||
|
||||
void fieldTextDrivesCapitalization()
|
||||
{
|
||||
TextContext context;
|
||||
context.hasSurroundingText = true;
|
||||
context.textBeforeCursor = u"Done! "_s;
|
||||
controller->setContext(context);
|
||||
QCOMPARE(controller->shiftMode(), KeyboardController::ShiftMode::Once);
|
||||
context.textBeforeCursor = u"Done, "_s;
|
||||
controller->setContext(context);
|
||||
QCOMPARE(controller->shiftMode(), KeyboardController::ShiftMode::Off);
|
||||
}
|
||||
|
||||
void doubleSpaceTypesPeriod()
|
||||
{
|
||||
const KeyDef space = makeKey(KeyType::Space);
|
||||
tap(makeKey(KeyType::Character, u"a"_s));
|
||||
tap(space);
|
||||
tap(space);
|
||||
QCOMPARE(engine.output, u"a . ");
|
||||
QCOMPARE(engine.keysyms, QList<quint32>{XKB_KEY_BackSpace}); // removed the first space
|
||||
QCOMPARE(controller->shiftMode(), KeyboardController::ShiftMode::Once);
|
||||
}
|
||||
|
||||
void slideTypesSymbolAndSwitchesBack()
|
||||
{
|
||||
KeyDef layer = makeKey(KeyType::LayerSwitch);
|
||||
|
||||
Reference in New Issue
Block a user