Files
Beyond-KLE/journal/2026-09-21-kle-lenient-row.md
T
ewdernaandClaude Opus 5 c31360a772 phy: 行の先頭以外の r, rx, ry を取り込みで受け入れる(P-16解消)
KLE本家は拒否するが、VIAとRemapは読む。Remapで扱える基板を取り込めない
状態にしないため、位置を問わず受け入れる。本家のコードから行頭チェックを
外した挙動をそのまま採る。出力は従来どおり行頭にのみ置く。

Journal: journal/2026-09-21-kle-lenient-row.md

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SSKcJLPAaPLchG4LXxk6cY
2026-09-21 21:57:45 +09:00

3.7 KiB

行の先頭以外の r, rx, ry を受け入れるか

結論

受け入れる。位置を問わず、そのキー以降に適用する。rx, ry は座標を (rx, ry) に戻してから x, y を加える (KLE本家のコードから行頭チェックだけを外したときの挙動と同じ)。

決め手は Remap が読めること。ユーザーの判断: 「Remapで扱えるものを拒否したくない」。

案 取り込める基板 既存の解釈への影響 出力への影響
本家に合わせて拒否 1505件中1504件 なし なし
r だけ受け入れ 1505件 なし なし
r, rx, ry とも受け入れ(採用) 1505件 なし なし

3案とも出力は変わらない。本家の serialize はクラスターが変わると必ず行を割るので、 r, rx, ry は常に行頭にしか出ない。寛容化しても非互換なJSONを生む側には回らない。

実データ

コーパス1505件(KLE本家プリセット12 + samples 9 + the-via/keyboards 1484)で、 行の先頭以外の r, rx, ry を持つのは owlab/spring/spring.json の1件だけ。内訳は r が15回、rx/ry は0回。

spring は Alice系。物理行ごとに配列を1つ書き、行の途中で r を 0 → 12 → -12 → 0 と切り替えている。 行頭チェックを外して読むと素直に開く(67キー、左右±12度のスプレイ + 回転なしの外側2列)。

0,3  x=3.25  r=0     0,4  x=4.44  r=12    0,8  x=8.72  r=-12   0,12 x=12.85 r=0
1,2  x=2.50  r=0     1,3  x=3.70  r=12    1,7  x=8.48  r=-12   1,11 x=12.60 r=0

寛容化が既存の解釈を変えないこと

本家 serial.js の該当箇所は throw だけで、意味づけは残りの行が決めている。

if(key.r != null) { if(k!=0) {deserializeError(...)} current.rotation_angle = key.r; }
if(key.rx != null) { if(k!=0) {deserializeError(...)} current.rotation_x = cluster.x = key.rx; extend(current, cluster); }

throw を3つ消したパーサーと本家で全1505件を読み比べ、本家が読めた1504件はキー配列が完全一致。 変わるのは今エラーになる1件だけ。

他のツールの受け入れ

ツール 行の途中の r/rx/ry 根拠
KLE本家 serial.js 拒否 'r' can only be used on the first key in a row
kle-serial (ijprest, TS移植) 拒否 同じチェックを移植
Vial kle_serial.py 拒否 k != 0 and ("r" in item or ...)
kicad-kbplacer 拒否 同じチェックあり
VIA @the-via/reader 許容 reduceで位置チェックなし
Remap KeyboardModel.ts 許容 Current.setOp() に位置チェックなし
QMK kle2xy.py 無関係 r/rx/ry を読まない(回転を捨てる)

Remap の Current を位置計算だけ移植して、throw を外した本家と突き合わせた。行の途中の r、 行の途中の rx/ry、途中で r=0 に戻す、spring 全体、いずれも一致する。VIA reader はコードを読んだだけで、 cursor.y = ry としか書いていないため rx/ry の扱いは本家と違う可能性がある(spring は rx=ry=0 なので影響なし)。

同じ突き合わせをコーパス全件でやると19件が不一致になるが、いずれも行頭側の ry の解釈やラベルなしキーの扱いで、 今回の話とは別件。簡易移植での比較なので Remap 本体で再現したわけでもない。追っていない。

取り込んで書き戻す

spring を寛容パーサーで読み、PHY経由で本家の serialize に通すと、5行 → 26行のJSONになる。 本家の deserialize が読め、配置も元と一致した。寛容化は本家で開けないファイルの修復経路になる。