Dumby - проверь плиз, код перехвата клавиш. b0ttle - Да, мой код глючит! (UPDATE пост обновил)
Проблема такая: если в поле ввода (ответа этого форума) нажать 1, вместе с запуском кода в поле ввода попадает вводимая клавиша.
Даже с preventDefault в поле ввода попадает символ, хотя на страницу ввод не передаётся, как это и задумано. (stopImmediatePropagation не помог)
Мне надо запретить передачу в поле ввода клавиши, если в блоке обработки прописано сочетание клавиш с нажатием этой клавиши в поле ввода - то есть Digit1_I.
В примере нажатия на странице и в поле ввода различаются (для поля ввода к имени нужно добавить "I").
(async anim => { // Для докум. окна браузера [ChromeOnly] var keyboard = { // нажатия клавиш Meta 8 Ctrl 4 Shift 2 Alt 1 Input 'I' Skip первая буква строчная Digit1() { console.log("■ клавиша 1 "+ Math.random()); }, // Alt+X Digit1_I() { this.Digit1(); }, KeyX_1(e) { console.log("■ Alt+X "+ Math.random()); }, KeyX_1I(e) { this.KeyX_1(e)}, // Alt+X в поле ввода } var args = ["keydown", e => { if (e.repeat) return; //e.getModifierState("CapsLock")*16 var k, m = (e.metaKey*8 +e.ctrlKey*4 +e.shiftKey*2 +e.altKey +"I".slice(!docShell.isCommandEnabled("cmd_insertText"))).replace(/^0/,''); m = e.code + ("_"+ m).slice(0, 5*Boolean(m)); k = m[0].toLowerCase() + m.slice(1); if (k in keyboard) m = k, k = 0; // не держать ввод if (e.keyCode > 31) if (m in keyboard) { keyboard[m](gBrowser.selectedTab); !k && e.preventDefault(); } console.log("■ "+ m +' '+ Math.random()); }, true]; addEventListener(...args); var id = Symbol(), ucf = ucf_custom_script_win; ucf.unloadlisteners.push(id); ucf[id] = {destructor: () => removeEventListener(...args)}; })({animate: true});
Отредактировано Dobrov (29-07-2023 09:44:44)
Отсутствует
Для Digit1_I (цифра 1 в поле ввода) выполняется preventDefault
Это каким же образом?
Перед if-проверками в переменной k
находится строка с LowerCase'нутой первой буквой, то есть digit1_I
Первую if-проверку k не проходит, поскольку digit1_I в keyboard нет,
таким образом k не меняется, остаётся всё той же строкой digit1_I
Так и остаётся далее, где подходим к строке !k && e.preventDefault();
Отрицание непустой строки (!k) даёт false
Выражение вида false && something
сразу возвращает false
something, при этом, даже не рассматривается и не вычисляется.
Иными словами, e.preventDefault(), вопреки утверждению, не выполняется.
Пропускаем объект klaBa через некий парсер (без валидации, конечно)
((obj, re) => { for(var p in klaBa) { var func = klaBa[p]; if (typeof func == "string") func = klaBa[func]; var [key, mod] = p.split("_"); mod = mod || ""; var first = key[0]; var upper = first.toUpperCase(); var prevent = first == upper; var [, m, i] = mod.match(re); m = m || 0; // modifiers bitmap var arr = [func, prevent, i ? i == "I" ? 1 : 0 : -1]; // textfields flag var prop = prevent ? key : upper + key.slice(1); var o = obj[prop] || (obj[prop] = Object.create(null)); o[m] ? o[m].push(arr) : o[m] = [arr]; } klaBa = obj; })(Object.create(null), /(\d+)?(i)?/i);
Тогда keydown_win() становится стройнее
keydown_win = e => { // перехват клавиш, учитывая поля ввода if (e.repeat) return; var data = klaBa[e.code]?.[e.metaKey*8 + e.ctrlKey*4 + e.shiftKey*2 + e.altKey]; if (data) { var cmd = docShell.isCommandEnabled("cmd_insertText"); for(var [func, p, i] of data) if (i ^ cmd) p && e.preventDefault(), func(e, gBrowser.selectedTab); } },
И примечания к синтаксису свойств klaBa:
Если начинается с маленькой буквы — не вызывать e.preventDefault().
Если заканчивается на «I» — не запускать в полях ввода.
Если заканчивается на «i» — запускать только в полях ввода.
При наличии модификаторов и/или «iI»-флага — отделять от кода клавиши символом «_».
Проброс одинакового — вместо функции вписываем соответствующую строку
digit5(e, t) {console.log("Digit 5!"); console.log(t.label);},
numpad5: "digit5",
—————
Но так получается, что в klaBa нельзя вписывать что-то постороннее,
только клавишные сочетания. Незнаю насколько это плохо.
Ну и вообще, под парсер как концепцию,
можно запилить какой-нибудь менее птичий синтаксис, наверно.
Отсутствует
Dumby - спасибо за помощь, изучу твой код и исправлю свои ошибки!
Всё круто, но зачем отдельный Объект-парсер, может в одном keydown_win будет компактней?
Варианты: 1) запускать везде 2) не вызывать e.preventDefault 3) не запускать в полях ввода 4) только в полях ввода.
Не смог запустить сочетание клавиш Alt+X. По одной клавише пашет, а так нет: KeyX_1(e) { console.log("Alt+X");
нельзя вписывать что-то постороннее, только клавишные сочетания.
Может, ещё надумаешь вариант покруче? Как я понял, теперь нельзя использовать что-то вроде
klaBa = {
gClipboard: {
write(str, ch = Cc["@mozilla.org/widget/clipboardhelper;1"]……
Первую if-проверку k не проходит, поскольку digit1_I в keyboard нет, таким образом k не меняется…
keydown_win = e => { if (e.repeat) return; var k, m = (e.metaKey*8 +e.ctrlKey*4 +e.shiftKey*2 +e.altKey +"I".slice(!docShell.isCommandEnabled("cmd_insertText"))).replace(/^0/,''); m = e.code + ("_"+ m).slice(0, 5*Boolean(m)); k = m[0].toLowerCase() + m.slice(1); // m = Digit1 k = digit1 if (m in klaBa) // если прописаны одинаковые клавиши (Digit1 и digit1), приоритет имеют имена с Заглавной k = m, m = 0; // m = 0 – выполнять preventDefault if (k in klaBa) { // если Digit1 не найдено, запускаем digit1 и не выполняем preventDefault !m && e.preventDefault(); // пропуск, если имя с прописной буквы. Отрицание непустой строки !m = !Digit1 = false klaBa[k](e); // execute } },
Отредактировано Dobrov (21-07-2023 15:50:51)
Отсутствует
зачем отдельный Объект-парсер, может в одном keydown_win будет компактней?
Парсер это не объект, а отдельный фрагмент кода.
Определяется функция и сразу вызывается.
В функцию завёрнуто просто чтобы внутри всякий свой var писать
не опасаясь, что он чего-нибудь испортит, ucf_hookClicks всё таки большой.
А в keydown_win() ему не место, она же по каждому keydown исполняется,
а парсер должен исполниться только один раз, подготовить что-то для keydown_win()
чтобы было оптимальней и выглядело понятнее и стройнее.
А сделать keydown_win() lazy-функцией не получится, она сразу регистрируется
как обработчик события, и после этого менять её бесполезно.
Разве что только переделать её в объект с методом handleEvent()
При первом вызове исполняется подготовительный код,
затем переопределяется handleEvent(), ну вызывается сразу. Да, так можно.
Может, ещё надумаешь вариант покруче? Как я понял, теперь нельзя использовать что-то вроде
klaBa = {
gClipboard: {
write(str, ch = Cc["@mozilla.org/widget/clipboardhelper;1"]……
Наверно можно, но не знаю нужно ли.
Допустим, выбрать из klaBa только клавишные свойства, и собрать в отдельную карту.
Попробовал — код получился жутковатый.
var keyMap = Object.create(null); (re => { var parse = (str, test) => { if (name.length < 2 || str.endsWith("_")) return null; var first = str[0]; var upper = first.toUpperCase(); var prevent = first == upper; upper = prevent ? str : upper + str.slice(1); if (test) return re.test(upper); var match = upper.match(re); if (match) { var [, kode, mod, i] = match; return [kode, str, prevent, i ? i == "I" ? 1 : 0 : -1, mod || 0]; } } for(var name in klaBa) { var arr = parse(name); if (!arr) continue; var desc = Object.getOwnPropertyDescriptor(klaBa, name); if ("value" in desc) { var val = klaBa[name]; if (typeof val == "string") { if (klaBa.hasOwnProperty(val) && parse(val, true)) arr[1] = val; else continue; // skip not alias strings } else if (typeof val != "function") continue; // skip not functions } else if (!desc.get) continue; // skip only setters var kode = arr.shift(), mod = arr.pop(); var o = keyMap[kode] || (keyMap[kode] = Object.create(null)); o[mod] ? o[mod].push(arr) : o[mod] = [arr]; } })(new RegExp(`^(${[ // https://developer.mozilla.org/en-US/docs/Web/API/UI_Events/Keyboard_event_code_values "Key[A-Z]|F(?:1?\\d|2[0-4])|Digit\\d", "Numpad(?:\\d|Enter|Add|Comma|Subtract|Decimal|Divide|Multiply|Equal)", "(?:Bracket|Arrow|Control|Shift|Alt|OS)(?:Left|Right)|(?:Arrow|Page)(?:Up|Down)", "Space|Quote|Equal|Comma|Minus|Period|Slash|Semicolon|Backslash|CapsLock|ContextMenu", "Backquote|Help|Backspace|Tab|Enter|Escape|End|Home|Insert|Delete|PrintScreen|NumLock", "Again|Convert|Copy|Cut|Eject|Find|IntlBackslash|IntlRo|IntlYen|KanaMode|NonConvert", "Open|Paste|Pause|Power|Props|ScrollLock|Select|Sleep|Undo|WakeUp|Lang[1-2]", "Media(?:PlayPause|Select|Stop|TrackNext|TrackPrevious)|Volume(?:Up|Down|Mute)", "Browser(?:Back|Favorites|Forward|Home|Refresh|Search|Stop)|Launch(?:App1|App2|Mail)" ].join("|")})(?:_(\\d\\d?)?([iI])?)?$`));
keydown_win = e => { // перехват клавиш, учитывая поля ввода if (e.repeat) return; var data = keyMap[e.code]?.[e.metaKey*8 + e.ctrlKey*4 + e.shiftKey*2 + e.altKey]; if (data) { var cmd = docShell.isCommandEnabled("cmd_insertText"); for(var [name, p, i] of data) if (i ^ cmd) p && e.preventDefault(), klaBa[name](e, gBrowser.selectedTab); } },
Ты проверял старый код
Какой был предоставлен, такой и проверял.
Отредактировано Dumby (23-07-2023 00:42:16)
Отсутствует
Dumby - придумал вариант списка нажатий клавиш проще прежнего. Код доделаю нескоро, может у тебя получится?
Формат: получаем имя нажатой кнопки вместе с управляющими клавишами: Digit1_1 равно Alt+1 (учитывая LED-индикаторы, если в объекте вместо функции Digit1_1 есть строка "Digit1_1").
Но управляющие клавиши можно отделить от имени, если это упростит код (как у тебя сделано для перехвата нажатий мыши).
var keyData = { // имя объекта: Клавиша_Shift+Alt+Ctrl[LED] Digit1_1(e) { // 1+Alt если Имя = Функция, считаем, что все режимы разрешены console.log("Digit1 везде"); }, "Digit1_1": { // 1+Alt 7(e){ // preventDefault*4 + Input*2 + MainPage console.log("Digit1 везде, игнорируя LED-индикаторы"); }, 2(){}, // только в полях ввода, Skip preventDefault 5(){}, // кроме полей ввода }, "Digit1_1_macosx": { // массив для переопределения отдельных сочетаний клавиш для вашей OS 16(e){ // только если CapsLock включен keyData["Digit1_1"][0]("Digit1_1_macosx"); // повторяем код из общего объекта } }, }
Отсутствует
Пример объекта - Если вместо функции строка, …
Что-то не вижу никакой строки вместо функции.
И, при такой записи, "Digit1_1" затрёт Digit1_1
то есть, у объекта keyData будет только два (не три) свойства,
Digit1_1 как объект (не фунция, функция затёрта объектом) и Digit1_1_macosx
Отсутствует
Что-то не вижу никакой строки вместо функции.
И, при такой записи, "Digit1_1" затрёт Digit1_1 то есть, у объекта keyData будет только два (не три) свойства,
В объекте все варианты для примера, а так должен быть только один из них. Далее разбор в зависисмости от режима e.getModifierState("CapsLock") и прочих LED…
То есть, эти две записи нельзя различить по типам, учитывая, что в объекте должна быть только одна из них?
KeyData = { Digit1_1(e) {}, "Digit1_1": {} }
Отсутствует
То есть, эти две записи нельзя различить по типам, учитывая, что в объекте должна быть только одна из них?
KeyData = { Digit1_1(e) {}, "Digit1_1": {} }
Не понял.
В одном объекте, даже не «должна», а «может»
быть только одна такая запись, то есть — различать просто не с чем.
А если имеется в виду, что различить такую же запись
но в другом объекте, то, разумеется, можно, это очевидно.
Отредактировано Dumby (25-07-2023 12:33:13)
Отсутствует
Dumby - я ранее расписал примерный алгоритм обработки нажатий. Различать по типу - если ключ это функция, то её запускаем, не проверяя режимы ввода. В примере это первый Digit1_1.
А в строковом ключе (имя свойства объекта) будут имена функций тех режимов, на которых надо запускать код для этого сочетания клавиш.
"Digit1_1": { // 1+Alt
7(e){}, // preventDefault*4 + Input*2 + MainPage
2(){}, // только в полях ввода, Skip preventDefault
16(e){} // только если CapsLock включен e.getModifierState("CapsLock")*16
Отредактировано Dobrov (25-07-2023 17:32:57)
Отсутствует
Dumby
Тут недавно говорили
https://forum.mozilla-russia.org/viewto … 64#p804264
и после последнего обновления ESR оно престало работать.
(async style => { var uri = Services.io.newURI("data:text/css;charset=utf-8," + encodeURIComponent(style)); var sss = Cc["@mozilla.org/content/style-sheet-service;1"].getService(Ci.nsIStyleSheetService); sss.loadAndRegisterSheet(uri, sss.USER_SHEET); })(` ... `);
Отсутствует
_zt
Прости великодушно, но я слишком глуп,
чтобы соотнести то, о чём «недавно говорили»,
с кодом регистрации стиля из-под спойлера.
Но да, на 115, вроде вполне достаточно будет просто только
(async ids => { for(var id of ids) document.getElementById(id)?.setAttribute("removable", true); })(["unified-extensions-button", "alltabs-button"]);
Отсутствует
Dumby, подскажите, в чем разница между этими двумя записями?
Cc['@mozilla.org/file/directory_service;1'].getService(Ci.nsIProperties).get('UChrm', Ci.nsIFile);
Services.dirsvc.get("UChrm", Ci.nsIFile);
Отсутствует
в чем разница между этими двумя записями?
Мне кажется, что хоть в сколько-нибудь актуальной версии лисицы,
эти две записи совершенно эквивалентны.
Но, если интересно копнуть вглубь веков относительно сахара,
то Cc и Ci определены с Firefox 60, а Services определён с Firefox 104.
Отсутствует
Dumby, благодарю, а чуть выше вы дали понять что в 115 записи для "unified-extensions-button" и "alltabs-button" могут быть эквивалентны, т.е. для config.js можно так
// сделать кнопку All Tabs (alltabs-button) съемной (async topic => { var obs = doc => doc.getElementById("alltabs-button")?.setAttribute("removable", true); Services.obs.addObserver(obs, topic); Services.obs.addObserver(function quit(s, t) { Services.obs.removeObserver(quit, t); Services.obs.removeObserver(obs, topic); }, "quit-application-granted"); })("chrome-document-interactive"); // сделать кнопку unified-extensions-button съемной (async topic => { var obs = doc => doc.getElementById("unified-extensions-button")?.setAttribute("removable", true); Services.obs.addObserver(obs, topic); Services.obs.addObserver(function quit(s, t) { Services.obs.removeObserver(quit, t); Services.obs.removeObserver(obs, topic); }, "quit-application-granted"); })("chrome-document-interactive");
Отредактировано 6e73epo (27-07-2023 14:41:38)
Отсутствует
Как бы это дело подсократить
Да обычный мерж, только и всего.
Не стал for of писать, чтобы не потерять наглядность.
// установить для кнопок #alltabs-button и #unified-extensions-button // атрибут "removable" как "true" (async topic => { var obs = doc => { doc.getElementById("alltabs-button")?.setAttribute("removable", true); doc.getElementById("unified-extensions-button")?.setAttribute("removable", true); } Services.obs.addObserver(obs, topic); Services.obs.addObserver(function quit(s, t) { Services.obs.removeObserver(quit, t); Services.obs.removeObserver(obs, topic); }, "quit-application-granted"); })("chrome-document-interactive");
Отсутствует
Dumby прошу дополнить первый вариант парсинга горячих клавиш, чтобы работал в зависимости от текущей операционной системы.
Логика такая: прописаны две одинаковых горячих клавиши, но у одной постфикс (или префикс, если это проще сделать в коде) с именем нужной ОС, для которой нужно выполнять код.
Если ОС, на которой запущен браузер, совпадает с именем сочетания клавиш Digit1_I_win с префиксом (постфиксом), то код из обычного имени Digit1_I игнорируется и выполняется Digit1_I_win (или Digit1_I_macosx, если браузер запущен на МакОС)
Тогда можно в один список включить как обычные сочетания клавиш, которые выполняются всегда, так и некоторые с постфиксом, которые будут действовать только на конкретной ОС (например, запуск Быстрых Заметок)
Вообще, синтаксис на твоё усмотрение, необязательно Клавиша_МОД Digit1_I, может вариант удобнее придумаешь ?
var KlaBa = { keyX_1(e) { // обычное сочетание клавиш работает всегда console.log("Alt+X skip preventDefault"); }, Digit1_I_macosx(e, t) { // приоритет для вашей OS shell_RunwA("/usr/bin/open", ["-n","-b","com.apple.Stickies"]); }, Digit1_I_win(e, t) { // приоритет для вашей OS shell_RunwA("C:\\Windows\\system32\\StikyNot.exe",""); }, Digit1_I(e, t) { // приоритет низкий run Notes }, Digit1: "Digit1_I" //ссылка на функцию };
Отредактировано Dobrov (29-07-2023 09:47:31)
Отсутствует
Dobrov
Во загадал загадку!
Что-то ничего умнее не смог придумать, чем так
((obj, re) => { var del = new Set(); var platformRe = /_(?:win|linux|macosx)$/; var {platform} = AppConstants, num = -platform.length - 1; for(var p in klaBa) platformRe.test(p) && del.add( p.endsWith(platform) ? p.slice(0, num) : p ); for(p in klaBa) del.has(klaBa[p]) && del.add(p); for(var d of del) delete klaBa[d];
Отсутствует
Во загадал загадку!
Спасибо! Но имена функций остаются в постфиксом ОС: Digit1_I_macosx(e, t)……
Перехват клавиш может не сработать ??? если нет нажатия управляющих клавиш: Digit1_macosx
var klaBa = { keyX_1(e) { console.log("Alt+X skip preventDefault"); }, Digit1_I_macosx(e, t) { // приоритет для вашей OS shell_RunwA("/usr/bin/open", ["-n","-b","com.apple.Stickies"]); }, Digit1_I_win(e, t) { // приоритет для вашей OS shell_RunwA("C:\\Windows\\system32\\StikyNot.exe",""); }, Digit1_I(e, t) { // приоритет низкий 0; }, Digit1: "Digit1_I" //ссылка на функцию }; ((obj, re) => { var del = new Set(); var platformRe = /_(?:win|linux|macosx)$/; var {platform} = AppConstants, num = -platform.length - 1; for(var p in klaBa) platformRe.test(p) && del.add( p.endsWith(platform) ? p.slice(0, num) : p ); for(var p in klaBa) del.has(klaBa[p]) && del.add(p); for(var d of del) delete klaBa[d]; //есть Key_OS ? удалить имена-клоны for(var p in klaBa) if (platformRe.test(p)) { //убрать имя вашей ОС из свойства klaBa[p.replace(platformRe,'')] = klaBa[p]; delete klaBa[p]; } for(var p in klaBa) { var func = klaBa[p]; if (typeof func == "string") func = klaBa[func]; //ссылка на функцию var [key, mod] = p.split("_"); mod = mod || ""; var upper = key[0].toUpperCase(); var prevent = key[0] == upper; var [, m, i] = mod.match(re); m = m || 0; // modifiers bitmap var arr = [func, prevent, i ? i == "I" ? 1 : 0 : -1]; // textfields flag var prop = prevent ? key : upper + key.slice(1); //имя клавиши без модификаторов var o = obj[prop] || (obj[prop] = Object.create(null)); o[m] ? o[m].push(arr) : o[m] = [arr]; } klaBa = obj; })(Object.create(null), /(\d+)?([a-z]+)?/i); for(p in klaBa) console.log(klaBa[p]);
Отсутствует
имена функций остаются в постфиксом ОС: Digit1_I_macosx(e, t)……
Имена функций значения не имеют, их вызов идёт без участия имени.
Функция перекочёвывает в массив,
а когда e.code и сумма модификаторов совпадает с нажатыми клавишами,
извлекается деструктурирующим присваиванием for(var [func, p, i] of data)
Перехват клавиш может не сработать ??? если нет нажатия управляющих клавиш: Digit1_macosx
Если отказаться от удаления ОС из свойств объекта, то будет работать неправильно.
Из-за того, что re был изменён с /(\d+)?(i)?/i на /(\d+)?([a-z]+)?/i
флаг полей ввода пропишется как ноль, то есть — только в полях ввода,
а должен быть минус единица, то есть — всегда.
пробовал убрать, создав копию свойства объекта, но не работает
Да вроде работает как написано, свойство Digit1_I_win успешно заменяется на Digit1_I
но имя самой функции, на которую ссылается klaBa.Digit1_I
при этом, конечно же, не меняется, остаётся Digit1_I_win
Отсутствует
После установки 116-й версии в очередной раз исчезла нижняя панель. Специалисты, подскажите как опять её вернуть-то? Пробовал вот это, но не помогло. Может надо версию обновить? У меня в version.txt прописано: "версия, дата г-м-д: 2021-9-23".
Windows 10 LTSC
Отсутствует