fix Greek dead key terminator (Ω→α), enable CapsLock language switch, fix parser key resolution

- change Greek dead key terminator from Ω to α in all layout versions,
  matching the official EurKEY spec (closes #11)
- change dead key state name from "dead: Ω" to "dead: α" in v1.2/v1.3
- enable TICapsLockLanguageSwitchCapable in build script (closes #8)
- fix parser to resolve all key codes from base keyMapSets, not just
  codes in explicit layout entry ranges
- add per-version exceptions for newly-discovered v1.2/v1.4 differences
- add Karabiner-Elements docs section, known issues section to README
- add Windows spec installers for reference
- regenerate all parsed JSON specs with fixed parser

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-04 12:59:46 +01:00
parent 859c26f64c
commit 9592b321b1
31 changed files with 15212 additions and 357 deletions

View File

@@ -91,7 +91,7 @@ for ver in "${VERSIONS[@]}"; do
<key>KLInfo_${layout_name}</key>
<dict>
<key>TICapsLockLanguageSwitchCapable</key>
<false/>
<true/>
<key>TISIconIsTemplate</key>
<true/>
<key>TISInputSourceID</key>

View File

@@ -163,8 +163,11 @@ def parse_keylayout(filepath):
# resolve layouts
layouts = root.findall(".//layout")
# build resolved key maps with all key codes from all layout entries
# build resolved key maps from all layout entries
# first pass: load ALL keys from each keyMapSet (base definitions)
# second pass: override with keys from layout entries that specify ranges
resolved = {}
seen_map_sets = set()
for layout in layouts:
map_set_id = layout.get("mapSet")
first_code = int(layout.get("first", "0"))
@@ -176,8 +179,13 @@ def parse_keylayout(filepath):
resolved[idx_str] = {}
for code_str, entry in keys.items():
code = int(code_str)
if first_code <= code <= last_code:
if map_set_id not in seen_map_sets:
# first time seeing this mapSet: include all keys
resolved[idx_str][code_str] = entry
elif first_code <= code <= last_code:
# subsequent layout with same mapSet: only override in range
resolved[idx_str][code_str] = entry
seen_map_sets.add(map_set_id)
# build the final keyMaps output
key_maps = {}

View File

@@ -185,7 +185,12 @@ V1_2_EXCEPTIONS = {
# Shift+Option S: v1.2 has § where v1.3 has ẞ (capital sharp s)
"4:1": {"output": "§"},
# v1.2 does not have the ¬ (negation) dead key — added in v1.3
# instead, Option+- has the © dead key, and Option+\ outputs plain ¬
"_dead_key_skip": ["dead: ¬"],
"3:27": {"deadKey": "dead: ©"}, # Option+-: © dead key instead of ¬ dead key
"3:42": {"output": "¬"}, # Option+\: plain ¬ instead of ¬ dead key
"4:27": {"output": ""}, # Shift+Option+-: № instead of ✗
"5:27": {"deadKey": "dead: ©"}, # Caps+Option+-: © dead key instead of ¬ dead key
}
# v1.4 differences from v1.3:
@@ -194,6 +199,7 @@ V1_2_EXCEPTIONS = {
V1_4_EXCEPTIONS = {
"2:10": {"output": ""}, # Caps: §/` → ẞ (capital sharp s)
"5:10": {"output": ""}, # Caps+Option: §/` → ẞ
"5:27": {"output": ""}, # Caps+Option+-: no output (missing ¬ dead key in this layer)
"dead:dead: ¬:extra:¬": True, # extra ¬ composition in negation dead key
}