diff --git a/src/control.js b/src/control.js index edc7d9c..556feeb 100644 --- a/src/control.js +++ b/src/control.js @@ -402,7 +402,7 @@ $('#btn-rec-folder').addEventListener('click', () => djv.openRecordingsFolder()) // ---------------------------------------------------------------- pad bank const PAD_COUNT = 20; // 5 × 4 let pads = new Array(PAD_COUNT).fill(null); // each: { path, name } or null -let activePad = -1, padPlaying = false, padLoadTarget = -1; +let activePad = -1, padPlaying = false, padLoadTarget = -1, padCapturing = -1; const padGrid = $('#pad-grid'); function savePadState() { if (djv.savePads) djv.savePads(pads); } @@ -415,7 +415,10 @@ function renderPads() { d.className = 'pad' + (p ? ' filled' : '') + (i === activePad && padPlaying ? ' active' : ''); d.dataset.i = i; d.innerHTML = '' + (i + 1) + '' + - (p ? '' + p.name.replace(/&/g, '&').replace(/' + (p ? '' + p.name.replace(/&/g, '&').replace(/' + + '' + + '' : '+'); padGrid.appendChild(d); }); @@ -452,6 +455,7 @@ padGrid.addEventListener('click', (e) => { if (!pad) return; const i = parseInt(pad.dataset.i, 10); if (e.target.closest('.pad-x')) { e.stopPropagation(); clearPad(i); return; } + if (e.target.closest('.pad-key')) { e.stopPropagation(); padCapturing = padCapturing === i ? -1 : i; renderPads(); return; } playPad(i); }); padGrid.addEventListener('contextmenu', (e) => { @@ -568,6 +572,19 @@ window.addEventListener('keydown', (e) => { renderSequence(); return; } + // Assigning a hotkey to a pad. + if (padCapturing >= 0) { + e.preventDefault(); + if (e.key !== 'Escape' && e.key.length === 1) { + const k = e.key.toLowerCase(); + pads.forEach(p => { if (p && p.key === k) p.key = null; }); // keys are unique + if (pads[padCapturing]) pads[padCapturing].key = k; + savePadState(); + } + padCapturing = -1; + renderPads(); + return; + } if (e.target.tagName === 'INPUT' && e.target.type === 'text') return; @@ -577,6 +594,8 @@ window.addEventListener('keydown', (e) => { if (hk >= 0) { playIndex(hk); return; } const ek = sequence.findIndex(s => s.key === lk); if (ek >= 0) { applySeqIndex(ek); return; } + const pk = pads.findIndex(p => p && p.key === lk); + if (pk >= 0) { playPad(pk); return; } // Number keys 1-9 apply the first nine sequence slots. if (e.key >= '1' && e.key <= '9') { applySeqIndex(parseInt(e.key, 10) - 1); return; } diff --git a/src/style.css b/src/style.css index 549be81..b889cd5 100644 --- a/src/style.css +++ b/src/style.css @@ -207,6 +207,24 @@ body.control select { width: 100%; max-width: 100%; } width: auto; } .pad:hover .pad-x { opacity: 0.9; } +.pad-key { + position: absolute; + bottom: 2px; + right: 3px; + background: rgba(255,255,255,0.12); + border: none; + color: #cdd6ff; + font-size: 9px; + font-weight: 700; + line-height: 1; + padding: 2px 4px; + border-radius: 4px; + min-width: 14px; + width: auto; + flex: none; + opacity: 0.85; +} +.pad-key:hover { background: rgba(120,150,255,0.45); } /* ---- Recording status ---- */ .rec-status {