From e798a9a53aa5c61f6ea9fca47f6ce991983ef951 Mon Sep 17 00:00:00 2001 From: ed Date: Wed, 3 Sep 2025 19:33:48 +0000 Subject: [PATCH] fix hotkeys on dvorak (closes #298, closes #733); apparently the convention is that hotkeys should follow the letters according to the layout, and not remain in the qwerty position this breaks apart the cluster of media controls (uiojkl), but that's the intended and expected behavior so it should be fine --- contrib/plugins/quickmove.js | 6 +-- copyparty/web/baguettebox.js | 56 +++++++++++++----------- copyparty/web/browser.js | 83 ++++++++++++++++++++---------------- copyparty/web/md2.js | 65 ++++++++++++++++------------ copyparty/web/up2k.js | 12 ++++-- copyparty/web/util.js | 4 +- 6 files changed, 128 insertions(+), 98 deletions(-) diff --git a/contrib/plugins/quickmove.js b/contrib/plugins/quickmove.js index 34b3a0d3..3a0381df 100644 --- a/contrib/plugins/quickmove.js +++ b/contrib/plugins/quickmove.js @@ -101,10 +101,10 @@ function our_hotkey_handler(e) { // bail if either ALT, CTRL, or SHIFT is pressed - if (e.altKey || e.shiftKey || e.isComposing || ctrl(e)) + if (anymod(e)) return main_hotkey_handler(e); // let copyparty handle this keystroke - var key_name = (e.code || e.key) + '', + var keycode = (e.key || e.code) + '', ae = document.activeElement, aet = ae && ae != document.body ? ae.nodeName.toLowerCase() : ''; @@ -114,7 +114,7 @@ if (aet && !/^(a|button|tr|td|div|pre)$/.test(aet)) return main_hotkey_handler(e); // let copyparty handle this keystroke - if (key_name == 'KeyW') { + if (keycode == 'w' || keycode == 'KeyW') { // okay, this one's for us... do the thing action_to_perform(); return ev(e); diff --git a/copyparty/web/baguettebox.js b/copyparty/web/baguettebox.js index 9a298e7b..ef5b81f7 100644 --- a/copyparty/web/baguettebox.js +++ b/copyparty/web/baguettebox.js @@ -278,23 +278,30 @@ window.baguetteBox = (function () { if (modal.busy) return; - if (e.key == '?') - return halp(); - if (anymod(e, true)) return; - var k = (e.code || e.key) + '', v = vid(), pos = -1; + var k = (e.key || e.code) + '', v = vid(); - if (k == "BracketLeft") + if (k.startsWith('Key')) + k = k.slice(3); + else if (k.startsWith('Digit')) + k = k.slice(5); + + var kl = k.toLowerCase(); + + if (k == '?') + return halp(); + + if (k == "[" || k == "BracketLeft") setloop(1); - else if (k == "BracketRight") + else if (k == "]" || k == "BracketRight") setloop(2); - else if (e.shiftKey && k != "KeyR" && k != "R") + else if (e.shiftKey && kl != "r") return; - else if (k == "ArrowLeft" || k == "KeyJ" || k == "Left" || k == "j") + else if (k == "ArrowLeft" || k == "Left" || kl == "j") showPreviousImage(); - else if (k == "ArrowRight" || k == "KeyL" || k == "Right" || k == "l") + else if (k == "ArrowRight" || k == "Right" || kl == "l") showNextImage(); else if (k == "Escape" || k == "Esc") hideOverlay(); @@ -302,33 +309,33 @@ window.baguetteBox = (function () { showFirstImage(e); else if (k == "End") showLastImage(e); - else if (k == "Space" || k == "KeyP" || k == "KeyK") + else if (k == "Space" || k == "Spacebar" || kl == " " || kl == "p" || kl == "k") playpause(); - else if (k == "KeyU" || k == "KeyO") - relseek(k == "KeyU" ? -10 : 10); - else if (k.indexOf('Digit') === 0 && v) - v.currentTime = v.duration * parseInt(k.slice(-1)) * 0.1; - else if (k == "KeyM" && v) { + else if (kl == "u" || kl == "o") + relseek(kl == "u" ? -10 : 10); + else if (v && /^[0-9]$/.test(k)) + v.currentTime = v.duration * parseInt(k) * 0.1; + else if (kl == "m" && v) { v.muted = vmute = !vmute; mp_ctl(); } - else if (k == "KeyV" && v) { + else if (kl == "v" && v) { vloop = !vloop; vnext = vnext && !vloop; setVmode(); } - else if (k == "KeyC" && v) { + else if (kl == "c" && v) { vnext = !vnext; vloop = vloop && !vnext; setVmode(); } - else if (k == "KeyF") + else if (kl == "f") tglfull(); - else if (k == "KeyS" || k == "s") + else if (kl == "s") tglsel(); - else if (k == "KeyR" || k == "r" || k == "R") + else if (kl == "r") rotn(e.shiftKey ? -1 : 1); - else if (k == "KeyY") + else if (kl == "y") dlpic(); } @@ -450,10 +457,11 @@ window.baguetteBox = (function () { if (anymod(e)) return; - var k = e.code + ''; + var k = (e.key || e.code) + ''; - if (k == "Space") - ev(e); + if (k == "Space" || k == "Spacebar" || k == " ") { + return ev(e); + } } var passiveSupp = false; diff --git a/copyparty/web/browser.js b/copyparty/web/browser.js index ba92fd49..f6cea77d 100644 --- a/copyparty/web/browser.js +++ b/copyparty/web/browser.js @@ -11787,6 +11787,7 @@ var ACtx = !IPHONE && (window.AudioContext || window.webkitAudioContext), hash0 = location.hash, sloc0 = '' + location, noih = /[?&]v\b/.exec(sloc0), + dbg_kbd = /[?&]dbgkbd\b/.exec(sloc0), abrt_key = "", rtt = null, ldks = [], @@ -14528,7 +14529,7 @@ var fileman = (function () { exm.onkeydown = exh.onkeydown = exd.onkeydown = sh_k.onkeydown = sh_pw.onkeydown = function (e) { - var kc = (e.code || e.key) + ''; + var kc = (e.key || e.code) + ''; if (kc.endsWith('Enter')) sh_apply.click(); }; @@ -14737,7 +14738,7 @@ var fileman = (function () { (function (a) { f[a].inew.onkeydown = function (e) { rn_ok(a, true); - var kc = (e.code || e.key) + ''; + var kc = (e.key || e.code) + ''; if (kc.endsWith('Enter')) return rn_apply(); }; @@ -14835,7 +14836,7 @@ var fileman = (function () { spresets(); ire.onkeydown = ifmt.onkeydown = function (e) { - var k = (e.code || e.key) + ''; + var k = (e.key || e.code) + ''; if (k == 'Escape' || k == 'Esc') return rn_cancel(); @@ -15307,7 +15308,7 @@ var fileman = (function () { (function (a) { var inew = ebi('rn_new_' + a); inew.onkeydown = function (e) { - if (((e.code || e.key) + '').endsWith('Enter')) + if (((e.key || e.code) + '').endsWith('Enter')) return rn_apply(); }; inew.oninput = function (e) { @@ -16493,10 +16494,20 @@ var ahotkeys = function (e) { if (QS('#bbox-overlay.visible') || modal.busy) return; - var k = (e.code || e.key) + '', pos = -1, n, + var k = (e.key || e.code) + '', pos = -1, n, ae = document.activeElement, aet = ae && ae != document.body ? ae.nodeName.toLowerCase() : ''; + if (k.startsWith('Key')) + k = k.slice(3); + else if (k.startsWith('Digit')) + k = k.slice(5); + + var kl = k.toLowerCase(); + + if (dbg_kbd) + console.log('KBD', k, kl, e.key, e.code, e.keyCode, e.which); + if (k == 'Escape' || k == 'Esc') { ae && ae.blur(); tt.hide(); @@ -16544,7 +16555,7 @@ var ahotkeys = function (e) { fselfunw(e, ae, d, rem); return ev(e); } - if (k == 'Space' || k == 'Spacebar') { + if (k == 'Space' || k == 'Spacebar' || k == ' ') { clmod(ae, 'sel', 't'); msel.origin_tr(ae); msel.selui(); @@ -16552,7 +16563,7 @@ var ahotkeys = function (e) { } } if (in_ftab || !aet || (ae && ae.closest('#ggrid'))) { - if ((k == 'KeyA' || k == 'a') && ctrl(e)) { + if ((kl == 'a') && ctrl(e)) { var ntot = treectl.lsc.files.length + treectl.lsc.dirs.length, sel = msel.getsel(), all = msel.getall(); @@ -16568,7 +16579,7 @@ var ahotkeys = function (e) { } if (ae && ae.closest('pre')) { - if ((k == 'KeyA' || k == 'a') && ctrl(e)) { + if ((kl == 'a') && ctrl(e)) { var sel = document.getSelection(), ran = document.createRange(); @@ -16585,107 +16596,105 @@ var ahotkeys = function (e) { if (aet && aet != 'a' && aet != 'tr' && aet != 'td' && aet != 'div' && aet != 'pre') return; - if (e.key == '?') + if (k == '?') return hkhelp(); if (!e.shiftKey && ctrl(e)) { var sel = window.getSelection && window.getSelection() || {}; sel = sel && !sel.isCollapsed && sel.direction != 'none'; - if (k == 'KeyX' || k == 'x') + if (kl == 'x') return fileman.cut(e); - if ((k == 'KeyC' || k == 'c') && !sel) + if (kl == 'c' && !sel) return fileman.cpy(e); - if (k == 'KeyV' || k == 'v') + if (kl == 'v') return fileman.d_paste(e); - if (k == 'KeyK' || k == 'k') + if (kl == 'k') return fileman.delete(e); return; } - if (e.shiftKey && k != 'KeyA' && k != 'KeyD' && k != 'A' && k != 'D') + if (e.shiftKey && kl != 'a' && kl != 'd') return; - if (k.indexOf('Digit') === 0) - pos = parseInt(k.slice(-1)) * 0.1; + if (/^[0-9]$/.test(k)) + pos = parseInt(k) * 0.1; if (pos !== -1) return seek_au_mul(pos) || true; - if (k == 'KeyJ' || k == 'j') + if (kl == 'j') return prev_song() || true; - if (k == 'KeyL' || k == 'l') + if (kl == 'l') return next_song() || true; - if (k == 'KeyP' || k == 'p') + if (kl == 'p') return playpause() || true; - n = (k == 'KeyU' || k == 'u') ? -10 : - (k == 'KeyO' || k == 'o') ? 10 : 0; + n = kl == 'u' ? -10 : kl == 'o' ? 10 : 0; if (n !== 0) return seek_au_rel(n) || true; - if (k == 'KeyY') + if (kl == 'y') return msel.getsel().length ? ebi('seldl').click() : showfile.active() ? ebi('dldoc').click() : dl_song(); - n = (k == 'KeyI' || k == 'i') ? -1 : - (k == 'KeyK' || k == 'k') ? 1 : 0; + n = kl == 'i' ? -1 : kl == 'k' ? 1 : 0; if (n !== 0) return tree_neigh(n, 1); - if (k == 'KeyM' || k == 'm') + if (kl == 'm') return tree_up(); - if (k == 'KeyB' || k == 'b') + if (kl == 'b') return treectl.hidden ? treectl.entree() : treectl.detree(); - if (k == 'KeyG' || k == 'g') + if (kl == 'g') return ebi('griden').click(); - if (k == 'KeyT' || k == 't') + if (kl == 't') return ebi('thumbs').click(); - if (k == 'KeyV' || k == 'v') + if (kl == 'v') return ebi('filetree').click(); if (k == 'F2') return fileman.rename(); if (!treectl.hidden && (!e.shiftKey || !thegrid.en)) { - if (k == 'KeyA' || k == 'a') + if (kl == 'a') return QS('#twig').click(); - if (k == 'KeyD' || k == 'd') + if (kl == 'd') return QS('#twobytwo').click(); } if (showfile.active()) { - if (k == 'KeyS' || k == 's') + if (kl == 's') showfile.tglsel(); - if ((k == 'KeyE' || k == 'e') && ebi('editdoc').style.display != 'none') + if (kl == 'e' && ebi('editdoc').style.display != 'none') ebi('editdoc').click(); } if (mp && mp.au && !mp.au.paused) { - if (k == 'KeyS') + if (kl == 's') return sel_song(); } if (thegrid.en) { - if (k == 'KeyS' || k == 's') + if (kl == 's') return ebi('gridsel').click(); - if (k == 'KeyA' || k == 'a') + if (kl == 'a') return QSA('#ghead a[z]')[0].click(); - if (k == 'KeyD' || k == 'd') + if (kl == 'd') return QSA('#ghead a[z]')[1].click(); } }; diff --git a/copyparty/web/md2.js b/copyparty/web/md2.js index a8229366..bb93247f 100644 --- a/copyparty/web/md2.js +++ b/copyparty/web/md2.js @@ -1,6 +1,10 @@ "use strict"; +var sloc0 = '' + location, + dbg_kbd = /[?&]dbgkbd\b/.exec(sloc0); + + // server state var server_md = dom_src.value; @@ -936,23 +940,30 @@ var set_lno = (function () { // hotkeys / toolbar (function () { - var keydown = function (ev) { - if (!ev && window.event) { - ev = window.event; + var keydown = function (e) { + if (!e && window.event) { + e = window.event; if (dev_fbw == 1) { toast.warn(10, 'hello from fallback code ;_;\ncheck console trace'); console.error('using window.event'); } } - var kc = ev.code || ev.keyCode || ev.which, + var k = (e.key || e.code) + '', editing = document.activeElement == dom_src; - //console.log(ev.key, ev.code, ev.keyCode, ev.which); - if (ctrl(ev) && (ev.code == "KeyS" || kc == 83)) { + if (k.startsWith('Key')) + k = k.slice(3); + + var kl = k.toLowerCase(); + + if (dbg_kbd) + console.log('KBD', k, kl, e.key, e.code, e.keyCode, e.which); + + if (ctrl(e) && kl == "s") { save(); return false; } - if (ev.code == "Escape" || kc == 27) { + if (k == "Escape" || k == "Esc") { var d = ebi('helpclose'); if (d) d.click(); @@ -960,46 +971,44 @@ var set_lno = (function () { if (editing) set_lno(); - if (ctrl(ev)) { - if (ev.code == "KeyE") { + if (ctrl(e)) { + if (kl == "e") { dom_nsbs.click(); return false; } if (!editing) return true; - if (ev.code == "KeyH" || kc == 72) { - md_header(ev.shiftKey); + if (kl == "h") { + md_header(e.shiftKey); return false; } - if (ev.code == "KeyZ" || kc == 90) { - if (ev.shiftKey) + if (kl == "z") { + if (e.shiftKey) action_stack.redo(); else action_stack.undo(); return false; } - if (ev.code == "KeyY" || kc == 89) { + if (kl == "y") { action_stack.redo(); return false; } - if (ev.code == "KeyK") { + if (kl == "k") { fmt_table(); return false; } - if (ev.code == "KeyU") { + if (kl == "u") { iter_uni(); return false; } - var up = ev.code == "ArrowUp" || kc == 38; - var dn = ev.code == "ArrowDown" || kc == 40; - if (up || dn) { - md_p_jump(dn); + if (k == "ArrowUp" || k == "ArrowDown") { + md_p_jump(k == "ArrowDown"); return false; } - if (ev.code == "KeyX" || ev.code == "KeyC") { - md_cut(ev.code == "KeyX"); + if (kl == "x" || kl == "c") { + md_cut(kl == "x"); return true; //sic } } @@ -1007,18 +1016,18 @@ var set_lno = (function () { if (!editing) return true; - if (ev.code == "Tab" || kc == 9) { - md_indent(ev.shiftKey); + if (k == "Tab") { + md_indent(e.shiftKey); return false; } - if (ev.code == "Home" || kc == 36) { - md_home(ev.shiftKey); + if (k == "Home") { + md_home(e.shiftKey); return false; } - if (!ev.shiftKey && ((ev.code + '').endsWith("Enter") || kc == 13)) { + if (!e.shiftKey && k.endsWith("Enter")) { return md_newline(); } - if (!ev.shiftKey && kc == 8) { + if (!e.shiftKey && k == "Backspace") { return md_backspace(); } } diff --git a/copyparty/web/up2k.js b/copyparty/web/up2k.js index a7094859..c512ea7a 100644 --- a/copyparty/web/up2k.js +++ b/copyparty/web/up2k.js @@ -3037,10 +3037,12 @@ function up2k_init(subtle) { if (anymod(e)) return; - if (e.code == 'ArrowUp') + var k = e.key || e.code; + + if (k == 'ArrowUp') bumpthread(1); - if (e.code == 'ArrowDown') + if (k == 'ArrowDown') bumpthread(-1); } @@ -3103,7 +3105,8 @@ function up2k_init(subtle) { ebi('u2szg').addEventListener('blur', read_u2sz); ebi('u2szg').onkeydown = function (e) { if (anymod(e)) return; - var n = e.code == 'ArrowUp' ? 1 : e.code == 'ArrowDown' ? -1 : 0; + var k = e.key || e.code, + n = k == 'ArrowUp' ? 1 : k == 'ArrowDown' ? -1 : 0; if (!n) return; this.value = parseInt(this.value) + n; read_u2sz(); @@ -3180,7 +3183,8 @@ function up2k_init(subtle) { function kd_life(e) { var el = e.target, - d = e.code == 'ArrowUp' ? 1 : e.code == 'ArrowDown' ? -1 : 0; + k = e.key || e.code, + d = k == 'ArrowUp' ? 1 : k == 'ArrowDown' ? -1 : 0; if (anymod(e) || !d) return; diff --git a/copyparty/web/util.js b/copyparty/web/util.js index b3a3c145..7bcc60ad 100644 --- a/copyparty/web/util.js +++ b/copyparty/web/util.js @@ -1824,12 +1824,12 @@ var modal = (function () { }; var onkey = function (e) { - var k = (e.code || e.key) + '', + var k = (e.key || e.code) + '', eok = ebi('modal-ok'), eng = ebi('modal-ng'), ae = document.activeElement; - if (k == 'Space' && ae && (ae === eok || ae === eng)) + if ((k == 'Space' || k == 'Spacebar' || k == ' ') && ae && (ae === eok || ae === eng)) k = 'Enter'; if (k.endsWith('Enter')) {