@aspiresys/visor 1.2.9 → 1.2.11
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/index.d.ts +127 -8
- package/dist/index.js +140 -2
- package/inspector/index.html +6 -15
- package/inspector/src/renderer.js +48 -2
- package/inspector/styles.css +6 -8
- package/package.json +1 -1
- package/readme.md +139 -3
- package/inspector/templates/template.png +0 -0
package/dist/index.d.ts
CHANGED
|
@@ -1,11 +1,129 @@
|
|
|
1
1
|
import { Key, Button, Point } from "@nut-tree-fork/nut-js";
|
|
2
|
+
import { Region } from "./types";
|
|
2
3
|
export declare class Visor {
|
|
3
|
-
mouse
|
|
4
|
-
keyboard
|
|
4
|
+
private mouse;
|
|
5
|
+
private keyboard;
|
|
5
6
|
Key: typeof Key;
|
|
6
7
|
Button: typeof Button;
|
|
7
8
|
private configWarningShown;
|
|
8
9
|
private checkConfig;
|
|
10
|
+
/**
|
|
11
|
+
* Moves the mouse cursor to the
|
|
12
|
+
* center of a specific screen region.
|
|
13
|
+
*
|
|
14
|
+
* Region coordinates typically come from:
|
|
15
|
+
* - visor.find()
|
|
16
|
+
* - visor.findAll()
|
|
17
|
+
* - OCR text matching
|
|
18
|
+
* - Visor Inspector
|
|
19
|
+
*
|
|
20
|
+
* Display scaling is automatically
|
|
21
|
+
* applied using the configured
|
|
22
|
+
* scale factor.
|
|
23
|
+
*
|
|
24
|
+
* @param region Screen region coordinates.
|
|
25
|
+
* @param offset Offset coords.
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* await visor.moveToRegion({
|
|
29
|
+
* x: 100,
|
|
30
|
+
* y: 200,
|
|
31
|
+
* width: 150,
|
|
32
|
+
* height: 50
|
|
33
|
+
* });
|
|
34
|
+
*/
|
|
35
|
+
moveToRegion(region: Region, offset?: {
|
|
36
|
+
x: number;
|
|
37
|
+
y: number;
|
|
38
|
+
}): Promise<void>;
|
|
39
|
+
/**
|
|
40
|
+
* Performs a left mouse click at the
|
|
41
|
+
* center of a specific screen region.
|
|
42
|
+
*
|
|
43
|
+
* Region coordinates typically come from:
|
|
44
|
+
* - visor.find()
|
|
45
|
+
* - visor.findAll()
|
|
46
|
+
* - OCR text matching
|
|
47
|
+
* - Visor Inspector
|
|
48
|
+
*
|
|
49
|
+
* Display scaling is automatically
|
|
50
|
+
* applied using the configured
|
|
51
|
+
* scale factor.
|
|
52
|
+
*
|
|
53
|
+
* @param region Screen region coordinates.
|
|
54
|
+
* @param offset Offset coords.
|
|
55
|
+
*
|
|
56
|
+
* @example
|
|
57
|
+
* await visor.clickRegion({
|
|
58
|
+
* x: 100,
|
|
59
|
+
* y: 200,
|
|
60
|
+
* width: 150,
|
|
61
|
+
* height: 50
|
|
62
|
+
* });
|
|
63
|
+
*/
|
|
64
|
+
clickRegion(region: Region, offset?: {
|
|
65
|
+
x: number;
|
|
66
|
+
y: number;
|
|
67
|
+
}): Promise<void>;
|
|
68
|
+
/**
|
|
69
|
+
* Performs a double left mouse click
|
|
70
|
+
* at the center of a specific
|
|
71
|
+
* screen region.
|
|
72
|
+
*
|
|
73
|
+
* Region coordinates typically come from:
|
|
74
|
+
* - visor.find()
|
|
75
|
+
* - visor.findAll()
|
|
76
|
+
* - OCR text matching
|
|
77
|
+
* - Visor Inspector
|
|
78
|
+
*
|
|
79
|
+
* Display scaling is automatically
|
|
80
|
+
* applied using the configured
|
|
81
|
+
* scale factor.
|
|
82
|
+
*
|
|
83
|
+
* @param region Screen region coordinates.
|
|
84
|
+
* @param offset Offset coords.
|
|
85
|
+
*
|
|
86
|
+
* @example
|
|
87
|
+
* await visor.doubleClickRegion({
|
|
88
|
+
* x: 100,
|
|
89
|
+
* y: 200,
|
|
90
|
+
* width: 150,
|
|
91
|
+
* height: 50
|
|
92
|
+
* });
|
|
93
|
+
*/
|
|
94
|
+
doubleClickRegion(region: Region, offset?: {
|
|
95
|
+
x: number;
|
|
96
|
+
y: number;
|
|
97
|
+
}): Promise<void>;
|
|
98
|
+
/**
|
|
99
|
+
* Performs a right mouse click at the
|
|
100
|
+
* center of a specific screen region.
|
|
101
|
+
*
|
|
102
|
+
* Region coordinates typically come from:
|
|
103
|
+
* - visor.find()
|
|
104
|
+
* - visor.findAll()
|
|
105
|
+
* - OCR text matching
|
|
106
|
+
* - Visor Inspector
|
|
107
|
+
*
|
|
108
|
+
* Display scaling is automatically
|
|
109
|
+
* applied using the configured
|
|
110
|
+
* scale factor.
|
|
111
|
+
*
|
|
112
|
+
* @param region Screen region coordinates.
|
|
113
|
+
* @param offset Offset coords.
|
|
114
|
+
*
|
|
115
|
+
* @example
|
|
116
|
+
* await visor.rightClickRegion({
|
|
117
|
+
* x: 100,
|
|
118
|
+
* y: 200,
|
|
119
|
+
* width: 150,
|
|
120
|
+
* height: 50
|
|
121
|
+
* });
|
|
122
|
+
*/
|
|
123
|
+
rightClickRegion(region: Region, offset?: {
|
|
124
|
+
x: number;
|
|
125
|
+
y: number;
|
|
126
|
+
}): Promise<void>;
|
|
9
127
|
/**
|
|
10
128
|
* Finds an image on screen using OpenCV
|
|
11
129
|
* and performs a left mouse click
|
|
@@ -126,7 +244,7 @@ export declare class Visor {
|
|
|
126
244
|
* const region =
|
|
127
245
|
* await visor.find("save.png");
|
|
128
246
|
*/
|
|
129
|
-
find(image: string, confidence?: number): Promise<
|
|
247
|
+
find(image: string, confidence?: number): Promise<Region>;
|
|
130
248
|
/**
|
|
131
249
|
* Checks whether an image exists
|
|
132
250
|
* on the current screen.
|
|
@@ -169,7 +287,7 @@ export declare class Visor {
|
|
|
169
287
|
* const matches =
|
|
170
288
|
* await visor.findAll("icon.png");
|
|
171
289
|
*/
|
|
172
|
-
findAll(image: string, confidence?: number): Promise<
|
|
290
|
+
findAll(image: string, confidence?: number): Promise<Region[]>;
|
|
173
291
|
/**
|
|
174
292
|
* Finds all image matches and prints
|
|
175
293
|
* a formatted match preview including
|
|
@@ -192,7 +310,7 @@ export declare class Visor {
|
|
|
192
310
|
* @example
|
|
193
311
|
* await visor.previewMatches("button.png");
|
|
194
312
|
*/
|
|
195
|
-
previewMatches(image: string, confidence?: number): Promise<
|
|
313
|
+
previewMatches(image: string, confidence?: number): Promise<Region[]>;
|
|
196
314
|
/**
|
|
197
315
|
* Waits until an image appears
|
|
198
316
|
* on the screen.
|
|
@@ -342,7 +460,7 @@ export declare class Visor {
|
|
|
342
460
|
y: number;
|
|
343
461
|
width: number;
|
|
344
462
|
height: number;
|
|
345
|
-
}): Promise<
|
|
463
|
+
}): Promise<Region>;
|
|
346
464
|
/**
|
|
347
465
|
* Checks whether specific text exists
|
|
348
466
|
* on screen using OCR.
|
|
@@ -601,11 +719,12 @@ export declare class Visor {
|
|
|
601
719
|
*
|
|
602
720
|
* @param x X coordinate.
|
|
603
721
|
* @param y Y coordinate.
|
|
722
|
+
* @param inspectorCoords Boolean to represent if the coords are from visor-inspector
|
|
604
723
|
*
|
|
605
724
|
* @example
|
|
606
725
|
* await visor.moveMouse(500, 300);
|
|
607
726
|
*/
|
|
608
|
-
moveMouse(x: number, y: number): Promise<void>;
|
|
727
|
+
moveMouse(x: number, y: number, inspectorCoords?: boolean): Promise<void>;
|
|
609
728
|
/**
|
|
610
729
|
* Returns the current mouse cursor
|
|
611
730
|
* position.
|
|
@@ -783,7 +902,7 @@ export declare class Visor {
|
|
|
783
902
|
*/
|
|
784
903
|
findAny(images: string[], confidence?: number): Promise<{
|
|
785
904
|
image: string;
|
|
786
|
-
region:
|
|
905
|
+
region: Region;
|
|
787
906
|
}>;
|
|
788
907
|
/**
|
|
789
908
|
* Checks whether any image from
|
package/dist/index.js
CHANGED
|
@@ -48,6 +48,134 @@ class Visor {
|
|
|
48
48
|
this.configWarningShown = true;
|
|
49
49
|
}
|
|
50
50
|
}
|
|
51
|
+
/**
|
|
52
|
+
* Moves the mouse cursor to the
|
|
53
|
+
* center of a specific screen region.
|
|
54
|
+
*
|
|
55
|
+
* Region coordinates typically come from:
|
|
56
|
+
* - visor.find()
|
|
57
|
+
* - visor.findAll()
|
|
58
|
+
* - OCR text matching
|
|
59
|
+
* - Visor Inspector
|
|
60
|
+
*
|
|
61
|
+
* Display scaling is automatically
|
|
62
|
+
* applied using the configured
|
|
63
|
+
* scale factor.
|
|
64
|
+
*
|
|
65
|
+
* @param region Screen region coordinates.
|
|
66
|
+
* @param offset Offset coords.
|
|
67
|
+
*
|
|
68
|
+
* @example
|
|
69
|
+
* await visor.moveToRegion({
|
|
70
|
+
* x: 100,
|
|
71
|
+
* y: 200,
|
|
72
|
+
* width: 150,
|
|
73
|
+
* height: 50
|
|
74
|
+
* });
|
|
75
|
+
*/
|
|
76
|
+
async moveToRegion(region, offset = {
|
|
77
|
+
x: 0,
|
|
78
|
+
y: 0
|
|
79
|
+
}) {
|
|
80
|
+
await (0, mouse_1.moveToRegion)(region, offset);
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Performs a left mouse click at the
|
|
84
|
+
* center of a specific screen region.
|
|
85
|
+
*
|
|
86
|
+
* Region coordinates typically come from:
|
|
87
|
+
* - visor.find()
|
|
88
|
+
* - visor.findAll()
|
|
89
|
+
* - OCR text matching
|
|
90
|
+
* - Visor Inspector
|
|
91
|
+
*
|
|
92
|
+
* Display scaling is automatically
|
|
93
|
+
* applied using the configured
|
|
94
|
+
* scale factor.
|
|
95
|
+
*
|
|
96
|
+
* @param region Screen region coordinates.
|
|
97
|
+
* @param offset Offset coords.
|
|
98
|
+
*
|
|
99
|
+
* @example
|
|
100
|
+
* await visor.clickRegion({
|
|
101
|
+
* x: 100,
|
|
102
|
+
* y: 200,
|
|
103
|
+
* width: 150,
|
|
104
|
+
* height: 50
|
|
105
|
+
* });
|
|
106
|
+
*/
|
|
107
|
+
async clickRegion(region, offset = {
|
|
108
|
+
x: 0,
|
|
109
|
+
y: 0
|
|
110
|
+
}) {
|
|
111
|
+
await (0, mouse_1.moveToRegion)(region, offset);
|
|
112
|
+
await this.mouse.click(this.Button.LEFT);
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Performs a double left mouse click
|
|
116
|
+
* at the center of a specific
|
|
117
|
+
* screen region.
|
|
118
|
+
*
|
|
119
|
+
* Region coordinates typically come from:
|
|
120
|
+
* - visor.find()
|
|
121
|
+
* - visor.findAll()
|
|
122
|
+
* - OCR text matching
|
|
123
|
+
* - Visor Inspector
|
|
124
|
+
*
|
|
125
|
+
* Display scaling is automatically
|
|
126
|
+
* applied using the configured
|
|
127
|
+
* scale factor.
|
|
128
|
+
*
|
|
129
|
+
* @param region Screen region coordinates.
|
|
130
|
+
* @param offset Offset coords.
|
|
131
|
+
*
|
|
132
|
+
* @example
|
|
133
|
+
* await visor.doubleClickRegion({
|
|
134
|
+
* x: 100,
|
|
135
|
+
* y: 200,
|
|
136
|
+
* width: 150,
|
|
137
|
+
* height: 50
|
|
138
|
+
* });
|
|
139
|
+
*/
|
|
140
|
+
async doubleClickRegion(region, offset = {
|
|
141
|
+
x: 0,
|
|
142
|
+
y: 0
|
|
143
|
+
}) {
|
|
144
|
+
await (0, mouse_1.moveToRegion)(region, offset);
|
|
145
|
+
await this.mouse.doubleClick(this.Button.LEFT);
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Performs a right mouse click at the
|
|
149
|
+
* center of a specific screen region.
|
|
150
|
+
*
|
|
151
|
+
* Region coordinates typically come from:
|
|
152
|
+
* - visor.find()
|
|
153
|
+
* - visor.findAll()
|
|
154
|
+
* - OCR text matching
|
|
155
|
+
* - Visor Inspector
|
|
156
|
+
*
|
|
157
|
+
* Display scaling is automatically
|
|
158
|
+
* applied using the configured
|
|
159
|
+
* scale factor.
|
|
160
|
+
*
|
|
161
|
+
* @param region Screen region coordinates.
|
|
162
|
+
* @param offset Offset coords.
|
|
163
|
+
*
|
|
164
|
+
* @example
|
|
165
|
+
* await visor.rightClickRegion({
|
|
166
|
+
* x: 100,
|
|
167
|
+
* y: 200,
|
|
168
|
+
* width: 150,
|
|
169
|
+
* height: 50
|
|
170
|
+
* });
|
|
171
|
+
*/
|
|
172
|
+
async rightClickRegion(region, offset = {
|
|
173
|
+
x: 0,
|
|
174
|
+
y: 0
|
|
175
|
+
}) {
|
|
176
|
+
await (0, mouse_1.moveToRegion)(region, offset);
|
|
177
|
+
await this.mouse.click(this.Button.RIGHT);
|
|
178
|
+
}
|
|
51
179
|
/**
|
|
52
180
|
* Finds an image on screen using OpenCV
|
|
53
181
|
* and performs a left mouse click
|
|
@@ -208,8 +336,12 @@ class Visor {
|
|
|
208
336
|
const start = Date.now();
|
|
209
337
|
const screen = await (0, screen_1.captureScreen)();
|
|
210
338
|
const template = await (0, matcher_1.loadTemplate)((0, path_1.resolveImagePath)(image));
|
|
339
|
+
const scaleFactor = config_1.visorConfig.scaleFactor;
|
|
211
340
|
try {
|
|
212
341
|
const result = (0, matcher_1.matchTemplate)(screen, template, confidence);
|
|
342
|
+
if (result) {
|
|
343
|
+
(0, logger_1.log)(`[FIND] Actual coords: (${Math.floor(result.x * scaleFactor)}, ${Math.floor(result.y * scaleFactor)})`);
|
|
344
|
+
}
|
|
213
345
|
(0, logger_1.log)(`[FIND] Total: ${Date.now() - start} ms`);
|
|
214
346
|
return result;
|
|
215
347
|
}
|
|
@@ -801,13 +933,19 @@ CONF:${m.confidence.toFixed(3)}
|
|
|
801
933
|
*
|
|
802
934
|
* @param x X coordinate.
|
|
803
935
|
* @param y Y coordinate.
|
|
936
|
+
* @param inspectorCoords Boolean to represent if the coords are from visor-inspector
|
|
804
937
|
*
|
|
805
938
|
* @example
|
|
806
939
|
* await visor.moveMouse(500, 300);
|
|
807
940
|
*/
|
|
808
|
-
async moveMouse(x, y) {
|
|
941
|
+
async moveMouse(x, y, inspectorCoords = false) {
|
|
809
942
|
this.checkConfig();
|
|
810
|
-
|
|
943
|
+
if (inspectorCoords) {
|
|
944
|
+
await this.mouse.move((0, nut_js_1.straightTo)(new nut_js_1.Point(x, y)));
|
|
945
|
+
return;
|
|
946
|
+
}
|
|
947
|
+
const scaleFactor = config_1.visorConfig.scaleFactor;
|
|
948
|
+
await this.mouse.move((0, nut_js_1.straightTo)(new nut_js_1.Point(Math.floor(x / scaleFactor), Math.floor(y / scaleFactor))));
|
|
811
949
|
}
|
|
812
950
|
/**
|
|
813
951
|
* Returns the current mouse cursor
|
package/inspector/index.html
CHANGED
|
@@ -24,7 +24,8 @@
|
|
|
24
24
|
<div class="input-wrapper">
|
|
25
25
|
<span class="input-hint">Confidence</span>
|
|
26
26
|
<input id="confidenceInput" type="number" min="0" max="1" step="0.01" value="0.8" />
|
|
27
|
-
<span class="input-hint">(0.0 - 1.0)</span>
|
|
27
|
+
<span class="input-hint">(0.0 - 1.0) </span>
|
|
28
|
+
Current Template: <span id="currentTemplate" class="template-status">None</span>
|
|
28
29
|
</div>
|
|
29
30
|
</div>
|
|
30
31
|
</div>
|
|
@@ -32,26 +33,16 @@
|
|
|
32
33
|
</section>
|
|
33
34
|
<div class="capture-layout">
|
|
34
35
|
<div class="capture-panel">
|
|
35
|
-
<h3 class="section-title"> Current Capture </h3>
|
|
36
|
+
<h3 class="section-title"> Current Capture (X:<span id="mousex"></span>, Y:<span id="mousey"></span>)</h3>
|
|
36
37
|
<canvas id="screenCanvas" class="canvas"></canvas>
|
|
37
38
|
</div>
|
|
38
39
|
<div class="result-panel">
|
|
40
|
+
<h3 class="section-title"> Template </h3>
|
|
41
|
+
<img id="templatePreview" class="template-preview" alt="No Template Loaded" src="data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs="/>
|
|
39
42
|
<h3 class="section-title"> Match Result </h3>
|
|
40
43
|
<div id="matchResult"> No Match Tested </div>
|
|
41
|
-
|
|
44
|
+
</div>
|
|
42
45
|
</div>
|
|
43
|
-
<section class="template-section">
|
|
44
|
-
<h3 class="section-title">Template Management</h3>
|
|
45
|
-
<div class="template-grid">
|
|
46
|
-
<div class="template-info">
|
|
47
|
-
<p>
|
|
48
|
-
<strong>Current Template: </strong>
|
|
49
|
-
<span id="currentTemplate" class="template-status">None</span>
|
|
50
|
-
</p>
|
|
51
|
-
</div>
|
|
52
|
-
<img id="templatePreview" class="template-preview" />
|
|
53
|
-
</div>
|
|
54
|
-
</section>
|
|
55
46
|
</div>
|
|
56
47
|
<script src="./src/renderer.js"></script>
|
|
57
48
|
</body>
|
|
@@ -30,6 +30,7 @@ captureBtn.addEventListener("click",
|
|
|
30
30
|
const scale = image.width > maxWidth ? maxWidth / image.width : 1;
|
|
31
31
|
canvas.width = image.width * scale;
|
|
32
32
|
canvas.height = image.height * scale;
|
|
33
|
+
matchResult.textContent = " No Match Tested ";
|
|
33
34
|
ctx.drawImage(
|
|
34
35
|
image,
|
|
35
36
|
0,
|
|
@@ -58,6 +59,8 @@ canvas.addEventListener("mousedown",
|
|
|
58
59
|
canvas.addEventListener("mousemove",
|
|
59
60
|
(e) => {
|
|
60
61
|
if (!selecting) {
|
|
62
|
+
document.getElementById("mousex").innerHTML = Math.round(e.offsetX * imageScaleX);
|
|
63
|
+
document.getElementById("mousey").innerHTML = Math.round(e.offsetY * imageScaleY);
|
|
61
64
|
return;
|
|
62
65
|
}
|
|
63
66
|
displayEndX = e.offsetX;
|
|
@@ -95,6 +98,7 @@ canvas.addEventListener("mouseup",
|
|
|
95
98
|
}
|
|
96
99
|
);
|
|
97
100
|
|
|
101
|
+
|
|
98
102
|
saveBtn.addEventListener("click",
|
|
99
103
|
async () => {
|
|
100
104
|
if (
|
|
@@ -122,8 +126,18 @@ saveBtn.addEventListener("click",
|
|
|
122
126
|
height: Math.abs(endY - startY),
|
|
123
127
|
outputPath: filePath
|
|
124
128
|
});
|
|
129
|
+
const fileName = filePath.split(/[\\/]/).pop();
|
|
125
130
|
selectedTemplatePath = filePath;
|
|
126
|
-
currentTemplate.textContent =
|
|
131
|
+
currentTemplate.textContent = fileName;
|
|
132
|
+
currentTemplate.title = filePath;
|
|
133
|
+
matchResult.textContent = " No Match Tested ";
|
|
134
|
+
ctx.drawImage(
|
|
135
|
+
image,
|
|
136
|
+
0,
|
|
137
|
+
0,
|
|
138
|
+
canvas.width,
|
|
139
|
+
canvas.height
|
|
140
|
+
);
|
|
127
141
|
templatePreview.src = filePath + "?t=" + Date.now();
|
|
128
142
|
alert("Template Saved");
|
|
129
143
|
}
|
|
@@ -152,8 +166,30 @@ testMatchBtn.addEventListener("click", async () => {
|
|
|
152
166
|
|
|
153
167
|
if (!result) {
|
|
154
168
|
matchResult.textContent = "✗ MATCH NOT FOUND";
|
|
169
|
+
ctx.drawImage(
|
|
170
|
+
image,
|
|
171
|
+
0,
|
|
172
|
+
0,
|
|
173
|
+
canvas.width,
|
|
174
|
+
canvas.height
|
|
175
|
+
);
|
|
155
176
|
return;
|
|
156
177
|
}
|
|
178
|
+
ctx.drawImage(
|
|
179
|
+
image,
|
|
180
|
+
0,
|
|
181
|
+
0,
|
|
182
|
+
canvas.width,
|
|
183
|
+
canvas.height
|
|
184
|
+
);
|
|
185
|
+
ctx.strokeStyle = "lime";
|
|
186
|
+
ctx.lineWidth = 3;
|
|
187
|
+
ctx.strokeRect(
|
|
188
|
+
result.x / imageScaleX,
|
|
189
|
+
result.y / imageScaleY,
|
|
190
|
+
result.width / imageScaleX,
|
|
191
|
+
result.height / imageScaleY
|
|
192
|
+
);
|
|
157
193
|
matchResult.textContent = `
|
|
158
194
|
✓ MATCH FOUND
|
|
159
195
|
|
|
@@ -175,8 +211,18 @@ loadTemplateBtn.addEventListener("click",
|
|
|
175
211
|
if (!path) {
|
|
176
212
|
return;
|
|
177
213
|
}
|
|
214
|
+
const fileName = path.split(/[\\/]/).pop();
|
|
178
215
|
selectedTemplatePath = path;
|
|
179
|
-
currentTemplate.textContent =
|
|
216
|
+
currentTemplate.textContent = fileName;
|
|
217
|
+
currentTemplate.title = path;
|
|
218
|
+
matchResult.textContent = " No Match Tested ";
|
|
219
|
+
ctx.drawImage(
|
|
220
|
+
image,
|
|
221
|
+
0,
|
|
222
|
+
0,
|
|
223
|
+
canvas.width,
|
|
224
|
+
canvas.height
|
|
225
|
+
);
|
|
180
226
|
templatePreview.src = path + "?t=" + Date.now();
|
|
181
227
|
}
|
|
182
228
|
);
|
package/inspector/styles.css
CHANGED
|
@@ -238,6 +238,7 @@ input[type="number"]:focus {
|
|
|
238
238
|
display: block;
|
|
239
239
|
margin-top: 15px;
|
|
240
240
|
box-shadow: 0 0 20px rgba(0, 212, 255, 0.1);
|
|
241
|
+
width: stretch;
|
|
241
242
|
}
|
|
242
243
|
|
|
243
244
|
/* TEMPLATE SECTION */
|
|
@@ -268,26 +269,23 @@ input[type="number"]:focus {
|
|
|
268
269
|
}
|
|
269
270
|
|
|
270
271
|
.template-status {
|
|
271
|
-
display: inline-block;
|
|
272
|
-
padding: 4px 7px;
|
|
273
|
-
background: rgba(76, 175, 80, 0.15);
|
|
274
|
-
border: 1px solid rgba(76, 175, 80, 0.3);
|
|
275
|
-
border-radius: 6px;
|
|
276
272
|
color: #4caf50;
|
|
277
|
-
font-
|
|
278
|
-
width: fit-content;
|
|
273
|
+
font-size: small;
|
|
279
274
|
}
|
|
280
275
|
|
|
281
276
|
.template-preview {
|
|
282
277
|
border: 2px solid #00d4ff;
|
|
283
278
|
border-radius: 8px;
|
|
279
|
+
width: 130px;
|
|
284
280
|
max-width: 100%;
|
|
285
|
-
height:
|
|
281
|
+
height: 130px;
|
|
286
282
|
max-height: 150px;
|
|
287
283
|
object-fit: contain;
|
|
288
284
|
background: #0a0a0a;
|
|
289
285
|
box-shadow: 0 0 20px rgba(0, 212, 255, 0.1);
|
|
290
286
|
display: none;
|
|
287
|
+
margin-top: 15px;
|
|
288
|
+
margin-bottom: 15px;
|
|
291
289
|
}
|
|
292
290
|
|
|
293
291
|
.template-preview[src]:not([src=""]) {
|
package/package.json
CHANGED
package/readme.md
CHANGED
|
@@ -22,6 +22,8 @@ Visor is designed for automating desktop workflows using visual interactions ins
|
|
|
22
22
|
* Region OCR support
|
|
23
23
|
* Automatic display scaling detection
|
|
24
24
|
* Mouse automation
|
|
25
|
+
* Region-based mouse automation
|
|
26
|
+
* Target offset support
|
|
25
27
|
* Keyboard automation
|
|
26
28
|
* Drag & drop support
|
|
27
29
|
* Multi-theme image handling
|
|
@@ -51,6 +53,23 @@ npm install @aspiresys/visor
|
|
|
51
53
|
|
|
52
54
|
---
|
|
53
55
|
|
|
56
|
+
# Visor Inspector
|
|
57
|
+
|
|
58
|
+
Visor includes an optional desktop Inspector tool for:
|
|
59
|
+
|
|
60
|
+
* Capturing templates
|
|
61
|
+
* Testing image matches
|
|
62
|
+
* Measuring screen coordinates
|
|
63
|
+
* Validating confidence thresholds
|
|
64
|
+
|
|
65
|
+
Run:
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
npx visor-inspector
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
54
73
|
# Quick Start
|
|
55
74
|
|
|
56
75
|
```ts
|
|
@@ -167,6 +186,67 @@ const region =
|
|
|
167
186
|
|
|
168
187
|
---
|
|
169
188
|
|
|
189
|
+
## Region-Based Automation
|
|
190
|
+
|
|
191
|
+
Regions can be obtained from:
|
|
192
|
+
|
|
193
|
+
* visor.find()
|
|
194
|
+
* visor.findAll()
|
|
195
|
+
* visor.findText()
|
|
196
|
+
* Visor Inspector
|
|
197
|
+
|
|
198
|
+
### Move To Region
|
|
199
|
+
|
|
200
|
+
```ts
|
|
201
|
+
const region =
|
|
202
|
+
await visor.find(
|
|
203
|
+
"save.png"
|
|
204
|
+
);
|
|
205
|
+
|
|
206
|
+
await visor.moveToRegion(
|
|
207
|
+
region
|
|
208
|
+
);
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
### Click Region
|
|
212
|
+
|
|
213
|
+
```ts
|
|
214
|
+
const region =
|
|
215
|
+
await visor.find(
|
|
216
|
+
"save.png"
|
|
217
|
+
);
|
|
218
|
+
|
|
219
|
+
await visor.clickRegion(
|
|
220
|
+
region
|
|
221
|
+
);
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
### Double Click Region
|
|
225
|
+
|
|
226
|
+
```ts
|
|
227
|
+
await visor.doubleClickRegion({
|
|
228
|
+
x: 100,
|
|
229
|
+
y: 200,
|
|
230
|
+
width: 150,
|
|
231
|
+
height: 50
|
|
232
|
+
});
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
### Right Click Region
|
|
236
|
+
|
|
237
|
+
```ts
|
|
238
|
+
await visor.rightClickRegion({
|
|
239
|
+
x: 100,
|
|
240
|
+
y: 200,
|
|
241
|
+
width: 150,
|
|
242
|
+
height: 50
|
|
243
|
+
});
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
Display scaling is automatically applied when using region-based APIs.
|
|
247
|
+
|
|
248
|
+
---
|
|
249
|
+
|
|
170
250
|
## Check Image Exists
|
|
171
251
|
|
|
172
252
|
```ts
|
|
@@ -230,6 +310,47 @@ await visor.hover("menu.png");
|
|
|
230
310
|
|
|
231
311
|
---
|
|
232
312
|
|
|
313
|
+
## Target Offsets
|
|
314
|
+
|
|
315
|
+
Target offsets allow mouse actions to be performed relative to the center of a matched image.
|
|
316
|
+
|
|
317
|
+
Useful for:
|
|
318
|
+
|
|
319
|
+
* Dropdown arrows
|
|
320
|
+
* Adjacent controls
|
|
321
|
+
* Dynamic layouts
|
|
322
|
+
* Composite UI elements
|
|
323
|
+
|
|
324
|
+
### Click With Offset
|
|
325
|
+
|
|
326
|
+
```ts
|
|
327
|
+
await visor.click(
|
|
328
|
+
"search.png",
|
|
329
|
+
0.8,
|
|
330
|
+
{
|
|
331
|
+
x: 50,
|
|
332
|
+
y: 0
|
|
333
|
+
}
|
|
334
|
+
);
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
### Hover With Offset
|
|
338
|
+
|
|
339
|
+
```ts
|
|
340
|
+
await visor.hover(
|
|
341
|
+
"menu.png",
|
|
342
|
+
0.8,
|
|
343
|
+
{
|
|
344
|
+
x: -20,
|
|
345
|
+
y: 10
|
|
346
|
+
}
|
|
347
|
+
);
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
Offsets are applied relative to the center of the matched region before display scaling adjustments are performed.
|
|
351
|
+
|
|
352
|
+
---
|
|
353
|
+
|
|
233
354
|
# OCR Automation
|
|
234
355
|
|
|
235
356
|
Visor includes OCR automation powered by Tesseract.js.
|
|
@@ -351,6 +472,21 @@ await visor.moveMouse(
|
|
|
351
472
|
|
|
352
473
|
---
|
|
353
474
|
|
|
475
|
+
### Move To Inspector Region
|
|
476
|
+
|
|
477
|
+
```ts
|
|
478
|
+
await visor.moveToRegion({
|
|
479
|
+
x: 90,
|
|
480
|
+
y: 61,
|
|
481
|
+
width: 138,
|
|
482
|
+
height: 69
|
|
483
|
+
});
|
|
484
|
+
```
|
|
485
|
+
|
|
486
|
+
Region coordinates can be copied directly from Visor Inspector match results.
|
|
487
|
+
|
|
488
|
+
---
|
|
489
|
+
|
|
354
490
|
## Scroll Down
|
|
355
491
|
|
|
356
492
|
```ts
|
|
@@ -497,9 +633,9 @@ visor.loadConfig({
|
|
|
497
633
|
|
|
498
634
|
# Roadmap
|
|
499
635
|
|
|
500
|
-
*
|
|
501
|
-
*
|
|
502
|
-
*
|
|
636
|
+
* Match visualization overlay
|
|
637
|
+
* Inspector coordinate picker
|
|
638
|
+
* Multi-monitor support improvements
|
|
503
639
|
* Parallel image matching
|
|
504
640
|
* Advanced OCR tuning
|
|
505
641
|
* Electron recorder
|
|
Binary file
|