Files
sloposk/tests/tst_layoutbuilder.cpp
T
ericek111andClaude Opus 5.5 b50667e508 Add an AltGr key; full-mode letters flick to their AltGr symbol
The right alt in full mode is now AltGr: sticky like the other modifiers,
it types the keymap's third/fourth level (sk: AltGr+J = ') instead of an
Alt shortcut. In hold-keys mode it holds the physical right alt, since
KWin resets the modifier state after an ISO_Level3_Shift keysym.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-30 23:59:37 +01:00

166 lines
5.8 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include "TestLayouts.h"
#include <QTest>
#include <xkbcommon/xkbcommon-keysyms.h>
using namespace Qt::StringLiterals;
namespace {
QString rowLetters(const Layout &layout, int row)
{
QString letters;
for (const KeyDef &key : layout.layers.first().rows[row]) {
if (key.type == KeyType::Character && key.label.front().isLetter())
letters += key.label;
}
return letters;
}
const KeyDef &letterKey(const Layout &layout, const QString &label)
{
for (const Row &row : layout.layers.first().rows) {
for (const KeyDef &key : row) {
if (key.label == label)
return key;
}
}
qFatal("no key %s", qPrintable(label));
}
} // namespace
class TestLayoutBuilder : public QObject
{
Q_OBJECT
private Q_SLOTS:
void readsLetterRowsFromKeymap()
{
const Layout us = TestLayouts::build("us");
QCOMPARE(rowLetters(us, 0), u"qwertyuiop");
QCOMPARE(rowLetters(us, 1), u"asdfghjkl");
QCOMPARE(rowLetters(us, 2), u"zxcvbnm");
const Layout sk = TestLayouts::build("sk");
QCOMPARE(sk.name, u"Slovak");
QCOMPARE(rowLetters(sk, 0), u"qwertzuiopúä");
QCOMPARE(rowLetters(sk, 1), u"asdfghjklô");
QCOMPARE(rowLetters(sk, 2), u"yxcvbnm");
const Layout se = TestLayouts::build("se");
QCOMPARE(rowLetters(se, 0), u"qwertyuiopå");
QCOMPARE(rowLetters(se, 1), u"asdfghjklöä");
}
void shiftedFormComesFromKeymap()
{
QCOMPARE(letterKey(TestLayouts::build("sk"), u"ô"_s).shifted, u"Ô");
}
void flicksFollowColumns()
{
const Layout sk = TestLayouts::build("sk");
QCOMPARE(letterKey(sk, u"q"_s).flick, u"1");
QCOMPARE(letterKey(sk, u"p"_s).flick, u"0");
QVERIFY(letterKey(sk, u"ú"_s).flick.isEmpty()); // more letters than flicks
}
void numberRowLettersBecomeAlternates()
{
const Layout sk = TestLayouts::build("sk");
// The keymap's own letters come first: they're what this language types.
QCOMPARE(letterKey(sk, u"s"_s).alternates.first(), u"š");
QCOMPARE(letterKey(sk, u"l"_s).alternates.first(), u"ľ");
QCOMPARE(letterKey(sk, u"n"_s).alternates.first(), u"ň"); // BKSL on sk
QCOMPARE(letterKey(sk, u"e"_s).alternates.first(), u"é");
QCOMPARE(letterKey(sk, u"y"_s).alternates.first(), u"ý");
}
void lettersWithoutDecompositionFindTheirBase()
{
QCOMPARE(letterKey(TestLayouts::build("de"), u"s"_s).alternates.first(), u"ß");
}
void alternatesSkipLettersThatHaveKeys()
{
const Layout se = TestLayouts::build("se");
const QStringList a = letterKey(se, u"a"_s).alternates;
QVERIFY(!a.contains(u"ä"_s));
QVERIFY(!a.contains(u"å"_s));
QVERIFY(a.contains(u"á"_s));
}
void fullModeHasEveryTypingKey()
{
const Layout us = TestLayouts::build("us", KeyboardMode::Full);
const auto labels = [&](int row) {
QString text;
for (const KeyDef &key : us.layers.first().rows[row]) {
if (key.type == KeyType::Character)
text += key.label;
}
return text;
};
QCOMPARE(labels(0), u"`1234567890-=");
QCOMPARE(labels(1), u"qwertyuiop[]\\");
QCOMPARE(labels(2), u"asdfghjkl;'");
QCOMPARE(labels(3), u"zxcvbnm,./"); // LSGT (< >) repeats , . shifted: left out
QCOMPARE(letterKey(us, u"1"_s).flick, u"!");
QCOMPARE(letterKey(us, u"1"_s).shifted, u"!");
}
void fullModeRowsStagger()
{
// The key ahead of A, and of the first key on the Z row: like a hardware keyboard,
// with the ISO key (sk: |) taking its room from left shift.
const auto offsets = [](const Layout &layout) {
const QList<Row> &rows = layout.layers.first().rows;
return std::pair{rows[2].first().width, rows[3].first().width};
};
QCOMPARE(offsets(TestLayouts::build("us", KeyboardMode::Full)), std::pair(1.75, 2.25));
const Layout sk = TestLayouts::build("sk", KeyboardMode::Full);
QCOMPARE(offsets(sk), std::pair(1.75, 1.25));
QCOMPARE(sk.layers.first().rows[3].at(1).label, u"\\"_s);
}
void fullModeKeepsDeadKeysAndKeymapShift()
{
const Layout sk = TestLayouts::build("sk", KeyboardMode::Full);
const KeyDef acute = letterKey(sk, u"´"_s);
QCOMPARE(acute.dead, quint32(XKB_KEY_dead_acute));
QCOMPARE(acute.deadShifted, quint32(XKB_KEY_dead_caron));
QCOMPARE(letterKey(sk, u"ô"_s).shifted, u"\""); // as the physical key
QCOMPARE(letterKey(sk, u"ľ"_s).shifted, u"2");
// Number-row letters are still long-press choices on their base letter.
QCOMPARE(letterKey(sk, u"t"_s).alternates.first(), u"ť");
QCOMPARE(letterKey(sk, u"l"_s).alternates.first(), u"ľ");
}
void fullModeLettersFlickToTheirAltGrSymbol()
{
const Layout sk = TestLayouts::build("sk", KeyboardMode::Full);
const KeyDef j = letterKey(sk, u"j"_s);
QCOMPARE(j.altGr, u"'");
QCOMPARE(j.flick, u"'");
QCOMPARE(j.text({ShiftLevel::None, true}), u"'");
QCOMPARE(letterKey(sk, u"ô"_s).flick, u"\""); // keys with a shifted symbol keep it
const KeyDef plus = letterKey(sk, u"+"_s);
QCOMPARE(plus.deadAt({ShiftLevel::Shifted, true}), quint32(XKB_KEY_dead_tilde));
QCOMPARE(plus.text({ShiftLevel::None, true}), u"!");
}
void noPlaceholdersRemain()
{
for (const Layer &layer : TestLayouts::build("us").layers) {
for (const Row &row : layer.rows) {
for (const KeyDef &key : row)
QVERIFY(key.type != KeyType::Letters);
}
}
}
};
QTEST_GUILESS_MAIN(TestLayoutBuilder)
#include "tst_layoutbuilder.moc"