diff --git a/app/Application.js b/app/Application.js index 28a8d03e..ff810d73 100644 --- a/app/Application.js +++ b/app/Application.js @@ -27,6 +27,7 @@ Ext.define('Rambox.Application', { ,launch: function () { const isOnline = require('is-online'); + const Mousetrap = require('mousetrap'); (async () => { await isOnline().then(res => { var hideNoConnection = ipc.sendSync('getConfig').hideNoConnectionDialog @@ -121,140 +122,58 @@ Ext.define('Rambox.Application', { // Check for updates if ( require('electron').remote.process.argv.indexOf('--without-update') === -1 ) Rambox.app.checkUpdate(true); - // Add shortcuts to switch services using CTRL + Number - document.keyMapping = new Ext.util.KeyMap({ - target: document - ,binding: [ - { - key: "\t" - ,ctrl: true - ,alt: false - ,shift: false - ,handler: function(key) { - var tabPanel = Ext.cq1('app-main'); - var activeIndex = tabPanel.items.indexOf(tabPanel.getActiveTab()); - var i = activeIndex + 1; - - // "cycle" (go to the start) when the end is reached or the end is the spacer "tbfill" - if (i === tabPanel.items.items.length || i === tabPanel.items.items.length - 1 && tabPanel.items.items[i].id === 'tbfill') i = 0; - - // skip spacer - while (tabPanel.items.items[i].id === 'tbfill') i++; - - tabPanel.setActiveTab(i); - } - } - ,{ - key: "f" - ,ctrl: false - ,alt: true - ,shift: true - ,handler: function(key) { - var currentTab = Ext.cq1('app-main').getActiveTab(); - if ( currentTab.getWebView ) currentTab.showSearchBox(true); - } - } - ,{ - key: "\t" - ,ctrl: true - ,alt: false - ,shift: true - ,handler: function(key) { - var tabPanel = Ext.cq1('app-main'); - var activeIndex = tabPanel.items.indexOf(tabPanel.getActiveTab()); - var i = activeIndex - 1; - if ( i < 0 ) i = tabPanel.items.items.length - 1; - while ( tabPanel.items.items[i].id === 'tbfill' || i < 0 ) i--; - tabPanel.setActiveTab( i ); - } - } - ,{ - key: Ext.event.Event.PAGE_DOWN - ,ctrl: true - ,alt: false - ,shift: false - ,handler: function(key) { - var tabPanel = Ext.cq1('app-main'); - var activeIndex = tabPanel.items.indexOf(tabPanel.getActiveTab()); - var i = activeIndex + 1; - - // "cycle" (go to the start) when the end is reached or the end is the spacer "tbfill" - if (i === tabPanel.items.items.length || i === tabPanel.items.items.length - 1 && tabPanel.items.items[i].id === 'tbfill') i = 0; - - // skip spacer - while (tabPanel.items.items[i].id === 'tbfill') i++; - tabPanel.setActiveTab(i); - } - } - ,{ - key: Ext.event.Event.PAGE_UP - ,ctrl: true - ,alt: false - ,shift: false - ,handler: function(key) { - var tabPanel = Ext.cq1('app-main'); - var activeIndex = tabPanel.items.indexOf(tabPanel.getActiveTab()); - var i = activeIndex - 1; - if ( i < 0 ) i = tabPanel.items.items.length - 1; - while ( tabPanel.items.items[i].id === 'tbfill' || i < 0 ) i--; - tabPanel.setActiveTab( i ); - } - } - ,{ - key: [Ext.event.Event.NUM_PLUS, Ext.event.Event.NUM_MINUS, 187, 189] - ,ctrl: true - ,alt: false - ,shift: false - ,handler: function(key) { - var tabPanel = Ext.cq1('app-main'); - if ( tabPanel.items.indexOf(tabPanel.getActiveTab()) === 0 ) return false; - - key === Ext.event.Event.NUM_PLUS || key === 187 ? tabPanel.getActiveTab().zoomIn() : tabPanel.getActiveTab().zoomOut(); - } - } - ,{ - key: [Ext.event.Event.NUM_ZERO, '0'] - ,ctrl: true - ,alt: false - ,shift: false - ,handler: function(key) { - var tabPanel = Ext.cq1('app-main'); - if ( tabPanel.items.indexOf(tabPanel.getActiveTab()) === 0 ) return false; - - tabPanel.getActiveTab().resetZoom(); - } - } - ,{ - key: 188 // comma - ,ctrl: true - ,alt: false - ,handler: function(key) { - Ext.cq1('app-main').setActiveTab(0); - } - } - ,{ - key: 'd' - ,ctrl: false - ,alt: true - ,shift: true - ,handler: function(key) { - var btn = Ext.getCmp('disturbBtn'); - btn.toggle(); - Ext.cq1('app-main').getController().dontDisturb(btn, true); - } - } - ,{ - key: 'l' - ,ctrl: false - ,alt: true - ,shift: true - ,handler: function(key) { - var btn = Ext.getCmp('lockRamboxBtn'); - Ext.cq1('app-main').getController().lockRambox(btn); - } - } - ] + // Shortcuts + const platform = require('electron').remote.process.platform; + // Prevents default behaviour of Mousetrap, that prevents shortcuts in textareas + Mousetrap.prototype.stopCallback = function(e, element, combo) { + return false; + }; + // Add shortcuts to switch services using CTRL + Number + Mousetrap.bind(platform === 'darwin' ? ["command+1","command+2","command+3","command+4","command+5","command+6","command+7","command+8","command+9"] : ["ctrl+1","ctrl+2","ctrl+3","ctrl+4","ctrl+5","ctrl+6","ctrl+7","ctrl+8","ctrl+9"], function(e, combo) { // GROUPS + var tabPanel = Ext.cq1('app-main'); + var arg = parseInt(e.key); + if ( arg >= tabPanel.items.indexOf(Ext.getCmp('tbfill')) ) arg++; + tabPanel.setActiveTab(arg); + }); + // Add shortcut to main tab (ctrl+,) + Mousetrap.bind(platform === 'darwin' ? 'command+,' : 'ctrl+,', (e, combo) => { + Ext.cq1('app-main').setActiveTab(0); + }); + // Add shortcuts to navigate through services + Mousetrap.bind(['ctrl+tab', 'ctrl+pagedown'], (e, combo) => { + var tabPanel = Ext.cq1('app-main'); + var activeIndex = tabPanel.items.indexOf(tabPanel.getActiveTab()); + var i = activeIndex + 1; + // "cycle" (go to the start) when the end is reached or the end is the spacer "tbfill" + if (i === tabPanel.items.items.length || i === tabPanel.items.items.length - 1 && tabPanel.items.items[i].id === 'tbfill') i = 0; + // skip spacer + while (tabPanel.items.items[i].id === 'tbfill') i++; + tabPanel.setActiveTab(i); + }); + Mousetrap.bind(['ctrl+shift+tab', 'ctrl+pageup'], (e, combo) => { + var tabPanel = Ext.cq1('app-main'); + var activeIndex = tabPanel.items.indexOf(tabPanel.getActiveTab()); + var i = activeIndex - 1; + if ( i < 0 ) i = tabPanel.items.items.length - 1; + while ( tabPanel.items.items[i].id === 'tbfill' || i < 0 ) i--; + tabPanel.setActiveTab(i); + }); + // Add shortcut to search inside a service + Mousetrap.bind(process.platform === 'darwin' ? ['command+alt+f'] : ['shift+alt+f'], (e, combo) => { + var currentTab = Ext.cq1('app-main').getActiveTab(); + if ( currentTab.getWebView ) currentTab.showSearchBox(true); + }); + // Add shortcut to Do Not Disturb + Mousetrap.bind(platform === 'darwin' ? ["command+d"] : ["shift+alt+d"], function(e, combo) { + var btn = Ext.getCmp('disturbBtn'); + btn.toggle(); + Ext.cq1('app-main').getController().dontDisturb(btn, true); + }); + // Add shortcut to Lock Rambox + Mousetrap.bind(platform === 'darwin' ? ['command+alt+l'] : ['shift+alt+l'], (e, combo) => { + var btn = Ext.getCmp('lockRamboxBtn'); + Ext.cq1('app-main').getController().lockRambox(btn); }); // Mouse Wheel zooming diff --git a/app/ux/WebView.js b/app/ux/WebView.js index 9ff96a67..42a18e75 100644 --- a/app/ux/WebView.js +++ b/app/ux/WebView.js @@ -504,6 +504,34 @@ Ext.define('Rambox.ux.WebView',{ webview.executeJavaScript(js_inject).then(result => {} ).catch(err => { console.log(err) }) }); + webview.getWebContents().on('before-input-event', (event, input) => { + if (input.type !== 'keyDown') return; + + var modifiers = []; + if ( input.shift ) modifiers.push('shift'); + if ( input.control ) modifiers.push('control'); + if ( input.alt ) modifiers.push('alt'); + if ( input.meta ) modifiers.push('meta'); + if ( input.isAutoRepeat ) modifiers.push('isAutoRepeat'); + + if ( input.key === 'Tab' && !(modifiers && modifiers.length) ) return; + + // Maps special keys to fire the correct event in Mac OS + if ( require('electron').remote.process.platform === 'darwin' ) { + var keys = []; + keys['ƒ'] = 'f'; // Search + + input.key = keys[input.key] ? keys[input.key] : input.key; + } + + if ( input.key === 'F11' || input.key === 'F12' || input.key === 'q' || (input.key === 'F1' && modifiers.includes('control'))) return; + + require('electron').remote.getCurrentWebContents().sendInputEvent({ + type: input.type, + keyCode: input.key, + modifiers: modifiers + }); + }) webview.addEventListener('ipc-message', function(event) { var channel = event.channel; @@ -517,30 +545,6 @@ Ext.define('Rambox.ux.WebView',{ case 'rambox.showWindowAndActivateTab': showWindowAndActivateTab(event); break; - case 'keydown': - handleKeydown(event.args[0]) - break; - } - /** - * Handles 'keydown' messages. - * Allow to handle shortcuts. - */ - function handleKeydown(event) { - var emulatedKeyboardEvent = new KeyboardEvent('keydown', { - code: event.code, - key: event.code.substring(0, 5) === 'Digit' ? event.code.substring(5, 6) : event.key, - shiftKey: event.shiftKey, - altKey: event.altKey, - ctrlKey: event.ctrlKey, - metaKey: event.metaKey, - repeat: event.repeat, - keyCode: event.keyCode, - charCode: event.charCode - }); - emulatedKeyboardEvent.getKey = function() { - return this.keyCode || this.charCode // fake function, normally used by Ext.js, simply returning keyCode - } - document.keyMapping.handleTargetEvent(emulatedKeyboardEvent) // we directly trigger handleTargetEvent. That's a private method normally. We can't fire the event directly with document.dispatch, unfortunately } /** * Handles 'rambox.clearUnreadCount' messages. diff --git a/app/view/main/Main.js b/app/view/main/Main.js index d2b3e801..656dea60 100644 --- a/app/view/main/Main.js +++ b/app/view/main/Main.js @@ -243,7 +243,7 @@ Ext.define('Rambox.view.main.Main', { { glyph: JSON.parse(localStorage.getItem('dontDisturb')) ? 'xf1f7@FontAwesome' : 'xf0f3@FontAwesome' ,text: locale['app.main[16]']+': '+(JSON.parse(localStorage.getItem('dontDisturb')) ? locale['app.window[20]'] : locale['app.window[21]']) - ,tooltip: locale['app.main[17]']+'
'+locale['app.main[18]']+': Alt + Shift + D' + ,tooltip: locale['app.main[17]']+'
'+locale['app.main[18]']+(require('electron').remote.process.platform === 'darwin' ? 'Cmd + D' : ': Alt + Shift + D') ,enableToggle: true ,handler: 'dontDisturb' ,reference: 'disturbBtn' @@ -253,7 +253,7 @@ Ext.define('Rambox.view.main.Main', { ,{ glyph: 'xf023@FontAwesome' ,text: locale['app.main[19]'] - ,tooltip: locale['app.main[20]']+'
'+locale['app.main[18]']+': Alt + Shift + L' + ,tooltip: locale['app.main[20]']+'
'+locale['app.main[18]']+(require('electron').remote.process.platform === 'darwin' ? 'Cmd + Alt + L' : ': Alt + Shift + L') ,handler: 'lockRambox' ,id: 'lockRamboxBtn' },'-' diff --git a/electron/main.js b/electron/main.js index 4da243e4..777f5834 100644 --- a/electron/main.js +++ b/electron/main.js @@ -1,6 +1,6 @@ 'use strict'; -const {app, protocol, BrowserWindow, dialog, shell, Menu, ipcMain, nativeImage, session, globalShortcut} = require('electron'); +const {app, protocol, BrowserWindow, dialog, shell, Menu, ipcMain, nativeImage, session} = require('electron'); // Tray const tray = require('./tray'); // AutoLaunch @@ -479,15 +479,6 @@ if ( config.get('disable_gpu') ) app.disableHardwareAcceleration(); // initialization and is ready to create browser windows. app.on('ready', function() { config.get('master_password') ? createMasterPasswordWindow() : createWindow(); - globalShortcut.register('CommandOrControl+1', () => { mainWindow.webContents.send('shortcut:tab', 1); }) - globalShortcut.register('CommandOrControl+2', () => { mainWindow.webContents.send('shortcut:tab', 2); }) - globalShortcut.register('CommandOrControl+3', () => { mainWindow.webContents.send('shortcut:tab', 3); }) - globalShortcut.register('CommandOrControl+4', () => { mainWindow.webContents.send('shortcut:tab', 4); }) - globalShortcut.register('CommandOrControl+5', () => { mainWindow.webContents.send('shortcut:tab', 5); }) - globalShortcut.register('CommandOrControl+6', () => { mainWindow.webContents.send('shortcut:tab', 6); }) - globalShortcut.register('CommandOrControl+7', () => { mainWindow.webContents.send('shortcut:tab', 7); }) - globalShortcut.register('CommandOrControl+8', () => { mainWindow.webContents.send('shortcut:tab', 8); }) - globalShortcut.register('CommandOrControl+9', () => { mainWindow.webContents.send('shortcut:tab', 9); }) }); // Quit when all windows are closed. diff --git a/electron/menu.js b/electron/menu.js index d5971bc3..f249d0e8 100644 --- a/electron/menu.js +++ b/electron/menu.js @@ -178,14 +178,17 @@ module.exports = function(config) { }, { label: 'Zoom In', + accelerator: 'Ctrl+Plus', click(item, win) { win.webContents.send('zoomin-webview')} }, { label: 'Zoom Out', + accelerator: 'Ctrl+-', click(item, win) { win.webContents.send('zoomout-webview')} }, { label: 'Reset Zoom', + accelerator: 'Ctrl+0', click(item, win) { win.webContents.send('resetzoom-webview')} } ] diff --git a/package-lock.json b/package-lock.json index 1cb19b48..dcaea870 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4041,6 +4041,11 @@ } } }, + "mousetrap": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/mousetrap/-/mousetrap-1.6.3.tgz", + "integrity": "sha512-bd+nzwhhs9ifsUrC2tWaSgm24/oo2c83zaRyZQF06hYA6sANfsXHtnZ19AbbbDXCDzeH5nZBSQ4NvCjgD62tJA==" + }, "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", diff --git a/package.json b/package.json index e2c2a0ee..cd0f4a30 100644 --- a/package.json +++ b/package.json @@ -205,6 +205,7 @@ "electron-updater": "4.1.2", "is-online": "^8.2.0", "mime": "^2.3.1", + "mousetrap": "^1.6.3", "request": "^2.88.0", "request-promise": "^4.2.2", "rimraf": "2.6.1", diff --git a/resources/js/rambox-service-api.js b/resources/js/rambox-service-api.js index a0958ef0..15e3d0ec 100644 --- a/resources/js/rambox-service-api.js +++ b/resources/js/rambox-service-api.js @@ -55,19 +55,3 @@ window.rambox.contextMenuBuilder = new ContextMenuBuilder(); window.rambox.contextMenuListener = new ContextMenuListener(function(event, info) { window.rambox.contextMenuBuilder.showPopupMenu(info); }); - -document.addEventListener("keydown", (event) => { - if (event.type !== 'keydown' || event.key === 'z' || event.key === 'a' ) return; // event used by default - var msg = { - code: event.code, - key: event.key, - shiftKey: event.shiftKey, - altKey: event.altKey, - ctrlKey: event.ctrlKey, - metaKey: event.metaKey, - repeat: event.repeat, - keyCode: event.keyCode, - charCode: event.charCode - }; - ipcRenderer.sendToHost('keydown', msg) -});