mirror of
https://github.com/felixfoertsch/EurKEY-macOS.git
synced 2026-04-16 06:28:28 +02:00
update v2.0 layout, fix keyboard viewer dead key cycling, clean up repo
- remove duplicate compositions from v2.0: § from Navigators, ± from Option+Shift §, ± from Mathematicians on -, terminator dupes on 5 - change Mathematicians terminator from space to 𝕄 - fix keyboard viewer: support multiple dead keys per key with click cycling, show active dead key's own layer character, hide others - add feature card SVG icons (dead keys, ISO enter, versions, install) - delete unused draft SVGs, remove leftover docs/ PDFs Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,13 +0,0 @@
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024">
|
|
||||||
<!-- Draft C: Single key cap with EU star — minimal, reads well at any size -->
|
|
||||||
<rect width="1024" height="1024" rx="180" fill="#003399"/>
|
|
||||||
<!-- Large key cap shape, centered -->
|
|
||||||
<rect x="172" y="172" width="680" height="680" rx="80" fill="rgba(255,255,255,0.92)"
|
|
||||||
stroke="rgba(255,255,255,0.3)" stroke-width="8"/>
|
|
||||||
<!-- Key shadow/depth -->
|
|
||||||
<rect x="172" y="180" width="680" height="680" rx="80" fill="none"
|
|
||||||
stroke="rgba(0,0,0,0.08)" stroke-width="8"/>
|
|
||||||
<!-- Single EU gold star centered on key -->
|
|
||||||
<polygon points="512,220 568,398 756,398 604,506 646,680 512,580 378,680 420,506 268,398 456,398"
|
|
||||||
fill="#FFCC00"/>
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 699 B |
@@ -1,7 +0,0 @@
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024">
|
|
||||||
<!-- Template icon: "EU" — transparent bg, black text
|
|
||||||
macOS TISIconIsTemplate renders this adaptively:
|
|
||||||
light mode: dark text, light pill background
|
|
||||||
dark mode: light text, dark pill background -->
|
|
||||||
<text x="512" y="700" text-anchor="middle" font-family="'SF Pro Text', '.AppleSystemUIFont', 'Helvetica Neue', sans-serif" font-size="620" font-weight="600" fill="#000" letter-spacing="-10">EU</text>
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 490 B |
@@ -1,4 +0,0 @@
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024">
|
|
||||||
<!-- Template icon: "EUR" text — macOS renders black in light mode, white in dark mode -->
|
|
||||||
<text x="512" y="640" text-anchor="middle" font-family="-apple-system, BlinkMacSystemFont, 'SF Pro Display', 'Helvetica Neue', sans-serif" font-size="480" font-weight="700" fill="#000" letter-spacing="-20">EUR</text>
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 384 B |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
8
eurkey-macos.eu/img/icon-deadkeys.svg
Normal file
8
eurkey-macos.eu/img/icon-deadkeys.svg
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" fill="none">
|
||||||
|
<!-- Key cap with accent mark -->
|
||||||
|
<rect x="8" y="12" width="32" height="28" rx="4" stroke="#003399" stroke-width="2.5" fill="none"/>
|
||||||
|
<!-- Letter a on key -->
|
||||||
|
<text x="24" y="35" text-anchor="middle" font-family="-apple-system, system-ui, sans-serif" font-size="16" font-weight="700" fill="#003399">a</text>
|
||||||
|
<!-- Accent mark floating above key -->
|
||||||
|
<path d="M20 8 L24 4 L28 8" stroke="#003399" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" fill="none"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 558 B |
7
eurkey-macos.eu/img/icon-iso.svg
Normal file
7
eurkey-macos.eu/img/icon-iso.svg
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" fill="none">
|
||||||
|
<!-- ISO Enter key shape (inverted L) -->
|
||||||
|
<path d="M18 6 H38 Q42 6 42 10 V38 Q42 42 38 42 H26 Q22 42 22 38 V22 H10 Q6 22 6 18 V10 Q6 6 10 6 Z" stroke="#003399" stroke-width="2.5" fill="none"/>
|
||||||
|
<!-- Enter arrow -->
|
||||||
|
<path d="M36 18 V30 H28" stroke="#003399" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M31 27 L28 30 L31 33" stroke="#003399" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 521 B |
@@ -54,22 +54,22 @@
|
|||||||
<h2>Features</h2>
|
<h2>Features</h2>
|
||||||
<div class="feature-grid">
|
<div class="feature-grid">
|
||||||
<div class="feature-card">
|
<div class="feature-card">
|
||||||
<div class="feature-icon">⌥</div>
|
<div class="feature-icon"><img src="img/icon-deadkeys.svg" alt="" width="36" height="36"></div>
|
||||||
<h3>Dead Keys for Diacritics</h3>
|
<h3>Dead Keys for Diacritics</h3>
|
||||||
<p>Type accented characters (ä, é, ñ, č, …) using intuitive Option-key combinations. No character palette needed.</p>
|
<p>Type accented characters (ä, é, ñ, č, …) using intuitive Option-key combinations. No character palette needed.</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="feature-card">
|
<div class="feature-card">
|
||||||
<div class="feature-icon">⌨</div>
|
<div class="feature-icon"><img src="img/icon-iso.svg" alt="" width="36" height="36"></div>
|
||||||
<h3>ISO International Layout</h3>
|
<h3>ISO International Layout</h3>
|
||||||
<p>Built for the physical English International keyboard found on European MacBooks — with the extra § key and big Enter.</p>
|
<p>Built for the physical English International keyboard found on European MacBooks — with the extra § key and big Enter.</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="feature-card">
|
<div class="feature-card">
|
||||||
<div class="feature-icon">◇</div>
|
<div class="feature-icon"><img src="img/icon-versions.svg" alt="" width="36" height="36"></div>
|
||||||
<h3>Multiple Versions</h3>
|
<h3>Multiple Versions</h3>
|
||||||
<p>Ships v1.2, v1.3, v1.4, and v2.0 in a single bundle. Pick the one that fits your workflow.</p>
|
<p>Ships v1.2, v1.3, v1.4, and v2.0 in a single bundle. Pick the one that fits your workflow.</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="feature-card">
|
<div class="feature-card">
|
||||||
<div class="feature-icon">↓</div>
|
<div class="feature-icon"><img src="img/icon-install.svg" alt="" width="36" height="36"></div>
|
||||||
<h3>Easy Install</h3>
|
<h3>Easy Install</h3>
|
||||||
<p>Download the DMG, drag the bundle to Keyboard Layouts, log out. Done in under a minute.</p>
|
<p>Download the DMG, drag the bundle to Keyboard Layouts, log out. Done in under a minute.</p>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ const DEAD_KEY_NAMES = {
|
|||||||
"\u00af": "The Macrons", "\u02da": "The Rings & Dots",
|
"\u00af": "The Macrons", "\u02da": "The Rings & Dots",
|
||||||
"\u03b1": "The Greeks", "\u221a": "The Mathematicians",
|
"\u03b1": "The Greeks", "\u221a": "The Mathematicians",
|
||||||
"\u00ac": "The Navigators", "\u00a9": "The Navigators",
|
"\u00ac": "The Navigators", "\u00a9": "The Navigators",
|
||||||
" ": "The Mathematicians",
|
"\uD835\uDD44": "The Mathematicians",
|
||||||
};
|
};
|
||||||
|
|
||||||
const cache = new Map();
|
const cache = new Map();
|
||||||
@@ -186,8 +186,7 @@ function renderKeyboard(data) {
|
|||||||
} else {
|
} else {
|
||||||
keyElements.set(keyCode, keyEl);
|
keyElements.set(keyCode, keyEl);
|
||||||
|
|
||||||
let hasDead = false;
|
const deadStates = [];
|
||||||
let deadState = null;
|
|
||||||
|
|
||||||
for (const layer of LAYERS) {
|
for (const layer of LAYERS) {
|
||||||
const info = charForKey(data, layer.mod, keyCode);
|
const info = charForKey(data, layer.mod, keyCode);
|
||||||
@@ -196,18 +195,19 @@ function renderKeyboard(data) {
|
|||||||
if (info) {
|
if (info) {
|
||||||
span.textContent = displayChar(info.char);
|
span.textContent = displayChar(info.char);
|
||||||
if (info.deadKey) {
|
if (info.deadKey) {
|
||||||
hasDead = true;
|
if (!deadStates.includes(info.deadKey)) deadStates.push(info.deadKey);
|
||||||
deadState = info.deadKey;
|
|
||||||
span.classList.add("key-char--is-dead");
|
span.classList.add("key-char--is-dead");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
keyEl.appendChild(span);
|
keyEl.appendChild(span);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hasDead) {
|
if (deadStates.length > 0) {
|
||||||
|
deadStates.reverse();
|
||||||
keyEl.classList.add("key--dead");
|
keyEl.classList.add("key--dead");
|
||||||
keyEl.dataset.deadKey = deadState;
|
keyEl.dataset.deadKey = deadStates[0];
|
||||||
keyEl.addEventListener("click", () => toggleDeadKeyMode(deadState));
|
keyEl.dataset.deadKeys = JSON.stringify(deadStates);
|
||||||
|
keyEl.addEventListener("click", () => cycleDeadKeyMode(keyEl));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -228,6 +228,23 @@ function toggleDeadKeyMode(deadState) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function cycleDeadKeyMode(keyEl) {
|
||||||
|
const deadStates = JSON.parse(keyEl.dataset.deadKeys || "[]");
|
||||||
|
if (deadStates.length === 0) return;
|
||||||
|
|
||||||
|
if (!currentDeadKey || !deadStates.includes(currentDeadKey)) {
|
||||||
|
enterDeadKeyMode(deadStates[0]);
|
||||||
|
} else {
|
||||||
|
const idx = deadStates.indexOf(currentDeadKey);
|
||||||
|
const next = idx + 1;
|
||||||
|
if (next < deadStates.length) {
|
||||||
|
enterDeadKeyMode(deadStates[next]);
|
||||||
|
} else {
|
||||||
|
exitDeadKeyMode();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function enterDeadKeyMode(deadState) {
|
function enterDeadKeyMode(deadState) {
|
||||||
if (!currentData) return;
|
if (!currentData) return;
|
||||||
const charMap = buildCompositionMap(currentData, deadState);
|
const charMap = buildCompositionMap(currentData, deadState);
|
||||||
@@ -260,6 +277,21 @@ function enterDeadKeyMode(deadState) {
|
|||||||
const baseComposed = charMap[baseChar] || "";
|
const baseComposed = charMap[baseChar] || "";
|
||||||
const shiftComposed = charMap[shiftChar] || "";
|
const shiftComposed = charMap[shiftChar] || "";
|
||||||
|
|
||||||
|
const allDead = JSON.parse(keyEl.dataset.deadKeys || "[]");
|
||||||
|
if (allDead.includes(deadState)) {
|
||||||
|
keyEl.classList.add("key--dead-active");
|
||||||
|
// only show the span for the layer that owns this dead key
|
||||||
|
const spans = keyEl.querySelectorAll(".key-char");
|
||||||
|
const layerOrder = [MOD_SHIFT, MOD_OPTION_SHIFT, MOD_BASE, MOD_OPTION];
|
||||||
|
for (let i = 0; i < spans.length; i++) {
|
||||||
|
const info = charForKey(currentData, layerOrder[i], keyCode);
|
||||||
|
if (info?.deadKey === deadState) {
|
||||||
|
spans[i].style.visibility = "visible";
|
||||||
|
} else {
|
||||||
|
spans[i].style.visibility = "hidden";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
const spans = keyEl.querySelectorAll(".key-char");
|
const spans = keyEl.querySelectorAll(".key-char");
|
||||||
// order: shift, option-shift, base, option
|
// order: shift, option-shift, base, option
|
||||||
if (spans[0]) spans[0].textContent = displayChar(shiftComposed);
|
if (spans[0]) spans[0].textContent = displayChar(shiftComposed);
|
||||||
@@ -267,9 +299,7 @@ function enterDeadKeyMode(deadState) {
|
|||||||
if (spans[2]) spans[2].textContent = displayChar(baseComposed);
|
if (spans[2]) spans[2].textContent = displayChar(baseComposed);
|
||||||
if (spans[3]) spans[3].textContent = "";
|
if (spans[3]) spans[3].textContent = "";
|
||||||
|
|
||||||
if (keyEl.dataset.deadKey === deadState) {
|
if (baseComposed || shiftComposed) {
|
||||||
keyEl.classList.add("key--dead-active");
|
|
||||||
} else if (baseComposed || shiftComposed) {
|
|
||||||
keyEl.classList.add("key--has-composition");
|
keyEl.classList.add("key--has-composition");
|
||||||
keyEl.classList.remove("key--no-composition");
|
keyEl.classList.remove("key--no-composition");
|
||||||
} else {
|
} else {
|
||||||
@@ -278,6 +308,7 @@ function enterDeadKeyMode(deadState) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function exitDeadKeyMode() {
|
function exitDeadKeyMode() {
|
||||||
if (!currentDeadKey || !currentData) return;
|
if (!currentDeadKey || !currentData) return;
|
||||||
@@ -302,6 +333,7 @@ function exitDeadKeyMode() {
|
|||||||
for (let i = 0; i < spans.length; i++) {
|
for (let i = 0; i < spans.length; i++) {
|
||||||
const info = charForKey(currentData, layerOrder[i], keyCode);
|
const info = charForKey(currentData, layerOrder[i], keyCode);
|
||||||
spans[i].textContent = info ? displayChar(info.char) : "";
|
spans[i].textContent = info ? displayChar(info.char) : "";
|
||||||
|
spans[i].style.visibility = "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -508,7 +508,7 @@
|
|||||||
<key code="7" output="Á"/>
|
<key code="7" output="Á"/>
|
||||||
<key code="8" output="Ç"/>
|
<key code="8" output="Ç"/>
|
||||||
<key code="9" output="Ì"/>
|
<key code="9" output="Ì"/>
|
||||||
<key code="10" output="±"/>
|
<key code="10" output=""/>
|
||||||
<key code="11" output="Í"/>
|
<key code="11" output="Í"/>
|
||||||
<key code="12" action="Æ"/>
|
<key code="12" action="Æ"/>
|
||||||
<key code="13" output="Å"/>
|
<key code="13" output="Å"/>
|
||||||
@@ -1093,7 +1093,6 @@
|
|||||||
<action id="-">
|
<action id="-">
|
||||||
<when state="none" output="-"/>
|
<when state="none" output="-"/>
|
||||||
<when state="⌥m" output="⁻"/>
|
<when state="⌥m" output="⁻"/>
|
||||||
<when state="⌥⇧m" output="±"/>
|
|
||||||
</action>
|
</action>
|
||||||
<action id=".">
|
<action id=".">
|
||||||
<when state="none" output="."/>
|
<when state="none" output="."/>
|
||||||
@@ -1132,10 +1131,6 @@
|
|||||||
<action id="5">
|
<action id="5">
|
||||||
<when state="none" output="5"/>
|
<when state="none" output="5"/>
|
||||||
<when state="⌥\" output="⅔"/>
|
<when state="⌥\" output="⅔"/>
|
||||||
<when state="⌥⇧7" output="¯"/>
|
|
||||||
<when state="⌥'" output="´"/>
|
|
||||||
<when state="⌥⇧6" output="ˇ"/>
|
|
||||||
<when state="⌥7" output="˚"/>
|
|
||||||
<when state="⌥m" output="₅"/>
|
<when state="⌥m" output="₅"/>
|
||||||
</action>
|
</action>
|
||||||
<action id="6">
|
<action id="6">
|
||||||
@@ -1584,7 +1579,6 @@
|
|||||||
<action id="s">
|
<action id="s">
|
||||||
<when state="none" output="s"/>
|
<when state="none" output="s"/>
|
||||||
<when state="⌥6" output="ŝ"/>
|
<when state="⌥6" output="ŝ"/>
|
||||||
<when state="⌥\" output="§"/>
|
|
||||||
<when state="⌥'" output="ś"/>
|
<when state="⌥'" output="ś"/>
|
||||||
<when state="⌥⇧6" output="š"/>
|
<when state="⌥⇧6" output="š"/>
|
||||||
<when state="⌥m" output="σ"/>
|
<when state="⌥m" output="σ"/>
|
||||||
@@ -1775,6 +1769,6 @@
|
|||||||
<when state="⌥⇧6" output="ˇ"/>
|
<when state="⌥⇧6" output="ˇ"/>
|
||||||
<when state="⌥7" output="˚"/>
|
<when state="⌥7" output="˚"/>
|
||||||
<when state="⌥m" output="α"/>
|
<when state="⌥m" output="α"/>
|
||||||
<when state="⌥⇧m" output=" "/>
|
<when state="⌥⇧m" output="𝕄"/>
|
||||||
</terminators>
|
</terminators>
|
||||||
</keyboard>
|
</keyboard>
|
||||||
|
|||||||
Reference in New Issue
Block a user