@aspiresys/visor 1.1.5 → 1.1.7
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/dist/app.js +4 -4
- package/dist/display.d.ts +1 -0
- package/dist/display.js +16 -0
- package/dist/index.d.ts +785 -783
- package/dist/index.js +812 -803
- package/dist/matcher.js +16 -9
- package/dist/mouse.js +2 -4
- package/dist/ocr.js +12 -13
- package/dist/screen.js +1 -1
- package/dist/text.js +17 -11
- package/package.json +1 -1
- package/readme.md +171 -203
package/dist/index.js
CHANGED
|
@@ -10,6 +10,8 @@ const config_1 = require("./config");
|
|
|
10
10
|
const app_1 = require("./app");
|
|
11
11
|
const nut_js_1 = require("@nut-tree-fork/nut-js");
|
|
12
12
|
const path_1 = require("./path");
|
|
13
|
+
const display_1 = require("./display");
|
|
14
|
+
const logger_1 = require("./logger");
|
|
13
15
|
class Visor {
|
|
14
16
|
constructor() {
|
|
15
17
|
this.mouse = nut_js_1.mouse;
|
|
@@ -18,72 +20,72 @@ class Visor {
|
|
|
18
20
|
this.Button = nut_js_1.Button;
|
|
19
21
|
}
|
|
20
22
|
/**
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
23
|
+
* Finds an image on screen using OpenCV
|
|
24
|
+
* and performs a left mouse click
|
|
25
|
+
* on the matched region.
|
|
26
|
+
*
|
|
27
|
+
* @param image Optional image filename or path.
|
|
28
|
+
*
|
|
29
|
+
* @param confidence Match confidence threshold.
|
|
30
|
+
*
|
|
31
|
+
* Accepted range:
|
|
32
|
+
* 0.0 to 1.0
|
|
33
|
+
*
|
|
34
|
+
* Default:
|
|
35
|
+
* 0.8
|
|
36
|
+
*
|
|
37
|
+
* Recommended values:
|
|
38
|
+
* - 0.7 for dynamic UI
|
|
39
|
+
* - 0.8 for standard usage
|
|
40
|
+
* - 0.9+ for strict matching
|
|
41
|
+
*
|
|
42
|
+
* Lower confidence increases
|
|
43
|
+
* flexibility but may increase
|
|
44
|
+
* false positives.
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* await visor.click("save.png");
|
|
48
|
+
*
|
|
49
|
+
* @example
|
|
50
|
+
* await visor.click("./images/save.png", 0.9);
|
|
51
|
+
*/
|
|
50
52
|
async click(image, confidence = 0.8) {
|
|
51
53
|
if (!image) {
|
|
52
54
|
await this.mouse.click(this.Button.LEFT);
|
|
53
|
-
|
|
55
|
+
(0, logger_1.log)("[MOUSE] Left click completed");
|
|
54
56
|
return;
|
|
55
57
|
}
|
|
56
58
|
const region = await this.find(image, confidence);
|
|
57
59
|
if (!region) {
|
|
58
60
|
throw new Error(`Image not found: ${image}`);
|
|
59
61
|
}
|
|
60
|
-
|
|
62
|
+
(0, logger_1.log)("[CV] Match found:", region);
|
|
61
63
|
await (0, mouse_1.clickRegion)(region);
|
|
62
64
|
}
|
|
63
65
|
/**
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
66
|
+
* Performs a right mouse click.
|
|
67
|
+
*
|
|
68
|
+
* If an image is provided, the framework
|
|
69
|
+
* first finds the image on screen and
|
|
70
|
+
* moves the mouse to the matched region
|
|
71
|
+
* before performing the click.
|
|
72
|
+
*
|
|
73
|
+
* @param image Image filename or path.
|
|
74
|
+
* @param confidence Match confidence threshold.
|
|
75
|
+
*
|
|
76
|
+
* Accepted range:
|
|
77
|
+
* 0.0 to 1.0
|
|
78
|
+
*
|
|
79
|
+
* Default:
|
|
80
|
+
* 0.8
|
|
81
|
+
* @throws Error if image is not found.
|
|
82
|
+
*
|
|
83
|
+
* @example
|
|
84
|
+
* await visor.rightClick("file.png");
|
|
85
|
+
*
|
|
86
|
+
* @example
|
|
87
|
+
* await visor.rightClick();
|
|
88
|
+
*/
|
|
87
89
|
async rightClick(image, confidence = 0.8) {
|
|
88
90
|
if (image) {
|
|
89
91
|
const region = await this.find(image, confidence);
|
|
@@ -93,33 +95,33 @@ class Visor {
|
|
|
93
95
|
await (0, mouse_1.moveToRegion)(region);
|
|
94
96
|
}
|
|
95
97
|
await this.mouse.click(this.Button.RIGHT);
|
|
96
|
-
|
|
98
|
+
(0, logger_1.log)("[MOUSE] Right click completed");
|
|
97
99
|
}
|
|
98
100
|
/**
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
101
|
+
* Performs a double left mouse click.
|
|
102
|
+
*
|
|
103
|
+
* If an image is provided, the framework
|
|
104
|
+
* first finds the image on screen and
|
|
105
|
+
* moves the mouse to the matched region
|
|
106
|
+
* before performing the click.
|
|
107
|
+
*
|
|
108
|
+
* @param image Image filename or path.
|
|
109
|
+
* @param confidence Match confidence threshold.
|
|
110
|
+
*
|
|
111
|
+
* Accepted range:
|
|
112
|
+
* 0.0 to 1.0
|
|
113
|
+
*
|
|
114
|
+
* Default:
|
|
115
|
+
* 0.8
|
|
116
|
+
*
|
|
117
|
+
* @throws Error if image is not found.
|
|
118
|
+
*
|
|
119
|
+
* @example
|
|
120
|
+
* await visor.doubleClick("folder.png");
|
|
121
|
+
*
|
|
122
|
+
* @example
|
|
123
|
+
* await visor.doubleClick();
|
|
124
|
+
*/
|
|
123
125
|
async doubleClick(image, confidence = 0.8) {
|
|
124
126
|
if (image) {
|
|
125
127
|
const region = await this.find(image, confidence);
|
|
@@ -129,37 +131,37 @@ class Visor {
|
|
|
129
131
|
await (0, mouse_1.moveToRegion)(region);
|
|
130
132
|
}
|
|
131
133
|
await this.mouse.doubleClick(this.Button.LEFT);
|
|
132
|
-
|
|
134
|
+
(0, logger_1.log)("[MOUSE] Double click completed");
|
|
133
135
|
}
|
|
134
136
|
/**
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
137
|
+
* Finds the best matching image on screen
|
|
138
|
+
* using OpenCV template matching.
|
|
139
|
+
*
|
|
140
|
+
* @param image Image filename or path.
|
|
141
|
+
*
|
|
142
|
+
* @param confidence Match confidence threshold.
|
|
143
|
+
*
|
|
144
|
+
* Accepted range:
|
|
145
|
+
* 0.0 to 1.0
|
|
146
|
+
*
|
|
147
|
+
* Default:
|
|
148
|
+
* 0.8
|
|
149
|
+
*
|
|
150
|
+
* Recommended values:
|
|
151
|
+
* - 0.7 for dynamic UI
|
|
152
|
+
* - 0.8 for standard usage
|
|
153
|
+
* - 0.9+ for strict matching
|
|
154
|
+
*
|
|
155
|
+
* Higher confidence improves
|
|
156
|
+
* matching accuracy but may fail
|
|
157
|
+
* on scaled or slightly modified UI.
|
|
158
|
+
*
|
|
159
|
+
* @returns Best matched region or null.
|
|
160
|
+
*
|
|
161
|
+
* @example
|
|
162
|
+
* const region =
|
|
163
|
+
* await visor.find("save.png");
|
|
164
|
+
*/
|
|
163
165
|
async find(image, confidence = 0.8) {
|
|
164
166
|
const screen = await (0, screen_1.captureScreen)();
|
|
165
167
|
const template = await (0, matcher_1.loadTemplate)((0, path_1.resolveImagePath)(image));
|
|
@@ -172,49 +174,49 @@ class Visor {
|
|
|
172
174
|
}
|
|
173
175
|
}
|
|
174
176
|
/**
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
177
|
+
* Checks whether an image exists
|
|
178
|
+
* on the current screen.
|
|
179
|
+
*
|
|
180
|
+
* @param image Image filename or path.
|
|
181
|
+
* @param confidence Match confidence threshold.
|
|
182
|
+
*
|
|
183
|
+
* Accepted range:
|
|
184
|
+
* 0.0 to 1.0
|
|
185
|
+
*
|
|
186
|
+
* Default:
|
|
187
|
+
* 0.8
|
|
188
|
+
*
|
|
189
|
+
* @returns True if image exists.
|
|
190
|
+
*
|
|
191
|
+
* @example
|
|
192
|
+
* const exists =
|
|
193
|
+
* await visor.exists("login.png");
|
|
194
|
+
*/
|
|
193
195
|
async exists(image, confidence = 0.8) {
|
|
194
196
|
return (await this.find(image, confidence)) !== null;
|
|
195
197
|
}
|
|
196
198
|
/**
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
199
|
+
* Finds all matching occurrences of an image
|
|
200
|
+
* on the current screen using OpenCV.
|
|
201
|
+
*
|
|
202
|
+
* @param image Image filename or path.
|
|
203
|
+
* @param confidence Match confidence threshold.
|
|
204
|
+
*
|
|
205
|
+
* Accepted range:
|
|
206
|
+
* 0.0 to 1.0
|
|
207
|
+
*
|
|
208
|
+
* Default:
|
|
209
|
+
* 0.8
|
|
210
|
+
*
|
|
211
|
+
* Lower confidence may return
|
|
212
|
+
* more false-positive matches.
|
|
213
|
+
*
|
|
214
|
+
* @returns Array of matched regions.
|
|
215
|
+
*
|
|
216
|
+
* @example
|
|
217
|
+
* const matches =
|
|
218
|
+
* await visor.findAll("icon.png");
|
|
219
|
+
*/
|
|
218
220
|
async findAll(image, confidence = 0.8) {
|
|
219
221
|
const screen = await (0, screen_1.captureScreen)();
|
|
220
222
|
const template = await (0, matcher_1.loadTemplate)((0, path_1.resolveImagePath)(image));
|
|
@@ -227,32 +229,32 @@ class Visor {
|
|
|
227
229
|
}
|
|
228
230
|
}
|
|
229
231
|
/**
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
232
|
+
* Finds all image matches and prints
|
|
233
|
+
* a formatted match preview including
|
|
234
|
+
* coordinates and confidence values.
|
|
235
|
+
*
|
|
236
|
+
* Useful for debugging and visual
|
|
237
|
+
* automation tuning.
|
|
238
|
+
*
|
|
239
|
+
* @param image Image filename or path.
|
|
240
|
+
* @param confidence Match confidence threshold.
|
|
241
|
+
*
|
|
242
|
+
* Accepted range:
|
|
243
|
+
* 0.0 to 1.0
|
|
244
|
+
*
|
|
245
|
+
* Default:
|
|
246
|
+
* 0.8
|
|
247
|
+
*
|
|
248
|
+
* @returns Array of matched regions.
|
|
249
|
+
*
|
|
250
|
+
* @example
|
|
251
|
+
* await visor.previewMatches("button.png");
|
|
252
|
+
*/
|
|
251
253
|
async previewMatches(image, confidence = 0.8) {
|
|
252
254
|
const matches = await this.findAll(image, confidence);
|
|
253
|
-
|
|
255
|
+
(0, logger_1.log)("\n=== MATCH PREVIEW ===\n");
|
|
254
256
|
matches.forEach((m, i) => {
|
|
255
|
-
|
|
257
|
+
(0, logger_1.log)(`#${i + 1}
|
|
256
258
|
X:${m.x}
|
|
257
259
|
Y:${m.y}
|
|
258
260
|
W:${m.width}
|
|
@@ -263,40 +265,40 @@ CONF:${m.confidence.toFixed(3)}
|
|
|
263
265
|
return matches;
|
|
264
266
|
}
|
|
265
267
|
/**
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
268
|
+
* Waits until an image appears
|
|
269
|
+
* on the screen.
|
|
270
|
+
*
|
|
271
|
+
* @param image Image filename or path.
|
|
272
|
+
*
|
|
273
|
+
* @param confidence Match confidence threshold.
|
|
274
|
+
*
|
|
275
|
+
* Accepted range:
|
|
276
|
+
* 0.0 to 1.0
|
|
277
|
+
*
|
|
278
|
+
* Default:
|
|
279
|
+
* 0.8
|
|
280
|
+
*
|
|
281
|
+
* Recommended values:
|
|
282
|
+
* - 0.7 for dynamic UI
|
|
283
|
+
* - 0.8 for standard usage
|
|
284
|
+
* - 0.9+ for strict matching
|
|
285
|
+
*
|
|
286
|
+
* @param timeout Timeout duration
|
|
287
|
+
* in milliseconds.
|
|
288
|
+
*
|
|
289
|
+
* Default:
|
|
290
|
+
* 5000ms
|
|
291
|
+
*
|
|
292
|
+
* Recommended range:
|
|
293
|
+
* 1000ms to 30000ms
|
|
294
|
+
*
|
|
295
|
+
* @throws Error if timeout occurs.
|
|
296
|
+
*
|
|
297
|
+
* @example
|
|
298
|
+
* await visor.wait("loading-done.png");
|
|
299
|
+
*/
|
|
298
300
|
async wait(image, { confidence = 0.8, timeout = 5000 } = {}) {
|
|
299
|
-
const interval =
|
|
301
|
+
const interval = 300;
|
|
300
302
|
const attempts = Math.ceil(timeout / interval);
|
|
301
303
|
for (let i = 0; i < attempts; i++) {
|
|
302
304
|
if (await this.exists(image, confidence)) {
|
|
@@ -307,30 +309,30 @@ CONF:${m.confidence.toFixed(3)}
|
|
|
307
309
|
throw new Error(`Timeout waiting for image: ${image}`);
|
|
308
310
|
}
|
|
309
311
|
/**
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
312
|
+
* Waits until an image disappears
|
|
313
|
+
* from the screen.
|
|
314
|
+
*
|
|
315
|
+
* @param image Image filename or path.
|
|
316
|
+
* @param confidence Match confidence threshold.
|
|
317
|
+
*
|
|
318
|
+
* Accepted range:
|
|
319
|
+
* 0.0 to 1.0
|
|
320
|
+
*
|
|
321
|
+
* Default:
|
|
322
|
+
* 0.8
|
|
323
|
+
* @param timeout Timeout duration
|
|
324
|
+
* in milliseconds.
|
|
325
|
+
*
|
|
326
|
+
* Default:
|
|
327
|
+
* 5000ms
|
|
328
|
+
*
|
|
329
|
+
* Recommended range:
|
|
330
|
+
* 1000ms to 30000ms
|
|
331
|
+
* @throws Error if timeout occurs.
|
|
332
|
+
*
|
|
333
|
+
* @example
|
|
334
|
+
* await visor.waitToVanish("spinner.png");
|
|
335
|
+
*/
|
|
334
336
|
async waitToVanish(image, { confidence = 0.8, timeout = 5000 } = {}) {
|
|
335
337
|
const start = Date.now();
|
|
336
338
|
while (Date.now() - start < timeout) {
|
|
@@ -342,30 +344,30 @@ CONF:${m.confidence.toFixed(3)}
|
|
|
342
344
|
throw new Error(`Timeout waiting for image to vanish: ${image}`);
|
|
343
345
|
}
|
|
344
346
|
/**
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
347
|
+
* Waits until specific text appears
|
|
348
|
+
* on screen using OCR.
|
|
349
|
+
*
|
|
350
|
+
* Performance Note:
|
|
351
|
+
* OCR operations are computationally
|
|
352
|
+
* expensive and may take 1–5 seconds
|
|
353
|
+
* depending on screen complexity.
|
|
354
|
+
*
|
|
355
|
+
* @param text Text to search for.
|
|
356
|
+
*
|
|
357
|
+
* @param timeout Timeout duration
|
|
358
|
+
* in milliseconds.
|
|
359
|
+
*
|
|
360
|
+
* Default:
|
|
361
|
+
* 5000ms
|
|
362
|
+
*
|
|
363
|
+
* Recommended range:
|
|
364
|
+
* 1000ms to 30000ms
|
|
365
|
+
*
|
|
366
|
+
* @throws Error if timeout occurs.
|
|
367
|
+
*
|
|
368
|
+
* @example
|
|
369
|
+
* await visor.waitText("Success");
|
|
370
|
+
*/
|
|
369
371
|
async waitText(text, timeout = 5000) {
|
|
370
372
|
const start = Date.now();
|
|
371
373
|
while (Date.now() - start < timeout) {
|
|
@@ -377,28 +379,28 @@ CONF:${m.confidence.toFixed(3)}
|
|
|
377
379
|
throw new Error(`Timeout waiting for text: ${text}`);
|
|
378
380
|
}
|
|
379
381
|
/**
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
382
|
+
* Waits until specific text disappears
|
|
383
|
+
* from screen using OCR.
|
|
384
|
+
* Performance Note:
|
|
385
|
+
* OCR operations are computationally
|
|
386
|
+
* expensive and may take 1–5 seconds
|
|
387
|
+
* depending on screen complexity.
|
|
388
|
+
*
|
|
389
|
+
* @param text Text to search for.
|
|
390
|
+
* @param timeout Timeout duration
|
|
391
|
+
* in milliseconds.
|
|
392
|
+
*
|
|
393
|
+
* Default:
|
|
394
|
+
* 5000ms
|
|
395
|
+
*
|
|
396
|
+
* Recommended range:
|
|
397
|
+
* 1000ms to 30000ms
|
|
398
|
+
*
|
|
399
|
+
* @throws Error if timeout occurs.
|
|
400
|
+
*
|
|
401
|
+
* @example
|
|
402
|
+
* await visor.waitTextToVanish("Loading");
|
|
403
|
+
*/
|
|
402
404
|
async waitTextToVanish(text, timeout = 5000) {
|
|
403
405
|
const start = Date.now();
|
|
404
406
|
while (Date.now() - start < timeout) {
|
|
@@ -410,18 +412,18 @@ CONF:${m.confidence.toFixed(3)}
|
|
|
410
412
|
throw new Error(`Timeout waiting for text to vanish: ${text}`);
|
|
411
413
|
}
|
|
412
414
|
/**
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
415
|
+
* Finds text on screen using OCR
|
|
416
|
+
* and performs a left mouse click
|
|
417
|
+
* on the matched text region.
|
|
418
|
+
*
|
|
419
|
+
* @param text Text to search for.
|
|
420
|
+
* @param index Index of the text to click.
|
|
421
|
+
*
|
|
422
|
+
* @throws Error if text is not found.
|
|
423
|
+
*
|
|
424
|
+
* @example
|
|
425
|
+
* await visor.clickText("Login");
|
|
426
|
+
*/
|
|
425
427
|
async clickText(text, index = 0) {
|
|
426
428
|
const region = await (0, text_1.findText)(text, index);
|
|
427
429
|
if (!region) {
|
|
@@ -430,167 +432,167 @@ CONF:${m.confidence.toFixed(3)}
|
|
|
430
432
|
await (0, mouse_1.clickRegion)(region);
|
|
431
433
|
}
|
|
432
434
|
/**
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
435
|
+
* Finds text on screen or inside
|
|
436
|
+
* a specific region using OCR.
|
|
437
|
+
*
|
|
438
|
+
* @param text Text to search for.
|
|
439
|
+
* @param index Index of the text to search.
|
|
440
|
+
* @param region Optional search region.
|
|
441
|
+
*
|
|
442
|
+
* @returns Matched text region or null.
|
|
443
|
+
*
|
|
444
|
+
* @example
|
|
445
|
+
* const region =
|
|
446
|
+
* await visor.findText("Submit");
|
|
447
|
+
*/
|
|
446
448
|
async findText(text, index = 0, region) {
|
|
447
449
|
return await (0, text_1.findText)(text, index, region);
|
|
448
450
|
}
|
|
449
451
|
/**
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
452
|
+
* Checks whether specific text exists
|
|
453
|
+
* on screen using OCR.
|
|
454
|
+
*
|
|
455
|
+
* @param text Text to search for.
|
|
456
|
+
* @param region Optional search region.
|
|
457
|
+
*
|
|
458
|
+
* @returns True if text exists.
|
|
459
|
+
*
|
|
460
|
+
* @example
|
|
461
|
+
* const exists =
|
|
462
|
+
* await visor.existsText("Teams");
|
|
463
|
+
*/
|
|
462
464
|
async existsText(text, region) {
|
|
463
465
|
return await (0, text_1.existsText)(text, region);
|
|
464
466
|
}
|
|
465
467
|
/**
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
468
|
+
* Performs OCR on a specific
|
|
469
|
+
* screen region.
|
|
470
|
+
*
|
|
471
|
+
* @param region Screen region coordinates.
|
|
472
|
+
*
|
|
473
|
+
* @returns OCR result object.
|
|
474
|
+
*
|
|
475
|
+
* @example
|
|
476
|
+
* const result =
|
|
477
|
+
* await visor.readRegion({
|
|
478
|
+
* x: 100,
|
|
479
|
+
* y: 100,
|
|
480
|
+
* width: 500,
|
|
481
|
+
* height: 300
|
|
482
|
+
* });
|
|
483
|
+
*/
|
|
482
484
|
async readRegion(region) {
|
|
483
485
|
return await (0, ocr_1.extractTextFromRegion)(region);
|
|
484
486
|
}
|
|
485
487
|
/**
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
488
|
+
* Performs OCR on the entire screen
|
|
489
|
+
* using Tesseract OCR.
|
|
490
|
+
*
|
|
491
|
+
* Captures the current screen,
|
|
492
|
+
* preprocesses the image, and
|
|
493
|
+
* extracts readable text content.
|
|
494
|
+
*
|
|
495
|
+
* Performance Note:
|
|
496
|
+
* OCR is computationally expensive
|
|
497
|
+
* and may take 1–5 seconds depending
|
|
498
|
+
* on:
|
|
499
|
+
* - screen complexity
|
|
500
|
+
* - text density
|
|
501
|
+
* - display resolution
|
|
502
|
+
* - system performance
|
|
503
|
+
*
|
|
504
|
+
* Returns:
|
|
505
|
+
* - extracted text
|
|
506
|
+
* - OCR metadata
|
|
507
|
+
* - TSV layout information
|
|
508
|
+
* - HOCR data
|
|
509
|
+
*
|
|
510
|
+
* @returns OCR result object.
|
|
511
|
+
*
|
|
512
|
+
* @example
|
|
513
|
+
* const result =
|
|
514
|
+
* await visor.readScreen();
|
|
515
|
+
*
|
|
516
|
+
* log(result.text);
|
|
517
|
+
*/
|
|
516
518
|
async readScreen() {
|
|
517
519
|
return await (0, ocr_1.extractTextFromRegion)();
|
|
518
520
|
}
|
|
519
521
|
/**
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
522
|
+
* Captures a screenshot of the
|
|
523
|
+
* current screen and saves it
|
|
524
|
+
* to the specified path.
|
|
525
|
+
*
|
|
526
|
+
* Supported formats depend on
|
|
527
|
+
* the output file extension.
|
|
528
|
+
*
|
|
529
|
+
* @param path Output image path.
|
|
530
|
+
*
|
|
531
|
+
* @example
|
|
532
|
+
* await visor.captureScreenshot(
|
|
533
|
+
* "./screenshots/home.png"
|
|
534
|
+
* );
|
|
535
|
+
*/
|
|
534
536
|
async captureScreenshot(path) {
|
|
535
537
|
path = config_1.visorConfig.outputPath + "/" + path;
|
|
536
|
-
|
|
538
|
+
(0, logger_1.log)(`[VISOR] Saving screenshot: ${path}`);
|
|
537
539
|
await (0, screen_1.saveScreenshot)(path);
|
|
538
|
-
|
|
540
|
+
(0, logger_1.log)("[VISOR] Screenshot saved");
|
|
539
541
|
}
|
|
540
542
|
/**
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
543
|
+
* Opens a desktop application,
|
|
544
|
+
* executable, file, folder,
|
|
545
|
+
* or URL using Windows shell.
|
|
546
|
+
*
|
|
547
|
+
* Performance Note:
|
|
548
|
+
* Some Electron-based applications
|
|
549
|
+
* may require additional startup
|
|
550
|
+
* stabilization time.
|
|
551
|
+
*
|
|
552
|
+
* @param command App name, executable,
|
|
553
|
+
* file path, or URL.
|
|
554
|
+
*
|
|
555
|
+
* @example
|
|
556
|
+
* await visor.openApp("notepad");
|
|
557
|
+
*
|
|
558
|
+
* @example
|
|
559
|
+
* await visor.openApp("chrome.exe");
|
|
560
|
+
*/
|
|
559
561
|
async openApp(command) {
|
|
560
|
-
|
|
562
|
+
(0, logger_1.log)(`[VISOR] Opening app: ${command}`);
|
|
561
563
|
await (0, app_1.openApp)(command);
|
|
562
564
|
}
|
|
563
565
|
/**
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
566
|
+
* Drags one visual element and
|
|
567
|
+
* drops it onto another using
|
|
568
|
+
* image matching.
|
|
569
|
+
*
|
|
570
|
+
* @param source Source image.
|
|
571
|
+
*
|
|
572
|
+
* @param target Target image.
|
|
573
|
+
*
|
|
574
|
+
* @param confidence Match confidence threshold.
|
|
575
|
+
*
|
|
576
|
+
* Accepted range:
|
|
577
|
+
* 0.0 to 1.0
|
|
578
|
+
*
|
|
579
|
+
* Default:
|
|
580
|
+
* 0.8
|
|
581
|
+
*
|
|
582
|
+
* Recommended values:
|
|
583
|
+
* - 0.7 for dynamic UI
|
|
584
|
+
* - 0.8 for standard usage
|
|
585
|
+
* - 0.9+ for strict matching
|
|
586
|
+
*
|
|
587
|
+
* @throws Error if source or target
|
|
588
|
+
* image is not found.
|
|
589
|
+
*
|
|
590
|
+
* @example
|
|
591
|
+
* await visor.dragDrop(
|
|
592
|
+
* "file.png",
|
|
593
|
+
* "folder.png"
|
|
594
|
+
* );
|
|
595
|
+
*/
|
|
594
596
|
async dragDrop(source, target, confidence = 0.8) {
|
|
595
597
|
const src = await this.find(source, confidence);
|
|
596
598
|
const dst = await this.find(target, confidence);
|
|
@@ -601,307 +603,314 @@ CONF:${m.confidence.toFixed(3)}
|
|
|
601
603
|
await this.mouse.pressButton(this.Button.LEFT);
|
|
602
604
|
await (0, mouse_1.moveToRegion)(dst);
|
|
603
605
|
await this.mouse.releaseButton(this.Button.LEFT);
|
|
604
|
-
|
|
606
|
+
(0, logger_1.log)("[MOUSE] Drag and drop completed");
|
|
605
607
|
}
|
|
606
608
|
/**
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
609
|
+
* Moves the mouse cursor to the
|
|
610
|
+
* matched image location without
|
|
611
|
+
* performing a click.
|
|
612
|
+
*
|
|
613
|
+
* @param image Image filename or path.
|
|
614
|
+
* @param confidence Match confidence threshold.
|
|
615
|
+
*
|
|
616
|
+
* Accepted range:
|
|
617
|
+
* 0.0 to 1.0
|
|
618
|
+
*
|
|
619
|
+
* Default:
|
|
620
|
+
* 0.8
|
|
621
|
+
*
|
|
622
|
+
* @throws Error if image is not found.
|
|
623
|
+
*
|
|
624
|
+
* @example
|
|
625
|
+
* await visor.hover("menu.png");
|
|
626
|
+
*/
|
|
625
627
|
async hover(image, confidence = 0.8) {
|
|
626
628
|
const region = await this.find(image, confidence);
|
|
627
629
|
if (!region) {
|
|
628
630
|
throw new Error(`Image not found: ${image}`);
|
|
629
631
|
}
|
|
630
632
|
await (0, mouse_1.moveToRegion)(region);
|
|
631
|
-
|
|
633
|
+
(0, logger_1.log)("[MOUSE] Hover completed");
|
|
632
634
|
}
|
|
633
635
|
/**
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
636
|
+
* Scrolls the mouse wheel downward.
|
|
637
|
+
*
|
|
638
|
+
* @param amount Scroll amount.
|
|
639
|
+
*
|
|
640
|
+
* Default:
|
|
641
|
+
* 500
|
|
642
|
+
*
|
|
643
|
+
* Recommended range:
|
|
644
|
+
* 100 to 3000
|
|
645
|
+
*
|
|
646
|
+
* @example
|
|
647
|
+
* await visor.scrollDown(1000);
|
|
648
|
+
*/
|
|
647
649
|
async scrollDown(amount = 500) {
|
|
648
650
|
await this.mouse.scrollDown(amount);
|
|
649
651
|
}
|
|
650
652
|
/**
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
653
|
+
* Scrolls the mouse wheel upward.
|
|
654
|
+
*
|
|
655
|
+
* @param amount Scroll amount.
|
|
656
|
+
*
|
|
657
|
+
* Default:
|
|
658
|
+
* 500
|
|
659
|
+
*
|
|
660
|
+
* Recommended range:
|
|
661
|
+
* 100 to 3000
|
|
662
|
+
*
|
|
663
|
+
* @example
|
|
664
|
+
* await visor.scrollUp(1000);
|
|
665
|
+
*/
|
|
664
666
|
async scrollUp(amount = 500) {
|
|
665
667
|
await this.mouse.scrollUp(amount);
|
|
666
668
|
}
|
|
667
669
|
/**
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
670
|
+
* Types text using keyboard automation.
|
|
671
|
+
*
|
|
672
|
+
* @param text Text to type.
|
|
673
|
+
*
|
|
674
|
+
* @example
|
|
675
|
+
* await visor.type("Hello World");
|
|
676
|
+
*/
|
|
675
677
|
async type(text) {
|
|
676
678
|
await this.keyboard.type(text);
|
|
677
679
|
}
|
|
678
680
|
/**
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
681
|
+
* Presses one or more keyboard keys.
|
|
682
|
+
*
|
|
683
|
+
* Supports both single key presses
|
|
684
|
+
* and hotkey combinations.
|
|
685
|
+
*
|
|
686
|
+
* @param keys Keyboard keys to press.
|
|
687
|
+
*
|
|
688
|
+
* @example
|
|
689
|
+
* await visor.press(visor.Key.Enter);
|
|
690
|
+
*
|
|
691
|
+
* @example
|
|
692
|
+
* await visor.press(
|
|
693
|
+
* visor.Key.LeftControl,
|
|
694
|
+
* visor.Key.S
|
|
695
|
+
* );
|
|
696
|
+
*/
|
|
695
697
|
async press(...keys) {
|
|
696
698
|
await this.keyboard.pressKey(...keys);
|
|
697
699
|
await this.keyboard.releaseKey(...keys);
|
|
698
700
|
}
|
|
699
701
|
/**
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
702
|
+
* Pauses execution for a specified
|
|
703
|
+
* duration.
|
|
704
|
+
*
|
|
705
|
+
* Useful for:
|
|
706
|
+
* - UI stabilization
|
|
707
|
+
* - animation completion
|
|
708
|
+
* - Electron rendering delays
|
|
709
|
+
* - OCR synchronization
|
|
710
|
+
* - desktop transition handling
|
|
711
|
+
*
|
|
712
|
+
* Recommended for short stabilization
|
|
713
|
+
* waits rather than long fixed delays.
|
|
714
|
+
*
|
|
715
|
+
* @param ms Delay duration
|
|
716
|
+
* in milliseconds.
|
|
717
|
+
*
|
|
718
|
+
* Recommended range:
|
|
719
|
+
* 200ms to 5000ms
|
|
720
|
+
*
|
|
721
|
+
* Excessive sleep usage may
|
|
722
|
+
* slow automation execution.
|
|
723
|
+
*
|
|
724
|
+
* @example
|
|
725
|
+
* await visor.sleep(2000);
|
|
726
|
+
*/
|
|
725
727
|
async sleep(ms) {
|
|
726
|
-
return new Promise(r => setTimeout(r, ms));
|
|
728
|
+
return new Promise((r) => setTimeout(r, ms));
|
|
727
729
|
}
|
|
728
730
|
/**
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
731
|
+
* Moves the mouse cursor to the
|
|
732
|
+
* specified screen coordinates.
|
|
733
|
+
*
|
|
734
|
+
* Coordinates should match the
|
|
735
|
+
* current display scaling setup.
|
|
736
|
+
*
|
|
737
|
+
* @param x X coordinate.
|
|
738
|
+
* @param y Y coordinate.
|
|
739
|
+
*
|
|
740
|
+
* @example
|
|
741
|
+
* await visor.moveMouse(500, 300);
|
|
742
|
+
*/
|
|
741
743
|
async moveMouse(x, y) {
|
|
742
744
|
await this.mouse.move((0, nut_js_1.straightTo)(new nut_js_1.Point(x, y)));
|
|
743
745
|
}
|
|
744
746
|
/**
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
747
|
+
* Returns the current mouse cursor
|
|
748
|
+
* position.
|
|
749
|
+
*
|
|
750
|
+
* @returns Current mouse coordinates.
|
|
751
|
+
*
|
|
752
|
+
* @example
|
|
753
|
+
* const pos =
|
|
754
|
+
* await visor.getMousePosition();
|
|
755
|
+
*/
|
|
754
756
|
async getMousePosition() {
|
|
755
757
|
return await this.mouse.getPosition();
|
|
756
758
|
}
|
|
757
759
|
/**
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
760
|
+
* Sets the display scaling factor
|
|
761
|
+
* used for coordinate normalization
|
|
762
|
+
* and image matching.
|
|
763
|
+
*
|
|
764
|
+
* Required for:
|
|
765
|
+
* - high-DPI displays
|
|
766
|
+
* - Windows display scaling
|
|
767
|
+
* - accurate mouse positioning
|
|
768
|
+
* - reliable template matching
|
|
769
|
+
*
|
|
770
|
+
* Common values:
|
|
771
|
+
* - 1.0 = 100% scaling
|
|
772
|
+
* - 1.25 = 125% scaling
|
|
773
|
+
* - 1.5 = 150% scaling
|
|
774
|
+
* - 2.0 = 200% scaling
|
|
775
|
+
*
|
|
776
|
+
* Incorrect scaling values may cause:
|
|
777
|
+
* - inaccurate clicks
|
|
778
|
+
* - failed image matching
|
|
779
|
+
* - incorrect OCR regions
|
|
780
|
+
* - offset mouse movement
|
|
781
|
+
*
|
|
782
|
+
* @param scale Display scaling factor.
|
|
783
|
+
*
|
|
784
|
+
* Recommended range:
|
|
785
|
+
* 1.0 to 2.0
|
|
786
|
+
*
|
|
787
|
+
* @example
|
|
788
|
+
* visor.setScaleFactor(1.5);
|
|
789
|
+
*/
|
|
788
790
|
setScaleFactor(scale) {
|
|
789
791
|
config_1.visorConfig.scaleFactor = scale;
|
|
790
792
|
}
|
|
791
793
|
/**
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
794
|
+
* Returns the current display
|
|
795
|
+
* scaling factor.
|
|
796
|
+
*
|
|
797
|
+
* @returns Current scale factor.
|
|
798
|
+
*
|
|
799
|
+
* @example
|
|
800
|
+
* const scale =
|
|
801
|
+
* visor.getScaleFactor();
|
|
802
|
+
*/
|
|
801
803
|
getScaleFactor() {
|
|
802
804
|
return config_1.visorConfig.scaleFactor;
|
|
803
805
|
}
|
|
804
806
|
/**
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
807
|
+
* Enables or disables debug logging.
|
|
808
|
+
*
|
|
809
|
+
* @param mode Debug mode state.
|
|
810
|
+
*
|
|
811
|
+
* @example
|
|
812
|
+
* visor.setDebug(true);
|
|
813
|
+
*/
|
|
812
814
|
setDebug(mode) {
|
|
813
815
|
config_1.visorConfig.debug = mode;
|
|
814
816
|
}
|
|
815
817
|
/**
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
818
|
+
* Sets the default image search path
|
|
819
|
+
* used for visual automation APIs.
|
|
820
|
+
*
|
|
821
|
+
* @param path Image directory path.
|
|
822
|
+
*
|
|
823
|
+
* @example
|
|
824
|
+
* visor.setImagePath("./images");
|
|
825
|
+
*/
|
|
824
826
|
setImagePath(path) {
|
|
825
827
|
config_1.visorConfig.imagePath = path;
|
|
826
828
|
}
|
|
827
829
|
/**
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
830
|
+
* Returns the current default
|
|
831
|
+
* image search path.
|
|
832
|
+
*
|
|
833
|
+
* @returns Image path.
|
|
834
|
+
*
|
|
835
|
+
* @example
|
|
836
|
+
* const path =
|
|
837
|
+
* visor.getImagePath();
|
|
838
|
+
*/
|
|
837
839
|
getImagePath() {
|
|
838
840
|
return config_1.visorConfig.imagePath;
|
|
839
841
|
}
|
|
840
842
|
/**
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
843
|
+
* Sets the default output path
|
|
844
|
+
* used for visual automation APIs.
|
|
845
|
+
*
|
|
846
|
+
* @param path Output directory path.
|
|
847
|
+
*
|
|
848
|
+
* @example
|
|
849
|
+
* visor.setOutputPath("./images");
|
|
850
|
+
*/
|
|
849
851
|
setOutputPath(path) {
|
|
850
852
|
config_1.visorConfig.outputPath = path;
|
|
851
853
|
}
|
|
852
854
|
/**
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
855
|
+
* Returns the current default
|
|
856
|
+
* Output path.
|
|
857
|
+
*
|
|
858
|
+
* @returns Output path.
|
|
859
|
+
*
|
|
860
|
+
* @example
|
|
861
|
+
* const path =
|
|
862
|
+
* visor.getOutputPath();
|
|
863
|
+
*/
|
|
862
864
|
getOutputPath() {
|
|
863
865
|
return config_1.visorConfig.outputPath;
|
|
864
866
|
}
|
|
865
867
|
/**
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
868
|
+
* Closes a desktop application
|
|
869
|
+
* using Windows taskkill.
|
|
870
|
+
*
|
|
871
|
+
* @param processName Process executable name.
|
|
872
|
+
*
|
|
873
|
+
* @example
|
|
874
|
+
* await visor.closeApp("notepad.exe");
|
|
875
|
+
*
|
|
876
|
+
* @example
|
|
877
|
+
* await visor.closeApp("ms-teams.exe");
|
|
878
|
+
*/
|
|
877
879
|
async closeApp(processName) {
|
|
878
880
|
await (0, app_1.closeApp)(processName);
|
|
879
881
|
}
|
|
880
882
|
/**
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
883
|
+
* Loads multiple framework settings
|
|
884
|
+
* at once from a configuration object.
|
|
885
|
+
*
|
|
886
|
+
* Useful for centralized framework
|
|
887
|
+
* initialization and project setup.
|
|
888
|
+
*
|
|
889
|
+
* Supported settings:
|
|
890
|
+
* - scaleFactor
|
|
891
|
+
* - imagePath
|
|
892
|
+
* - ssOutputPath
|
|
893
|
+
* - debug
|
|
894
|
+
*
|
|
895
|
+
* @param config Framework configuration object.
|
|
896
|
+
*
|
|
897
|
+
* @example
|
|
898
|
+
* visor.loadConfig({
|
|
899
|
+
* scaleFactor: 1.5,
|
|
900
|
+
* imagePath: "./images",
|
|
901
|
+
* ssOutputPath: "./screenshots",
|
|
902
|
+
* debug: true
|
|
903
|
+
* });
|
|
904
|
+
*/
|
|
901
905
|
loadConfig(config) {
|
|
902
906
|
if (config.scaleFactor !== undefined) {
|
|
903
907
|
this.setScaleFactor(config.scaleFactor);
|
|
904
908
|
}
|
|
909
|
+
else {
|
|
910
|
+
const detectedScale = (0, display_1.getWindowsScaleFactor)();
|
|
911
|
+
config_1.visorConfig.scaleFactor = detectedScale;
|
|
912
|
+
(0, logger_1.log)(`[VISOR] Auto-detected display scaling: ${detectedScale}`);
|
|
913
|
+
}
|
|
905
914
|
if (config.imagePath) {
|
|
906
915
|
this.setImagePath(config.imagePath);
|
|
907
916
|
}
|
|
@@ -911,36 +920,36 @@ CONF:${m.confidence.toFixed(3)}
|
|
|
911
920
|
if (config.debug !== undefined) {
|
|
912
921
|
this.setDebug(config.debug);
|
|
913
922
|
}
|
|
914
|
-
|
|
923
|
+
(0, logger_1.log)("[VISOR] Config loaded");
|
|
915
924
|
}
|
|
916
925
|
/**
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
926
|
+
* Finds the first matching image
|
|
927
|
+
* from a list of possible images.
|
|
928
|
+
*
|
|
929
|
+
* Useful for handling:
|
|
930
|
+
* - light/dark themes
|
|
931
|
+
* - UI variations
|
|
932
|
+
* - multiple visual states
|
|
933
|
+
*
|
|
934
|
+
* @param images Array of image filenames or paths.
|
|
935
|
+
* @param confidence Match confidence threshold.
|
|
936
|
+
*
|
|
937
|
+
* Accepted range:
|
|
938
|
+
* 0.0 to 1.0
|
|
939
|
+
*
|
|
940
|
+
* Default:
|
|
941
|
+
* 0.8
|
|
942
|
+
*
|
|
943
|
+
* @returns Object containing matched image
|
|
944
|
+
* and region, or null if none matched.
|
|
945
|
+
*
|
|
946
|
+
* @example
|
|
947
|
+
* const result =
|
|
948
|
+
* await visor.findAny([
|
|
949
|
+
* "chat-light.png",
|
|
950
|
+
* "chat-dark.png"
|
|
951
|
+
* ]);
|
|
952
|
+
*/
|
|
944
953
|
async findAny(images, confidence = 0.8) {
|
|
945
954
|
const screen = await (0, screen_1.captureScreen)();
|
|
946
955
|
try {
|
|
@@ -951,7 +960,7 @@ CONF:${m.confidence.toFixed(3)}
|
|
|
951
960
|
if (region) {
|
|
952
961
|
return {
|
|
953
962
|
image,
|
|
954
|
-
region
|
|
963
|
+
region,
|
|
955
964
|
};
|
|
956
965
|
}
|
|
957
966
|
}
|
|
@@ -966,138 +975,138 @@ CONF:${m.confidence.toFixed(3)}
|
|
|
966
975
|
}
|
|
967
976
|
}
|
|
968
977
|
/**
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
978
|
+
* Checks whether any image from
|
|
979
|
+
* a list exists on the current screen.
|
|
980
|
+
*
|
|
981
|
+
* Useful for handling:
|
|
982
|
+
* - multiple themes
|
|
983
|
+
* - alternate UI layouts
|
|
984
|
+
* - dynamic visual states
|
|
985
|
+
*
|
|
986
|
+
* @param images Array of image filenames or paths.
|
|
987
|
+
* @param confidence Match confidence threshold.
|
|
988
|
+
*
|
|
989
|
+
* Accepted range:
|
|
990
|
+
* 0.0 to 1.0
|
|
991
|
+
*
|
|
992
|
+
* Default:
|
|
993
|
+
* 0.8
|
|
994
|
+
*
|
|
995
|
+
* @returns True if any image exists.
|
|
996
|
+
*
|
|
997
|
+
* @example
|
|
998
|
+
* const exists =
|
|
999
|
+
* await visor.existsAny([
|
|
1000
|
+
* "save-light.png",
|
|
1001
|
+
* "save-dark.png"
|
|
1002
|
+
* ]);
|
|
1003
|
+
*/
|
|
995
1004
|
async existsAny(images, confidence = 0.8) {
|
|
996
1005
|
return (await this.findAny(images, confidence)) !== null;
|
|
997
1006
|
}
|
|
998
1007
|
/**
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1008
|
+
* Finds the first matching image
|
|
1009
|
+
* from a list and performs a
|
|
1010
|
+
* left mouse click on it.
|
|
1011
|
+
*
|
|
1012
|
+
* Useful for handling:
|
|
1013
|
+
* - light/dark themes
|
|
1014
|
+
* - UI variations
|
|
1015
|
+
* - dynamic buttons/icons
|
|
1016
|
+
*
|
|
1017
|
+
* @param images Array of image
|
|
1018
|
+
* filenames or paths.
|
|
1019
|
+
*
|
|
1020
|
+
* @param confidence Match confidence threshold.
|
|
1021
|
+
*
|
|
1022
|
+
* Accepted range:
|
|
1023
|
+
* 0.0 to 1.0
|
|
1024
|
+
*
|
|
1025
|
+
* Default:
|
|
1026
|
+
* 0.8
|
|
1027
|
+
*
|
|
1028
|
+
* Recommended values:
|
|
1029
|
+
* - 0.7 for dynamic UI
|
|
1030
|
+
* - 0.8 for standard usage
|
|
1031
|
+
* - 0.9+ for strict matching
|
|
1032
|
+
*
|
|
1033
|
+
* Lower confidence increases
|
|
1034
|
+
* flexibility but may increase
|
|
1035
|
+
* false positives.
|
|
1036
|
+
*
|
|
1037
|
+
* @throws Error if none of the
|
|
1038
|
+
* images are found.
|
|
1039
|
+
*
|
|
1040
|
+
* @example
|
|
1041
|
+
* await visor.clickAny([
|
|
1042
|
+
* "send-light.png",
|
|
1043
|
+
* "send-dark.png"
|
|
1044
|
+
* ]);
|
|
1045
|
+
*/
|
|
1037
1046
|
async clickAny(images, confidence = 0.8) {
|
|
1038
1047
|
const result = await this.findAny(images, confidence);
|
|
1039
1048
|
if (!result) {
|
|
1040
1049
|
throw new Error(`None of the images were found`);
|
|
1041
1050
|
}
|
|
1042
|
-
|
|
1051
|
+
(0, logger_1.log)(`[VISOR] Clicking image: ${result.image}`);
|
|
1043
1052
|
await (0, mouse_1.clickRegion)(result.region);
|
|
1044
1053
|
}
|
|
1045
1054
|
/**
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1055
|
+
* Waits until any image from
|
|
1056
|
+
* a list appears on screen.
|
|
1057
|
+
*
|
|
1058
|
+
* Useful for handling:
|
|
1059
|
+
* - multiple themes
|
|
1060
|
+
* - alternate UI layouts
|
|
1061
|
+
* - dynamic application states
|
|
1062
|
+
*
|
|
1063
|
+
* @param images Array of image
|
|
1064
|
+
* filenames or paths.
|
|
1065
|
+
*
|
|
1066
|
+
* @param confidence Match confidence threshold.
|
|
1067
|
+
*
|
|
1068
|
+
* Accepted range:
|
|
1069
|
+
* 0.0 to 1.0
|
|
1070
|
+
*
|
|
1071
|
+
* Default:
|
|
1072
|
+
* 0.8
|
|
1073
|
+
*
|
|
1074
|
+
* Recommended values:
|
|
1075
|
+
* - 0.7 for dynamic UI
|
|
1076
|
+
* - 0.8 for standard usage
|
|
1077
|
+
* - 0.9+ for strict matching
|
|
1078
|
+
*
|
|
1079
|
+
* Lower confidence increases
|
|
1080
|
+
* flexibility but may increase
|
|
1081
|
+
* false positives.
|
|
1082
|
+
*
|
|
1083
|
+
* @param timeout Timeout duration
|
|
1084
|
+
* in milliseconds.
|
|
1085
|
+
*
|
|
1086
|
+
* Default:
|
|
1087
|
+
* 5000ms
|
|
1088
|
+
*
|
|
1089
|
+
* Recommended range:
|
|
1090
|
+
* 1000ms to 30000ms
|
|
1091
|
+
*
|
|
1092
|
+
* @throws Error if timeout occurs.
|
|
1093
|
+
*
|
|
1094
|
+
* @example
|
|
1095
|
+
* await visor.waitAny([
|
|
1096
|
+
* "home-light.png",
|
|
1097
|
+
* "home-dark.png"
|
|
1098
|
+
* ]);
|
|
1099
|
+
*/
|
|
1091
1100
|
async waitAny(images, { confidence = 0.8, timeout = 5000 } = {}) {
|
|
1092
|
-
const interval =
|
|
1101
|
+
const interval = 300;
|
|
1093
1102
|
const attempts = Math.ceil(timeout / interval);
|
|
1094
1103
|
for (let i = 0; i < attempts; i++) {
|
|
1095
|
-
|
|
1104
|
+
(0, logger_1.log)(`[WAITANY] Attempt ${i + 1}`);
|
|
1096
1105
|
for (const image of images) {
|
|
1097
|
-
|
|
1106
|
+
(0, logger_1.log)(`[WAITANY] Checking ${image}`);
|
|
1098
1107
|
const exists = await this.exists(image, confidence);
|
|
1099
1108
|
if (exists) {
|
|
1100
|
-
|
|
1109
|
+
(0, logger_1.log)(`[WAITANY] Found ${image}`);
|
|
1101
1110
|
return true;
|
|
1102
1111
|
}
|
|
1103
1112
|
}
|
|
@@ -1106,18 +1115,18 @@ CONF:${m.confidence.toFixed(3)}
|
|
|
1106
1115
|
throw new Error("Timeout waiting for images");
|
|
1107
1116
|
}
|
|
1108
1117
|
/**
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1118
|
+
* Terminates shared OCR worker.
|
|
1119
|
+
*
|
|
1120
|
+
* Useful for framework cleanup
|
|
1121
|
+
* after long automation sessions.
|
|
1122
|
+
*
|
|
1123
|
+
* Recommended for:
|
|
1124
|
+
* - long-running automation
|
|
1125
|
+
* - memory cleanup
|
|
1126
|
+
* - graceful framework shutdown
|
|
1127
|
+
* @example
|
|
1128
|
+
* await visor.terminateOCR();
|
|
1129
|
+
*/
|
|
1121
1130
|
async terminateOCR() {
|
|
1122
1131
|
await (0, ocr_1.terminateOCR)();
|
|
1123
1132
|
}
|