mirror of
https://github.com/fofolee/uTools-quickcommand.git
synced 2025-06-28 20:02:44 +08:00
windows自动化新增基于C#的浏览器控制,和macos自动化下基于AppleScript的浏览器自动化一起作为备选方案
This commit is contained in:
parent
1a1ec4b45f
commit
59b5c220ed
@ -11,6 +11,7 @@ const quickcomposer = {
|
||||
windows: require("./quickcomposer/windows"),
|
||||
macos: require("./quickcomposer/macos"),
|
||||
status: require("./quickcomposer/status"),
|
||||
browser: require("./quickcomposer/browser"),
|
||||
};
|
||||
|
||||
module.exports = quickcomposer;
|
||||
|
296
plugin/lib/quickcomposer/windows/browser.js
Normal file
296
plugin/lib/quickcomposer/windows/browser.js
Normal file
@ -0,0 +1,296 @@
|
||||
const { runCsharpFeature } = require("../../csharp");
|
||||
|
||||
const addressBarName = "地址和搜索栏";
|
||||
const addressBarXpath =
|
||||
"/Pane[3]/Pane/Pane[1]/Pane[2]/Pane[1]/ToolBar/Pane/Group/Edit";
|
||||
|
||||
const runBrowserAutomation = async (params) => {
|
||||
const { value, browser = "msedge" } = params;
|
||||
const baseArgs = ["-method", "process", "-window", browser];
|
||||
|
||||
if (value) {
|
||||
baseArgs.push("-type", "setvalue", "-value", value, "-sendenter");
|
||||
} else {
|
||||
baseArgs.push("-type", "getvalue");
|
||||
}
|
||||
|
||||
try {
|
||||
return await runCsharpFeature("automation", [
|
||||
...baseArgs,
|
||||
"-name",
|
||||
addressBarName,
|
||||
]);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
try {
|
||||
return await runCsharpFeature("automation", [
|
||||
...baseArgs,
|
||||
"-xpath",
|
||||
addressBarXpath,
|
||||
]);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
throw "获取浏览器地址栏失败";
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const setUrl = async (browser = "msedge", url) => {
|
||||
return await runBrowserAutomation({ value: url, browser });
|
||||
};
|
||||
|
||||
const getUrl = async (browser = "msedge") => {
|
||||
return await runBrowserAutomation({ browser });
|
||||
};
|
||||
|
||||
const executeScript = async (browser = "msedge", script, args = {}) => {
|
||||
// 构建参数列表
|
||||
const argNames = Object.keys(args);
|
||||
const argValues = Object.values(args).map((v) => JSON.stringify(v));
|
||||
|
||||
const wrapperScript = `
|
||||
(function(${argNames.join(", ")}) {
|
||||
${script}
|
||||
})(${argValues.join(", ")})
|
||||
`;
|
||||
return await runBrowserAutomation({
|
||||
value: `javascript:${encodeURIComponent(wrapperScript)}`,
|
||||
browser,
|
||||
});
|
||||
};
|
||||
|
||||
// 点击元素
|
||||
const clickElement = async (browser = "msedge", selector) => {
|
||||
const script = `
|
||||
const element = document.querySelector('${selector}');
|
||||
if (element) {
|
||||
element.click();
|
||||
return '##execute_script_success##';
|
||||
} else {
|
||||
return '##execute_script_failed##';
|
||||
}
|
||||
`;
|
||||
return await executeScript(browser, script);
|
||||
};
|
||||
|
||||
// 输入文本
|
||||
const inputText = async (browser = "msedge", selector, text) => {
|
||||
const script = `
|
||||
const element = document.querySelector('${selector}');
|
||||
if (element) {
|
||||
element.value = '${text}';
|
||||
element.dispatchEvent(new Event('input'));
|
||||
element.dispatchEvent(new Event('change'));
|
||||
return '##execute_script_success##';
|
||||
} else {
|
||||
return '##execute_script_failed##';
|
||||
}
|
||||
`;
|
||||
return await executeScript(browser, script);
|
||||
};
|
||||
|
||||
// 获取文本
|
||||
const getText = async (browser = "msedge", selector) => {
|
||||
const script = `
|
||||
const element = document.querySelector('${selector}');
|
||||
return element ? element.textContent : '';
|
||||
`;
|
||||
return await executeScript(browser, script);
|
||||
};
|
||||
|
||||
// 获取HTML
|
||||
const getHtml = async (browser = "msedge", selector) => {
|
||||
const script = `
|
||||
const element = document.querySelector('${selector}');
|
||||
return element ? element.innerHTML : '';
|
||||
`;
|
||||
return await executeScript(browser, script);
|
||||
};
|
||||
|
||||
// 隐藏元素
|
||||
const hideElement = async (browser = "msedge", selector) => {
|
||||
const script = `
|
||||
const element = document.querySelector('${selector}');
|
||||
if (element) {
|
||||
element.style.display = 'none';
|
||||
return '##execute_script_success##';
|
||||
} else {
|
||||
return '##execute_script_failed##';
|
||||
}
|
||||
`;
|
||||
return await executeScript(browser, script);
|
||||
};
|
||||
|
||||
// 显示元素
|
||||
const showElement = async (browser = "msedge", selector) => {
|
||||
const script = `
|
||||
const element = document.querySelector('${selector}');
|
||||
if (element) {
|
||||
element.style.display = '';
|
||||
return '##execute_script_success##';
|
||||
} else {
|
||||
return '##execute_script_failed##';
|
||||
}
|
||||
`;
|
||||
return await executeScript(browser, script);
|
||||
};
|
||||
|
||||
// 注入CSS
|
||||
const injectCSS = async (browser = "msedge", css) => {
|
||||
const script = `
|
||||
const style = document.createElement('style');
|
||||
style.textContent = \`${css}\`;
|
||||
document.head.appendChild(style);
|
||||
return '##execute_script_success##';
|
||||
`;
|
||||
return await executeScript(browser, script);
|
||||
};
|
||||
|
||||
// 设置Cookie
|
||||
const setCookie = async (browser = "msedge", cookies, options = {}) => {
|
||||
const cookieStatements = cookies
|
||||
.map((cookie) => {
|
||||
let cookieString = `${cookie.name}=${cookie.value}`;
|
||||
if (options.expires) {
|
||||
const expiresDate = new Date(
|
||||
Date.now() + options.expires * 60 * 60 * 1000
|
||||
);
|
||||
cookieString += `;expires=${expiresDate.toUTCString()}`;
|
||||
}
|
||||
if (options.path) cookieString += `;path=${options.path}`;
|
||||
if (options.domain) cookieString += `;domain=${options.domain}`;
|
||||
if (options.secure) cookieString += ";secure";
|
||||
return `document.cookie = ${JSON.stringify(cookieString)};`;
|
||||
})
|
||||
.join("\n");
|
||||
|
||||
const script = `
|
||||
${cookieStatements}
|
||||
return '##execute_script_success##';
|
||||
`;
|
||||
|
||||
return await this.executeScript(browser, script);
|
||||
};
|
||||
|
||||
// 获取Cookie
|
||||
const getCookie = async (browser = "msedge", name) => {
|
||||
const script = `
|
||||
const value = document.cookie
|
||||
.split('; ')
|
||||
.find(row => row.startsWith('${name}='))
|
||||
?.split('=')[1];
|
||||
return value || '';
|
||||
`;
|
||||
return await executeScript(browser, script);
|
||||
};
|
||||
|
||||
// 删除Cookie
|
||||
const deleteCookie = async (
|
||||
browser = "msedge",
|
||||
name,
|
||||
path = "/",
|
||||
domain = ""
|
||||
) => {
|
||||
const script = `
|
||||
document.cookie = '${name}=; expires=Thu, 01 Jan 1970 00:00:00 GMT' +
|
||||
(${domain ? `'; domain=${domain}'` : "''"}) +
|
||||
(${path ? `'; path=${path}'` : "''"});
|
||||
return '##execute_script_success##';
|
||||
`;
|
||||
return await executeScript(browser, script);
|
||||
};
|
||||
|
||||
// 滚动到指定位置
|
||||
const scrollTo = async (browser = "msedge", x, y) => {
|
||||
const script = `
|
||||
window.scrollTo(${x}, ${y});
|
||||
return '##execute_script_success##';
|
||||
`;
|
||||
return await executeScript(browser, script);
|
||||
};
|
||||
|
||||
// 滚动到元素位置
|
||||
const scrollToElement = async (browser = "msedge", selector) => {
|
||||
const script = `
|
||||
const element = document.querySelector('${selector}');
|
||||
if (element) {
|
||||
element.scrollIntoView({ behavior: 'smooth', block: 'center' });
|
||||
return '##execute_script_success##';
|
||||
} else {
|
||||
return '##execute_script_failed##';
|
||||
}
|
||||
`;
|
||||
return await executeScript(browser, script);
|
||||
};
|
||||
|
||||
// 获取滚动位置
|
||||
const getScrollPosition = async (browser = "msedge") => {
|
||||
const script = `
|
||||
return JSON.stringify({
|
||||
x: window.pageXOffset || document.documentElement.scrollLeft,
|
||||
y: window.pageYOffset || document.documentElement.scrollTop
|
||||
});
|
||||
`;
|
||||
return await executeScript(browser, script);
|
||||
};
|
||||
|
||||
// 获取页面尺寸
|
||||
const getPageSize = async (browser = "msedge") => {
|
||||
const script = `
|
||||
return JSON.stringify({
|
||||
width: Math.max(
|
||||
document.documentElement.scrollWidth,
|
||||
document.documentElement.clientWidth
|
||||
),
|
||||
height: Math.max(
|
||||
document.documentElement.scrollHeight,
|
||||
document.documentElement.clientHeight
|
||||
)
|
||||
});
|
||||
`;
|
||||
return await executeScript(browser, script);
|
||||
};
|
||||
|
||||
// 等待元素出现
|
||||
const waitForElement = async (browser = "msedge", selector, timeout = 5000) => {
|
||||
const startTime = Date.now();
|
||||
|
||||
// 检查元素是否存在的函数
|
||||
const checkScript = `
|
||||
const element = document.querySelector('${selector}');
|
||||
return element ? '##execute_script_success##' : '##execute_script_failed##';
|
||||
`;
|
||||
|
||||
// 轮询检查元素
|
||||
while (Date.now() - startTime < timeout) {
|
||||
const result = await executeScript(browser, checkScript);
|
||||
if (result === true) {
|
||||
return true;
|
||||
}
|
||||
// 等待100ms再次检查
|
||||
await new Promise((resolve) => setTimeout(resolve, 100));
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
getUrl,
|
||||
setUrl,
|
||||
executeScript,
|
||||
clickElement,
|
||||
inputText,
|
||||
getText,
|
||||
getHtml,
|
||||
hideElement,
|
||||
showElement,
|
||||
injectCSS,
|
||||
setCookie,
|
||||
getCookie,
|
||||
deleteCookie,
|
||||
scrollTo,
|
||||
scrollToElement,
|
||||
getScrollPosition,
|
||||
getPageSize,
|
||||
waitForElement,
|
||||
};
|
@ -7,6 +7,7 @@ const service = require("./service");
|
||||
const software = require("./software");
|
||||
const utils = require("./utils");
|
||||
const automation = require("./automation");
|
||||
const browser = require("./browser");
|
||||
|
||||
module.exports = {
|
||||
window,
|
||||
@ -18,4 +19,5 @@ module.exports = {
|
||||
software,
|
||||
utils,
|
||||
automation,
|
||||
browser,
|
||||
};
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { newVarInputVal } from "js/composer/varInputValManager.js";
|
||||
|
||||
import { browserCommands } from "js/composer/commands/browserCommands.js";
|
||||
const sendKeys = [
|
||||
// 特殊按键
|
||||
{ value: "{ENTER}", label: "回车键 (Enter)" },
|
||||
@ -109,7 +109,7 @@ const registryPaths = [
|
||||
const searchWindowConfig = [
|
||||
{
|
||||
label: "窗口查找方式",
|
||||
component: "q-select",
|
||||
component: "QSelect",
|
||||
icon: "search",
|
||||
width: 3,
|
||||
options: [
|
||||
@ -160,7 +160,7 @@ const searchElementConfig = [
|
||||
...windowHandleConfig,
|
||||
{
|
||||
label: "元素查找方式",
|
||||
component: "q-select",
|
||||
component: "QSelect",
|
||||
icon: "search",
|
||||
width: 4,
|
||||
options: [
|
||||
@ -804,6 +804,49 @@ export const windowsCommands = {
|
||||
},
|
||||
],
|
||||
},
|
||||
// 浏览器
|
||||
{
|
||||
value: "quickcomposer.windows.browser.getUrl",
|
||||
label: "浏览器控制",
|
||||
icon: "language",
|
||||
isAsync: true,
|
||||
config: [
|
||||
{
|
||||
component: "ButtonGroup",
|
||||
width: 12,
|
||||
options: [
|
||||
{ label: "Microsoft Edge", value: "msedge" },
|
||||
{ label: "Google Chrome", value: "chrome" },
|
||||
],
|
||||
defaultValue: "msedge",
|
||||
},
|
||||
],
|
||||
subCommands: browserCommands.commands
|
||||
.find((command) => command.label === "浏览器操作")
|
||||
.subCommands.map((command) => ({
|
||||
...command,
|
||||
value: command.value.replace(
|
||||
"quickcomposer.browser.",
|
||||
"quickcomposer.windows.browser."
|
||||
),
|
||||
}))
|
||||
// 无法获得输出,过滤相关命令
|
||||
.filter(
|
||||
(command) =>
|
||||
![
|
||||
"getTabs",
|
||||
"activateTab",
|
||||
"getText",
|
||||
"getHtml",
|
||||
"getCookie",
|
||||
"getScrollPosition",
|
||||
"getPageSize",
|
||||
"waitForElement",
|
||||
]
|
||||
.map((func) => `quickcomposer.windows.browser.${func}`)
|
||||
.includes(command.value)
|
||||
),
|
||||
},
|
||||
// 监控
|
||||
{
|
||||
value: "quickcomposer.windows.monitor.watchClipboard",
|
||||
@ -1019,7 +1062,7 @@ export const windowsCommands = {
|
||||
},
|
||||
{
|
||||
label: "值类型",
|
||||
component: "q-select",
|
||||
component: "QSelect",
|
||||
icon: "category",
|
||||
width: 4,
|
||||
options: [
|
||||
|
Loading…
x
Reference in New Issue
Block a user