Full keyboard: stagger the letter rows like a hardware keyboard

- The ISO key left of Z takes its room from left shift (2.25 → 1.25 + 1),
  so ISO layouts no longer make the shift row the widest
- Caps lock and left shift keep their width; only right-hand keys stretch,
  so A no longer lines up with the key below it

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-14 22:42:11 +02:00
co-authored by Claude Opus 5.5
parent ac0bfc2741
commit ac67ceac18
3 changed files with 30 additions and 5 deletions
+2 -2
View File
@@ -88,12 +88,12 @@
{"type": "keys", "row": 1}
],
[
{"type": "capslock", "label": "caps lock", "width": 1.75, "stretch": true},
{"type": "capslock", "label": "caps lock", "width": 1.75},
{"type": "keys", "row": 2},
{"type": "enter", "width": 1.75, "stretch": true}
],
[
{"type": "shift", "width": 2.25, "stretch": true},
{"type": "shift", "width": 2.25},
{"type": "keys", "row": 3},
{"type": "shift", "width": 2.25, "stretch": true}
],
+14 -3
View File
@@ -2,6 +2,8 @@
#include <QSet>
#include <algorithm>
namespace {
// Letters without a Unicode decomposition, and the key they belong under.
@@ -53,8 +55,10 @@ QList<KeyDef> letterKeys(const KeymapKeys &keymap, int row, const QStringList &f
}
// A full row: every typing key, the shifted symbol shown (and flickable) above.
QList<KeyDef> rowKeys(const KeymapKeys &keymap, int row)
// `withLessGreater` tells whether the ISO key left of Z is among them.
QList<KeyDef> rowKeys(const KeymapKeys &keymap, int row, bool *withLessGreater)
{
*withLessGreater = false;
QSet<QString> elsewhere; // LSGT often repeats a pair that exists elsewhere (US: < >)
for (const auto &keys : keymap.rows) {
for (const KeymapKey &key : keys) {
@@ -67,6 +71,7 @@ QList<KeyDef> rowKeys(const KeymapKeys &keymap, int row)
for (const KeymapKey &source : keymap.rows.value(row)) {
if (source.position == KeymapKey::Position::LessGreater && elsewhere.contains(source.lower))
continue;
*withLessGreater |= source.position == KeymapKey::Position::LessGreater;
KeyDef key = characterKey(source);
// Show (and flick for) a shifted level that isn't just the capital letter: ! on 1, " on sk ô.
if (!source.deadUpper && source.upper != source.lower && source.upper != source.lower.toUpper())
@@ -82,8 +87,14 @@ Row expandPlaceholders(const Row &row, const KeymapKeys &keymap)
for (const KeyDef &key : row) {
if (key.type == KeyType::Letters)
result += letterKeys(keymap, key.lettersRow, key.flicks);
else if (key.type == KeyType::Keys)
result += rowKeys(keymap, key.lettersRow);
else if (key.type == KeyType::Keys) {
bool withLessGreater = false;
const QList<KeyDef> keys = rowKeys(keymap, key.lettersRow, &withLessGreater);
// As on ISO keyboards, that key takes its room from the one before it (left shift).
if (withLessGreater && !result.isEmpty())
result.back().width = std::max(1.0, result.back().width - 1);
result += keys;
}
else
result.append(key);
}
+14
View File
@@ -110,6 +110,20 @@ private Q_SLOTS:
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);