diff --git a/app/scripts/auto-type/helper/auto-type-helper-darwin.js b/app/scripts/auto-type/helper/auto-type-helper-darwin.js index 5f4dd8d9..75ab5079 100644 --- a/app/scripts/auto-type/helper/auto-type-helper-darwin.js +++ b/app/scripts/auto-type/helper/auto-type-helper-darwin.js @@ -1,7 +1,11 @@ const Launcher = require('../../comp/launcher'); const ForeMostAppScript = - 'tell application "System Events" to set frontApp to name of first process whose frontmost is true'; + 'tell application "System Events"\n' + + ' set frontAppName to name of first process whose frontmost is true\n' + + ' set frontAppId to id of first process whose frontmost is true\n' + + 'end tell\n' + + '"" & frontAppId & " " & frontAppName'; const ChromeScript = 'tell application "{}" to set appUrl to URL of active tab of front window\n' + 'tell application "{}" to set appTitle to title of active tab of front window\n' + @@ -21,12 +25,19 @@ const OtherAppsScript = const AutoTypeHelper = function() {}; -AutoTypeHelper.prototype.getActiveWindowTitle = function(callback) { +AutoTypeHelper.prototype.getActiveWindowInfo = function(callback) { AutoTypeHelper.exec(ForeMostAppScript, (err, out) => { if (err) { return callback(err); } - const appName = out.trim(); + const output = out.trim(); + const spaceIx = output.indexOf(' '); + let id = '', + appName = ''; + if (spaceIx >= 0) { + id = output.substr(0, spaceIx); + appName = output.substr(spaceIx + 1).trim(); + } // getting urls and titles from Chrome or Safari: // - will suit in 90% cases // - does not require assistive access @@ -34,26 +45,37 @@ AutoTypeHelper.prototype.getActiveWindowTitle = function(callback) { if (['Google Chrome', 'Chromium', 'Google Chrome Canary'].indexOf(appName) >= 0) { AutoTypeHelper.exec(ChromeScript.replace(/\{}/g, appName), (err, out) => { if (err) { - return callback(err); + return callback(err, { id }); } const parts = out.split('\n'); - return callback(null, (parts[1] || '').trim(), parts[0].trim()); + return callback(null, { + id, + url: parts[0].trim(), + title: (parts[1] || '').trim() + }); }); } else if (['Safari', 'Webkit'].indexOf(appName) >= 0) { AutoTypeHelper.exec(SafariScript.replace(/\{}/g, appName), (err, out) => { if (err) { - return callback(err); + return callback(err, { id }); } const parts = out.split('\n'); - return callback(null, (parts[1] || '').trim(), parts[0].trim()); + return callback(null, { + id, + url: parts[0].trim(), + title: (parts[1] || '').trim() + }); }); } else { // special cases are not available. this method may ask the user about assistive access AutoTypeHelper.exec(OtherAppsScript.replace(/\{}/g, appName), (err, out) => { if (err) { - return callback(err); + return callback(err, { id }); } - return callback(null, out.trim()); + return callback(null, { + id, + title: out.trim() + }); }); } }); diff --git a/app/scripts/auto-type/helper/auto-type-helper-linux.js b/app/scripts/auto-type/helper/auto-type-helper-linux.js index 4254d95a..19d3877b 100644 --- a/app/scripts/auto-type/helper/auto-type-helper-linux.js +++ b/app/scripts/auto-type/helper/auto-type-helper-linux.js @@ -2,12 +2,20 @@ const Launcher = require('../../comp/launcher'); const AutoTypeHelper = function() {}; -AutoTypeHelper.prototype.getActiveWindowTitle = function(callback) { +AutoTypeHelper.prototype.getActiveWindowInfo = function(callback) { Launcher.spawn({ cmd: 'xdotool', - args: ['getactivewindow', 'getwindowname'], - complete(err, res) { - return callback(err, res ? res.trim() : undefined); + args: ['getactivewindow', 'getwindowname', 'getactivewindow'], + complete(err, out) { + let windowInfo; + if (out) { + const [id, title] = out.trim().split('\n'); + windowInfo = { + id, + title + }; + } + return callback(err, windowInfo); } }); }; diff --git a/app/scripts/auto-type/helper/auto-type-helper-win32.js b/app/scripts/auto-type/helper/auto-type-helper-win32.js index 8226c768..44d03b0b 100644 --- a/app/scripts/auto-type/helper/auto-type-helper-win32.js +++ b/app/scripts/auto-type/helper/auto-type-helper-win32.js @@ -3,7 +3,7 @@ const AutoTypeNativeHelper = require('./auto-type-native-helper'); const AutoTypeHelper = function() {}; -AutoTypeHelper.prototype.getActiveWindowTitle = function(callback) { +AutoTypeHelper.prototype.getActiveWindowInfo = function(callback) { Launcher.spawn({ cmd: AutoTypeNativeHelper.getHelperPath(), args: ['--window-info'], @@ -11,8 +11,13 @@ AutoTypeHelper.prototype.getActiveWindowTitle = function(callback) { if (err) { return callback(err); } - const parts = out.split('\n'); - return callback(null, (parts[0] || '').trim(), parts[1] ? parts[1].trim() : undefined); + const [id, title, url] = out.trim().split('\n'); + const windowInfo = { + id, + title, + url + }; + return callback(null, windowInfo); } }); }; diff --git a/app/scripts/auto-type/index.js b/app/scripts/auto-type/index.js index 2913fa6b..05ba1215 100644 --- a/app/scripts/auto-type/index.js +++ b/app/scripts/auto-type/index.js @@ -152,30 +152,59 @@ const AutoType = { } }, - getActiveWindowTitle(callback) { - logger.debug('Get window title'); - return this.helper.getActiveWindowTitle((err, title, url) => { + getActiveWindowInfo(callback) { + logger.debug('Getting window info'); + return this.helper.getActiveWindowInfo((err, windowInfo) => { if (err) { - logger.error('Error get window title', err); + logger.error('Error getting window info', err); } else { - if (!url) { + if (!windowInfo.url) { // try to find a URL in the title const urlMatcher = new RegExp( 'https?:\\/\\/(www\\.)?[-a-zA-Z0-9@:%._\\+~#=]{2,256}\\.[a-z]{2,4}\\b([-a-zA-Z0-9@:%_\\+.~#?&//=]*)' ); - const urlMatches = urlMatcher.exec(title); - url = urlMatches && urlMatches.length > 0 ? urlMatches[0] : null; + const urlMatches = urlMatcher.exec(windowInfo.title); + windowInfo.url = urlMatches && urlMatches.length > 0 ? urlMatches[0] : null; } - logger.debug('Window title', title, url); + logger.debug('Window info', windowInfo.id, windowInfo.title, windowInfo.url); } - return callback(err, title, url); + return callback(err, windowInfo); + }); + }, + + activeWindowMatches(windowInfo, callback) { + if (!windowInfo || !windowInfo.id) { + logger.debug('Skipped active window check because window id is unknown'); + return callback(true); + } + this.getActiveWindowInfo((err, activeWindowInfo) => { + if (!activeWindowInfo) { + logger.debug('Error during active window check, something is wrong', err); + return callback(false); + } + if (activeWindowInfo.id !== windowInfo.id) { + logger.info( + `Active window doesn't match: ID is different. ` + + `Expected ${windowInfo.id}, got ${activeWindowInfo.id}` + ); + return callback(false, activeWindowInfo); + } + if (activeWindowInfo.url !== windowInfo.url) { + logger.info( + `Active window doesn't match: url is different. ` + + `Expected "${windowInfo.url}", got "${activeWindowInfo.url}"` + ); + return callback(false, activeWindowInfo); + } + logger.info('Active window matches'); + callback(true, activeWindowInfo); }); }, selectEntryAndRun() { - this.getActiveWindowTitle((e, title, url) => { - const filter = new AutoTypeFilter({ title, url }, this.appModel); - const evt = { filter }; + this.getActiveWindowInfo((e, windowInfo) => { + const filter = new AutoTypeFilter(windowInfo, this.appModel); + const evt = { filter, windowInfo }; if (!this.appModel.files.hasOpenFiles()) { this.pendingEvent = evt; this.appModel.files.once('update', this.processPendingEvent, this); @@ -211,7 +240,11 @@ const AutoType = { this.selectEntryView = null; this.hideWindow(() => { if (result) { - this.runAndHandleResult(result); + this.activeWindowMatches(evt.windowInfo, (matches, activeWindowInfo) => { + if (matches) { + this.runAndHandleResult(result); + } + }); } }); }); diff --git a/release-notes.md b/release-notes.md index 9d34cbd8..8c58565b 100644 --- a/release-notes.md +++ b/release-notes.md @@ -6,6 +6,7 @@ Release notes `+` #1243: auto-type any field `-` fix #764: multiple attachments display `-` fix multi-line fields display in history +`-` fix #554: checking active window id during auto-type ##### v1.10.0 (2019-09-09) `+` macOS Dark theme