command-cmd 1.0.2 → 1.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cmd.js +2165 -16
- package/doc.md +292 -152
- package/docPTBR.md +299 -152
- package/map.md +244 -0
- package/mapPTBR.md +244 -0
- package/package.json +5 -2
package/cmd.js
CHANGED
|
@@ -1,3 +1,135 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { fileURLToPath } from 'url';
|
|
4
|
+
|
|
5
|
+
const { readFile, writeFile, mkdir } = fs.promises;
|
|
6
|
+
const { resolve: resolvePath, dirname: dirnamePath } = path;
|
|
7
|
+
|
|
8
|
+
const MODULE_DIR = dirnamePath(fileURLToPath(import.meta.url));
|
|
9
|
+
|
|
10
|
+
const DEFAULT_APPS = Object.freeze({
|
|
11
|
+
spotify: {
|
|
12
|
+
launcher: { x: -2, y: 145 },
|
|
13
|
+
searchIcon: { x: 584, y: 90 }
|
|
14
|
+
},
|
|
15
|
+
chrome: {
|
|
16
|
+
launcher: { x: 20, y: 219 },
|
|
17
|
+
searchIcon: { x: 546, y: 87 }
|
|
18
|
+
},
|
|
19
|
+
youtube: {
|
|
20
|
+
launcher: { x: 20, y: 225 },
|
|
21
|
+
searchIcon: { x: 575, y: 144 }
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
const DOC_TEMPLATE_MAP = Object.freeze({
|
|
26
|
+
doc_en: Object.freeze({
|
|
27
|
+
key: 'doc_en',
|
|
28
|
+
source: 'doc.md',
|
|
29
|
+
target: 'doc.md',
|
|
30
|
+
isMapDoc: false
|
|
31
|
+
}),
|
|
32
|
+
doc_ptbr: Object.freeze({
|
|
33
|
+
key: 'doc_ptbr',
|
|
34
|
+
source: 'docPTBR.md',
|
|
35
|
+
target: 'docPTBR.md',
|
|
36
|
+
isMapDoc: false
|
|
37
|
+
}),
|
|
38
|
+
map_en: Object.freeze({
|
|
39
|
+
key: 'map_en',
|
|
40
|
+
source: 'map.md',
|
|
41
|
+
target: 'map.md',
|
|
42
|
+
isMapDoc: true
|
|
43
|
+
}),
|
|
44
|
+
map_ptbr: Object.freeze({
|
|
45
|
+
key: 'map_ptbr',
|
|
46
|
+
source: 'mapPTBR.md',
|
|
47
|
+
target: 'mapPTBR.md',
|
|
48
|
+
isMapDoc: true
|
|
49
|
+
})
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
const DOC_TEMPLATES = Object.freeze(Object.values(DOC_TEMPLATE_MAP));
|
|
53
|
+
|
|
54
|
+
const ACTION_ALIASES = Object.freeze({
|
|
55
|
+
skip_ads: 'skip_ads',
|
|
56
|
+
skipads: 'skip_ads',
|
|
57
|
+
pular_ads: 'skip_ads',
|
|
58
|
+
pularads: 'skip_ads',
|
|
59
|
+
click: 'click',
|
|
60
|
+
clicar: 'click',
|
|
61
|
+
double_click: 'double_click',
|
|
62
|
+
doubleclick: 'double_click',
|
|
63
|
+
clique_duplo: 'double_click',
|
|
64
|
+
cliqueduplo: 'double_click',
|
|
65
|
+
scroll: 'scroll',
|
|
66
|
+
rolar: 'scroll',
|
|
67
|
+
move_sequence: 'move_sequence',
|
|
68
|
+
movesequence: 'move_sequence',
|
|
69
|
+
mover_sequencia: 'move_sequence',
|
|
70
|
+
moversequencia: 'move_sequence',
|
|
71
|
+
sequencia_movimento: 'move_sequence',
|
|
72
|
+
sequence_move: 'move_sequence',
|
|
73
|
+
open_app: 'open_app',
|
|
74
|
+
openapp: 'open_app',
|
|
75
|
+
abrir_app: 'open_app',
|
|
76
|
+
abrirapp: 'open_app',
|
|
77
|
+
close_app: 'close_app',
|
|
78
|
+
closeapp: 'close_app',
|
|
79
|
+
fechar_app: 'close_app',
|
|
80
|
+
fecharapp: 'close_app',
|
|
81
|
+
key_tap: 'key_tap',
|
|
82
|
+
keytap: 'key_tap',
|
|
83
|
+
tap_key: 'key_tap',
|
|
84
|
+
tapkey: 'key_tap',
|
|
85
|
+
press_key: 'key_tap',
|
|
86
|
+
pressionar_tecla: 'key_tap',
|
|
87
|
+
tecla: 'key_tap',
|
|
88
|
+
type_string_delayed: 'type_string_delayed',
|
|
89
|
+
typestringdelayed: 'type_string_delayed',
|
|
90
|
+
type_string: 'type_string_delayed',
|
|
91
|
+
typestring: 'type_string_delayed',
|
|
92
|
+
digitar: 'type_string_delayed',
|
|
93
|
+
escrever: 'type_string_delayed'
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
const BUTTON_ALIASES = Object.freeze({
|
|
97
|
+
pularads: 'pular_ads',
|
|
98
|
+
pular_ads: 'pular_ads',
|
|
99
|
+
pular_anuncio: 'pular_ads',
|
|
100
|
+
pular_anuncios: 'pular_ads',
|
|
101
|
+
skip_ads: 'pular_ads',
|
|
102
|
+
skipad: 'pular_ads',
|
|
103
|
+
search: 'barra_pesquisa',
|
|
104
|
+
searchbar: 'barra_pesquisa',
|
|
105
|
+
search_bar: 'barra_pesquisa',
|
|
106
|
+
barra_pesquisa: 'barra_pesquisa',
|
|
107
|
+
barrapesquisa: 'barra_pesquisa',
|
|
108
|
+
fechar: 'fechar',
|
|
109
|
+
close: 'fechar',
|
|
110
|
+
close_app: 'fechar'
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
const APP_ALIASES = Object.freeze({
|
|
114
|
+
google: 'chrome',
|
|
115
|
+
google_chrome: 'chrome'
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
const APP_STATE = Object.freeze({
|
|
119
|
+
OPEN: 'aberto',
|
|
120
|
+
CLOSED: 'fechado'
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
const CLICK_MODE = Object.freeze({
|
|
124
|
+
NONE: 'none',
|
|
125
|
+
BETWEEN: 'between',
|
|
126
|
+
EACH: 'each',
|
|
127
|
+
FIRST: 'first',
|
|
128
|
+
LAST: 'last'
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
let robotCache;
|
|
132
|
+
|
|
1
133
|
export function cmd(message) {
|
|
2
134
|
if (typeof message !== 'string') {
|
|
3
135
|
return [];
|
|
@@ -11,10 +143,21 @@ export function cmd(message) {
|
|
|
11
143
|
const inside = match[1].trim();
|
|
12
144
|
if (!inside) continue;
|
|
13
145
|
|
|
14
|
-
const
|
|
146
|
+
const command = {
|
|
15
147
|
type: undefined,
|
|
16
148
|
command: undefined,
|
|
17
149
|
extra: undefined,
|
|
150
|
+
button: undefined,
|
|
151
|
+
key: undefined,
|
|
152
|
+
modifiers: undefined,
|
|
153
|
+
text: undefined,
|
|
154
|
+
typeDelay: undefined,
|
|
155
|
+
points: undefined,
|
|
156
|
+
path: undefined,
|
|
157
|
+
interval: undefined,
|
|
158
|
+
clickDelay: undefined,
|
|
159
|
+
click: undefined,
|
|
160
|
+
doubleClick: undefined,
|
|
18
161
|
seq: undefined
|
|
19
162
|
};
|
|
20
163
|
|
|
@@ -24,6 +167,13 @@ export function cmd(message) {
|
|
|
24
167
|
const part = rawPart.trim();
|
|
25
168
|
if (!part) continue;
|
|
26
169
|
|
|
170
|
+
if (part.indexOf(':') === -1) {
|
|
171
|
+
if (!command.type) {
|
|
172
|
+
command.type = part;
|
|
173
|
+
}
|
|
174
|
+
continue;
|
|
175
|
+
}
|
|
176
|
+
|
|
27
177
|
const [rawKey, ...rest] = part.split(':');
|
|
28
178
|
if (!rawKey || rest.length === 0) continue;
|
|
29
179
|
|
|
@@ -32,28 +182,111 @@ export function cmd(message) {
|
|
|
32
182
|
if (!value) continue;
|
|
33
183
|
|
|
34
184
|
if (key === 'type' || key === 'tipo') {
|
|
35
|
-
|
|
185
|
+
command.type = value;
|
|
36
186
|
} else if (key === 'command' || key === 'comando') {
|
|
37
|
-
|
|
187
|
+
command.command = value;
|
|
38
188
|
} else if (key === 'extra') {
|
|
39
|
-
|
|
189
|
+
command.extra = value;
|
|
190
|
+
} else if (key === 'button' || key === 'botao' || key === 'botão') {
|
|
191
|
+
command.button = value;
|
|
192
|
+
} else if (key === 'key' || key === 'tecla' || key === 'hotkey') {
|
|
193
|
+
command.key = value;
|
|
194
|
+
if (!command.command) {
|
|
195
|
+
command.command = value;
|
|
196
|
+
}
|
|
197
|
+
} else if (
|
|
198
|
+
key === 'modifier' ||
|
|
199
|
+
key === 'modifiers' ||
|
|
200
|
+
key === 'modificador' ||
|
|
201
|
+
key === 'modificadores'
|
|
202
|
+
) {
|
|
203
|
+
command.modifiers = value;
|
|
204
|
+
} else if (
|
|
205
|
+
key === 'text' ||
|
|
206
|
+
key === 'texto' ||
|
|
207
|
+
key === 'string' ||
|
|
208
|
+
key === 'mensagem'
|
|
209
|
+
) {
|
|
210
|
+
command.text = value;
|
|
211
|
+
if (!command.command) {
|
|
212
|
+
command.command = value;
|
|
213
|
+
}
|
|
214
|
+
} else if (
|
|
215
|
+
key === 'typedelay' ||
|
|
216
|
+
key === 'type_delay' ||
|
|
217
|
+
key === 'typingdelay' ||
|
|
218
|
+
key === 'typing_delay' ||
|
|
219
|
+
key === 'textdelay' ||
|
|
220
|
+
key === 'delaytexto' ||
|
|
221
|
+
key === 'delaydigitacao' ||
|
|
222
|
+
key === 'delaydigitar'
|
|
223
|
+
) {
|
|
224
|
+
const typeDelay = toNonNegativeInteger(value);
|
|
225
|
+
if (typeDelay !== null) {
|
|
226
|
+
command.typeDelay = typeDelay;
|
|
227
|
+
}
|
|
228
|
+
} else if (
|
|
229
|
+
key === 'points' ||
|
|
230
|
+
key === 'pontos' ||
|
|
231
|
+
key === 'path' ||
|
|
232
|
+
key === 'trajeto' ||
|
|
233
|
+
key === 'caminho' ||
|
|
234
|
+
key === 'coords' ||
|
|
235
|
+
key === 'coordenadas'
|
|
236
|
+
) {
|
|
237
|
+
command.points = value;
|
|
238
|
+
command.path = value;
|
|
239
|
+
if (!command.command) {
|
|
240
|
+
command.command = value;
|
|
241
|
+
}
|
|
242
|
+
} else if (key === 'interval' || key === 'intervalo') {
|
|
243
|
+
const interval = toNonNegativeInteger(value);
|
|
244
|
+
if (interval !== null) {
|
|
245
|
+
command.interval = interval;
|
|
246
|
+
}
|
|
247
|
+
} else if (
|
|
248
|
+
key === 'clickdelay' ||
|
|
249
|
+
key === 'delayclick' ||
|
|
250
|
+
key === 'delay_clique' ||
|
|
251
|
+
key === 'delayclique' ||
|
|
252
|
+
key === 'click_delay' ||
|
|
253
|
+
key === 'delay'
|
|
254
|
+
) {
|
|
255
|
+
const clickDelay = toNonNegativeInteger(value);
|
|
256
|
+
if (clickDelay !== null) {
|
|
257
|
+
command.clickDelay = clickDelay;
|
|
258
|
+
}
|
|
259
|
+
} else if (key === 'click' || key === 'clique') {
|
|
260
|
+
command.click = value;
|
|
261
|
+
} else if (
|
|
262
|
+
key === 'doubleclick' ||
|
|
263
|
+
key === 'double_click' ||
|
|
264
|
+
key === 'double' ||
|
|
265
|
+
key === 'duplo' ||
|
|
266
|
+
key === 'cliqueduplo' ||
|
|
267
|
+
key === 'clique_duplo'
|
|
268
|
+
) {
|
|
269
|
+
const doubleClick = parseBooleanValue(value);
|
|
270
|
+
if (doubleClick !== null) {
|
|
271
|
+
command.doubleClick = doubleClick;
|
|
272
|
+
}
|
|
40
273
|
} else if (key === 'seq') {
|
|
41
|
-
const seq =
|
|
42
|
-
if (
|
|
43
|
-
|
|
274
|
+
const seq = toNonNegativeInteger(value);
|
|
275
|
+
if (seq !== null) {
|
|
276
|
+
command.seq = seq;
|
|
44
277
|
}
|
|
45
|
-
} else if (!
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
} else if (!
|
|
49
|
-
|
|
50
|
-
} else if (!
|
|
51
|
-
|
|
278
|
+
} else if (!command.type) {
|
|
279
|
+
command.type = rawKey.trim();
|
|
280
|
+
command.command = value;
|
|
281
|
+
} else if (!command.command) {
|
|
282
|
+
command.command = value;
|
|
283
|
+
} else if (!command.extra) {
|
|
284
|
+
command.extra = value;
|
|
52
285
|
}
|
|
53
286
|
}
|
|
54
287
|
|
|
55
|
-
if (
|
|
56
|
-
results.push(
|
|
288
|
+
if (hasCommandPayload(command)) {
|
|
289
|
+
results.push(command);
|
|
57
290
|
}
|
|
58
291
|
}
|
|
59
292
|
|
|
@@ -64,3 +297,1919 @@ export function extractFirstCommand(message) {
|
|
|
64
297
|
const [first] = cmd(message);
|
|
65
298
|
return first || null;
|
|
66
299
|
}
|
|
300
|
+
|
|
301
|
+
export async function initMap(options = {}) {
|
|
302
|
+
const config = buildCursorConfig(options);
|
|
303
|
+
const mapAlreadyExists = await pathExists(config.mapPath);
|
|
304
|
+
const store = await createMapStore(config);
|
|
305
|
+
|
|
306
|
+
const persistMerged =
|
|
307
|
+
parseBooleanValue(options && options.persistMerged) === true ||
|
|
308
|
+
parseBooleanValue(options && options.writeMerged) === true;
|
|
309
|
+
|
|
310
|
+
if (!mapAlreadyExists && config.persistMap) {
|
|
311
|
+
// already persisted by createMapStore when file is missing
|
|
312
|
+
} else if (persistMerged && config.persistMap) {
|
|
313
|
+
await persistMapStore(store);
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
return {
|
|
317
|
+
path: store.path,
|
|
318
|
+
created: !mapAlreadyExists,
|
|
319
|
+
persisted: (!mapAlreadyExists || persistMerged) && config.persistMap,
|
|
320
|
+
version: store.map.version,
|
|
321
|
+
appCount: Object.keys(store.map.apps || {}).length,
|
|
322
|
+
map: store.map
|
|
323
|
+
};
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
export async function initDoc(options = {}) {
|
|
327
|
+
const raw = options && typeof options === 'object' ? options : {};
|
|
328
|
+
const outputDir = resolveDocOutputDir(raw);
|
|
329
|
+
const overwrite = parseBooleanValue(raw.overwrite) === true;
|
|
330
|
+
const includeMapDocs = shouldIncludeMapDocs(raw.includeMapDocs);
|
|
331
|
+
const templates = resolveDocTemplates(raw.files, includeMapDocs);
|
|
332
|
+
|
|
333
|
+
await mkdir(outputDir, { recursive: true });
|
|
334
|
+
|
|
335
|
+
const created = [];
|
|
336
|
+
const updated = [];
|
|
337
|
+
const skipped = [];
|
|
338
|
+
|
|
339
|
+
for (const template of templates) {
|
|
340
|
+
const sourcePath = resolvePath(MODULE_DIR, template.source);
|
|
341
|
+
const targetPath = resolvePath(outputDir, template.target);
|
|
342
|
+
const targetExists = await pathExists(targetPath);
|
|
343
|
+
|
|
344
|
+
if (targetExists && !overwrite) {
|
|
345
|
+
skipped.push({
|
|
346
|
+
key: template.key,
|
|
347
|
+
path: targetPath,
|
|
348
|
+
reason: 'exists'
|
|
349
|
+
});
|
|
350
|
+
continue;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
let content;
|
|
354
|
+
try {
|
|
355
|
+
content = await readFile(sourcePath, 'utf8');
|
|
356
|
+
} catch (error) {
|
|
357
|
+
if (error && error.code === 'ENOENT') {
|
|
358
|
+
throw new Error(`doc_template_not_found:${template.source}`);
|
|
359
|
+
}
|
|
360
|
+
throw error;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
await writeFile(targetPath, content, 'utf8');
|
|
364
|
+
|
|
365
|
+
if (targetExists) {
|
|
366
|
+
updated.push({ key: template.key, path: targetPath });
|
|
367
|
+
} else {
|
|
368
|
+
created.push({ key: template.key, path: targetPath });
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
return {
|
|
373
|
+
outputDir,
|
|
374
|
+
overwrite,
|
|
375
|
+
created,
|
|
376
|
+
updated,
|
|
377
|
+
skipped
|
|
378
|
+
};
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
export async function cursor(input, options = {}) {
|
|
382
|
+
const commands = normalizeCursorInput(input);
|
|
383
|
+
if (commands.length === 0) {
|
|
384
|
+
return {
|
|
385
|
+
executed: [],
|
|
386
|
+
skipped: [{ reason: 'no_commands' }],
|
|
387
|
+
totalCommands: 0,
|
|
388
|
+
totalExecutions: 0
|
|
389
|
+
};
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
const runtime = createCursorRuntime(options);
|
|
393
|
+
let actions;
|
|
394
|
+
const executed = [];
|
|
395
|
+
const skipped = [];
|
|
396
|
+
|
|
397
|
+
async function getActions() {
|
|
398
|
+
if (actions) {
|
|
399
|
+
return actions;
|
|
400
|
+
}
|
|
401
|
+
const robot = await getRobot();
|
|
402
|
+
actions = createActionHandlers(robot, runtime);
|
|
403
|
+
return actions;
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
for (let commandIndex = 0; commandIndex < commands.length; commandIndex++) {
|
|
407
|
+
const command = commands[commandIndex];
|
|
408
|
+
const actionKey = resolveActionKey(command.type);
|
|
409
|
+
|
|
410
|
+
if (!actionKey) {
|
|
411
|
+
skipped.push({
|
|
412
|
+
commandIndex,
|
|
413
|
+
type: command.type,
|
|
414
|
+
command: command.command,
|
|
415
|
+
reason: 'unknown_type'
|
|
416
|
+
});
|
|
417
|
+
continue;
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
const repeatCount = getRepeatCount(command.seq);
|
|
421
|
+
if (repeatCount === 0) {
|
|
422
|
+
skipped.push({
|
|
423
|
+
commandIndex,
|
|
424
|
+
type: command.type,
|
|
425
|
+
command: command.command,
|
|
426
|
+
reason: 'seq_zero'
|
|
427
|
+
});
|
|
428
|
+
continue;
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
if (isMapAwareAction(actionKey)) {
|
|
432
|
+
try {
|
|
433
|
+
await runtime.getMapStore();
|
|
434
|
+
} catch (error) {
|
|
435
|
+
skipped.push({
|
|
436
|
+
commandIndex,
|
|
437
|
+
type: command.type,
|
|
438
|
+
command: command.command,
|
|
439
|
+
reason: 'map_unavailable',
|
|
440
|
+
detail: error instanceof Error ? error.message : String(error)
|
|
441
|
+
});
|
|
442
|
+
continue;
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
let action;
|
|
447
|
+
try {
|
|
448
|
+
const actionHandlers = await getActions();
|
|
449
|
+
action = actionHandlers[actionKey];
|
|
450
|
+
} catch (error) {
|
|
451
|
+
skipped.push({
|
|
452
|
+
commandIndex,
|
|
453
|
+
type: command.type,
|
|
454
|
+
command: command.command,
|
|
455
|
+
reason: 'robot_unavailable',
|
|
456
|
+
detail: error instanceof Error ? error.message : String(error)
|
|
457
|
+
});
|
|
458
|
+
continue;
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
if (!action) {
|
|
462
|
+
skipped.push({
|
|
463
|
+
commandIndex,
|
|
464
|
+
type: command.type,
|
|
465
|
+
command: command.command,
|
|
466
|
+
reason: 'unknown_type'
|
|
467
|
+
});
|
|
468
|
+
continue;
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
for (let iteration = 1; iteration <= repeatCount; iteration++) {
|
|
472
|
+
try {
|
|
473
|
+
await action(command);
|
|
474
|
+
executed.push({
|
|
475
|
+
commandIndex,
|
|
476
|
+
iteration,
|
|
477
|
+
type: command.type,
|
|
478
|
+
command: command.command,
|
|
479
|
+
extra: command.extra,
|
|
480
|
+
button: command.button,
|
|
481
|
+
key: command.key,
|
|
482
|
+
modifiers: command.modifiers,
|
|
483
|
+
text: command.text,
|
|
484
|
+
typeDelay: command.typeDelay,
|
|
485
|
+
points: command.points,
|
|
486
|
+
path: command.path,
|
|
487
|
+
interval: command.interval,
|
|
488
|
+
clickDelay: command.clickDelay,
|
|
489
|
+
click: command.click,
|
|
490
|
+
doubleClick: command.doubleClick,
|
|
491
|
+
seq: command.seq
|
|
492
|
+
});
|
|
493
|
+
} catch (error) {
|
|
494
|
+
skipped.push({
|
|
495
|
+
commandIndex,
|
|
496
|
+
iteration,
|
|
497
|
+
type: command.type,
|
|
498
|
+
command: command.command,
|
|
499
|
+
reason: 'action_error',
|
|
500
|
+
detail: error instanceof Error ? error.message : String(error)
|
|
501
|
+
});
|
|
502
|
+
break;
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
return {
|
|
508
|
+
executed,
|
|
509
|
+
skipped,
|
|
510
|
+
totalCommands: commands.length,
|
|
511
|
+
totalExecutions: executed.length
|
|
512
|
+
};
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
function createCursorRuntime(options) {
|
|
516
|
+
const config = buildCursorConfig(options);
|
|
517
|
+
let mapStorePromise;
|
|
518
|
+
|
|
519
|
+
return {
|
|
520
|
+
config,
|
|
521
|
+
async getMapStore() {
|
|
522
|
+
if (mapStorePromise) {
|
|
523
|
+
return mapStorePromise;
|
|
524
|
+
}
|
|
525
|
+
mapStorePromise = createMapStore(config);
|
|
526
|
+
return mapStorePromise;
|
|
527
|
+
}
|
|
528
|
+
};
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
function buildCursorConfig(options) {
|
|
532
|
+
const raw = options && typeof options === 'object' ? options : {};
|
|
533
|
+
const mapPath =
|
|
534
|
+
typeof raw.mapPath === 'string' && raw.mapPath.trim()
|
|
535
|
+
? raw.mapPath.trim()
|
|
536
|
+
: 'map.json';
|
|
537
|
+
|
|
538
|
+
return {
|
|
539
|
+
mapPath: resolvePath(mapPath),
|
|
540
|
+
persistMap: raw.persistMap !== false,
|
|
541
|
+
createMapIfMissing: raw.createMapIfMissing !== false,
|
|
542
|
+
apps: mergeOptionApps(raw.apps),
|
|
543
|
+
launchKey:
|
|
544
|
+
raw.launchKey === false || raw.launchKey === null
|
|
545
|
+
? undefined
|
|
546
|
+
: typeof raw.launchKey === 'string' && raw.launchKey.trim()
|
|
547
|
+
? raw.launchKey.trim()
|
|
548
|
+
: 'command',
|
|
549
|
+
typeDelay: parseIntegerOption(raw.typeDelay, 50, 0),
|
|
550
|
+
moveSteps: parseIntegerOption(raw.moveSteps, 50, 1),
|
|
551
|
+
moveDelay: parseIntegerOption(raw.moveDelay, 8, 0),
|
|
552
|
+
scrollSteps: parseIntegerOption(raw.scrollSteps, 10, 1),
|
|
553
|
+
scrollDelay: parseIntegerOption(raw.scrollDelay, 20, 0),
|
|
554
|
+
sequenceInterval: parseIntegerOption(raw.sequenceInterval, 250, 0),
|
|
555
|
+
sequenceClickMode: normalizeClickMode(raw.sequenceClick, CLICK_MODE.NONE),
|
|
556
|
+
sequenceDoubleClick:
|
|
557
|
+
parseBooleanValue(raw.sequenceDoubleClick) === true,
|
|
558
|
+
defaultClosePoint: parsePoint(raw.defaultClosePoint) || { x: 1888, y: 16 },
|
|
559
|
+
skipAdsPoint: parsePoint(raw.skipAdsPoint) || { x: 808, y: 569 }
|
|
560
|
+
};
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
function mergeOptionApps(customApps) {
|
|
564
|
+
const merged = {};
|
|
565
|
+
|
|
566
|
+
for (const [appName, appConfig] of Object.entries(DEFAULT_APPS)) {
|
|
567
|
+
merged[appName] = cloneAppMap(appConfig);
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
if (!customApps || typeof customApps !== 'object') {
|
|
571
|
+
return merged;
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
for (const [rawName, rawConfig] of Object.entries(customApps)) {
|
|
575
|
+
const appName = resolveAppName(rawName);
|
|
576
|
+
const normalized = normalizeAppConfig(rawConfig);
|
|
577
|
+
if (!normalized) continue;
|
|
578
|
+
|
|
579
|
+
const current = merged[appName] || {
|
|
580
|
+
launcher: undefined,
|
|
581
|
+
searchIcon: undefined,
|
|
582
|
+
state: APP_STATE.CLOSED,
|
|
583
|
+
buttons: {}
|
|
584
|
+
};
|
|
585
|
+
|
|
586
|
+
merged[appName] = {
|
|
587
|
+
launcher: normalized.launcher || current.launcher,
|
|
588
|
+
searchIcon: normalized.searchIcon || current.searchIcon,
|
|
589
|
+
state: normalized.state || current.state || APP_STATE.CLOSED,
|
|
590
|
+
buttons: {
|
|
591
|
+
...(current.buttons || {}),
|
|
592
|
+
...(normalized.buttons || {})
|
|
593
|
+
}
|
|
594
|
+
};
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
return merged;
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
function toCommandText(value) {
|
|
601
|
+
if (typeof value === 'string') {
|
|
602
|
+
const trimmed = value.trim();
|
|
603
|
+
return trimmed || '';
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
if (Number.isFinite(value)) {
|
|
607
|
+
return String(value);
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
return '';
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
function hasCommandPayload(command) {
|
|
614
|
+
if (!command || !command.type) {
|
|
615
|
+
return false;
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
const actionKey = resolveActionKey(command.type);
|
|
619
|
+
|
|
620
|
+
if (actionKey === 'key_tap') {
|
|
621
|
+
return Boolean(toCommandText(command.key) || toCommandText(command.command));
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
if (actionKey === 'type_string_delayed') {
|
|
625
|
+
return Boolean(
|
|
626
|
+
toCommandText(command.text) ||
|
|
627
|
+
toCommandText(command.command) ||
|
|
628
|
+
toCommandText(command.extra)
|
|
629
|
+
);
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
if (actionKey === 'move_sequence') {
|
|
633
|
+
return Boolean(command.points || command.path || toCommandText(command.command));
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
return Boolean(toCommandText(command.command));
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
function normalizeCommandObject(value) {
|
|
640
|
+
if (!value || typeof value !== 'object') {
|
|
641
|
+
return null;
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
const rawType = value.type !== undefined ? value.type : value.tipo;
|
|
645
|
+
const rawCommand = value.command !== undefined ? value.command : value.comando;
|
|
646
|
+
const rawKey =
|
|
647
|
+
value.key !== undefined
|
|
648
|
+
? value.key
|
|
649
|
+
: value.tecla !== undefined
|
|
650
|
+
? value.tecla
|
|
651
|
+
: value.hotkey;
|
|
652
|
+
const rawModifiers =
|
|
653
|
+
value.modifiers !== undefined
|
|
654
|
+
? value.modifiers
|
|
655
|
+
: value.modifier !== undefined
|
|
656
|
+
? value.modifier
|
|
657
|
+
: value.modificadores !== undefined
|
|
658
|
+
? value.modificadores
|
|
659
|
+
: value.modificador;
|
|
660
|
+
const rawText =
|
|
661
|
+
value.text !== undefined
|
|
662
|
+
? value.text
|
|
663
|
+
: value.texto !== undefined
|
|
664
|
+
? value.texto
|
|
665
|
+
: value.string !== undefined
|
|
666
|
+
? value.string
|
|
667
|
+
: value.mensagem;
|
|
668
|
+
const rawButton =
|
|
669
|
+
value.button !== undefined
|
|
670
|
+
? value.button
|
|
671
|
+
: value.botao !== undefined
|
|
672
|
+
? value.botao
|
|
673
|
+
: value['botão'];
|
|
674
|
+
const rawPoints =
|
|
675
|
+
value.points !== undefined
|
|
676
|
+
? value.points
|
|
677
|
+
: value.pontos !== undefined
|
|
678
|
+
? value.pontos
|
|
679
|
+
: value.path !== undefined
|
|
680
|
+
? value.path
|
|
681
|
+
: value.trajeto !== undefined
|
|
682
|
+
? value.trajeto
|
|
683
|
+
: value.caminho !== undefined
|
|
684
|
+
? value.caminho
|
|
685
|
+
: value.coords !== undefined
|
|
686
|
+
? value.coords
|
|
687
|
+
: value.coordenadas;
|
|
688
|
+
const rawPath =
|
|
689
|
+
value.path !== undefined
|
|
690
|
+
? value.path
|
|
691
|
+
: value.caminho !== undefined
|
|
692
|
+
? value.caminho
|
|
693
|
+
: value.trajeto;
|
|
694
|
+
const rawInterval =
|
|
695
|
+
value.interval !== undefined ? value.interval : value.intervalo;
|
|
696
|
+
const rawClickDelay =
|
|
697
|
+
value.clickDelay !== undefined
|
|
698
|
+
? value.clickDelay
|
|
699
|
+
: value.delayClick !== undefined
|
|
700
|
+
? value.delayClick
|
|
701
|
+
: value.delayClique !== undefined
|
|
702
|
+
? value.delayClique
|
|
703
|
+
: value.delay;
|
|
704
|
+
const rawClick = value.click !== undefined ? value.click : value.clique;
|
|
705
|
+
const rawDoubleClick =
|
|
706
|
+
value.doubleClick !== undefined
|
|
707
|
+
? value.doubleClick
|
|
708
|
+
: value.double_click !== undefined
|
|
709
|
+
? value.double_click
|
|
710
|
+
: value.duplo !== undefined
|
|
711
|
+
? value.duplo
|
|
712
|
+
: value.cliqueDuplo !== undefined
|
|
713
|
+
? value.cliqueDuplo
|
|
714
|
+
: value.clique_duplo;
|
|
715
|
+
const rawTypeDelay =
|
|
716
|
+
value.typeDelay !== undefined
|
|
717
|
+
? value.typeDelay
|
|
718
|
+
: value.type_delay !== undefined
|
|
719
|
+
? value.type_delay
|
|
720
|
+
: value.typingDelay !== undefined
|
|
721
|
+
? value.typingDelay
|
|
722
|
+
: value.typing_delay !== undefined
|
|
723
|
+
? value.typing_delay
|
|
724
|
+
: value.textDelay !== undefined
|
|
725
|
+
? value.textDelay
|
|
726
|
+
: value.delayTexto !== undefined
|
|
727
|
+
? value.delayTexto
|
|
728
|
+
: value.delayDigitacao !== undefined
|
|
729
|
+
? value.delayDigitacao
|
|
730
|
+
: value.delayDigitar;
|
|
731
|
+
|
|
732
|
+
const type =
|
|
733
|
+
typeof rawType === 'string' ? rawType.trim() : String(rawType || '').trim();
|
|
734
|
+
const actionKey = resolveActionKey(type);
|
|
735
|
+
|
|
736
|
+
const normalizedPoints = normalizePointsValue(
|
|
737
|
+
rawPoints !== undefined ? rawPoints : rawPath
|
|
738
|
+
);
|
|
739
|
+
|
|
740
|
+
const key = toCommandText(rawKey);
|
|
741
|
+
const text = toCommandText(rawText);
|
|
742
|
+
|
|
743
|
+
let command = toCommandText(rawCommand);
|
|
744
|
+
|
|
745
|
+
if (!command && normalizedPoints) {
|
|
746
|
+
command = serializePoints(normalizedPoints);
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
if (!command && text) {
|
|
750
|
+
command = text;
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
if (!command && key) {
|
|
754
|
+
command = key;
|
|
755
|
+
}
|
|
756
|
+
|
|
757
|
+
const extra =
|
|
758
|
+
value.extra === undefined || value.extra === null
|
|
759
|
+
? undefined
|
|
760
|
+
: toCommandText(value.extra) || String(value.extra);
|
|
761
|
+
|
|
762
|
+
if (!command && actionKey === 'type_string_delayed' && extra) {
|
|
763
|
+
command = extra;
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
const normalized = {
|
|
767
|
+
type,
|
|
768
|
+
command,
|
|
769
|
+
extra,
|
|
770
|
+
button: undefined,
|
|
771
|
+
key: undefined,
|
|
772
|
+
modifiers: undefined,
|
|
773
|
+
text: undefined,
|
|
774
|
+
typeDelay: undefined,
|
|
775
|
+
points: undefined,
|
|
776
|
+
path: undefined,
|
|
777
|
+
interval: undefined,
|
|
778
|
+
clickDelay: undefined,
|
|
779
|
+
click: undefined,
|
|
780
|
+
doubleClick: undefined,
|
|
781
|
+
seq: undefined
|
|
782
|
+
};
|
|
783
|
+
|
|
784
|
+
if (rawButton !== undefined && rawButton !== null) {
|
|
785
|
+
const buttonText = String(rawButton).trim();
|
|
786
|
+
if (buttonText) {
|
|
787
|
+
normalized.button = buttonText;
|
|
788
|
+
}
|
|
789
|
+
}
|
|
790
|
+
|
|
791
|
+
if (key) {
|
|
792
|
+
normalized.key = key;
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
const modifiers = parseKeyModifiers(rawModifiers);
|
|
796
|
+
if (modifiers && modifiers.length > 0) {
|
|
797
|
+
normalized.modifiers = modifiers;
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
if (text) {
|
|
801
|
+
normalized.text = text;
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
const typeDelay = toNonNegativeInteger(rawTypeDelay);
|
|
805
|
+
if (typeDelay !== null) {
|
|
806
|
+
normalized.typeDelay = typeDelay;
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
if (normalizedPoints) {
|
|
810
|
+
normalized.points = normalizedPoints;
|
|
811
|
+
normalized.path = normalizedPoints;
|
|
812
|
+
}
|
|
813
|
+
|
|
814
|
+
const interval = toNonNegativeInteger(rawInterval);
|
|
815
|
+
if (interval !== null) {
|
|
816
|
+
normalized.interval = interval;
|
|
817
|
+
}
|
|
818
|
+
|
|
819
|
+
const clickDelay = toNonNegativeInteger(rawClickDelay);
|
|
820
|
+
if (clickDelay !== null) {
|
|
821
|
+
normalized.clickDelay = clickDelay;
|
|
822
|
+
}
|
|
823
|
+
|
|
824
|
+
if (rawClick !== undefined && rawClick !== null) {
|
|
825
|
+
const clickMode = String(rawClick).trim();
|
|
826
|
+
if (clickMode) {
|
|
827
|
+
normalized.click = clickMode;
|
|
828
|
+
}
|
|
829
|
+
}
|
|
830
|
+
|
|
831
|
+
const doubleClick = parseBooleanValue(rawDoubleClick);
|
|
832
|
+
if (doubleClick !== null) {
|
|
833
|
+
normalized.doubleClick = doubleClick;
|
|
834
|
+
}
|
|
835
|
+
|
|
836
|
+
const rawSeq = value.seq !== undefined ? value.seq : value.sequencia;
|
|
837
|
+
const seq = toNonNegativeInteger(rawSeq);
|
|
838
|
+
if (seq !== null) {
|
|
839
|
+
normalized.seq = seq;
|
|
840
|
+
}
|
|
841
|
+
|
|
842
|
+
return hasCommandPayload(normalized) ? normalized : null;
|
|
843
|
+
}
|
|
844
|
+
|
|
845
|
+
function normalizeCursorInput(input) {
|
|
846
|
+
if (typeof input === 'string') {
|
|
847
|
+
return cmd(input);
|
|
848
|
+
}
|
|
849
|
+
|
|
850
|
+
if (Array.isArray(input)) {
|
|
851
|
+
return input.map(normalizeCommandObject).filter(Boolean);
|
|
852
|
+
}
|
|
853
|
+
|
|
854
|
+
const single = normalizeCommandObject(input);
|
|
855
|
+
return single ? [single] : [];
|
|
856
|
+
}
|
|
857
|
+
|
|
858
|
+
function getRepeatCount(seq) {
|
|
859
|
+
const parsed = toNonNegativeInteger(seq);
|
|
860
|
+
if (parsed === null) {
|
|
861
|
+
return 1;
|
|
862
|
+
}
|
|
863
|
+
return parsed;
|
|
864
|
+
}
|
|
865
|
+
|
|
866
|
+
function toNonNegativeInteger(value) {
|
|
867
|
+
const parsed = Number(value);
|
|
868
|
+
if (!Number.isInteger(parsed) || parsed < 0) {
|
|
869
|
+
return null;
|
|
870
|
+
}
|
|
871
|
+
return parsed;
|
|
872
|
+
}
|
|
873
|
+
|
|
874
|
+
function parseIntegerOption(value, fallback, min) {
|
|
875
|
+
const parsed = Number(value);
|
|
876
|
+
if (!Number.isInteger(parsed) || parsed < min) {
|
|
877
|
+
return fallback;
|
|
878
|
+
}
|
|
879
|
+
return parsed;
|
|
880
|
+
}
|
|
881
|
+
|
|
882
|
+
function parseBooleanValue(value) {
|
|
883
|
+
if (value === undefined || value === null) {
|
|
884
|
+
return null;
|
|
885
|
+
}
|
|
886
|
+
|
|
887
|
+
if (typeof value === 'boolean') {
|
|
888
|
+
return value;
|
|
889
|
+
}
|
|
890
|
+
|
|
891
|
+
const token = canonicalToken(value);
|
|
892
|
+
if (
|
|
893
|
+
token === 'true' ||
|
|
894
|
+
token === '1' ||
|
|
895
|
+
token === 'sim' ||
|
|
896
|
+
token === 'yes' ||
|
|
897
|
+
token === 'on'
|
|
898
|
+
) {
|
|
899
|
+
return true;
|
|
900
|
+
}
|
|
901
|
+
|
|
902
|
+
if (
|
|
903
|
+
token === 'false' ||
|
|
904
|
+
token === '0' ||
|
|
905
|
+
token === 'nao' ||
|
|
906
|
+
token === 'no' ||
|
|
907
|
+
token === 'off'
|
|
908
|
+
) {
|
|
909
|
+
return false;
|
|
910
|
+
}
|
|
911
|
+
|
|
912
|
+
return null;
|
|
913
|
+
}
|
|
914
|
+
|
|
915
|
+
function normalizeClickMode(value, fallback) {
|
|
916
|
+
if (value === true) {
|
|
917
|
+
return CLICK_MODE.BETWEEN;
|
|
918
|
+
}
|
|
919
|
+
|
|
920
|
+
if (value === false) {
|
|
921
|
+
return CLICK_MODE.NONE;
|
|
922
|
+
}
|
|
923
|
+
|
|
924
|
+
const token = canonicalToken(value);
|
|
925
|
+
|
|
926
|
+
if (
|
|
927
|
+
token === CLICK_MODE.EACH ||
|
|
928
|
+
token === 'cada' ||
|
|
929
|
+
token === 'todos' ||
|
|
930
|
+
token === 'todas'
|
|
931
|
+
) {
|
|
932
|
+
return CLICK_MODE.EACH;
|
|
933
|
+
}
|
|
934
|
+
|
|
935
|
+
if (token === CLICK_MODE.BETWEEN || token === 'entre') {
|
|
936
|
+
return CLICK_MODE.BETWEEN;
|
|
937
|
+
}
|
|
938
|
+
|
|
939
|
+
if (token === CLICK_MODE.FIRST || token === 'primeiro') {
|
|
940
|
+
return CLICK_MODE.FIRST;
|
|
941
|
+
}
|
|
942
|
+
|
|
943
|
+
if (token === CLICK_MODE.LAST || token === 'ultimo' || token === 'final') {
|
|
944
|
+
return CLICK_MODE.LAST;
|
|
945
|
+
}
|
|
946
|
+
|
|
947
|
+
if (
|
|
948
|
+
token === CLICK_MODE.NONE ||
|
|
949
|
+
token === 'sem' ||
|
|
950
|
+
token === 'nenhum' ||
|
|
951
|
+
token === 'desligado'
|
|
952
|
+
) {
|
|
953
|
+
return CLICK_MODE.NONE;
|
|
954
|
+
}
|
|
955
|
+
|
|
956
|
+
return fallback || CLICK_MODE.NONE;
|
|
957
|
+
}
|
|
958
|
+
|
|
959
|
+
function parsePointToken(token) {
|
|
960
|
+
const value = String(token || '').trim();
|
|
961
|
+
if (!value) return null;
|
|
962
|
+
|
|
963
|
+
const match = value.match(/^(-?\d+)\s*(?:x|:|,)\s*(-?\d+)$/i);
|
|
964
|
+
if (!match) return null;
|
|
965
|
+
|
|
966
|
+
return {
|
|
967
|
+
x: Number(match[1]),
|
|
968
|
+
y: Number(match[2])
|
|
969
|
+
};
|
|
970
|
+
}
|
|
971
|
+
|
|
972
|
+
function normalizePointsValue(value) {
|
|
973
|
+
if (value === undefined || value === null) {
|
|
974
|
+
return undefined;
|
|
975
|
+
}
|
|
976
|
+
|
|
977
|
+
if (Array.isArray(value)) {
|
|
978
|
+
const points = [];
|
|
979
|
+
for (const item of value) {
|
|
980
|
+
const point = parsePoint(item) || parsePointToken(item);
|
|
981
|
+
if (!point) {
|
|
982
|
+
return undefined;
|
|
983
|
+
}
|
|
984
|
+
points.push(point);
|
|
985
|
+
}
|
|
986
|
+
return points.length > 0 ? points : undefined;
|
|
987
|
+
}
|
|
988
|
+
|
|
989
|
+
if (typeof value === 'string') {
|
|
990
|
+
const parts = value
|
|
991
|
+
.split(/[|;>]/g)
|
|
992
|
+
.map((part) => part.trim())
|
|
993
|
+
.filter(Boolean);
|
|
994
|
+
|
|
995
|
+
if (parts.length === 0) {
|
|
996
|
+
return undefined;
|
|
997
|
+
}
|
|
998
|
+
|
|
999
|
+
const points = [];
|
|
1000
|
+
for (const part of parts) {
|
|
1001
|
+
const point = parsePointToken(part);
|
|
1002
|
+
if (!point) {
|
|
1003
|
+
return undefined;
|
|
1004
|
+
}
|
|
1005
|
+
points.push(point);
|
|
1006
|
+
}
|
|
1007
|
+
return points.length > 0 ? points : undefined;
|
|
1008
|
+
}
|
|
1009
|
+
|
|
1010
|
+
const singlePoint = parsePoint(value);
|
|
1011
|
+
if (singlePoint) {
|
|
1012
|
+
return [singlePoint];
|
|
1013
|
+
}
|
|
1014
|
+
|
|
1015
|
+
return undefined;
|
|
1016
|
+
}
|
|
1017
|
+
|
|
1018
|
+
function serializePoints(points) {
|
|
1019
|
+
if (!Array.isArray(points) || points.length === 0) {
|
|
1020
|
+
return '';
|
|
1021
|
+
}
|
|
1022
|
+
|
|
1023
|
+
return points.map((point) => `${point.x}x${point.y}`).join('|');
|
|
1024
|
+
}
|
|
1025
|
+
|
|
1026
|
+
function normalizePathConfig(rawPath) {
|
|
1027
|
+
if (rawPath === undefined || rawPath === null) {
|
|
1028
|
+
return undefined;
|
|
1029
|
+
}
|
|
1030
|
+
|
|
1031
|
+
let points;
|
|
1032
|
+
let clickMode = CLICK_MODE.NONE;
|
|
1033
|
+
let interval = 0;
|
|
1034
|
+
let clickDelay = 0;
|
|
1035
|
+
let doubleClick = false;
|
|
1036
|
+
|
|
1037
|
+
if (typeof rawPath === 'string' || Array.isArray(rawPath)) {
|
|
1038
|
+
points = normalizePointsValue(rawPath);
|
|
1039
|
+
} else if (typeof rawPath === 'object') {
|
|
1040
|
+
points = normalizePointsValue(
|
|
1041
|
+
rawPath.points !== undefined
|
|
1042
|
+
? rawPath.points
|
|
1043
|
+
: rawPath.pontos !== undefined
|
|
1044
|
+
? rawPath.pontos
|
|
1045
|
+
: rawPath.path !== undefined
|
|
1046
|
+
? rawPath.path
|
|
1047
|
+
: rawPath.caminho !== undefined
|
|
1048
|
+
? rawPath.caminho
|
|
1049
|
+
: rawPath.coords !== undefined
|
|
1050
|
+
? rawPath.coords
|
|
1051
|
+
: rawPath.coordenadas
|
|
1052
|
+
);
|
|
1053
|
+
|
|
1054
|
+
clickMode = normalizeClickMode(
|
|
1055
|
+
rawPath.click !== undefined ? rawPath.click : rawPath.clique,
|
|
1056
|
+
CLICK_MODE.NONE
|
|
1057
|
+
);
|
|
1058
|
+
|
|
1059
|
+
interval =
|
|
1060
|
+
toNonNegativeInteger(
|
|
1061
|
+
rawPath.interval !== undefined ? rawPath.interval : rawPath.intervalo
|
|
1062
|
+
) || 0;
|
|
1063
|
+
|
|
1064
|
+
clickDelay =
|
|
1065
|
+
toNonNegativeInteger(
|
|
1066
|
+
rawPath.clickDelay !== undefined
|
|
1067
|
+
? rawPath.clickDelay
|
|
1068
|
+
: rawPath.delayClick !== undefined
|
|
1069
|
+
? rawPath.delayClick
|
|
1070
|
+
: rawPath.delayClique !== undefined
|
|
1071
|
+
? rawPath.delayClique
|
|
1072
|
+
: rawPath.delay
|
|
1073
|
+
) || 0;
|
|
1074
|
+
|
|
1075
|
+
doubleClick =
|
|
1076
|
+
parseBooleanValue(
|
|
1077
|
+
rawPath.doubleClick !== undefined
|
|
1078
|
+
? rawPath.doubleClick
|
|
1079
|
+
: rawPath.double_click !== undefined
|
|
1080
|
+
? rawPath.double_click
|
|
1081
|
+
: rawPath.duplo
|
|
1082
|
+
) === true;
|
|
1083
|
+
} else {
|
|
1084
|
+
return undefined;
|
|
1085
|
+
}
|
|
1086
|
+
|
|
1087
|
+
if (!points || points.length === 0) {
|
|
1088
|
+
return undefined;
|
|
1089
|
+
}
|
|
1090
|
+
|
|
1091
|
+
return {
|
|
1092
|
+
points,
|
|
1093
|
+
clickMode,
|
|
1094
|
+
interval,
|
|
1095
|
+
clickDelay,
|
|
1096
|
+
doubleClick
|
|
1097
|
+
};
|
|
1098
|
+
}
|
|
1099
|
+
|
|
1100
|
+
function normalizeTargetConfig(rawTarget) {
|
|
1101
|
+
if (rawTarget === undefined || rawTarget === null) {
|
|
1102
|
+
return undefined;
|
|
1103
|
+
}
|
|
1104
|
+
|
|
1105
|
+
if (typeof rawTarget !== 'object') {
|
|
1106
|
+
const directPoint = parsePoint(rawTarget);
|
|
1107
|
+
return directPoint ? { position: directPoint } : undefined;
|
|
1108
|
+
}
|
|
1109
|
+
|
|
1110
|
+
let position =
|
|
1111
|
+
parsePoint(
|
|
1112
|
+
rawTarget.position !== undefined
|
|
1113
|
+
? rawTarget.position
|
|
1114
|
+
: rawTarget.posicao !== undefined
|
|
1115
|
+
? rawTarget.posicao
|
|
1116
|
+
: rawTarget.destino !== undefined
|
|
1117
|
+
? rawTarget.destino
|
|
1118
|
+
: rawTarget.target !== undefined
|
|
1119
|
+
? rawTarget.target
|
|
1120
|
+
: rawTarget
|
|
1121
|
+
) || undefined;
|
|
1122
|
+
|
|
1123
|
+
const pathConfig = normalizePathConfig(
|
|
1124
|
+
rawTarget.caminho !== undefined ? rawTarget.caminho : rawTarget.path
|
|
1125
|
+
);
|
|
1126
|
+
|
|
1127
|
+
if (!position && pathConfig && pathConfig.points.length > 0) {
|
|
1128
|
+
const lastPoint = pathConfig.points[pathConfig.points.length - 1];
|
|
1129
|
+
position = { x: lastPoint.x, y: lastPoint.y };
|
|
1130
|
+
}
|
|
1131
|
+
|
|
1132
|
+
if (!position) {
|
|
1133
|
+
return undefined;
|
|
1134
|
+
}
|
|
1135
|
+
|
|
1136
|
+
return {
|
|
1137
|
+
position,
|
|
1138
|
+
...(pathConfig ? { path: pathConfig } : {})
|
|
1139
|
+
};
|
|
1140
|
+
}
|
|
1141
|
+
|
|
1142
|
+
function shouldClickOnStep(mode, index, totalPoints) {
|
|
1143
|
+
if (mode === CLICK_MODE.EACH) {
|
|
1144
|
+
return true;
|
|
1145
|
+
}
|
|
1146
|
+
|
|
1147
|
+
if (mode === CLICK_MODE.BETWEEN) {
|
|
1148
|
+
return index < totalPoints - 1;
|
|
1149
|
+
}
|
|
1150
|
+
|
|
1151
|
+
if (mode === CLICK_MODE.FIRST) {
|
|
1152
|
+
return index === 0;
|
|
1153
|
+
}
|
|
1154
|
+
|
|
1155
|
+
if (mode === CLICK_MODE.LAST) {
|
|
1156
|
+
return index === totalPoints - 1;
|
|
1157
|
+
}
|
|
1158
|
+
|
|
1159
|
+
return false;
|
|
1160
|
+
}
|
|
1161
|
+
|
|
1162
|
+
function removeDiacritics(value) {
|
|
1163
|
+
return String(value || '')
|
|
1164
|
+
.normalize('NFD')
|
|
1165
|
+
.replace(/[\u0300-\u036f]/g, '');
|
|
1166
|
+
}
|
|
1167
|
+
|
|
1168
|
+
function canonicalToken(value) {
|
|
1169
|
+
return removeDiacritics(value)
|
|
1170
|
+
.trim()
|
|
1171
|
+
.toLowerCase()
|
|
1172
|
+
.replace(/[^a-z0-9_\-\s]/g, '')
|
|
1173
|
+
.replace(/[-\s]+/g, '_');
|
|
1174
|
+
}
|
|
1175
|
+
|
|
1176
|
+
function normalizeKeyTapToken(value) {
|
|
1177
|
+
const token = canonicalToken(value);
|
|
1178
|
+
if (!token) {
|
|
1179
|
+
return undefined;
|
|
1180
|
+
}
|
|
1181
|
+
|
|
1182
|
+
if (
|
|
1183
|
+
token === 'cmd' ||
|
|
1184
|
+
token === 'command' ||
|
|
1185
|
+
token === 'meta' ||
|
|
1186
|
+
token === 'super' ||
|
|
1187
|
+
token === 'win' ||
|
|
1188
|
+
token === 'windows'
|
|
1189
|
+
) {
|
|
1190
|
+
return 'command';
|
|
1191
|
+
}
|
|
1192
|
+
|
|
1193
|
+
if (token === 'ctrl' || token === 'control' || token === 'ctl') {
|
|
1194
|
+
return 'control';
|
|
1195
|
+
}
|
|
1196
|
+
|
|
1197
|
+
if (token === 'option' || token === 'opt') {
|
|
1198
|
+
return 'alt';
|
|
1199
|
+
}
|
|
1200
|
+
|
|
1201
|
+
if (token === 'spacebar') {
|
|
1202
|
+
return 'space';
|
|
1203
|
+
}
|
|
1204
|
+
|
|
1205
|
+
return token;
|
|
1206
|
+
}
|
|
1207
|
+
|
|
1208
|
+
function parseKeyModifiers(value) {
|
|
1209
|
+
if (value === undefined || value === null) {
|
|
1210
|
+
return undefined;
|
|
1211
|
+
}
|
|
1212
|
+
|
|
1213
|
+
const list = Array.isArray(value) ? value : [value];
|
|
1214
|
+
const modifiers = [];
|
|
1215
|
+
|
|
1216
|
+
for (const item of list) {
|
|
1217
|
+
if (item === undefined || item === null) {
|
|
1218
|
+
continue;
|
|
1219
|
+
}
|
|
1220
|
+
|
|
1221
|
+
const chunks =
|
|
1222
|
+
typeof item === 'string'
|
|
1223
|
+
? item.split(/[+|,\s]+/g)
|
|
1224
|
+
: [String(item)];
|
|
1225
|
+
|
|
1226
|
+
for (const chunk of chunks) {
|
|
1227
|
+
const modifier = normalizeKeyTapToken(chunk);
|
|
1228
|
+
if (!modifier) continue;
|
|
1229
|
+
modifiers.push(modifier);
|
|
1230
|
+
}
|
|
1231
|
+
}
|
|
1232
|
+
|
|
1233
|
+
if (modifiers.length === 0) {
|
|
1234
|
+
return undefined;
|
|
1235
|
+
}
|
|
1236
|
+
|
|
1237
|
+
return Array.from(new Set(modifiers));
|
|
1238
|
+
}
|
|
1239
|
+
|
|
1240
|
+
function resolveActionKey(type) {
|
|
1241
|
+
const key = canonicalToken(type);
|
|
1242
|
+
return ACTION_ALIASES[key];
|
|
1243
|
+
}
|
|
1244
|
+
|
|
1245
|
+
function isMapAwareAction(actionKey) {
|
|
1246
|
+
return (
|
|
1247
|
+
actionKey === 'open_app' ||
|
|
1248
|
+
actionKey === 'close_app' ||
|
|
1249
|
+
actionKey === 'skip_ads'
|
|
1250
|
+
);
|
|
1251
|
+
}
|
|
1252
|
+
|
|
1253
|
+
function resolveAppName(name) {
|
|
1254
|
+
const key = canonicalToken(name);
|
|
1255
|
+
return APP_ALIASES[key] || key;
|
|
1256
|
+
}
|
|
1257
|
+
|
|
1258
|
+
function resolveButtonKey(name) {
|
|
1259
|
+
const key = canonicalToken(name);
|
|
1260
|
+
return BUTTON_ALIASES[key] || key;
|
|
1261
|
+
}
|
|
1262
|
+
|
|
1263
|
+
function normalizeState(value) {
|
|
1264
|
+
const key = canonicalToken(value);
|
|
1265
|
+
if (key === 'aberto' || key === 'open' || key === 'opened') {
|
|
1266
|
+
return APP_STATE.OPEN;
|
|
1267
|
+
}
|
|
1268
|
+
if (key === 'fechado' || key === 'closed') {
|
|
1269
|
+
return APP_STATE.CLOSED;
|
|
1270
|
+
}
|
|
1271
|
+
return undefined;
|
|
1272
|
+
}
|
|
1273
|
+
|
|
1274
|
+
function parsePoint(value) {
|
|
1275
|
+
if (Array.isArray(value) && value.length === 2) {
|
|
1276
|
+
const x = Number(value[0]);
|
|
1277
|
+
const y = Number(value[1]);
|
|
1278
|
+
if (Number.isFinite(x) && Number.isFinite(y)) {
|
|
1279
|
+
return { x, y };
|
|
1280
|
+
}
|
|
1281
|
+
}
|
|
1282
|
+
|
|
1283
|
+
if (value && typeof value === 'object') {
|
|
1284
|
+
const x = Number(value.x);
|
|
1285
|
+
const y = Number(value.y);
|
|
1286
|
+
if (Number.isFinite(x) && Number.isFinite(y)) {
|
|
1287
|
+
return { x, y };
|
|
1288
|
+
}
|
|
1289
|
+
}
|
|
1290
|
+
|
|
1291
|
+
return null;
|
|
1292
|
+
}
|
|
1293
|
+
|
|
1294
|
+
function clonePoint(value) {
|
|
1295
|
+
if (!value) return undefined;
|
|
1296
|
+
return { x: value.x, y: value.y };
|
|
1297
|
+
}
|
|
1298
|
+
|
|
1299
|
+
function clonePathConfig(pathConfig) {
|
|
1300
|
+
if (!pathConfig || typeof pathConfig !== 'object') {
|
|
1301
|
+
return undefined;
|
|
1302
|
+
}
|
|
1303
|
+
|
|
1304
|
+
return {
|
|
1305
|
+
points: (pathConfig.points || []).map((point) => clonePoint(point)),
|
|
1306
|
+
clickMode: pathConfig.clickMode || CLICK_MODE.NONE,
|
|
1307
|
+
interval: toNonNegativeInteger(pathConfig.interval) || 0,
|
|
1308
|
+
clickDelay: toNonNegativeInteger(pathConfig.clickDelay) || 0,
|
|
1309
|
+
doubleClick: pathConfig.doubleClick === true
|
|
1310
|
+
};
|
|
1311
|
+
}
|
|
1312
|
+
|
|
1313
|
+
function cloneTargetConfig(targetConfig) {
|
|
1314
|
+
if (!targetConfig || typeof targetConfig !== 'object') {
|
|
1315
|
+
return undefined;
|
|
1316
|
+
}
|
|
1317
|
+
|
|
1318
|
+
const position = targetConfig.position
|
|
1319
|
+
? clonePoint(targetConfig.position)
|
|
1320
|
+
: clonePoint(parsePoint(targetConfig));
|
|
1321
|
+
|
|
1322
|
+
if (!position) {
|
|
1323
|
+
return undefined;
|
|
1324
|
+
}
|
|
1325
|
+
|
|
1326
|
+
return {
|
|
1327
|
+
position,
|
|
1328
|
+
...(targetConfig.path ? { path: clonePathConfig(targetConfig.path) } : {})
|
|
1329
|
+
};
|
|
1330
|
+
}
|
|
1331
|
+
|
|
1332
|
+
function cloneButtonMap(buttons) {
|
|
1333
|
+
const cloned = {};
|
|
1334
|
+
if (!buttons || typeof buttons !== 'object') {
|
|
1335
|
+
return cloned;
|
|
1336
|
+
}
|
|
1337
|
+
|
|
1338
|
+
for (const [buttonName, buttonConfig] of Object.entries(buttons)) {
|
|
1339
|
+
if (!buttonConfig || typeof buttonConfig !== 'object') continue;
|
|
1340
|
+
if (!buttonConfig.position) continue;
|
|
1341
|
+
cloned[buttonName] = {
|
|
1342
|
+
position: clonePoint(buttonConfig.position),
|
|
1343
|
+
...(buttonConfig.path ? { path: clonePathConfig(buttonConfig.path) } : {}),
|
|
1344
|
+
...(buttonConfig.setState ? { setState: buttonConfig.setState } : {})
|
|
1345
|
+
};
|
|
1346
|
+
}
|
|
1347
|
+
|
|
1348
|
+
return cloned;
|
|
1349
|
+
}
|
|
1350
|
+
|
|
1351
|
+
function cloneAppMap(app) {
|
|
1352
|
+
return {
|
|
1353
|
+
launcher: cloneTargetConfig(app.launcher),
|
|
1354
|
+
searchIcon: cloneTargetConfig(app.searchIcon),
|
|
1355
|
+
state: app.state || APP_STATE.CLOSED,
|
|
1356
|
+
buttons: cloneButtonMap(app.buttons)
|
|
1357
|
+
};
|
|
1358
|
+
}
|
|
1359
|
+
|
|
1360
|
+
async function pathExists(filePath) {
|
|
1361
|
+
try {
|
|
1362
|
+
await readFile(filePath, 'utf8');
|
|
1363
|
+
return true;
|
|
1364
|
+
} catch (error) {
|
|
1365
|
+
if (error && error.code === 'ENOENT') {
|
|
1366
|
+
return false;
|
|
1367
|
+
}
|
|
1368
|
+
throw error;
|
|
1369
|
+
}
|
|
1370
|
+
}
|
|
1371
|
+
|
|
1372
|
+
function shouldIncludeMapDocs(value) {
|
|
1373
|
+
const parsed = parseBooleanValue(value);
|
|
1374
|
+
if (parsed === null) {
|
|
1375
|
+
return value !== false;
|
|
1376
|
+
}
|
|
1377
|
+
return parsed;
|
|
1378
|
+
}
|
|
1379
|
+
|
|
1380
|
+
function resolveDocTemplateByName(value) {
|
|
1381
|
+
const token = canonicalToken(value);
|
|
1382
|
+
if (!token) {
|
|
1383
|
+
return null;
|
|
1384
|
+
}
|
|
1385
|
+
|
|
1386
|
+
if (
|
|
1387
|
+
token === 'doc' ||
|
|
1388
|
+
token === 'doc_en' ||
|
|
1389
|
+
token === 'docmd' ||
|
|
1390
|
+
token === 'en' ||
|
|
1391
|
+
token === 'english'
|
|
1392
|
+
) {
|
|
1393
|
+
return DOC_TEMPLATE_MAP.doc_en;
|
|
1394
|
+
}
|
|
1395
|
+
|
|
1396
|
+
if (
|
|
1397
|
+
token === 'doc_ptbr' ||
|
|
1398
|
+
token === 'docptbr' ||
|
|
1399
|
+
token === 'ptbr' ||
|
|
1400
|
+
token === 'pt_br' ||
|
|
1401
|
+
token === 'pt'
|
|
1402
|
+
) {
|
|
1403
|
+
return DOC_TEMPLATE_MAP.doc_ptbr;
|
|
1404
|
+
}
|
|
1405
|
+
|
|
1406
|
+
if (
|
|
1407
|
+
token === 'map' ||
|
|
1408
|
+
token === 'map_en' ||
|
|
1409
|
+
token === 'mapmd' ||
|
|
1410
|
+
token === 'map_doc' ||
|
|
1411
|
+
token === 'mapdoc'
|
|
1412
|
+
) {
|
|
1413
|
+
return DOC_TEMPLATE_MAP.map_en;
|
|
1414
|
+
}
|
|
1415
|
+
|
|
1416
|
+
if (
|
|
1417
|
+
token === 'map_ptbr' ||
|
|
1418
|
+
token === 'mapptbr' ||
|
|
1419
|
+
token === 'map_pt' ||
|
|
1420
|
+
token === 'map_ptbr_md'
|
|
1421
|
+
) {
|
|
1422
|
+
return DOC_TEMPLATE_MAP.map_ptbr;
|
|
1423
|
+
}
|
|
1424
|
+
|
|
1425
|
+
return null;
|
|
1426
|
+
}
|
|
1427
|
+
|
|
1428
|
+
function resolveDocTemplates(filesOption, includeMapDocs) {
|
|
1429
|
+
const defaultTemplates = includeMapDocs
|
|
1430
|
+
? DOC_TEMPLATES
|
|
1431
|
+
: DOC_TEMPLATES.filter((template) => !template.isMapDoc);
|
|
1432
|
+
|
|
1433
|
+
if (filesOption === undefined || filesOption === null) {
|
|
1434
|
+
return defaultTemplates;
|
|
1435
|
+
}
|
|
1436
|
+
|
|
1437
|
+
const values = Array.isArray(filesOption) ? filesOption : [filesOption];
|
|
1438
|
+
const selected = [];
|
|
1439
|
+
const invalid = [];
|
|
1440
|
+
|
|
1441
|
+
for (const value of values) {
|
|
1442
|
+
const template = resolveDocTemplateByName(value);
|
|
1443
|
+
if (!template) {
|
|
1444
|
+
invalid.push(String(value));
|
|
1445
|
+
continue;
|
|
1446
|
+
}
|
|
1447
|
+
if (!includeMapDocs && template.isMapDoc) {
|
|
1448
|
+
continue;
|
|
1449
|
+
}
|
|
1450
|
+
if (!selected.find((item) => item.key === template.key)) {
|
|
1451
|
+
selected.push(template);
|
|
1452
|
+
}
|
|
1453
|
+
}
|
|
1454
|
+
|
|
1455
|
+
if (selected.length === 0 && invalid.length > 0) {
|
|
1456
|
+
throw new Error(`invalid_doc_templates:${invalid.join('|')}`);
|
|
1457
|
+
}
|
|
1458
|
+
|
|
1459
|
+
return selected.length > 0 ? selected : defaultTemplates;
|
|
1460
|
+
}
|
|
1461
|
+
|
|
1462
|
+
function resolveDocOutputDir(options) {
|
|
1463
|
+
const rawOutput =
|
|
1464
|
+
options.outputDir !== undefined
|
|
1465
|
+
? options.outputDir
|
|
1466
|
+
: options.dir !== undefined
|
|
1467
|
+
? options.dir
|
|
1468
|
+
: options.path;
|
|
1469
|
+
|
|
1470
|
+
const output = typeof rawOutput === 'string' ? rawOutput.trim() : '';
|
|
1471
|
+
if (!output) {
|
|
1472
|
+
return resolvePath(process.cwd());
|
|
1473
|
+
}
|
|
1474
|
+
|
|
1475
|
+
return resolvePath(output);
|
|
1476
|
+
}
|
|
1477
|
+
|
|
1478
|
+
function normalizeButtonConfig(rawConfig) {
|
|
1479
|
+
if (rawConfig === undefined || rawConfig === null) {
|
|
1480
|
+
return null;
|
|
1481
|
+
}
|
|
1482
|
+
|
|
1483
|
+
const target = normalizeTargetConfig(rawConfig);
|
|
1484
|
+
if (!target) {
|
|
1485
|
+
return null;
|
|
1486
|
+
}
|
|
1487
|
+
|
|
1488
|
+
const rawState =
|
|
1489
|
+
rawConfig && typeof rawConfig === 'object'
|
|
1490
|
+
? rawConfig.setState !== undefined
|
|
1491
|
+
? rawConfig.setState
|
|
1492
|
+
: rawConfig.stateAfter !== undefined
|
|
1493
|
+
? rawConfig.stateAfter
|
|
1494
|
+
: rawConfig.estadoDepois !== undefined
|
|
1495
|
+
? rawConfig.estadoDepois
|
|
1496
|
+
: undefined
|
|
1497
|
+
: undefined;
|
|
1498
|
+
|
|
1499
|
+
const state = normalizeState(rawState);
|
|
1500
|
+
|
|
1501
|
+
return {
|
|
1502
|
+
position: target.position,
|
|
1503
|
+
...(target.path ? { path: target.path } : {}),
|
|
1504
|
+
...(state ? { setState: state } : {})
|
|
1505
|
+
};
|
|
1506
|
+
}
|
|
1507
|
+
|
|
1508
|
+
function mergeTargetPath(target, rawPath) {
|
|
1509
|
+
if (!target || target.path) {
|
|
1510
|
+
return target;
|
|
1511
|
+
}
|
|
1512
|
+
|
|
1513
|
+
const pathConfig = normalizePathConfig(rawPath);
|
|
1514
|
+
if (!pathConfig) {
|
|
1515
|
+
return target;
|
|
1516
|
+
}
|
|
1517
|
+
|
|
1518
|
+
return {
|
|
1519
|
+
...target,
|
|
1520
|
+
path: pathConfig
|
|
1521
|
+
};
|
|
1522
|
+
}
|
|
1523
|
+
|
|
1524
|
+
function normalizeButtons(rawButtons) {
|
|
1525
|
+
const buttons = {};
|
|
1526
|
+
if (!rawButtons || typeof rawButtons !== 'object') {
|
|
1527
|
+
return buttons;
|
|
1528
|
+
}
|
|
1529
|
+
|
|
1530
|
+
for (const [rawName, rawConfig] of Object.entries(rawButtons)) {
|
|
1531
|
+
const button = normalizeButtonConfig(rawConfig);
|
|
1532
|
+
if (!button) continue;
|
|
1533
|
+
|
|
1534
|
+
const buttonName = resolveButtonKey(rawName);
|
|
1535
|
+
buttons[buttonName] = button;
|
|
1536
|
+
}
|
|
1537
|
+
|
|
1538
|
+
return buttons;
|
|
1539
|
+
}
|
|
1540
|
+
|
|
1541
|
+
function normalizeAppConfig(rawConfig) {
|
|
1542
|
+
if (!rawConfig || typeof rawConfig !== 'object') {
|
|
1543
|
+
return null;
|
|
1544
|
+
}
|
|
1545
|
+
|
|
1546
|
+
const rawLauncher =
|
|
1547
|
+
rawConfig.launcher !== undefined
|
|
1548
|
+
? rawConfig.launcher
|
|
1549
|
+
: rawConfig.position !== undefined
|
|
1550
|
+
? rawConfig.position
|
|
1551
|
+
: rawConfig.posicao;
|
|
1552
|
+
|
|
1553
|
+
let launcher = normalizeTargetConfig(rawLauncher);
|
|
1554
|
+
launcher = mergeTargetPath(
|
|
1555
|
+
launcher,
|
|
1556
|
+
rawConfig.caminho !== undefined ? rawConfig.caminho : rawConfig.path
|
|
1557
|
+
);
|
|
1558
|
+
|
|
1559
|
+
const rawSearchIcon =
|
|
1560
|
+
rawConfig.searchIcon !== undefined
|
|
1561
|
+
? rawConfig.searchIcon
|
|
1562
|
+
: rawConfig.lupa !== undefined
|
|
1563
|
+
? rawConfig.lupa
|
|
1564
|
+
: rawConfig.search;
|
|
1565
|
+
|
|
1566
|
+
const searchIcon = normalizeTargetConfig(rawSearchIcon);
|
|
1567
|
+
|
|
1568
|
+
const state = normalizeState(
|
|
1569
|
+
rawConfig.state !== undefined ? rawConfig.state : rawConfig.estado
|
|
1570
|
+
);
|
|
1571
|
+
|
|
1572
|
+
const buttons = normalizeButtons(
|
|
1573
|
+
rawConfig.buttons !== undefined ? rawConfig.buttons : rawConfig.botoes
|
|
1574
|
+
);
|
|
1575
|
+
|
|
1576
|
+
return {
|
|
1577
|
+
...(launcher ? { launcher } : {}),
|
|
1578
|
+
...(searchIcon ? { searchIcon } : {}),
|
|
1579
|
+
...(state ? { state } : {}),
|
|
1580
|
+
buttons
|
|
1581
|
+
};
|
|
1582
|
+
}
|
|
1583
|
+
|
|
1584
|
+
function buildFallbackMap(config) {
|
|
1585
|
+
const apps = {};
|
|
1586
|
+
|
|
1587
|
+
for (const [appName, appConfig] of Object.entries(config.apps)) {
|
|
1588
|
+
const normalizedApp = cloneAppMap({
|
|
1589
|
+
...appConfig,
|
|
1590
|
+
state: appConfig.state || APP_STATE.CLOSED
|
|
1591
|
+
});
|
|
1592
|
+
const buttons = normalizedApp.buttons || {};
|
|
1593
|
+
if (!buttons.fechar) {
|
|
1594
|
+
buttons.fechar = {
|
|
1595
|
+
position: clonePoint(config.defaultClosePoint),
|
|
1596
|
+
setState: APP_STATE.CLOSED
|
|
1597
|
+
};
|
|
1598
|
+
}
|
|
1599
|
+
normalizedApp.buttons = buttons;
|
|
1600
|
+
apps[appName] = normalizedApp;
|
|
1601
|
+
}
|
|
1602
|
+
|
|
1603
|
+
if (apps.youtube) {
|
|
1604
|
+
const buttons = apps.youtube.buttons || {};
|
|
1605
|
+
if (!buttons.pular_ads) {
|
|
1606
|
+
buttons.pular_ads = {
|
|
1607
|
+
position: clonePoint(config.skipAdsPoint)
|
|
1608
|
+
};
|
|
1609
|
+
}
|
|
1610
|
+
apps.youtube.buttons = buttons;
|
|
1611
|
+
}
|
|
1612
|
+
|
|
1613
|
+
return {
|
|
1614
|
+
version: 1,
|
|
1615
|
+
apps
|
|
1616
|
+
};
|
|
1617
|
+
}
|
|
1618
|
+
|
|
1619
|
+
function normalizeMapObject(rawMap) {
|
|
1620
|
+
const result = {
|
|
1621
|
+
version: 1,
|
|
1622
|
+
apps: {}
|
|
1623
|
+
};
|
|
1624
|
+
|
|
1625
|
+
if (!rawMap || typeof rawMap !== 'object') {
|
|
1626
|
+
return result;
|
|
1627
|
+
}
|
|
1628
|
+
|
|
1629
|
+
if (Number.isFinite(rawMap.version)) {
|
|
1630
|
+
result.version = Number(rawMap.version);
|
|
1631
|
+
}
|
|
1632
|
+
|
|
1633
|
+
const rawApps =
|
|
1634
|
+
rawMap.apps !== undefined
|
|
1635
|
+
? rawMap.apps
|
|
1636
|
+
: rawMap.aplicativos !== undefined
|
|
1637
|
+
? rawMap.aplicativos
|
|
1638
|
+
: undefined;
|
|
1639
|
+
|
|
1640
|
+
if (!rawApps || typeof rawApps !== 'object') {
|
|
1641
|
+
return result;
|
|
1642
|
+
}
|
|
1643
|
+
|
|
1644
|
+
for (const [rawAppName, rawAppConfig] of Object.entries(rawApps)) {
|
|
1645
|
+
const appName = resolveAppName(rawAppName);
|
|
1646
|
+
const appConfig = normalizeAppConfig(rawAppConfig);
|
|
1647
|
+
if (!appConfig) continue;
|
|
1648
|
+
|
|
1649
|
+
result.apps[appName] = {
|
|
1650
|
+
launcher: appConfig.launcher,
|
|
1651
|
+
searchIcon: appConfig.searchIcon,
|
|
1652
|
+
state: appConfig.state || APP_STATE.CLOSED,
|
|
1653
|
+
buttons: appConfig.buttons || {}
|
|
1654
|
+
};
|
|
1655
|
+
}
|
|
1656
|
+
|
|
1657
|
+
return result;
|
|
1658
|
+
}
|
|
1659
|
+
|
|
1660
|
+
function mergeMaps(baseMap, overrideMap) {
|
|
1661
|
+
const merged = {
|
|
1662
|
+
version:
|
|
1663
|
+
overrideMap && Number.isFinite(overrideMap.version)
|
|
1664
|
+
? overrideMap.version
|
|
1665
|
+
: baseMap.version,
|
|
1666
|
+
apps: {}
|
|
1667
|
+
};
|
|
1668
|
+
|
|
1669
|
+
for (const [appName, appConfig] of Object.entries(baseMap.apps || {})) {
|
|
1670
|
+
merged.apps[appName] = cloneAppMap(appConfig);
|
|
1671
|
+
}
|
|
1672
|
+
|
|
1673
|
+
for (const [appName, appConfig] of Object.entries(overrideMap.apps || {})) {
|
|
1674
|
+
const current = merged.apps[appName] || {
|
|
1675
|
+
launcher: undefined,
|
|
1676
|
+
searchIcon: undefined,
|
|
1677
|
+
state: APP_STATE.CLOSED,
|
|
1678
|
+
buttons: {}
|
|
1679
|
+
};
|
|
1680
|
+
|
|
1681
|
+
merged.apps[appName] = {
|
|
1682
|
+
launcher: appConfig.launcher || current.launcher,
|
|
1683
|
+
searchIcon: appConfig.searchIcon || current.searchIcon,
|
|
1684
|
+
state: appConfig.state || current.state || APP_STATE.CLOSED,
|
|
1685
|
+
buttons: {
|
|
1686
|
+
...(current.buttons || {}),
|
|
1687
|
+
...(appConfig.buttons || {})
|
|
1688
|
+
}
|
|
1689
|
+
};
|
|
1690
|
+
}
|
|
1691
|
+
|
|
1692
|
+
return merged;
|
|
1693
|
+
}
|
|
1694
|
+
|
|
1695
|
+
async function createMapStore(config) {
|
|
1696
|
+
const fallbackMap = buildFallbackMap(config);
|
|
1697
|
+
let fromFileMap = null;
|
|
1698
|
+
let mapCreatedFromMissing = false;
|
|
1699
|
+
|
|
1700
|
+
try {
|
|
1701
|
+
const content = await readFile(config.mapPath, 'utf8');
|
|
1702
|
+
let parsed;
|
|
1703
|
+
try {
|
|
1704
|
+
parsed = JSON.parse(content);
|
|
1705
|
+
} catch (error) {
|
|
1706
|
+
throw new Error(`invalid_map_json:${config.mapPath}`);
|
|
1707
|
+
}
|
|
1708
|
+
fromFileMap = normalizeMapObject(parsed);
|
|
1709
|
+
} catch (error) {
|
|
1710
|
+
if (error && error.code === 'ENOENT') {
|
|
1711
|
+
if (!config.createMapIfMissing) {
|
|
1712
|
+
throw new Error(
|
|
1713
|
+
`map_not_found:${config.mapPath}. Crie o arquivo map.json ou use { createMapIfMissing: true }.`
|
|
1714
|
+
);
|
|
1715
|
+
}
|
|
1716
|
+
fromFileMap = { version: 1, apps: {} };
|
|
1717
|
+
mapCreatedFromMissing = true;
|
|
1718
|
+
} else if (error instanceof Error) {
|
|
1719
|
+
throw error;
|
|
1720
|
+
} else {
|
|
1721
|
+
throw new Error(`map_read_error:${config.mapPath}`);
|
|
1722
|
+
}
|
|
1723
|
+
}
|
|
1724
|
+
|
|
1725
|
+
const map = mergeMaps(fallbackMap, fromFileMap);
|
|
1726
|
+
const store = {
|
|
1727
|
+
path: config.mapPath,
|
|
1728
|
+
persistMap: config.persistMap,
|
|
1729
|
+
map
|
|
1730
|
+
};
|
|
1731
|
+
|
|
1732
|
+
if (config.createMapIfMissing && mapCreatedFromMissing) {
|
|
1733
|
+
await persistMapStore(store);
|
|
1734
|
+
}
|
|
1735
|
+
|
|
1736
|
+
return store;
|
|
1737
|
+
}
|
|
1738
|
+
|
|
1739
|
+
function resolveAppInMap(store, rawAppName) {
|
|
1740
|
+
const appName = resolveAppName(rawAppName);
|
|
1741
|
+
return {
|
|
1742
|
+
appName,
|
|
1743
|
+
app: store.map.apps[appName]
|
|
1744
|
+
};
|
|
1745
|
+
}
|
|
1746
|
+
|
|
1747
|
+
function resolveMappedButton(appConfig, rawButtonName) {
|
|
1748
|
+
if (!rawButtonName) return null;
|
|
1749
|
+
const buttonName = resolveButtonKey(rawButtonName);
|
|
1750
|
+
return appConfig.buttons && appConfig.buttons[buttonName]
|
|
1751
|
+
? appConfig.buttons[buttonName]
|
|
1752
|
+
: null;
|
|
1753
|
+
}
|
|
1754
|
+
|
|
1755
|
+
async function updateAppState(store, appName, nextState) {
|
|
1756
|
+
const state = normalizeState(nextState);
|
|
1757
|
+
if (!state) return;
|
|
1758
|
+
|
|
1759
|
+
const app = store.map.apps[appName];
|
|
1760
|
+
if (!app) return;
|
|
1761
|
+
if (app.state === state) return;
|
|
1762
|
+
|
|
1763
|
+
app.state = state;
|
|
1764
|
+
await persistMapStore(store);
|
|
1765
|
+
}
|
|
1766
|
+
|
|
1767
|
+
async function persistMapStore(store) {
|
|
1768
|
+
if (!store.persistMap) return;
|
|
1769
|
+
await mkdir(dirnamePath(store.path), { recursive: true });
|
|
1770
|
+
const serialized = JSON.stringify(store.map, null, 2) + '\n';
|
|
1771
|
+
await writeFile(store.path, serialized, 'utf8');
|
|
1772
|
+
}
|
|
1773
|
+
|
|
1774
|
+
function getAppState(appConfig) {
|
|
1775
|
+
return normalizeState(appConfig && appConfig.state) || APP_STATE.CLOSED;
|
|
1776
|
+
}
|
|
1777
|
+
|
|
1778
|
+
function sleep(ms) {
|
|
1779
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
1780
|
+
}
|
|
1781
|
+
|
|
1782
|
+
async function smoothMove(robot, xFinal, yFinal, steps, delay) {
|
|
1783
|
+
const current = robot.getMousePos();
|
|
1784
|
+
const totalSteps = Math.max(1, parseIntegerOption(steps, 50, 1));
|
|
1785
|
+
|
|
1786
|
+
for (let i = 1; i <= totalSteps; i++) {
|
|
1787
|
+
const progress = i / totalSteps;
|
|
1788
|
+
const x = Math.round(current.x + (xFinal - current.x) * progress);
|
|
1789
|
+
const y = Math.round(current.y + (yFinal - current.y) * progress);
|
|
1790
|
+
robot.moveMouse(x, y);
|
|
1791
|
+
await sleep(delay);
|
|
1792
|
+
}
|
|
1793
|
+
}
|
|
1794
|
+
|
|
1795
|
+
async function smoothScroll(robot, amount, steps, delay) {
|
|
1796
|
+
const totalSteps = Math.max(1, parseIntegerOption(steps, 10, 1));
|
|
1797
|
+
let applied = 0;
|
|
1798
|
+
|
|
1799
|
+
for (let i = 1; i <= totalSteps; i++) {
|
|
1800
|
+
const target = Math.round((amount * i) / totalSteps);
|
|
1801
|
+
const delta = target - applied;
|
|
1802
|
+
if (delta !== 0) {
|
|
1803
|
+
robot.scrollMouse(0, delta);
|
|
1804
|
+
applied = target;
|
|
1805
|
+
}
|
|
1806
|
+
await sleep(delay);
|
|
1807
|
+
}
|
|
1808
|
+
}
|
|
1809
|
+
|
|
1810
|
+
function clickCurrentPosition(robot, doubleClick) {
|
|
1811
|
+
if (doubleClick) {
|
|
1812
|
+
robot.mouseClick('left', true);
|
|
1813
|
+
return;
|
|
1814
|
+
}
|
|
1815
|
+
robot.mouseClick();
|
|
1816
|
+
}
|
|
1817
|
+
|
|
1818
|
+
async function clickPoint(robot, point, config, clickOptions = {}) {
|
|
1819
|
+
await smoothMove(robot, point.x, point.y, config.moveSteps, config.moveDelay);
|
|
1820
|
+
clickCurrentPosition(robot, clickOptions.doubleClick === true);
|
|
1821
|
+
}
|
|
1822
|
+
|
|
1823
|
+
async function runConfiguredPath(robot, pathConfig, config) {
|
|
1824
|
+
if (!pathConfig || !Array.isArray(pathConfig.points) || pathConfig.points.length === 0) {
|
|
1825
|
+
return;
|
|
1826
|
+
}
|
|
1827
|
+
|
|
1828
|
+
const clickMode = normalizeClickMode(pathConfig.clickMode, CLICK_MODE.NONE);
|
|
1829
|
+
const interval = toNonNegativeInteger(pathConfig.interval) || 0;
|
|
1830
|
+
const clickDelay = toNonNegativeInteger(pathConfig.clickDelay) || 0;
|
|
1831
|
+
const doubleClick = pathConfig.doubleClick === true;
|
|
1832
|
+
|
|
1833
|
+
for (let index = 0; index < pathConfig.points.length; index++) {
|
|
1834
|
+
const point = pathConfig.points[index];
|
|
1835
|
+
await smoothMove(robot, point.x, point.y, config.moveSteps, config.moveDelay);
|
|
1836
|
+
|
|
1837
|
+
if (shouldClickOnStep(clickMode, index, pathConfig.points.length)) {
|
|
1838
|
+
if (clickDelay > 0) {
|
|
1839
|
+
await sleep(clickDelay);
|
|
1840
|
+
}
|
|
1841
|
+
clickCurrentPosition(robot, doubleClick);
|
|
1842
|
+
}
|
|
1843
|
+
|
|
1844
|
+
if (index < pathConfig.points.length - 1 && interval > 0) {
|
|
1845
|
+
await sleep(interval);
|
|
1846
|
+
}
|
|
1847
|
+
}
|
|
1848
|
+
}
|
|
1849
|
+
|
|
1850
|
+
async function clickTarget(robot, target, config, clickOptions = {}) {
|
|
1851
|
+
if (!target || !target.position) {
|
|
1852
|
+
throw new Error('invalid_target_config');
|
|
1853
|
+
}
|
|
1854
|
+
|
|
1855
|
+
if (target.path) {
|
|
1856
|
+
await runConfiguredPath(robot, target.path, config);
|
|
1857
|
+
}
|
|
1858
|
+
|
|
1859
|
+
await clickPoint(robot, target.position, config, clickOptions);
|
|
1860
|
+
}
|
|
1861
|
+
|
|
1862
|
+
function createActionHandlers(robot, runtime) {
|
|
1863
|
+
const config = runtime.config;
|
|
1864
|
+
let mapStorePromise;
|
|
1865
|
+
|
|
1866
|
+
async function getMapStore() {
|
|
1867
|
+
if (mapStorePromise) {
|
|
1868
|
+
return mapStorePromise;
|
|
1869
|
+
}
|
|
1870
|
+
mapStorePromise = runtime.getMapStore();
|
|
1871
|
+
return mapStorePromise;
|
|
1872
|
+
}
|
|
1873
|
+
|
|
1874
|
+
async function openAppIfNeeded(appName, appConfig, mapStore) {
|
|
1875
|
+
if (getAppState(appConfig) === APP_STATE.OPEN) {
|
|
1876
|
+
return;
|
|
1877
|
+
}
|
|
1878
|
+
|
|
1879
|
+
if (!appConfig.launcher || !appConfig.launcher.position) {
|
|
1880
|
+
throw new Error(`missing_launcher:${appName}`);
|
|
1881
|
+
}
|
|
1882
|
+
|
|
1883
|
+
if (appConfig.launcher.path) {
|
|
1884
|
+
await clickTarget(robot, appConfig.launcher, config);
|
|
1885
|
+
} else {
|
|
1886
|
+
await smoothMove(robot, 0, 0, config.moveSteps, config.moveDelay);
|
|
1887
|
+
await smoothMove(
|
|
1888
|
+
robot,
|
|
1889
|
+
appConfig.launcher.position.x,
|
|
1890
|
+
appConfig.launcher.position.y,
|
|
1891
|
+
config.moveSteps,
|
|
1892
|
+
config.moveDelay
|
|
1893
|
+
);
|
|
1894
|
+
await smoothMove(
|
|
1895
|
+
robot,
|
|
1896
|
+
appConfig.launcher.position.x + 20,
|
|
1897
|
+
appConfig.launcher.position.y + 10,
|
|
1898
|
+
config.moveSteps,
|
|
1899
|
+
config.moveDelay
|
|
1900
|
+
);
|
|
1901
|
+
await smoothMove(
|
|
1902
|
+
robot,
|
|
1903
|
+
appConfig.launcher.position.x - 20,
|
|
1904
|
+
appConfig.launcher.position.y - 10,
|
|
1905
|
+
config.moveSteps,
|
|
1906
|
+
config.moveDelay
|
|
1907
|
+
);
|
|
1908
|
+
robot.mouseClick();
|
|
1909
|
+
}
|
|
1910
|
+
|
|
1911
|
+
await updateAppState(mapStore, appName, APP_STATE.OPEN);
|
|
1912
|
+
}
|
|
1913
|
+
|
|
1914
|
+
function resolveSequencePoints(command) {
|
|
1915
|
+
const points = normalizePointsValue(
|
|
1916
|
+
command.points !== undefined
|
|
1917
|
+
? command.points
|
|
1918
|
+
: command.path !== undefined
|
|
1919
|
+
? command.path
|
|
1920
|
+
: command.command
|
|
1921
|
+
);
|
|
1922
|
+
|
|
1923
|
+
if (!points || points.length < 2) {
|
|
1924
|
+
throw new Error('move_sequence_requires_at_least_2_points');
|
|
1925
|
+
}
|
|
1926
|
+
|
|
1927
|
+
return points;
|
|
1928
|
+
}
|
|
1929
|
+
|
|
1930
|
+
function resolveSequenceInterval(command) {
|
|
1931
|
+
const interval = toNonNegativeInteger(command.interval);
|
|
1932
|
+
if (interval !== null) {
|
|
1933
|
+
return interval;
|
|
1934
|
+
}
|
|
1935
|
+
return config.sequenceInterval;
|
|
1936
|
+
}
|
|
1937
|
+
|
|
1938
|
+
function resolveSequenceClickMode(command) {
|
|
1939
|
+
return normalizeClickMode(command.click, config.sequenceClickMode);
|
|
1940
|
+
}
|
|
1941
|
+
|
|
1942
|
+
function resolveSequenceClickDelay(command) {
|
|
1943
|
+
const clickDelay = toNonNegativeInteger(command.clickDelay);
|
|
1944
|
+
if (clickDelay !== null) {
|
|
1945
|
+
return clickDelay;
|
|
1946
|
+
}
|
|
1947
|
+
return 0;
|
|
1948
|
+
}
|
|
1949
|
+
|
|
1950
|
+
function resolveSequenceDoubleClick(command) {
|
|
1951
|
+
const value = parseBooleanValue(command.doubleClick);
|
|
1952
|
+
if (value !== null) {
|
|
1953
|
+
return value;
|
|
1954
|
+
}
|
|
1955
|
+
return config.sequenceDoubleClick;
|
|
1956
|
+
}
|
|
1957
|
+
|
|
1958
|
+
async function tapKey(key, modifiers) {
|
|
1959
|
+
if (modifiers && modifiers.length > 0) {
|
|
1960
|
+
robot.keyTap(key, modifiers);
|
|
1961
|
+
return;
|
|
1962
|
+
}
|
|
1963
|
+
robot.keyTap(key);
|
|
1964
|
+
}
|
|
1965
|
+
|
|
1966
|
+
function resolveKeyTapPayload(command) {
|
|
1967
|
+
const key = normalizeKeyTapToken(
|
|
1968
|
+
command.key !== undefined ? command.key : command.command
|
|
1969
|
+
);
|
|
1970
|
+
|
|
1971
|
+
if (!key) {
|
|
1972
|
+
throw new Error('key_tap_requires_key');
|
|
1973
|
+
}
|
|
1974
|
+
|
|
1975
|
+
const modifiers =
|
|
1976
|
+
command.modifiers !== undefined
|
|
1977
|
+
? parseKeyModifiers(command.modifiers)
|
|
1978
|
+
: parseKeyModifiers(command.extra);
|
|
1979
|
+
|
|
1980
|
+
return {
|
|
1981
|
+
key,
|
|
1982
|
+
modifiers
|
|
1983
|
+
};
|
|
1984
|
+
}
|
|
1985
|
+
|
|
1986
|
+
function resolveTypeStringPayload(command) {
|
|
1987
|
+
const text =
|
|
1988
|
+
command.text !== undefined && command.text !== null
|
|
1989
|
+
? String(command.text)
|
|
1990
|
+
: command.command !== undefined && command.command !== null
|
|
1991
|
+
? String(command.command)
|
|
1992
|
+
: command.extra !== undefined && command.extra !== null
|
|
1993
|
+
? String(command.extra)
|
|
1994
|
+
: '';
|
|
1995
|
+
|
|
1996
|
+
if (!text.trim()) {
|
|
1997
|
+
throw new Error('type_string_delayed_requires_text');
|
|
1998
|
+
}
|
|
1999
|
+
|
|
2000
|
+
const customDelay = toNonNegativeInteger(
|
|
2001
|
+
command.typeDelay !== undefined ? command.typeDelay : command.interval
|
|
2002
|
+
);
|
|
2003
|
+
|
|
2004
|
+
return {
|
|
2005
|
+
text,
|
|
2006
|
+
typeDelay: customDelay !== null ? customDelay : config.typeDelay
|
|
2007
|
+
};
|
|
2008
|
+
}
|
|
2009
|
+
|
|
2010
|
+
return {
|
|
2011
|
+
async skip_ads(command) {
|
|
2012
|
+
let point = config.skipAdsPoint;
|
|
2013
|
+
|
|
2014
|
+
if (command.command) {
|
|
2015
|
+
try {
|
|
2016
|
+
const mapStore = await getMapStore();
|
|
2017
|
+
const appRef = resolveAppInMap(mapStore, command.command);
|
|
2018
|
+
const appConfig = appRef.app;
|
|
2019
|
+
if (appConfig) {
|
|
2020
|
+
const button = resolveMappedButton(
|
|
2021
|
+
appConfig,
|
|
2022
|
+
command.button || 'pular_ads'
|
|
2023
|
+
);
|
|
2024
|
+
if (button && button.position) {
|
|
2025
|
+
if (button.path) {
|
|
2026
|
+
await clickTarget(robot, button, config);
|
|
2027
|
+
point = null;
|
|
2028
|
+
} else {
|
|
2029
|
+
point = button.position;
|
|
2030
|
+
}
|
|
2031
|
+
if (button.setState) {
|
|
2032
|
+
await updateAppState(mapStore, appRef.appName, button.setState);
|
|
2033
|
+
}
|
|
2034
|
+
}
|
|
2035
|
+
}
|
|
2036
|
+
} catch (error) {
|
|
2037
|
+
// keep fallback point when map is unavailable for skip_ads
|
|
2038
|
+
}
|
|
2039
|
+
}
|
|
2040
|
+
|
|
2041
|
+
if (point) {
|
|
2042
|
+
await clickPoint(robot, point, config);
|
|
2043
|
+
}
|
|
2044
|
+
},
|
|
2045
|
+
|
|
2046
|
+
async click() {
|
|
2047
|
+
const size = robot.getScreenSize();
|
|
2048
|
+
const centerX = Math.floor(size.width / 2);
|
|
2049
|
+
const centerY = Math.floor(size.height / 2);
|
|
2050
|
+
await clickPoint(robot, { x: centerX, y: centerY }, config);
|
|
2051
|
+
},
|
|
2052
|
+
|
|
2053
|
+
async double_click() {
|
|
2054
|
+
const size = robot.getScreenSize();
|
|
2055
|
+
const centerX = Math.floor(size.width / 2);
|
|
2056
|
+
const centerY = Math.floor(size.height / 2);
|
|
2057
|
+
await clickPoint(
|
|
2058
|
+
robot,
|
|
2059
|
+
{ x: centerX, y: centerY },
|
|
2060
|
+
config,
|
|
2061
|
+
{ doubleClick: true }
|
|
2062
|
+
);
|
|
2063
|
+
},
|
|
2064
|
+
|
|
2065
|
+
async scroll(command) {
|
|
2066
|
+
const amount = Number(command.command);
|
|
2067
|
+
if (!Number.isFinite(amount)) {
|
|
2068
|
+
throw new Error('scroll_requires_numeric_command');
|
|
2069
|
+
}
|
|
2070
|
+
|
|
2071
|
+
const size = robot.getScreenSize();
|
|
2072
|
+
const centerX = Math.floor(size.width / 2);
|
|
2073
|
+
const centerY = Math.floor(size.height / 2);
|
|
2074
|
+
|
|
2075
|
+
await smoothMove(robot, centerX, centerY, config.moveSteps, config.moveDelay);
|
|
2076
|
+
await smoothScroll(robot, amount, config.scrollSteps, config.scrollDelay);
|
|
2077
|
+
},
|
|
2078
|
+
|
|
2079
|
+
async move_sequence(command) {
|
|
2080
|
+
const points = resolveSequencePoints(command);
|
|
2081
|
+
const interval = resolveSequenceInterval(command);
|
|
2082
|
+
const clickMode = resolveSequenceClickMode(command);
|
|
2083
|
+
const clickDelay = resolveSequenceClickDelay(command);
|
|
2084
|
+
const doubleClick = resolveSequenceDoubleClick(command);
|
|
2085
|
+
|
|
2086
|
+
for (let index = 0; index < points.length; index++) {
|
|
2087
|
+
const point = points[index];
|
|
2088
|
+
await smoothMove(
|
|
2089
|
+
robot,
|
|
2090
|
+
point.x,
|
|
2091
|
+
point.y,
|
|
2092
|
+
config.moveSteps,
|
|
2093
|
+
config.moveDelay
|
|
2094
|
+
);
|
|
2095
|
+
|
|
2096
|
+
if (shouldClickOnStep(clickMode, index, points.length)) {
|
|
2097
|
+
if (clickDelay > 0) {
|
|
2098
|
+
await sleep(clickDelay);
|
|
2099
|
+
}
|
|
2100
|
+
clickCurrentPosition(robot, doubleClick);
|
|
2101
|
+
}
|
|
2102
|
+
|
|
2103
|
+
if (index < points.length - 1 && interval > 0) {
|
|
2104
|
+
await sleep(interval);
|
|
2105
|
+
}
|
|
2106
|
+
}
|
|
2107
|
+
},
|
|
2108
|
+
|
|
2109
|
+
async key_tap(command) {
|
|
2110
|
+
const payload = resolveKeyTapPayload(command);
|
|
2111
|
+
await tapKey(payload.key, payload.modifiers);
|
|
2112
|
+
},
|
|
2113
|
+
|
|
2114
|
+
async type_string_delayed(command) {
|
|
2115
|
+
const payload = resolveTypeStringPayload(command);
|
|
2116
|
+
robot.typeStringDelayed(payload.text, payload.typeDelay);
|
|
2117
|
+
},
|
|
2118
|
+
|
|
2119
|
+
async open_app(command) {
|
|
2120
|
+
await tapKey('command');
|
|
2121
|
+
|
|
2122
|
+
const mapStore = await getMapStore();
|
|
2123
|
+
const appRef = resolveAppInMap(mapStore, command.command);
|
|
2124
|
+
if (!appRef.app) {
|
|
2125
|
+
throw new Error(`unknown_app:${appRef.appName}`);
|
|
2126
|
+
}
|
|
2127
|
+
|
|
2128
|
+
await openAppIfNeeded(appRef.appName, appRef.app, mapStore);
|
|
2129
|
+
|
|
2130
|
+
if (command.button) {
|
|
2131
|
+
const mappedButton = resolveMappedButton(appRef.app, command.button);
|
|
2132
|
+
if (!mappedButton) {
|
|
2133
|
+
throw new Error(
|
|
2134
|
+
`unknown_button:${appRef.appName}:${resolveButtonKey(command.button)}`
|
|
2135
|
+
);
|
|
2136
|
+
}
|
|
2137
|
+
|
|
2138
|
+
await clickTarget(robot, mappedButton, config);
|
|
2139
|
+
if (mappedButton.setState) {
|
|
2140
|
+
await updateAppState(mapStore, appRef.appName, mappedButton.setState);
|
|
2141
|
+
}
|
|
2142
|
+
return;
|
|
2143
|
+
}
|
|
2144
|
+
|
|
2145
|
+
if (command.extra) {
|
|
2146
|
+
if (appRef.app.searchIcon && appRef.app.searchIcon.position) {
|
|
2147
|
+
await clickTarget(robot, appRef.app.searchIcon, config);
|
|
2148
|
+
}
|
|
2149
|
+
|
|
2150
|
+
const customTypeDelay = toNonNegativeInteger(command.typeDelay);
|
|
2151
|
+
const typeDelay =
|
|
2152
|
+
customTypeDelay !== null ? customTypeDelay : config.typeDelay;
|
|
2153
|
+
|
|
2154
|
+
robot.typeStringDelayed(String(command.extra), typeDelay);
|
|
2155
|
+
}
|
|
2156
|
+
},
|
|
2157
|
+
|
|
2158
|
+
async close_app(command) {
|
|
2159
|
+
const mapStore = await getMapStore();
|
|
2160
|
+
const appRef = resolveAppInMap(mapStore, command.command);
|
|
2161
|
+
if (!appRef.app) {
|
|
2162
|
+
throw new Error(`unknown_app:${appRef.appName}`);
|
|
2163
|
+
}
|
|
2164
|
+
|
|
2165
|
+
if (getAppState(appRef.app) === APP_STATE.CLOSED) {
|
|
2166
|
+
return;
|
|
2167
|
+
}
|
|
2168
|
+
|
|
2169
|
+
const mappedButton = resolveMappedButton(
|
|
2170
|
+
appRef.app,
|
|
2171
|
+
command.button || 'fechar'
|
|
2172
|
+
);
|
|
2173
|
+
|
|
2174
|
+
if (mappedButton) {
|
|
2175
|
+
await clickTarget(robot, mappedButton, config);
|
|
2176
|
+
await updateAppState(
|
|
2177
|
+
mapStore,
|
|
2178
|
+
appRef.appName,
|
|
2179
|
+
mappedButton.setState || APP_STATE.CLOSED
|
|
2180
|
+
);
|
|
2181
|
+
return;
|
|
2182
|
+
}
|
|
2183
|
+
|
|
2184
|
+
const modifier =
|
|
2185
|
+
config.launchKey === 'command' ? 'command' : config.launchKey || 'command';
|
|
2186
|
+
robot.keyTap('w', modifier);
|
|
2187
|
+
await updateAppState(mapStore, appRef.appName, APP_STATE.CLOSED);
|
|
2188
|
+
}
|
|
2189
|
+
};
|
|
2190
|
+
}
|
|
2191
|
+
|
|
2192
|
+
async function getRobot() {
|
|
2193
|
+
if (robotCache) {
|
|
2194
|
+
return robotCache;
|
|
2195
|
+
}
|
|
2196
|
+
|
|
2197
|
+
let module;
|
|
2198
|
+
try {
|
|
2199
|
+
module = await import('robotjs');
|
|
2200
|
+
} catch (error) {
|
|
2201
|
+
throw new Error(
|
|
2202
|
+
'robotjs_not_available: install dependencies and run in a supported desktop environment.'
|
|
2203
|
+
);
|
|
2204
|
+
}
|
|
2205
|
+
|
|
2206
|
+
const robot = module && module.default ? module.default : module;
|
|
2207
|
+
if (!robot || typeof robot.mouseClick !== 'function') {
|
|
2208
|
+
throw new Error(
|
|
2209
|
+
'robotjs_not_available: install dependencies and run in a supported desktop environment.'
|
|
2210
|
+
);
|
|
2211
|
+
}
|
|
2212
|
+
|
|
2213
|
+
robotCache = robot;
|
|
2214
|
+
return robot;
|
|
2215
|
+
}
|