mirror of
https://github.com/fofolee/uTools-quickcommand.git
synced 2025-06-29 12:22:44 +08:00
编排补齐utools窗口交互和内容输入的功能
This commit is contained in:
parent
036b6fa934
commit
682f6d0bcd
@ -1,12 +1,10 @@
|
||||
const { findImage } = require("./imageFinder");
|
||||
const { captureScreen } = require("./screenCapture");
|
||||
const sendText = require("./sendText");
|
||||
const { keyboardTap, keySequence } = require("./keyboardTap");
|
||||
|
||||
module.exports = {
|
||||
findImage,
|
||||
captureScreen,
|
||||
sendText,
|
||||
keyboardTap,
|
||||
keySequence,
|
||||
};
|
||||
|
@ -1,11 +0,0 @@
|
||||
const sendText = (text, simulateCopy = false) => {
|
||||
if (simulateCopy) {
|
||||
window.utools.copyText(text);
|
||||
quickcommand.sleep(200);
|
||||
quickcommand.simulatePaste();
|
||||
} else {
|
||||
window.utools.hideMainWindowTypeString(text);
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = sendText;
|
@ -7,42 +7,69 @@
|
||||
>
|
||||
<div class="dict-editor">
|
||||
<div
|
||||
v-for="(item, index) in items"
|
||||
:key="index"
|
||||
v-for="(item, index) in allItems"
|
||||
:key="`${item.type}-${index}`"
|
||||
class="row q-col-gutter-sm items-center"
|
||||
>
|
||||
<div class="col-4">
|
||||
<q-select
|
||||
v-if="options?.items"
|
||||
:model-value="item.key"
|
||||
:options="options.items"
|
||||
label="名称"
|
||||
dense
|
||||
filled
|
||||
use-input
|
||||
input-debounce="0"
|
||||
:hide-selected="!!inputValue"
|
||||
@filter="filterFn"
|
||||
@update:model-value="(val) => handleSelect(val, index)"
|
||||
@input-value="(val) => handleInput(val, index)"
|
||||
@blur="handleBlur"
|
||||
>
|
||||
<template v-slot:prepend>
|
||||
<q-icon name="code" />
|
||||
</template>
|
||||
</q-select>
|
||||
<q-input
|
||||
v-else
|
||||
:model-value="item.key"
|
||||
label="名称"
|
||||
dense
|
||||
filled
|
||||
@update:model-value="(val) => updateItemKey(val, index)"
|
||||
>
|
||||
<template v-slot:prepend>
|
||||
<q-icon name="code" />
|
||||
</template>
|
||||
</q-input>
|
||||
<template v-if="item.type === 'fixed'">
|
||||
<q-input
|
||||
:model-value="item.key"
|
||||
:label="getKeyLabel(item.key)"
|
||||
dense
|
||||
filled
|
||||
readonly
|
||||
disable
|
||||
>
|
||||
<template v-slot:prepend>
|
||||
<q-icon name="lock" />
|
||||
</template>
|
||||
</q-input>
|
||||
</template>
|
||||
<template v-else>
|
||||
<q-select
|
||||
v-if="options?.optionKeys"
|
||||
:model-value="item.key"
|
||||
:options="normalizedOptionKeys"
|
||||
label="名称"
|
||||
dense
|
||||
filled
|
||||
use-input
|
||||
input-debounce="0"
|
||||
:hide-selected="!!inputValue"
|
||||
@filter="filterFn"
|
||||
@update:model-value="
|
||||
(val) => handleSelect(val, getEditableIndex(index))
|
||||
"
|
||||
@input-value="(val) => handleInput(val, getEditableIndex(index))"
|
||||
@blur="handleBlur"
|
||||
>
|
||||
<template v-slot:prepend>
|
||||
<q-icon name="code" />
|
||||
</template>
|
||||
<template v-slot:option="scope">
|
||||
<q-item v-bind="scope.itemProps">
|
||||
<q-item-section>
|
||||
{{ getKeyLabel(scope.opt) }}
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
</template>
|
||||
</q-select>
|
||||
<q-input
|
||||
v-else
|
||||
:model-value="item.key"
|
||||
label="名称"
|
||||
dense
|
||||
filled
|
||||
@update:model-value="
|
||||
(val) => updateItemKey(val, getEditableIndex(index))
|
||||
"
|
||||
>
|
||||
<template v-slot:prepend>
|
||||
<q-icon name="code" />
|
||||
</template>
|
||||
</q-input>
|
||||
</template>
|
||||
</div>
|
||||
<div class="col">
|
||||
<VariableInput
|
||||
@ -50,12 +77,14 @@
|
||||
label="值"
|
||||
icon="code"
|
||||
class="col-grow"
|
||||
@update:model-value="(val) => updateItemValue(val, index)"
|
||||
@update:model-value="
|
||||
(val) => updateItemValue(val, index, item.type === 'fixed')
|
||||
"
|
||||
/>
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<div v-if="item.type !== 'fixed'" class="col-auto">
|
||||
<div class="btn-container">
|
||||
<template v-if="items.length === 1">
|
||||
<template v-if="editableItems.length === 1">
|
||||
<q-btn
|
||||
flat
|
||||
dense
|
||||
@ -65,14 +94,16 @@
|
||||
@click="addItem"
|
||||
/>
|
||||
</template>
|
||||
<template v-else-if="index === items.length - 1">
|
||||
<template
|
||||
v-else-if="getEditableIndex(index) === editableItems.length - 1"
|
||||
>
|
||||
<q-btn
|
||||
flat
|
||||
dense
|
||||
size="sm"
|
||||
icon="remove"
|
||||
class="top-btn"
|
||||
@click="removeItem(index)"
|
||||
@click="removeItem(getEditableIndex(index))"
|
||||
/>
|
||||
<q-btn
|
||||
flat
|
||||
@ -90,7 +121,7 @@
|
||||
size="sm"
|
||||
icon="remove"
|
||||
class="center-btn"
|
||||
@click="removeItem(index)"
|
||||
@click="removeItem(getEditableIndex(index))"
|
||||
/>
|
||||
</template>
|
||||
</div>
|
||||
@ -112,7 +143,8 @@ import BorderLabel from "components/composer/common/BorderLabel.vue";
|
||||
*
|
||||
* @property {Object} modelValue - 绑定的字典对象
|
||||
* @property {Object} options - 配置选项
|
||||
* @property {String[]} [options.items] - 键名的下拉选择选项
|
||||
* @property {String[]|Object[]} [options.optionKeys] - 可选键名
|
||||
* @property {String[]|Object[]} [options.fixedKeys] - 固定键名
|
||||
*
|
||||
* @example
|
||||
* // 基础字典对象
|
||||
@ -164,40 +196,105 @@ export default defineComponent({
|
||||
emits: ["update:modelValue"],
|
||||
data() {
|
||||
const modelEntries = Object.entries(this.modelValue || {});
|
||||
const fixedKeys = this.normalizeKeys(this.options?.fixedKeys || []);
|
||||
const fixedKeyValues = fixedKeys.map((key) => ({
|
||||
type: "fixed",
|
||||
key: key.value,
|
||||
value:
|
||||
modelEntries.find(([k]) => k === key.value)?.[1] ||
|
||||
newVarInputVal("str"),
|
||||
}));
|
||||
|
||||
const editableEntries = modelEntries.filter(
|
||||
([key]) => !fixedKeys.some((k) => k.value === key)
|
||||
);
|
||||
|
||||
return {
|
||||
localItems: modelEntries.length
|
||||
? modelEntries.map(([key, value]) => ({ key, value }))
|
||||
: [
|
||||
{
|
||||
key: "",
|
||||
value: newVarInputVal("str"),
|
||||
},
|
||||
],
|
||||
filterOptions: this.options?.items || [],
|
||||
fixedItems: fixedKeyValues,
|
||||
localItems: editableEntries.length
|
||||
? editableEntries.map(([key, value]) => ({
|
||||
type: "editable",
|
||||
key,
|
||||
value,
|
||||
}))
|
||||
: [{ type: "editable", key: "", value: newVarInputVal("str") }],
|
||||
filterOptions: this.normalizeKeys(this.options?.optionKeys || []),
|
||||
inputValue: "",
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
items: {
|
||||
editableItems: {
|
||||
get() {
|
||||
return this.localItems;
|
||||
},
|
||||
set(newItems) {
|
||||
this.localItems = newItems;
|
||||
const dict = {};
|
||||
newItems.forEach((item) => {
|
||||
if (item.key) {
|
||||
dict[item.key] = item.value;
|
||||
}
|
||||
});
|
||||
this.$emit("update:modelValue", dict);
|
||||
this.updateModelValue();
|
||||
},
|
||||
},
|
||||
allItems() {
|
||||
return [...this.fixedItems, ...this.localItems];
|
||||
},
|
||||
normalizedOptionKeys() {
|
||||
return this.filterOptions;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
normalizeKeys(keys) {
|
||||
return keys.map((key) => {
|
||||
if (typeof key === "string") {
|
||||
return { value: key, label: key };
|
||||
}
|
||||
return key;
|
||||
});
|
||||
},
|
||||
|
||||
getKeyLabel(key) {
|
||||
if (typeof key === "object") return key.label;
|
||||
const allKeys = [
|
||||
...this.normalizeKeys(this.options?.fixedKeys || []),
|
||||
...this.normalizeKeys(this.options?.optionKeys || []),
|
||||
];
|
||||
return allKeys.find((k) => k.value === key)?.label || key;
|
||||
},
|
||||
|
||||
getEditableIndex(index) {
|
||||
return index - this.fixedItems.length;
|
||||
},
|
||||
|
||||
updateModelValue() {
|
||||
const dict = {};
|
||||
// 先添加固定键
|
||||
this.fixedItems.forEach((item) => {
|
||||
if (item.key) {
|
||||
dict[item.key] = item.value;
|
||||
}
|
||||
});
|
||||
// 再添加可编辑键
|
||||
this.localItems.forEach((item) => {
|
||||
if (item.key) {
|
||||
dict[item.key] = item.value;
|
||||
}
|
||||
});
|
||||
this.$emit("update:modelValue", dict);
|
||||
},
|
||||
|
||||
updateItemValue(val, index, isFixed = false) {
|
||||
if (isFixed) {
|
||||
const newItems = [...this.fixedItems];
|
||||
newItems[index].value = val;
|
||||
this.fixedItems = newItems;
|
||||
} else {
|
||||
const newItems = [...this.localItems];
|
||||
newItems[index].value = val;
|
||||
this.localItems = newItems;
|
||||
}
|
||||
this.updateModelValue();
|
||||
},
|
||||
|
||||
addItem() {
|
||||
this.items = [
|
||||
...this.items,
|
||||
this.localItems = [
|
||||
...this.localItems,
|
||||
{
|
||||
key: "",
|
||||
value: newVarInputVal("str"),
|
||||
@ -205,7 +302,7 @@ export default defineComponent({
|
||||
];
|
||||
},
|
||||
removeItem(index) {
|
||||
const newItems = [...this.items];
|
||||
const newItems = [...this.localItems];
|
||||
newItems.splice(index, 1);
|
||||
if (newItems.length === 0) {
|
||||
newItems.push({
|
||||
@ -213,45 +310,46 @@ export default defineComponent({
|
||||
value: newVarInputVal("str"),
|
||||
});
|
||||
}
|
||||
this.items = newItems;
|
||||
this.localItems = newItems;
|
||||
},
|
||||
updateItemKey(val, index) {
|
||||
const newItems = [...this.items];
|
||||
const newItems = [...this.localItems];
|
||||
newItems[index].key = val;
|
||||
this.items = newItems;
|
||||
},
|
||||
updateItemValue(val, index) {
|
||||
const newItems = [...this.items];
|
||||
newItems[index].value = val;
|
||||
this.items = newItems;
|
||||
this.localItems = newItems;
|
||||
},
|
||||
handleInput(val, index) {
|
||||
this.inputValue = val;
|
||||
if (val && !this.filterOptions.includes(val)) {
|
||||
const newItems = [...this.items];
|
||||
if (val) {
|
||||
const newItems = [...this.localItems];
|
||||
newItems[index].key = val;
|
||||
this.items = newItems;
|
||||
this.localItems = newItems;
|
||||
this.updateModelValue();
|
||||
}
|
||||
},
|
||||
handleSelect(val, index) {
|
||||
this.inputValue = "";
|
||||
const newItems = [...this.items];
|
||||
newItems[index].key = val;
|
||||
this.items = newItems;
|
||||
const newItems = [...this.localItems];
|
||||
newItems[index].key = val.value || val;
|
||||
this.localItems = newItems;
|
||||
this.updateModelValue();
|
||||
},
|
||||
handleBlur() {
|
||||
this.inputValue = "";
|
||||
},
|
||||
filterFn(val, update) {
|
||||
if (!this.options?.items) return;
|
||||
if (!this.options?.optionKeys) return;
|
||||
|
||||
update(() => {
|
||||
if (val === "") {
|
||||
this.filterOptions = this.options.items;
|
||||
this.filterOptions = this.normalizeKeys(this.options.optionKeys);
|
||||
} else {
|
||||
const needle = val.toLowerCase();
|
||||
this.filterOptions = this.options.items.filter(
|
||||
(v) => v.toLowerCase().indexOf(needle) > -1
|
||||
this.filterOptions = this.normalizeKeys(
|
||||
this.options.optionKeys
|
||||
).filter(
|
||||
(v) =>
|
||||
v.label.toLowerCase().indexOf(needle) > -1 ||
|
||||
v.value.toLowerCase().indexOf(needle) > -1
|
||||
);
|
||||
}
|
||||
});
|
||||
|
@ -102,7 +102,7 @@
|
||||
<DictEditor
|
||||
v-model="argvs.otherHeaders"
|
||||
:options="{
|
||||
items: commonHeaderOptions,
|
||||
optionKeys: commonHeaderOptions,
|
||||
}"
|
||||
@update:model-value="updateHeaders"
|
||||
/>
|
||||
|
@ -33,7 +33,7 @@ export const simulateCommands = {
|
||||
],
|
||||
},
|
||||
{
|
||||
value: "quickcomposer.simulate.sendText",
|
||||
value: "utools.hideMainWindowTypeString",
|
||||
label: "发送文本",
|
||||
config: [
|
||||
{
|
||||
@ -41,18 +41,73 @@ export const simulateCommands = {
|
||||
label: "要发送的文本内容",
|
||||
type: "varInput",
|
||||
icon: "send",
|
||||
width: 9,
|
||||
width: 12,
|
||||
},
|
||||
],
|
||||
subCommands: [
|
||||
{
|
||||
value: "utools.hideMainWindowTypeString",
|
||||
label: "模拟输入",
|
||||
icon: "keyboard",
|
||||
},
|
||||
{
|
||||
label: "发送方式",
|
||||
type: "select",
|
||||
defaultValue: false,
|
||||
icon: "keyboard",
|
||||
options: [
|
||||
{ label: "模拟输入", value: false },
|
||||
{ label: "模拟粘贴", value: true },
|
||||
value: "utools.hideMainWindowPasteText",
|
||||
label: "模拟粘贴",
|
||||
icon: "content_paste",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
value: "utools.hideMainWindowPasteFile",
|
||||
label: "模拟粘贴文件/图片",
|
||||
icon: "file_copy",
|
||||
subCommands: [
|
||||
{
|
||||
value: "utools.hideMainWindowPasteFile",
|
||||
label: "粘贴文件",
|
||||
icon: "file_copy",
|
||||
config: [
|
||||
{
|
||||
key: "file",
|
||||
label: "文件路径",
|
||||
type: "varInput",
|
||||
icon: "description",
|
||||
width: 12,
|
||||
options: {
|
||||
dialog: {
|
||||
type: "open",
|
||||
options: {
|
||||
title: "选择文件",
|
||||
properties: [
|
||||
"openFile",
|
||||
"multiSelections",
|
||||
"showHiddenFiles",
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
value: "utools.hideMainWindowPasteImage",
|
||||
label: "粘贴图片",
|
||||
icon: "image",
|
||||
config: [
|
||||
{
|
||||
key: "image",
|
||||
label: "图片路径/base64",
|
||||
type: "varInput",
|
||||
icon: "image",
|
||||
width: 12,
|
||||
options: {
|
||||
dialog: {
|
||||
title: "选择图片",
|
||||
properties: ["openFile", "showHiddenFiles"],
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
width: 3,
|
||||
},
|
||||
],
|
||||
},
|
||||
|
@ -1,3 +1,5 @@
|
||||
import { newVarInputVal } from "js/composer/varInputValManager";
|
||||
|
||||
export const utoolsCommands = {
|
||||
label: "uTools功能",
|
||||
icon: "insights",
|
||||
@ -83,5 +85,95 @@ export const utoolsCommands = {
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
value: "utools.findInPage",
|
||||
label: "插件内查找",
|
||||
desc: "插件内查找",
|
||||
icon: "search",
|
||||
subCommands: [
|
||||
{
|
||||
value: "utools.findInPage",
|
||||
label: "查找文本",
|
||||
desc: "查找文本",
|
||||
icon: "search",
|
||||
config: [
|
||||
{
|
||||
key: "text",
|
||||
label: "文本",
|
||||
type: "varInput",
|
||||
icon: "search",
|
||||
width: 12,
|
||||
},
|
||||
{
|
||||
key: "options",
|
||||
label: "选项",
|
||||
type: "dictEditor",
|
||||
icon: "settings",
|
||||
options: {
|
||||
fixedKeys: [
|
||||
{
|
||||
value: "forward",
|
||||
label: "向前查找",
|
||||
},
|
||||
{
|
||||
value: "findNext",
|
||||
label: "查找下一个",
|
||||
},
|
||||
{
|
||||
value: "matchCase",
|
||||
label: "区分大小写",
|
||||
},
|
||||
{
|
||||
value: "wordStart",
|
||||
label: "单词开头",
|
||||
},
|
||||
{
|
||||
value: "medialCapitalAsWordStart",
|
||||
label: "中缀大写作为单词开头",
|
||||
},
|
||||
],
|
||||
},
|
||||
defaultValue: {
|
||||
forward: newVarInputVal("var", "true"),
|
||||
findNext: newVarInputVal("var", "false"),
|
||||
matchCase: newVarInputVal("var", "false"),
|
||||
wordStart: newVarInputVal("var", "false"),
|
||||
medialCapitalAsWordStart: newVarInputVal("var", "false"),
|
||||
},
|
||||
width: 12,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
value: "utools.stopFindInPage",
|
||||
label: "停止查找",
|
||||
desc: "停止查找",
|
||||
icon: "stop",
|
||||
config: [
|
||||
{
|
||||
key: "action",
|
||||
label: "动作",
|
||||
type: "buttonGroup",
|
||||
icon: "settings",
|
||||
width: 12,
|
||||
options: [
|
||||
{ label: "清除选择", value: "clearSelection" },
|
||||
{ label: "保持选择", value: "keepSelection" },
|
||||
{ label: "激活选择", value: "activateSelection" },
|
||||
],
|
||||
defaultValue: "clearSelection",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
value: "utools.getWindowType",
|
||||
label: "获取当前窗口类型",
|
||||
desc: "获取当前窗口类型",
|
||||
icon: "window",
|
||||
outputVariable: "windowType",
|
||||
saveOutput: true,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
4
src/plugins/monaco/types/utools.api.d.ts
vendored
4
src/plugins/monaco/types/utools.api.d.ts
vendored
@ -424,6 +424,10 @@ interface UToolsApi {
|
||||
* 拖拽文件
|
||||
*/
|
||||
startDrag(file: string | string[]): void;
|
||||
/**
|
||||
* 获取当前窗口类型
|
||||
*/
|
||||
getWindowType(): "main" | "detach" | "browser";
|
||||
/**
|
||||
* 屏幕取色
|
||||
*/
|
||||
|
Loading…
x
Reference in New Issue
Block a user