Type into any window: fake input when no text field is focused
- KWinFakeInput (org_kde_kwin_fake_input v6, offered by KWin to the input-method process): keysyms with real modifier keys held - The KWin backend uses the input method in text fields and fake input everywhere else, so shortcuts, terminals and the desktop get keys - Text rules (auto-capitalization, double-space) only apply in fields - Always Show setting keeps the keyboard up without a text field Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -10,6 +10,10 @@ using namespace Qt::StringLiterals;
|
||||
|
||||
namespace {
|
||||
|
||||
const TextContext Field{.field = true};
|
||||
// A field with some text already: no auto-shift until a test asks for it.
|
||||
const TextContext MidSentence{.field = true, .hasSurroundingText = true, .textBeforeCursor = u"so"_s};
|
||||
|
||||
KeyDef makeKey(KeyType type, const QString &label = {})
|
||||
{
|
||||
KeyDef k;
|
||||
@@ -44,6 +48,7 @@ private Q_SLOTS:
|
||||
model.setLayout(TestLayouts::build("us"));
|
||||
model.setVisibleSections({MainSectionId});
|
||||
controller = std::make_unique<KeyboardController>(engine, model);
|
||||
controller->resetContext(MidSentence); // most tests type into a text field
|
||||
}
|
||||
|
||||
void typesLowercase()
|
||||
@@ -103,7 +108,7 @@ private Q_SLOTS:
|
||||
|
||||
void capitalizesAtSentenceStart()
|
||||
{
|
||||
controller->resetContext();
|
||||
controller->resetContext(Field);
|
||||
QCOMPARE(controller->shiftMode(), KeyboardController::ShiftMode::Once);
|
||||
for (const char *c : {"h", "i", ".", " "})
|
||||
tap(makeKey(KeyType::Character, QString::fromLatin1(c)));
|
||||
@@ -114,7 +119,7 @@ private Q_SLOTS:
|
||||
|
||||
void noCapitalizationInPasswordFields()
|
||||
{
|
||||
TextContext context;
|
||||
TextContext context = Field;
|
||||
context.purpose = TextContext::Purpose::Password;
|
||||
controller->setContext(context);
|
||||
QCOMPARE(controller->shiftMode(), KeyboardController::ShiftMode::Off);
|
||||
@@ -122,7 +127,7 @@ private Q_SLOTS:
|
||||
|
||||
void fieldTextDrivesCapitalization()
|
||||
{
|
||||
TextContext context;
|
||||
TextContext context = Field;
|
||||
context.hasSurroundingText = true;
|
||||
context.textBeforeCursor = u"Done! "_s;
|
||||
controller->setContext(context);
|
||||
@@ -152,12 +157,12 @@ private Q_SLOTS:
|
||||
tap(makeKey(KeyType::Character, u"a"_s));
|
||||
tap(space);
|
||||
tap(space);
|
||||
QCOMPARE(engine.output, u"A ");
|
||||
QCOMPARE(engine.output, u"a ");
|
||||
}
|
||||
|
||||
void autoCapitalizationCanBeTurnedOff()
|
||||
{
|
||||
controller->resetContext();
|
||||
controller->resetContext(Field);
|
||||
controller->setOptions({.autoCapitalize = false});
|
||||
QCOMPARE(controller->shiftMode(), KeyboardController::ShiftMode::Off);
|
||||
tap(makeKey(KeyType::Character, u"a"_s));
|
||||
@@ -166,7 +171,7 @@ private Q_SLOTS:
|
||||
|
||||
void doubleTapShiftLocksAtSentenceStart()
|
||||
{
|
||||
controller->resetContext(); // a field was focused
|
||||
controller->resetContext(Field); // a field was focused
|
||||
QCOMPARE(controller->shiftMode(), KeyboardController::ShiftMode::Once); // auto-shift
|
||||
const KeyDef shift = makeKey(KeyType::Shift);
|
||||
controller->keyDown(shift, 5000);
|
||||
@@ -281,7 +286,7 @@ private Q_SLOTS:
|
||||
|
||||
void autoShiftAndCapsLockDontApplyToFunctionKeys()
|
||||
{
|
||||
controller->resetContext(); // sentence start: auto-shift on
|
||||
controller->resetContext(Field); // sentence start: auto-shift on
|
||||
QCOMPARE(controller->shiftMode(), KeyboardController::ShiftMode::Once);
|
||||
tap(keysymKey(XKB_KEY_Left));
|
||||
QCOMPARE(engine.lastModifiers, Qt::NoModifier);
|
||||
@@ -303,10 +308,10 @@ private Q_SLOTS:
|
||||
lj.shifted = u"2"_s;
|
||||
KeyDef one = makeKey(KeyType::Character, u"+"_s);
|
||||
one.shifted = u"1"_s;
|
||||
controller->resetContext(); // sentence start
|
||||
controller->resetContext(Field); // sentence start
|
||||
tap(one);
|
||||
QCOMPARE(engine.output, u"+"); // not the shifted level
|
||||
controller->resetContext();
|
||||
controller->resetContext(Field);
|
||||
tap(lj);
|
||||
QCOMPARE(engine.output, u"+Ľ");
|
||||
tap(makeKey(KeyType::Shift)); // the user's shift does pick it
|
||||
@@ -325,6 +330,17 @@ private Q_SLOTS:
|
||||
QVERIFY(engine.output.endsWith(u"é"_s));
|
||||
}
|
||||
|
||||
void noTextRulesWithoutAField()
|
||||
{
|
||||
controller->resetContext({}); // keys go to a window, not a text field
|
||||
QCOMPARE(controller->shiftMode(), KeyboardController::ShiftMode::Off);
|
||||
const KeyDef space = makeKey(KeyType::Space);
|
||||
tap(makeKey(KeyType::Character, u"a"_s));
|
||||
tap(space);
|
||||
tap(space);
|
||||
QCOMPARE(engine.output, u"a ");
|
||||
}
|
||||
|
||||
void dismissEmitsSignal()
|
||||
{
|
||||
int dismissed = 0;
|
||||
|
||||
Reference in New Issue
Block a user