diff --git a/CHANGELOG.md b/CHANGELOG.md index 92e3dd8..f6a6cce 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,8 +4,11 @@ ### v3.3.0 +This will probably get promoted to 4.0, continuing the trend of version something.3 not happening. Eulul + * Basic mode added -* Per-video controls in popup +* Per-site controls in popup (to control embedded videos) +* Rewrote keyboard shortcuts and changed how they're handled. Massively. ### v3.2.2 diff --git a/js/conf/ExtensionConf.js b/js/conf/ExtensionConf.js index a5407ab..ce3cf6e 100644 --- a/js/conf/ExtensionConf.js +++ b/js/conf/ExtensionConf.js @@ -130,75 +130,207 @@ var ExtensionConf = { // criticalFail: "background: #fa2; color: #000" }, keyboard: { - shortcuts: { - // automatic - "a": { - action: "auto-ar", - }, - //#region crop - "r": { - action: "crop", - arg: "reset" - }, - "w": { - action: "crop", - arg: "fitw" - }, - "e": { - action: "crop", - arg: "fith" - }, - "s": { - action: "crop", - arg: 1.78 - }, - "d": { - action: "crop", - arg: 2.39 - }, - "x": { - action: "crop", - arg: 2.0 - }, - "q": { - action: "crop", - arg: 2.35 - }, - //#endregion - //#region zoom - "z": { - action: "zoom", - arg: 0.1 - }, - "u": { - action: "zoom", - arg: -0.1 - }, - "p": { - action: "pan", - arg: 'toggle' // possible: 'enable', 'disable', 'toggle' - }, - "shiftKey_shift": { - action: "pan", - arg: 'toggle', - keyup: { - action: 'pan', - arg: 'toggle' - } - }, - "shift": { - action: "", - arg: "", - keyup: { - action: 'pan', - arg: 'toggle', - } - } - //#endregion - }, - modKeys: ["ctrlKey", "shiftKey", "altKey"] }, // ----------------------------------------- + // ::: ACTIONS ::: + // ----------------------------------------- + // Nastavitve za ukaze. Zamenja stare nastavitve za bližnične tipke. + // + // Polje 'shortcut' je tabela, če se slučajno lotimo kdaj delati choordov. + actions: [{ + cmd: [{ + action: 'crop', + arg: 'auto' + }], + shortcut: [{ + key: 'a', + ctrlKey: false, + metaKey: false, + altKey: false, + shiftKey: false, + onKeyUp: true, + onKeyDown: false, + }], + popup: true, + ui: true, + },{ + cmd: [{ + action: 'crop', + arg: 'reset', + }], + shortcut: [{ + key: 'r', + ctrlKey: false, + metaKey: false, + altKey: false, + shiftKey: false, + onKeyUp: true, + onKeyDown: false, + }], + popup: true, + ui: true, + },{ + cmd: [{ + action: 'crop', + arg: 'fitw', + }], + shortcut: [{ + key: 'w', + ctrlKey: false, + metaKey: false, + altKey: false, + shiftKey: false, + onKeyUp: false, + onKeyDown: true, + }], + popup: true, + ui: true, + },{ + cmd: [{ + action: 'crop', + arg: 'fith', + }], + shortcut: [{ + key: 'e', + ctrlKey: false, + metaKey: false, + altKey: false, + shiftKey: false, + onKeyUp: true, + onKeyDown: false, + }], + popup: true, + ui: true, + },{ + cmd: [{ + action: 'crop', + arg: 1.78, + }], + shortcut: [{ + key: 's', + ctrlKey: false, + metaKey: false, + altKey: false, + shiftKey: false, + onKeyUp: false, + onKeyDown: true, + }], + popup: true, + ui: true, + },{ + cmd: [{ + action: 'crop', + arg: 2.39, + }], + shortcut: [{ + key: 'd', + ctrlKey: false, + metaKey: false, + altKey: false, + shiftKey: false, + onKeyUp: false, + onKeyDown: true, + }], + popup: true, + ui: true, + },{ + cmd: [{ + action: 'crop', + arg: 2.35, + }], + shortcut: [{ + key: 'q', + ctrlKey: false, + metaKey: false, + altKey: false, + shiftKey: false, + onKeyUp: false, + onKeyDown: true, + }], + popup: true, + ui: true, + },{ + cmd: [{ + action: 'crop', + arg: 2.0, + }], + shortcut: [{ + key: 'x', + ctrlKey: false, + metaKey: false, + altKey: false, + shiftKey: false, + onKeyUp: true, + onKeyDown: false, + }], + popup: true, + ui: true, + },{ + cmd: [{ + action: 'zoom', + arg: 0.1 + }], + shortcut: [{ + key: 'z', + ctrlKey: false, + metaKey: false, + altKey: false, + shiftKey: false, + onKeyUp: true, + onKeyDown: false, + }], + popup: true, + ui: true, + },{ + cmd: [{ + action: 'zoom', + arg: -0.1 + }], + shortcut: [{ + key: 'u', + ctrlKey: false, + metaKey: false, + altKey: false, + shiftKey: false, + onKeyUp: true, + onKeyDown: false, + }], + popup: true, + ui: true, + },{ + cmd: [{ + action: 'toggle-pan', + arg: 'toggle' + }], + shortcut: [{ + key: 'p', + ctrlKey: false, + metaKey: false, + altKey: false, + shiftKey: false, + onKeyUp: true, + onKeyDown: false, + }], + popup: true, + ui: true, + },{ + cmd: [{ + action: 'pan', + arg: 1, + }], + shortcut: [{ + ctrlKey: false, + metaKey: false, + altKey: false, + shiftKey: true, + onKeyDown: false, + onKeyUp: false, + onMouseMove: true, + }], + popup: false, + ui: false, + }], + // ----------------------------------------- // ::: SITE CONFIGURATION ::: // ----------------------------------------- // Nastavitve za posamezno stran @@ -235,7 +367,8 @@ var ExtensionConf = { arStatus: "default", // should we enable autodetection statusEmbedded: "enabled", // should extension work for this site when embedded on other sites? override: false, // ignore value localStorage in favour of this - type: 'official' // is officially supported? (Alternatives are 'community' and 'user-defined') + type: 'official', // is officially supported? (Alternatives are 'community' and 'user-defined') + actions: null, // overrides global keyboard shortcuts and button configs. Is array, is optional. }, "www.netflix.com" : { status: "enabled", diff --git a/js/modules/ActionHandler.js b/js/modules/ActionHandler.js new file mode 100644 index 0000000..5396246 --- /dev/null +++ b/js/modules/ActionHandler.js @@ -0,0 +1,158 @@ +if (Debug.debug) { + console.log("Loading: ActionHandler.js"); +} + +class ActionHandler { + + constructor(pageInfo) { + this.pageInfo = pageInfo; + this.settings = pageInfo.settings; + + this.inputs = ['input', 'select', 'button', 'textarea']; + } + + init() { + this.keyUpActions = []; + this.keyDownActions = []; + this.mouseMoveActions = []; + this.mouseScrollUpActions = []; + this.mouseScrollDownActions = []; + this.mouseEnterActions = []; + this.mouseLeaveActions = []; + + var ths = this; + + var actions; + try { + if (this.settings.active.sites[window.location.host].actions) { + actions = this.settings.active.sites[window.location.host].actions; + } else { + actions = this.settings.active.actions; + } + } catch (e) { + actions = this.settings.active.actions; + } + + for (var action of actions) { + if (action.onKeyDown) { + this.keyDownActions.push(action); + } + if (action.onKeyUp) { + this.keyUpActions.push(action); + } + if (action.onScrollUp) { + this.mouseScrollUpActions.push(action); + } + if (action.onScrollDown) { + this.mouseScrollDownActions.push(action); + } + if (action.onMouseEnter) { + this.mouseEnterActions.push(action); + } + if (action.onMouseLeave) { + this.mouseLeaveActions.push(action); + } + if (action.onMouseMove) { + this.mouseMoveActions.push(action); + } + } + + document.addEventListener('keydown', (event) => ths.handleKeydown(event) ); + document.addEventListener('keyup', (event) => ths.handleKeyup(event) ); + } + + preventAction() { + var activeElement = document.activeElement; + + if(Debug.debug && Debug.keyboard) { + Debug.debug = false; // temp disable to avoid recursing; + + console.log("[ActionHandler::preventAction] Testing whether we're in a textbox or something. Detailed rundown of conditions:\n" + + "is full screen? (yes->allow):", PlayerData.isFullScreen(), + "\nis tag one of defined inputs? (no->prevent):", this.inputs.indexOf(activeElement.tagName.toLocaleLowerCase()) !== -1, + "\nis role = textbox? (yes -> prevent):", activeElement.getAttribute("role") === "textbox", + "\nis type === 'text'? (yes -> prevent):", activeElement.getAttribute("type") === "text", + "\nwill the action be prevented? (yes -> prevent)", this.preventAction(), + "\n-----------------{ extra debug info }-------------------", + "\ntag name? (lowercase):", activeElement.tagName, activeElement.tagName.toLocaleLowerCase(), + "\nrole:", activeElement.getAttribute('role'), + "\ntype:", activeElement.getAttribute('type'), + "insta-fail inputs:", this.inputs + ); + + Debug.debug = true; // undisable + } + + if (PlayerData.isFullScreen()) { + return false; + } + if (this.inputs.indexOf(activeElement.tagName.toLocaleLowerCase()) !== -1) { + return true; + } + if (activeElement.getAttribute("role") === "textbox") { + return true; + } + if (activeElement.getAttribute("type") === "text") { + return true; + } + return false; + } + + isActionMatch(shortcut, event) { + return shortcut.key === event.key && + shortcut.ctrlKey === event.ctrlKey && + shortcut.metaKey === event.metaKey && + shortcut.altKey === event.altKey && + shortcut.shiftKey === event.shiftKey + } + + execAction(actions, event, shortcutIndex) { + if(Debug.debug && Debug.keyboard ){ + console.log("%c[ActionHandler::execAction] Trying to find and execute action for event.: ", "color: #ff0"); + } + + if (!shortcutIndex) { + shortcutIndex = 0; + } + + for (var action of actions) { + if (this.isActionMatch(action.shortcut[shortcutIndex], event)) { + if(Debug.debug && Debug.keyboard ){ + console.log("%c[ActionHandler::execAction] found an action associated with keypress/event: ", "color: #ff0", action); + } + + for (var cmd of action.cmd) { + if (cmd.action === "crop") { + this.pageInfo.stopArDetection(); + this.pageInfo.setAr(cmd.arg); + } else if (cmd.action === "zoom") { + this.pageInfo.stopArDetection(); + this.pageInfo.zoomStep(cmd.arg); + } else if (cmd.action === "stretch") { + this.pageInfo.setStretchMode(cmd.arg); + } else if (cmd.action === "toggle-pan") { + this.pageInfo.setPanMode(cmd.arg) + } else if (cmd.action === "pan") { + // todo: handle this + } + + } + + return; + } + } + } + + handleKeyup(event) { + if(Debug.debug && Debug.keyboard ){ + console.log("%c[ActionHandler::handleKeyup] we pressed a key: ", "color: #ff0", event.key , " | keydown: ", event.keydown, "event:", event); + } + + if (this.preventAction()) { + return; + } + + + } + +} \ No newline at end of file