/** * @author Matt C [matt@artemisbot.uk] * @copyright Crown Copyright 2016 * @license Apache-2.0 */ /** * Waiter to handle keybindings to CyberChef functions (i.e. Bake, Step, Save, Load etc.) */ class BindingsWaiter { /** * BindingsWaiter constructor. * * @param {App} app - The main view object for CyberChef. * @param {Manager} manager - The CyberChef event manager. */ constructor(app, manager) { this.app = app; this.manager = manager; } /** * Handler for all keydown events * Checks whether valid keyboard shortcut has been instated * * @fires Manager#statechange * @param {event} e */ parseInput(e) { const modKey = this.app.options.useMetaKey ? e.metaKey : e.altKey; if (e.ctrlKey && modKey) { let elem; switch (e.code) { case "KeyF": // Focus search e.preventDefault(); document.getElementById("search").focus(); break; case "KeyI": // Focus input e.preventDefault(); document.getElementById("input-text").focus(); break; case "KeyO": // Focus output e.preventDefault(); document.getElementById("output-text").focus(); break; case "Period": // Focus next operation e.preventDefault(); try { elem = document.activeElement.closest(".operation") || document.querySelector("#rec-list .operation"); if (elem.parentNode.lastChild === elem) { // If operation is last in recipe, loop around to the top operation's first argument elem.parentNode.firstChild.querySelectorAll(".arg")[0].focus(); } else { // Focus first argument of next operation elem.nextSibling.querySelectorAll(".arg")[0].focus(); } } catch (e) { // do nothing, just don't throw an error } break; case "KeyB": // Set breakpoint e.preventDefault(); try { elem = document.activeElement.closest(".operation").querySelectorAll(".breakpoint")[0]; if (elem.getAttribute("break") === "false") { elem.setAttribute("break", "true"); // add break point if not already enabled elem.classList.add("breakpoint-selected"); } else { elem.setAttribute("break", "false"); // remove break point if already enabled elem.classList.remove("breakpoint-selected"); } window.dispatchEvent(this.manager.statechange); } catch (e) { // do nothing, just don't throw an error } break; case "KeyD": // Disable operation e.preventDefault(); try { elem = document.activeElement.closest(".operation").querySelectorAll(".disable-icon")[0]; if (elem.getAttribute("disabled") === "false") { elem.setAttribute("disabled", "true"); // disable operation if enabled elem.classList.add("disable-elem-selected"); elem.parentNode.parentNode.classList.add("disabled"); } else { elem.setAttribute("disabled", "false"); // enable operation if disabled elem.classList.remove("disable-elem-selected"); elem.parentNode.parentNode.classList.remove("disabled"); } this.app.progress = 0; window.dispatchEvent(this.manager.statechange); } catch (e) { // do nothing, just don't throw an error } break; case "Space": // Bake e.preventDefault(); this.app.bake(); break; case "Quote": // Step through e.preventDefault(); this.app.bake(true); break; case "KeyC": // Clear recipe e.preventDefault(); this.manager.recipe.clearRecipe(); break; case "KeyS": // Save output to file e.preventDefault(); this.manager.output.saveClick(); break; case "KeyL": // Load recipe e.preventDefault(); this.manager.controls.loadClick(); break; case "KeyM": // Switch input and output e.preventDefault(); this.manager.output.switchClick(); break; default: if (e.code.match(/Digit[0-9]/g)) { // Select nth operation e.preventDefault(); try { // Select the first argument of the operation corresponding to the number pressed document.querySelector(`li:nth-child(${e.code.substr(-1)}) .arg`).focus(); } catch (e) { // do nothing, just don't throw an error } } break; } } } /** * Updates keybinding list when metaKey option is toggled */ updateKeybList() { let modWinLin = "Alt"; let modMac = "Opt"; if (this.app.options.useMetaKey) { modWinLin = "Win"; modMac = "Cmd"; } document.getElementById("keybList").innerHTML = ` Command Shortcut (Win/Linux) Shortcut (Mac) Place cursor in search field Ctrl+${modWinLin}+f Ctrl+${modMac}+f Place cursor in input box Ctrl+${modWinLin}+i Ctrl+${modMac}+i Place cursor in output box Ctrl+${modWinLin}+o Ctrl+${modMac}+o Place cursor in first argument field of the next operation in the recipe Ctrl+${modWinLin}+. Ctrl+${modMac}+. Place cursor in first argument field of the nth operation in the recipe Ctrl+${modWinLin}+[1-9] Ctrl+${modMac}+[1-9] Disable current operation Ctrl+${modWinLin}+d Ctrl+${modMac}+d Set/clear breakpoint Ctrl+${modWinLin}+b Ctrl+${modMac}+b Bake Ctrl+${modWinLin}+Space Ctrl+${modMac}+Space Step Ctrl+${modWinLin}+' Ctrl+${modMac}+' Clear recipe Ctrl+${modWinLin}+c Ctrl+${modMac}+c Save to file Ctrl+${modWinLin}+s Ctrl+${modMac}+s Load recipe Ctrl+${modWinLin}+l Ctrl+${modMac}+l Move output to input Ctrl+${modWinLin}+m Ctrl+${modMac}+m `; } } export default BindingsWaiter;