Files
Beyond-KLE/journal/2026-09-21-led-chain-variant.md
ewdernaandClaude Opus 5 e1aee6c92c elc: LEDチェーンをバリアントごとに分けないことを確定する
QMKの rgb_matrix はボードに1つで、レイアウトごとに分かれない。
バリアント固有の位置にLEDが載る基板も載らない基板も実在するが、どちらもチェーンは1本で、
選択によって並びが変わらない。載らないキーはPHYのper-key LEDの有無でそのまま表せる。

Journal: journal/2026-09-21-led-chain-variant.md

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

3.9 KiB

LEDチェーンとレイアウトバリアント

ELC P-4 の検証。

結論

チェーンはレイアウトの選択と無関係に固定されている。バリアントごとにチェーンの並びを分ける必要はない。

理由は、per-key LEDがスイッチとは独立に基板へ実装されるため。排他な2つのキー位置の両方にLEDが載る。 QMKの rgb_matrix.layout はボードに1つしかなく、レイアウトごとに分かれていない。

ボード レイアウト数 LED数 バリアント固有のマトリクス位置 そこへのLED割り当て
dp60 7 72 8 8個すべてにあり
cherrybstudio/cb87rgb 9 92 6 6個すべてにあり
crkbd/r2g 2 54 6 (外側の列) 6個すべてにあり
annepro2/c18 2 61 1 (ISOの追加キー) なし
boardsource/sessanta 2 72 4 (分割スペース) なし

annepro2/c18 と boardsource/sessanta は、バリアント固有のキーにLEDが無い。 チェーンが切れるのではなく、そのキーにper-key LEDが載っていないだけである。 PHYがper-key LEDの有無をキーごとに持つ形でそのまま表せる。

どちらの型でも、LEDの番号はレイアウトの選択で動かない。

調べ方

QMKのinfo.json 400件から、レイアウトを2つ以上持ち rgb_matrix.layout を持つ19件を抽出。 全レイアウトのマトリクス位置の和集合から共通部分を引いた「バリアント固有の位置」に、 LEDが割り当てられているかを見た。11件は割り当てあり、12件は一部に無し(両方に該当する板がある)。

限界

回路図そのものではなく、ファームウェアが持つLED配列を見ている。 LEDが基板に実装されているかどうかまでは確認できない。ただしQMKの rgb_matrix.layout は レイアウトごとに分けられない構造なので、「選択によってチェーンの並びが変わる基板」は 少なくともQMKでは成立しない。

検証スクリプト

# QMKのinfo.jsonを無作為抽出で取得する。qmk_list.json は
#   curl -o qmk_list.json https://keyboards.qmk.fm/v1/keyboard_list.json
import json, random, urllib.request, concurrent.futures, os
kbs=json.load(open('qmk_list.json'))['keyboards']
random.seed(42)
os.makedirs('qmk', exist_ok=True)
def fetch(kb):
    p='qmk/'+kb.replace('/','__')+'.json'
    if os.path.exists(p): return True
    try:
        with urllib.request.urlopen(f'https://keyboards.qmk.fm/v1/keyboards/{kb}/info.json', timeout=30) as r:
            open(p,'wb').write(r.read())
        return True
    except Exception as e:
        return str(e)[:60]
with concurrent.futures.ThreadPoolExecutor(8) as ex:
    res=list(ex.map(fetch, random.sample(kbs, 400)))
print('fetched', sum(1 for r in res if r is True), 'failed', sum(1 for r in res if r is not True))
# レイアウトバリアントとper-key LEDの関係。rgb_matrix.layout はボードに1つしかない
import json, glob, collections
st=collections.Counter()
for f in glob.glob('qmk/*.json'):
    d=json.load(open(f,encoding='utf-8'))
    for kb,v in (d.get('keyboards') or {}).items():
        lays=v.get('layouts') or {}; rm=(v.get('rgb_matrix') or {}).get('layout')
        if not rm or len(lays)<2: continue
        st['対象ボード']+=1
        used=[set(tuple(k['matrix']) for k in l['layout']) for l in lays.values()]
        variant_only=set().union(*used)-set.intersection(*used)  # バリアント固有の位置
        led=set(tuple(l['matrix']) for l in rm if 'matrix' in l)
        if not variant_only: continue
        if variant_only & led: st['固有位置にLEDあり']+=1
        if variant_only - led: st['固有位置にLEDなし']+=1
        print(kb, 'レイアウト', len(lays), 'LED', len(rm),
              '固有位置', len(variant_only), 'うちLEDあり', len(variant_only & led))
print(st)