v2.4 : choix du clavier azerty ou qwerty

This commit is contained in:
lrdlg
2026-07-21 06:39:45 +02:00
parent 166ec447d5
commit 55eabec68c
6 changed files with 949 additions and 23 deletions
+69 -9
View File
@@ -136,7 +136,18 @@
}
.bkey:active,.bkey.pressed{background:#3A362C}
.bkey.outkey{background:#4B4739}
.kbd-hint{font-size:.55rem;color:var(--silk-light);opacity:.4;margin-top:.5rem;letter-spacing:.08em}
.kbd-hint{font-size:.55rem;color:var(--silk-light);opacity:.4;letter-spacing:.08em}
.kbd-foot{display:flex;align-items:center;justify-content:space-between;gap:.6rem;margin-top:.5rem;flex-wrap:wrap}
.seg{display:inline-flex;border:1px solid #4A4436;border-radius:6px;overflow:hidden;flex:none}
.segbtn{
background:var(--module-2);border:none;
color:var(--silk-light);font-family:var(--mono);
font-size:.55rem;letter-spacing:.1em;
padding:.28rem .5rem;cursor:pointer;opacity:.5;
}
.segbtn + .segbtn{border-left:1px solid #4A4436}
.segbtn.on{background:#4A4436;color:var(--led-on);opacity:1}
.segbtn:focus-visible{outline:2px solid var(--led-on);outline-offset:-2px}
/* ---------- Colonne voicing ---------- */
.side{display:flex;flex-direction:column;gap:.65rem}
@@ -220,6 +231,15 @@
}
footer{margin-top:1rem;font-size:.55rem;opacity:.5;letter-spacing:.1em;text-align:right}
footer .doclink{
color:var(--silk);text-decoration:none;
border-bottom:1px solid rgba(64,58,47,.45);
padding-bottom:1px;
}
footer .doclink:hover,footer .doclink:focus-visible{
color:var(--accent);border-bottom-color:var(--accent);outline:none;
}
footer .docsep{margin:0 .35rem;opacity:.5}
@media (max-width:900px){
.deck{grid-template-columns:1fr}
@@ -234,7 +254,7 @@
<body>
<div class="unit">
<header>
<h1><span>_chordlab.v2</span></h1>
<h1>_chordlab <span>ORC·v2</span></h1>
<div class="sub">chord ideas machine · underscorelab / leradiologue</div>
</header>
@@ -291,7 +311,12 @@
<div class="mod kbd-mod">
<h2>Root</h2>
<div class="kbd" id="kbd"></div>
<div class="kbd-hint">clavier PC : A W S E D F T G Y H U J · ␣ = ADD · ← → = voicing</div>
<div class="kbd-foot">
<span class="kbd-hint" id="kbdHint">clavier PC : A W S E D F T G Y H U J · ␣ = ADD · ← → = voicing</span>
<span class="seg" role="group" aria-label="Disposition du clavier">
<button class="segbtn" id="layQwerty" aria-pressed="false">QWERTY</button><button class="segbtn on" id="layAzerty" aria-pressed="true">AZERTY</button>
</span>
</div>
</div>
<!-- Voicing / drop / slash / bass / key -->
@@ -435,7 +460,13 @@
</div>
</div>
<footer>_chordlab v2.3 · logique d'accords</footer>
<footer>
<a href="tuto.html" class="doclink">Manuel (FR)</a>
<span class="docsep">·</span>
<a href="tuto_en.html" class="doclink">Manual (EN)</a>
<span class="docsep">·</span>
_chordlab v2.4 · underscorelab / leradiologue
</footer>
</div>
<script>
@@ -466,6 +497,7 @@ const state = {
vlAuto:false,
perf:"block", rate:0.25,
humanize:false,
layout:(navigator.language||"").toLowerCase().startsWith("fr") ? "azerty" : "qwerty",
};
/* ---------- Moteur d'accords ---------- */
@@ -875,6 +907,7 @@ function saveSession(){
drop:state.drop, slash:state.slash, bass:state.bass, bassOct:state.bassOct,
keyMode:state.keyMode, keyRoot:state.keyRoot, keyScale:state.keyScale,
perf:state.perf, rate:state.rate, humanize:state.humanize,
layout:state.layout,
bpm:getBpm(), vlAuto:state.vlAuto,
},
progression:state.progression,
@@ -905,6 +938,7 @@ function loadSession(file){
state.perf=s.perf||"block";
state.rate=s.rate||0.25;
state.humanize=!!s.humanize;
state.layout=(s.layout==="qwerty")?"qwerty":(s.layout==="azerty"?"azerty":state.layout);
state.vlAuto=!!s.vlAuto;
state.progression=Array.isArray(d.progression)?d.progression:[];
state.progression.forEach(c=>{ c.beats=Math.max(1,Math.min(16,c.beats||4)); });
@@ -927,6 +961,7 @@ function syncUiFromState(){
$("keyScaleSel").value=state.keyScale;
$("perfSel").value=state.perf; $("rateSel").value=state.rate;
$("humanBtn").classList.toggle("on", state.humanize);
setLayout(state.layout);
$("vlBtn").classList.toggle("on", state.vlAuto);
$("lcdDrop").textContent=state.drop.toUpperCase();
$("lcdPerf").textContent=$("perfSel").selectedOptions[0].textContent.toUpperCase();
@@ -1006,21 +1041,45 @@ kbdEl.addEventListener("pointerdown",ev=>{
kbdEl.addEventListener("pointerup",ev=>{
ev.target.classList&&ev.target.classList.remove("pressed");
});
const PCKEYS={a:0,w:1,s:2,e:3,d:4,f:5,t:6,g:7,y:8,h:9,u:10,j:11};
/* Dispositions clavier : mêmes touches physiques, lettres différentes.
Sur AZERTY, A→Q et W→Z ; le reste de la rangée est identique. */
const KEYMAPS = {
qwerty:{a:0,w:1,s:2,e:3,d:4,f:5,t:6,g:7,y:8,h:9,u:10,j:11},
azerty:{q:0,z:1,s:2,e:3,d:4,f:5,t:6,g:7,y:8,h:9,u:10,j:11},
};
const KEYHINT = {
qwerty:"clavier PC : A W S E D F T G Y H U J · ␣ = ADD · ← → = voicing",
azerty:"clavier PC : Q Z S E D F T G Y H U J · ␣ = ADD · ← → = voicing",
};
function pcKeys(){ return KEYMAPS[state.layout]; }
function setLayout(l, silent){
state.layout = (l==="qwerty") ? "qwerty" : "azerty";
const isQ = state.layout==="qwerty";
$("layQwerty").classList.toggle("on", isQ);
$("layAzerty").classList.toggle("on", !isQ);
$("layQwerty").setAttribute("aria-pressed", isQ);
$("layAzerty").setAttribute("aria-pressed", !isQ);
$("kbdHint").textContent = KEYHINT[state.layout];
}
window.addEventListener("keydown",ev=>{
if (ev.repeat||ev.target.tagName==="INPUT"||ev.target.tagName==="SELECT") return;
const k=ev.key.toLowerCase();
if (k in PCKEYS){
keyEls[PCKEYS[k]].classList.add("pressed");
triggerChord(PCKEYS[k]);
const map=pcKeys();
if (k in map){
keyEls[map[k]].classList.add("pressed");
triggerChord(map[k]);
} else if (ev.code==="Space"){ ev.preventDefault(); addToProgression(); }
else if (ev.key==="ArrowRight"){ setVoicing(state.voicing+1); }
else if (ev.key==="ArrowLeft"){ setVoicing(state.voicing-1); }
});
window.addEventListener("keyup",ev=>{
const k=ev.key.toLowerCase();
if (k in PCKEYS) keyEls[PCKEYS[k]].classList.remove("pressed");
const map=pcKeys();
if (k in map) keyEls[map[k]].classList.remove("pressed");
});
$("layQwerty").addEventListener("click",()=>setLayout("qwerty"));
$("layAzerty").addEventListener("click",()=>setLayout("azerty"));
/* knob voicing */
const knob=$("voicingKnob");
@@ -1270,6 +1329,7 @@ $("fileInput").addEventListener("change",function(){
/* init */
buildKeyboard();
setLayout(state.layout);
renderProgression();
refreshKeyDimming();
setVoicing(0,true);