Full keyboard mode, Ctrl/Alt/Super, dead keys, shift levels
- Full (iPad Pro) mode: every typing key from the keymap, number row, tab, caps lock, ctrl/super/alt; shifted symbol shown above and flickable - Dead keys compose with the locale's XKB compose table - Ctrl/Alt/Super stick like shift and turn keys into shortcuts; a tapped or held shift joins shortcuts and non-text keys, auto-shift and caps lock don't - Auto-capitalization and caps lock only capitalize letters; the user's shift picks the keymap's shifted level - Mode switch in settings keeps key size by resizing the window Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -230,6 +230,101 @@ private Q_SLOTS:
|
||||
QCOMPARE(model.rowCount(), mainKeys); // never nothing
|
||||
}
|
||||
|
||||
KeyDef keysymKey(quint32 keysym)
|
||||
{
|
||||
KeyDef key = makeKey(KeyType::Keysym);
|
||||
key.keysym = keysym;
|
||||
return key;
|
||||
}
|
||||
|
||||
KeyDef modifierKey(const QString &name)
|
||||
{
|
||||
KeyDef key = makeKey(KeyType::Modifier);
|
||||
key.modifier = name;
|
||||
return key;
|
||||
}
|
||||
|
||||
void ctrlTurnsKeysIntoShortcuts()
|
||||
{
|
||||
tap(modifierKey(u"ctrl"_s));
|
||||
QCOMPARE(controller->modifierModes().value(u"ctrl"_s).toInt(), int(KeyboardController::ShiftMode::Once));
|
||||
tap(makeKey(KeyType::Character, u"c"_s));
|
||||
QCOMPARE(engine.keysyms, QList<quint32>{XKB_KEY_c});
|
||||
QCOMPARE(engine.lastModifiers, Qt::ControlModifier);
|
||||
QVERIFY(engine.output.isEmpty());
|
||||
// One-shot: the next key types again.
|
||||
tap(makeKey(KeyType::Character, u"c"_s));
|
||||
QCOMPARE(engine.output, u"c");
|
||||
}
|
||||
|
||||
void heldModifierAppliesToEveryKey()
|
||||
{
|
||||
const KeyDef alt = modifierKey(u"alt"_s);
|
||||
controller->keyDown(alt, 0);
|
||||
tap(keysymKey(XKB_KEY_Tab));
|
||||
tap(keysymKey(XKB_KEY_Tab));
|
||||
controller->keyUp(alt, KeyOutput::Primary, {}, 9000);
|
||||
QCOMPARE(engine.keysyms.size(), 2);
|
||||
QCOMPARE(engine.lastModifiers, Qt::AltModifier);
|
||||
QCOMPARE(controller->modifierModes().value(u"alt"_s).toInt(), int(KeyboardController::ShiftMode::Off));
|
||||
}
|
||||
|
||||
void tappedShiftAppliesToFunctionKeys()
|
||||
{
|
||||
tap(makeKey(KeyType::Character, u"a"_s)); // mid-sentence: no auto-shift
|
||||
tap(makeKey(KeyType::Shift));
|
||||
tap(keysymKey(XKB_KEY_F5));
|
||||
QCOMPARE(engine.keysyms.last(), quint32(XKB_KEY_F5));
|
||||
QCOMPARE(engine.lastModifiers, Qt::ShiftModifier);
|
||||
QCOMPARE(controller->shiftMode(), KeyboardController::ShiftMode::Off); // used up
|
||||
}
|
||||
|
||||
void autoShiftAndCapsLockDontApplyToFunctionKeys()
|
||||
{
|
||||
controller->resetContext(); // sentence start: auto-shift on
|
||||
QCOMPARE(controller->shiftMode(), KeyboardController::ShiftMode::Once);
|
||||
tap(keysymKey(XKB_KEY_Left));
|
||||
QCOMPARE(engine.lastModifiers, Qt::NoModifier);
|
||||
|
||||
tap(makeKey(KeyType::CapsLock));
|
||||
QCOMPARE(controller->shiftMode(), KeyboardController::ShiftMode::Locked);
|
||||
tap(keysymKey(XKB_KEY_Left));
|
||||
QCOMPARE(engine.lastModifiers, Qt::NoModifier);
|
||||
tap(makeKey(KeyType::Character, u"a"_s));
|
||||
tap(makeKey(KeyType::Character, u"b"_s));
|
||||
QCOMPARE(engine.output, u"AB");
|
||||
tap(makeKey(KeyType::CapsLock));
|
||||
QCOMPARE(controller->shiftMode(), KeyboardController::ShiftMode::Off);
|
||||
}
|
||||
|
||||
void autoShiftCapitalizesLettersOnly()
|
||||
{
|
||||
KeyDef lj = makeKey(KeyType::Character, u"ľ"_s); // sk number row: Shift+ľ = 2
|
||||
lj.shifted = u"2"_s;
|
||||
KeyDef one = makeKey(KeyType::Character, u"+"_s);
|
||||
one.shifted = u"1"_s;
|
||||
controller->resetContext(); // sentence start
|
||||
tap(one);
|
||||
QCOMPARE(engine.output, u"+"); // not the shifted level
|
||||
controller->resetContext();
|
||||
tap(lj);
|
||||
QCOMPARE(engine.output, u"+Ľ");
|
||||
tap(makeKey(KeyType::Shift)); // the user's shift does pick it
|
||||
tap(lj);
|
||||
QCOMPARE(engine.output, u"+Ľ2");
|
||||
}
|
||||
|
||||
void deadKeyComposesWithNextCharacter()
|
||||
{
|
||||
KeyDef acute = makeKey(KeyType::Character, u"´"_s);
|
||||
acute.dead = XKB_KEY_dead_acute;
|
||||
tap(makeKey(KeyType::Character, u"x"_s));
|
||||
tap(acute);
|
||||
QVERIFY(engine.output == u"x"); // nothing typed yet
|
||||
tap(makeKey(KeyType::Character, u"e"_s));
|
||||
QVERIFY(engine.output.endsWith(u"é"_s));
|
||||
}
|
||||
|
||||
void dismissEmitsSignal()
|
||||
{
|
||||
int dismissed = 0;
|
||||
|
||||
Reference in New Issue
Block a user