fix #554: checking active window id during auto-type

This commit is contained in:
antelle 2019-09-12 22:38:21 +02:00
parent 068e49c53c
commit e0291b2d52
5 changed files with 98 additions and 29 deletions

View File

@ -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()
});
});
}
});

View File

@ -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);
}
});
};

View File

@ -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);
}
});
};

View File

@ -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);
}
});
}
});
});

View File

@ -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