appium-novawindows2-driver 0.1.3 → 0.1.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/LICENSE +201 -201
- package/README.md +557 -557
- package/build/lib/commands/actions.d.ts.map +1 -1
- package/build/lib/commands/actions.js +3 -4
- package/build/lib/commands/actions.js.map +1 -1
- package/build/lib/commands/app.d.ts.map +1 -1
- package/build/lib/commands/app.js +53 -45
- package/build/lib/commands/app.js.map +1 -1
- package/build/lib/commands/device.d.ts.map +1 -1
- package/build/lib/commands/device.js +2 -0
- package/build/lib/commands/device.js.map +1 -1
- package/build/lib/commands/element.d.ts.map +1 -1
- package/build/lib/commands/element.js +42 -12
- package/build/lib/commands/element.js.map +1 -1
- package/build/lib/commands/extension.d.ts.map +1 -1
- package/build/lib/commands/extension.js +29 -17
- package/build/lib/commands/extension.js.map +1 -1
- package/build/lib/commands/file.d.ts +5 -0
- package/build/lib/commands/file.d.ts.map +1 -0
- package/build/lib/commands/file.js +49 -0
- package/build/lib/commands/file.js.map +1 -0
- package/build/lib/commands/functions.d.ts.map +1 -1
- package/build/lib/commands/functions.js +189 -187
- package/build/lib/commands/functions.js.map +1 -1
- package/build/lib/commands/index.d.ts +3 -0
- package/build/lib/commands/index.d.ts.map +1 -1
- package/build/lib/commands/index.js +2 -0
- package/build/lib/commands/index.js.map +1 -1
- package/build/lib/commands/powershell.d.ts.map +1 -1
- package/build/lib/commands/powershell.js +114 -68
- package/build/lib/commands/powershell.js.map +1 -1
- package/build/lib/constraints.d.ts +18 -0
- package/build/lib/constraints.d.ts.map +1 -1
- package/build/lib/constraints.js +18 -0
- package/build/lib/constraints.js.map +1 -1
- package/build/lib/driver.d.ts.map +1 -1
- package/build/lib/driver.js +35 -4
- package/build/lib/driver.js.map +1 -1
- package/build/lib/powershell/converter.d.ts.map +1 -1
- package/build/lib/powershell/converter.js +12 -0
- package/build/lib/powershell/converter.js.map +1 -1
- package/build/lib/powershell/elements.d.ts.map +1 -1
- package/build/lib/powershell/elements.js +270 -265
- package/build/lib/powershell/elements.js.map +1 -1
- package/build/lib/winapi/user32.js.map +1 -1
- package/build/lib/xpath/core.d.ts +2 -2
- package/build/lib/xpath/core.d.ts.map +1 -1
- package/build/lib/xpath/core.js +32 -26
- package/build/lib/xpath/core.js.map +1 -1
- package/build/lib/xpath/functions.d.ts +1 -1
- package/build/lib/xpath/functions.d.ts.map +1 -1
- package/build/lib/xpath/functions.js +2 -2
- package/build/lib/xpath/functions.js.map +1 -1
- package/build/tsconfig.tsbuildinfo +1 -0
- package/package.json +67 -62
- package/.github/ISSUE_TEMPLATE/bug_report.yml +0 -97
- package/.github/ISSUE_TEMPLATE/feature_request.yml +0 -33
- package/.github/PULL_REQUEST_TEMPLATE.md +0 -28
- package/.github/workflows/lint-build.yml +0 -30
- package/.github/workflows/release.yml +0 -39
- package/.releaserc +0 -41
- package/CHANGELOG.md +0 -33
- package/eslint.config.mjs +0 -11
- package/examples/api_test.js +0 -69
- package/examples/concurrency_test.js +0 -82
- package/examples/debug_test.js +0 -36
- package/examples/stress_test.js +0 -94
- package/examples/verify_driver.js +0 -142
- package/lib/commands/actions.ts +0 -229
- package/lib/commands/app.ts +0 -227
- package/lib/commands/device.ts +0 -41
- package/lib/commands/element.ts +0 -242
- package/lib/commands/extension.ts +0 -640
- package/lib/commands/functions.ts +0 -192
- package/lib/commands/index.ts +0 -28
- package/lib/commands/powershell.ts +0 -256
- package/lib/commands/system.ts +0 -7
- package/lib/constants.ts +0 -1
- package/lib/constraints.ts +0 -43
- package/lib/driver.ts +0 -266
- package/lib/enums.ts +0 -96
- package/lib/powershell/common.ts +0 -137
- package/lib/powershell/conditions.ts +0 -169
- package/lib/powershell/converter.ts +0 -373
- package/lib/powershell/core.ts +0 -29
- package/lib/powershell/elements.ts +0 -584
- package/lib/powershell/index.ts +0 -7
- package/lib/powershell/regex.ts +0 -77
- package/lib/powershell/types.ts +0 -208
- package/lib/util.ts +0 -52
- package/lib/winapi/types/index.ts +0 -7
- package/lib/winapi/types/input.ts +0 -12
- package/lib/winapi/types/keyeventf.ts +0 -14
- package/lib/winapi/types/mouseeventf.ts +0 -37
- package/lib/winapi/types/scancode.ts +0 -96
- package/lib/winapi/types/systemmetric.ts +0 -215
- package/lib/winapi/types/virtualkey.ts +0 -354
- package/lib/winapi/types/xmousebutton.ts +0 -8
- package/lib/winapi/user32.ts +0 -842
- package/lib/xpath/core.ts +0 -699
- package/lib/xpath/functions.ts +0 -366
- package/lib/xpath/index.ts +0 -2
- package/tsconfig.json +0 -13
|
@@ -1,640 +0,0 @@
|
|
|
1
|
-
import { W3C_ELEMENT_KEY, errors } from '@appium/base-driver';
|
|
2
|
-
import { Element, Rect } from '@appium/types';
|
|
3
|
-
import { NovaWindows2Driver } from '../driver';
|
|
4
|
-
import { $, sleep } from '../util';
|
|
5
|
-
import { POWER_SHELL_FEATURE } from '../constants';
|
|
6
|
-
import {
|
|
7
|
-
keyDown,
|
|
8
|
-
keyUp,
|
|
9
|
-
mouseDown,
|
|
10
|
-
mouseMoveAbsolute,
|
|
11
|
-
mouseScroll,
|
|
12
|
-
mouseUp,
|
|
13
|
-
sendKeyboardEvents
|
|
14
|
-
} from '../winapi/user32';
|
|
15
|
-
import { KeyEventFlags, VirtualKey } from '../winapi/types';
|
|
16
|
-
import {
|
|
17
|
-
AutomationElement,
|
|
18
|
-
AutomationElementMode,
|
|
19
|
-
FoundAutomationElement,
|
|
20
|
-
PSInt32Array,
|
|
21
|
-
Property,
|
|
22
|
-
PropertyCondition,
|
|
23
|
-
PropertyRegexMatcher,
|
|
24
|
-
TreeScope,
|
|
25
|
-
convertStringToCondition,
|
|
26
|
-
pwsh
|
|
27
|
-
} from '../powershell';
|
|
28
|
-
import { ClickType, Enum, Key } from '../enums';
|
|
29
|
-
|
|
30
|
-
const PLATFORM_COMMAND_PREFIX = 'windows:';
|
|
31
|
-
|
|
32
|
-
const EXTENSION_COMMANDS = Object.freeze({
|
|
33
|
-
cacheRequest: 'pushCacheRequest',
|
|
34
|
-
invoke: 'patternInvoke',
|
|
35
|
-
expand: 'patternExpand',
|
|
36
|
-
collapse: 'patternCollapse',
|
|
37
|
-
isMultiple: 'patternIsMultiple',
|
|
38
|
-
scrollIntoView: 'patternScrollIntoView',
|
|
39
|
-
selectedItem: 'patternGetSelectedItem',
|
|
40
|
-
allSelectedItems: 'patternGetAllSelectedItems',
|
|
41
|
-
addToSelection: 'patternAddToSelection',
|
|
42
|
-
removeFromSelection: 'patternRemoveFromSelection',
|
|
43
|
-
select: 'patternSelect',
|
|
44
|
-
toggle: 'patternToggle',
|
|
45
|
-
setValue: 'patternSetValue',
|
|
46
|
-
getValue: 'patternGetValue',
|
|
47
|
-
maximize: 'patternMaximize',
|
|
48
|
-
minimize: 'patternMinimize',
|
|
49
|
-
restore: 'patternRestore',
|
|
50
|
-
close: 'patternClose',
|
|
51
|
-
keys: 'executeKeys',
|
|
52
|
-
click: 'executeClick',
|
|
53
|
-
hover: 'executeHover',
|
|
54
|
-
scroll: 'executeScroll',
|
|
55
|
-
setFocus: 'focusElement',
|
|
56
|
-
getClipboard: 'getClipboardBase64',
|
|
57
|
-
setClipboard: 'setClipboardFromBase64',
|
|
58
|
-
} as const);
|
|
59
|
-
|
|
60
|
-
const ContentType = Object.freeze({
|
|
61
|
-
PLAINTEXT: 'plaintext',
|
|
62
|
-
IMAGE: 'image',
|
|
63
|
-
} as const);
|
|
64
|
-
|
|
65
|
-
type ContentType = Enum<typeof ContentType>;
|
|
66
|
-
|
|
67
|
-
const TREE_FILTER_COMMAND = $ /* ps1 */ `$cacheRequest.Pop(); $cacheRequest.TreeFilter = ${0}; $cacheRequest.Push()`;
|
|
68
|
-
const TREE_SCOPE_COMMAND = $ /* ps1 */ `$cacheRequest.Pop(); $cacheRequest.TreeScope = ${0}; $cacheRequest.Push()`;
|
|
69
|
-
const AUTOMATION_ELEMENT_MODE = $ /* ps1 */ `$cacheRequest.Pop(); $cacheRequest.AutomationElementMode = ${0}; $cacheRequest.Push()`;
|
|
70
|
-
|
|
71
|
-
const SET_PLAINTEXT_CLIPBOARD_FROM_BASE64 = $ /* ps1 */ `Set-Clipboard -Value [System.Text.Encoding]::UTF8.GetString([Convert]::FromBase64String(${0}))`;
|
|
72
|
-
const GET_PLAINTEXT_CLIPBOARD_BASE64 = /* ps1 */ `[Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes((Get-Clipboard)))`;
|
|
73
|
-
|
|
74
|
-
const SET_IMAGE_CLIPBOARD_FROM_BASE64 = $ /* ps1 */ `$b = [Convert]::FromBase64String(${0}); $s = New-Object IO.MemoryStream; $s.Write($b, 0, $b.Length); $s.Position = 0; $i = [System.Windows.Media.Imaging.BitmapFrame]::Create($s); [Windows.Clipboard]::SetImage($i); $s.Close()`;
|
|
75
|
-
const GET_IMAGE_CLIPBOARD_BASE64 = pwsh /* ps1 */ `
|
|
76
|
-
[Windows.Clipboard]::GetImage() | ForEach-Object {
|
|
77
|
-
if ($_ -ne $null) {
|
|
78
|
-
$stream = New-Object IO.MemoryStream
|
|
79
|
-
$encoder = New-Object Windows.Media.Imaging.PngBitmapEncoder
|
|
80
|
-
$encoder.Frames.Add([Windows.Media.Imaging.BitmapFrame]::Create($_))
|
|
81
|
-
$encoder.Save($stream)
|
|
82
|
-
$stream.Position = 0
|
|
83
|
-
$bytes = $stream.ToArray()
|
|
84
|
-
$base64String = [Convert]::ToBase64String($bytes)
|
|
85
|
-
$stream.Close()
|
|
86
|
-
Write-Output $base64String
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
`;
|
|
90
|
-
|
|
91
|
-
type KeyAction = {
|
|
92
|
-
pause?: number,
|
|
93
|
-
text?: string,
|
|
94
|
-
virtualKeyCode?: number,
|
|
95
|
-
down?: boolean,
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
export async function execute(this: NovaWindows2Driver, script: string, args: any[]) {
|
|
99
|
-
if (script.startsWith(PLATFORM_COMMAND_PREFIX)) {
|
|
100
|
-
script = script.replace(PLATFORM_COMMAND_PREFIX, '').trim();
|
|
101
|
-
this.log.info(`Executing command '${PLATFORM_COMMAND_PREFIX} ${script}'...`);
|
|
102
|
-
|
|
103
|
-
if (!Object.hasOwn(EXTENSION_COMMANDS, script)) {
|
|
104
|
-
throw new errors.UnknownCommandError(`Unknown command '${PLATFORM_COMMAND_PREFIX} ${script}'.`);
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
return await this[EXTENSION_COMMANDS[script]](...args);
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
if (script === 'powerShell') {
|
|
111
|
-
this.assertFeatureEnabled(POWER_SHELL_FEATURE);
|
|
112
|
-
// this.log.info(`Executing command: \n${args[0]}`);
|
|
113
|
-
return await this.executePowerShellScript(args[0]);
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
if (script === 'return window.name') {
|
|
117
|
-
const command = AutomationElement.automationRoot.buildGetPropertyCommand(Property.NAME);
|
|
118
|
-
// this.log.info(`Executing command: \n${command}`);
|
|
119
|
-
return await this.sendPowerShellCommand(command);
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
throw new errors.NotImplementedError();
|
|
123
|
-
};
|
|
124
|
-
|
|
125
|
-
type CacheRequest = {
|
|
126
|
-
treeScope?: string,
|
|
127
|
-
treeFilter?: string,
|
|
128
|
-
automationElementMode?: string,
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
const TREE_SCOPE_REGEX = new PropertyRegexMatcher('System.Windows.Automation.TreeScope', ...Object.values(TreeScope)).toRegex('i');
|
|
132
|
-
const AUTOMATION_ELEMENT_MODE_REGEX = new PropertyRegexMatcher('System.Windows.Automation.AutomationElementMode', ...Object.values(AutomationElementMode)).toRegex('i');
|
|
133
|
-
|
|
134
|
-
export async function pushCacheRequest(this: NovaWindows2Driver, cacheRequest: CacheRequest): Promise<void> {
|
|
135
|
-
if (Object.keys(cacheRequest).every((key) => cacheRequest[key] === undefined)) {
|
|
136
|
-
throw new errors.InvalidArgumentError('At least one property of the cache request must be set.');
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
if (cacheRequest.treeFilter) {
|
|
140
|
-
await this.sendPowerShellCommand(TREE_FILTER_COMMAND.format(convertStringToCondition(cacheRequest.treeFilter)));
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
if (cacheRequest.treeScope) {
|
|
144
|
-
const treeScope = TREE_SCOPE_REGEX.exec(cacheRequest.treeScope)?.groups?.[0];
|
|
145
|
-
if (!treeScope || (Number(cacheRequest.treeScope) < 1 && Number(cacheRequest.treeScope) > 16)) {
|
|
146
|
-
throw new errors.InvalidArgumentError(`Invalid value '${cacheRequest.treeScope}' passed to TreeScope for cache request.`);
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
await this.sendPowerShellCommand(TREE_SCOPE_COMMAND.format(isNaN(Number(cacheRequest.treeScope)) ? /* ps1 */ `[TreeScope]::${cacheRequest.treeScope}` : cacheRequest.treeScope));
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
if (cacheRequest.automationElementMode) {
|
|
153
|
-
const treeScope = AUTOMATION_ELEMENT_MODE_REGEX.exec(cacheRequest.automationElementMode)?.groups?.[0];
|
|
154
|
-
|
|
155
|
-
if (!treeScope || (Number(cacheRequest.automationElementMode) < 0 && Number(cacheRequest.automationElementMode) > 1)) {
|
|
156
|
-
throw new errors.InvalidArgumentError(`Invalid value '${cacheRequest.automationElementMode}' passed to AutomationElementMode for cache request.`);
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
let automationElementMode: string;
|
|
160
|
-
if (isNaN(Number(cacheRequest.automationElementMode))) {
|
|
161
|
-
automationElementMode = /* ps1 */ `[AutomationElementMode]::${cacheRequest.automationElementMode}`;
|
|
162
|
-
} else {
|
|
163
|
-
automationElementMode = cacheRequest.automationElementMode;
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
await this.sendPowerShellCommand(AUTOMATION_ELEMENT_MODE.format(automationElementMode));
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
export async function patternInvoke(this: NovaWindows2Driver, element: Element): Promise<void> {
|
|
171
|
-
await this.sendPowerShellCommand(new FoundAutomationElement(element[W3C_ELEMENT_KEY]).buildInvokeCommand());
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
export async function patternExpand(this: NovaWindows2Driver, element: Element): Promise<void> {
|
|
175
|
-
await this.sendPowerShellCommand(new FoundAutomationElement(element[W3C_ELEMENT_KEY]).buildExpandCommand());
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
export async function patternCollapse(this: NovaWindows2Driver, element: Element): Promise<void> {
|
|
179
|
-
await this.sendPowerShellCommand(new FoundAutomationElement(element[W3C_ELEMENT_KEY]).buildCollapseCommand());
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
export async function patternScrollIntoView(this: NovaWindows2Driver, element: Element): Promise<void> {
|
|
183
|
-
await this.sendPowerShellCommand(new FoundAutomationElement(element[W3C_ELEMENT_KEY]).buildScrollIntoViewCommand());
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
export async function patternIsMultiple(this: NovaWindows2Driver, element: Element): Promise<boolean> {
|
|
187
|
-
const result = await this.sendPowerShellCommand(new FoundAutomationElement(element[W3C_ELEMENT_KEY]).buildIsMultipleSelectCommand());
|
|
188
|
-
return result.toLowerCase() === 'true' ? true : false;
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
export async function patternGetSelectedItem(this: NovaWindows2Driver, element: Element): Promise<Element> {
|
|
192
|
-
const result = await this.sendPowerShellCommand(new FoundAutomationElement(element[W3C_ELEMENT_KEY]).buildGetSelectionCommand());
|
|
193
|
-
const elId = result.split('\n').filter(Boolean)[0];
|
|
194
|
-
|
|
195
|
-
if (!elId) {
|
|
196
|
-
throw new errors.NoSuchElementError();
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
return { [W3C_ELEMENT_KEY]: elId };
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
export async function patternGetAllSelectedItems(this: NovaWindows2Driver, element: Element): Promise<Element[]> {
|
|
203
|
-
const result = await this.sendPowerShellCommand(new FoundAutomationElement(element[W3C_ELEMENT_KEY]).buildGetSelectionCommand());
|
|
204
|
-
return result.split('\n').filter(Boolean).map((elId) => ({ [W3C_ELEMENT_KEY]: elId }));
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
export async function patternAddToSelection(this: NovaWindows2Driver, element: Element): Promise<void> {
|
|
208
|
-
await this.sendPowerShellCommand(new FoundAutomationElement(element[W3C_ELEMENT_KEY]).buildAddToSelectionCommand());
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
export async function patternRemoveFromSelection(this: NovaWindows2Driver, element: Element): Promise<void> {
|
|
212
|
-
await this.sendPowerShellCommand(new FoundAutomationElement(element[W3C_ELEMENT_KEY]).buildRemoveFromSelectionCommand());
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
export async function patternSelect(this: NovaWindows2Driver, element: Element): Promise<void> {
|
|
216
|
-
await this.sendPowerShellCommand(new FoundAutomationElement(element[W3C_ELEMENT_KEY]).buildSelectCommand());
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
export async function patternToggle(this: NovaWindows2Driver, element: Element): Promise<void> {
|
|
220
|
-
await this.sendPowerShellCommand(new FoundAutomationElement(element[W3C_ELEMENT_KEY]).buildToggleCommand());
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
export async function patternSetValue(this: NovaWindows2Driver, element: Element, value: string): Promise<void> {
|
|
224
|
-
try {
|
|
225
|
-
await this.sendPowerShellCommand(new FoundAutomationElement(element[W3C_ELEMENT_KEY]).buildSetValueCommand(value));
|
|
226
|
-
} catch {
|
|
227
|
-
await this.sendPowerShellCommand(new FoundAutomationElement(element[W3C_ELEMENT_KEY]).buildSetRangeValueCommand(value));
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
export async function patternGetValue(this: NovaWindows2Driver, element: Element): Promise<void> {
|
|
232
|
-
await this.sendPowerShellCommand(new FoundAutomationElement(element[W3C_ELEMENT_KEY]).buildGetValueCommand());
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
export async function patternMaximize(this: NovaWindows2Driver, element: Element): Promise<void> {
|
|
236
|
-
await this.sendPowerShellCommand(new FoundAutomationElement(element[W3C_ELEMENT_KEY]).buildMaximizeCommand());
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
export async function patternMinimize(this: NovaWindows2Driver, element: Element): Promise<void> {
|
|
240
|
-
await this.sendPowerShellCommand(new FoundAutomationElement(element[W3C_ELEMENT_KEY]).buildMinimizeCommand());
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
export async function patternRestore(this: NovaWindows2Driver, element: Element): Promise<void> {
|
|
244
|
-
await this.sendPowerShellCommand(new FoundAutomationElement(element[W3C_ELEMENT_KEY]).buildRestoreCommand());
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
export async function patternClose(this: NovaWindows2Driver, element: Element): Promise<void> {
|
|
248
|
-
await this.sendPowerShellCommand(new FoundAutomationElement(element[W3C_ELEMENT_KEY]).buildCloseCommand());
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
export async function focusElement(this: NovaWindows2Driver, element: Element): Promise<void> {
|
|
252
|
-
await this.sendPowerShellCommand(new FoundAutomationElement(element[W3C_ELEMENT_KEY]).buildSetFocusCommand());
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
export async function getClipboardBase64(this: NovaWindows2Driver, contentType?: ContentType | { contentType?: ContentType }): Promise<string> {
|
|
256
|
-
if (!contentType || (contentType && typeof contentType === 'object')) {
|
|
257
|
-
contentType = contentType?.contentType ?? ContentType.PLAINTEXT;
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
switch (contentType.toLowerCase()) {
|
|
261
|
-
case ContentType.PLAINTEXT:
|
|
262
|
-
return await this.sendPowerShellCommand(GET_PLAINTEXT_CLIPBOARD_BASE64);
|
|
263
|
-
case ContentType.IMAGE:
|
|
264
|
-
return await this.sendPowerShellCommand(GET_IMAGE_CLIPBOARD_BASE64);
|
|
265
|
-
default:
|
|
266
|
-
throw new errors.InvalidArgumentError(`Unsupported content type '${contentType}'.`);
|
|
267
|
-
}
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
export async function setClipboardFromBase64(this: NovaWindows2Driver, args: { contentType?: ContentType, b64Content: string }): Promise<string> {
|
|
271
|
-
if (!args || typeof args !== 'object' || !args.b64Content) {
|
|
272
|
-
throw new errors.InvalidArgumentError(`'b64Content' must be provided.`);
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
const contentType = args.contentType ?? ContentType.PLAINTEXT;
|
|
276
|
-
|
|
277
|
-
switch (contentType.toLowerCase()) {
|
|
278
|
-
case ContentType.PLAINTEXT:
|
|
279
|
-
return await this.sendPowerShellCommand(SET_PLAINTEXT_CLIPBOARD_FROM_BASE64.format(args.b64Content));
|
|
280
|
-
case ContentType.IMAGE:
|
|
281
|
-
return await this.sendPowerShellCommand(SET_IMAGE_CLIPBOARD_FROM_BASE64.format(args.b64Content));
|
|
282
|
-
default:
|
|
283
|
-
throw new errors.InvalidArgumentError(`Unsupported content type '${contentType}'.`);
|
|
284
|
-
}
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
export async function executePowerShellScript(this: NovaWindows2Driver, script: string | { script: string, command: undefined } | { script: undefined, command: string }): Promise<string> {
|
|
288
|
-
if (script && typeof script === 'object') {
|
|
289
|
-
if (script.script) {
|
|
290
|
-
script = script.script;
|
|
291
|
-
} else if (script.command) {
|
|
292
|
-
script = script.command;
|
|
293
|
-
} else {
|
|
294
|
-
throw new errors.InvalidArgumentError('Either script or command must be provided.');
|
|
295
|
-
}
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
const scriptToExecute = pwsh`${script}`;
|
|
299
|
-
if (this.caps.isolatedScriptExecution) {
|
|
300
|
-
return await this.sendIsolatedPowerShellCommand(scriptToExecute);
|
|
301
|
-
} else {
|
|
302
|
-
return await this.sendPowerShellCommand(scriptToExecute);
|
|
303
|
-
}
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
export async function executeKeys(this: NovaWindows2Driver, keyActions: { actions: KeyAction | KeyAction[], forceUnicode: boolean }) {
|
|
307
|
-
if (!Array.isArray(keyActions.actions)) {
|
|
308
|
-
keyActions.actions = [keyActions.actions];
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
keyActions.forceUnicode ??= false;
|
|
312
|
-
|
|
313
|
-
for (const action of keyActions.actions) {
|
|
314
|
-
if (Number(!!action.pause) + Number(!!action.text) + Number(!!action.virtualKeyCode) !== 1) {
|
|
315
|
-
throw new errors.InvalidArgumentError('Either pause, text or virtualKeyCode should be set.');
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
if (action.pause) {
|
|
319
|
-
await sleep(action.pause);
|
|
320
|
-
continue;
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
if (action.virtualKeyCode) {
|
|
324
|
-
if (action.down === undefined) {
|
|
325
|
-
sendKeyboardEvents([{
|
|
326
|
-
wVk: action.virtualKeyCode as VirtualKey,
|
|
327
|
-
wScan: 0,
|
|
328
|
-
dwFlags: 0,
|
|
329
|
-
time: 0,
|
|
330
|
-
dwExtraInfo: 0,
|
|
331
|
-
}, {
|
|
332
|
-
wVk: action.virtualKeyCode as VirtualKey,
|
|
333
|
-
wScan: 0,
|
|
334
|
-
dwFlags: KeyEventFlags.KEYEVENTF_KEYUP,
|
|
335
|
-
time: 0,
|
|
336
|
-
dwExtraInfo: 0,
|
|
337
|
-
}]);
|
|
338
|
-
} else {
|
|
339
|
-
sendKeyboardEvents([{
|
|
340
|
-
wVk: action.virtualKeyCode as VirtualKey,
|
|
341
|
-
wScan: 0,
|
|
342
|
-
dwFlags: action.down ? 0 : KeyEventFlags.KEYEVENTF_KEYUP,
|
|
343
|
-
time: 0,
|
|
344
|
-
dwExtraInfo: 0,
|
|
345
|
-
}]);
|
|
346
|
-
}
|
|
347
|
-
continue;
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
for (const key of action.text ?? []) {
|
|
351
|
-
if (action.down !== undefined) {
|
|
352
|
-
if (action.down) {
|
|
353
|
-
keyDown(key, keyActions.forceUnicode);
|
|
354
|
-
} else {
|
|
355
|
-
keyUp(key, keyActions.forceUnicode);
|
|
356
|
-
}
|
|
357
|
-
} else {
|
|
358
|
-
keyDown(key, keyActions.forceUnicode);
|
|
359
|
-
keyUp(key, keyActions.forceUnicode);
|
|
360
|
-
}
|
|
361
|
-
}
|
|
362
|
-
}
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
export async function executeClick(this: NovaWindows2Driver, clickArgs: {
|
|
366
|
-
elementId?: string,
|
|
367
|
-
x?: number,
|
|
368
|
-
y?: number,
|
|
369
|
-
button?: ClickType,
|
|
370
|
-
modifierKeys?: ('shift' | 'ctrl' | 'alt' | 'win') | ('shift' | 'ctrl' | 'alt' | 'win')[], // TODO: add types
|
|
371
|
-
durationMs?: number,
|
|
372
|
-
times?: number,
|
|
373
|
-
interClickDelayMs?: number
|
|
374
|
-
}) {
|
|
375
|
-
const {
|
|
376
|
-
elementId,
|
|
377
|
-
x, y,
|
|
378
|
-
button = ClickType.LEFT,
|
|
379
|
-
modifierKeys = [],
|
|
380
|
-
durationMs = 0,
|
|
381
|
-
times = 1,
|
|
382
|
-
interClickDelayMs = 100,
|
|
383
|
-
} = clickArgs;
|
|
384
|
-
|
|
385
|
-
if ((x != null) !== (y != null)) {
|
|
386
|
-
throw new errors.InvalidArgumentError('Both x and y must be provided if either is set.');
|
|
387
|
-
}
|
|
388
|
-
|
|
389
|
-
let pos: [number, number];
|
|
390
|
-
if (elementId) {
|
|
391
|
-
if (await this.sendPowerShellCommand(/* ps1 */ `$null -eq ${new FoundAutomationElement(elementId).toString()}`)) {
|
|
392
|
-
const condition = new PropertyCondition(Property.RUNTIME_ID, new PSInt32Array(elementId.split('.').map(Number)));
|
|
393
|
-
const elId = await this.sendPowerShellCommand(AutomationElement.automationRoot.findFirst(TreeScope.SUBTREE, condition).buildCommand());
|
|
394
|
-
|
|
395
|
-
if (elId.trim() === '') {
|
|
396
|
-
throw new errors.NoSuchElementError();
|
|
397
|
-
}
|
|
398
|
-
}
|
|
399
|
-
|
|
400
|
-
const rectJson = await this.sendPowerShellCommand(new FoundAutomationElement(elementId).buildGetElementRectCommand());
|
|
401
|
-
const rect = JSON.parse(rectJson.replaceAll(/(?:infinity)/gi, 0x7FFFFFFF.toString())) as Rect;
|
|
402
|
-
pos = [
|
|
403
|
-
rect.x + (x ?? Math.trunc(rect.width / 2)),
|
|
404
|
-
rect.y + (y ?? Math.trunc(rect.height / 2)),
|
|
405
|
-
];
|
|
406
|
-
} else {
|
|
407
|
-
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
408
|
-
pos = [x!, y!];
|
|
409
|
-
}
|
|
410
|
-
|
|
411
|
-
const clickTypeToButtonMapping: { [key in ClickType]: number } = {
|
|
412
|
-
[ClickType.LEFT]: 0,
|
|
413
|
-
[ClickType.MIDDLE]: 1,
|
|
414
|
-
[ClickType.RIGHT]: 2,
|
|
415
|
-
[ClickType.BACK]: 3,
|
|
416
|
-
[ClickType.FORWARD]: 4
|
|
417
|
-
};
|
|
418
|
-
const mouseButton: number = clickTypeToButtonMapping[button];
|
|
419
|
-
|
|
420
|
-
const processesModifierKeys = Array.isArray(modifierKeys) ? modifierKeys : [modifierKeys];
|
|
421
|
-
await mouseMoveAbsolute(pos[0], pos[1], 0);
|
|
422
|
-
for (let i = 0; i < times; i++) {
|
|
423
|
-
if (i !== 0) {
|
|
424
|
-
await sleep(interClickDelayMs);
|
|
425
|
-
}
|
|
426
|
-
|
|
427
|
-
if (processesModifierKeys.some((key) => key.toLowerCase() === 'ctrl')) {
|
|
428
|
-
keyDown(Key.CONTROL);
|
|
429
|
-
}
|
|
430
|
-
if (processesModifierKeys.some((key) => key.toLowerCase() === 'alt')) {
|
|
431
|
-
keyDown(Key.ALT);
|
|
432
|
-
}
|
|
433
|
-
if (processesModifierKeys.some((key) => key.toLowerCase() === 'shift')) {
|
|
434
|
-
keyDown(Key.SHIFT);
|
|
435
|
-
}
|
|
436
|
-
if (processesModifierKeys.some((key) => key.toLowerCase() === 'win')) {
|
|
437
|
-
keyDown(Key.META);
|
|
438
|
-
}
|
|
439
|
-
|
|
440
|
-
mouseDown(mouseButton);
|
|
441
|
-
if (durationMs > 0) {
|
|
442
|
-
await sleep(durationMs);
|
|
443
|
-
}
|
|
444
|
-
mouseUp(mouseButton);
|
|
445
|
-
|
|
446
|
-
if (processesModifierKeys.some((key) => key.toLowerCase() === 'ctrl')) {
|
|
447
|
-
keyUp(Key.CONTROL);
|
|
448
|
-
}
|
|
449
|
-
if (processesModifierKeys.some((key) => key.toLowerCase() === 'alt')) {
|
|
450
|
-
keyUp(Key.ALT);
|
|
451
|
-
}
|
|
452
|
-
if (processesModifierKeys.some((key) => key.toLowerCase() === 'shift')) {
|
|
453
|
-
keyUp(Key.SHIFT);
|
|
454
|
-
}
|
|
455
|
-
if (processesModifierKeys.some((key) => key.toLowerCase() === 'win')) {
|
|
456
|
-
keyUp(Key.META);
|
|
457
|
-
}
|
|
458
|
-
}
|
|
459
|
-
|
|
460
|
-
if (this.caps.delayAfterClick) {
|
|
461
|
-
await sleep(this.caps.delayAfterClick ?? 0);
|
|
462
|
-
}
|
|
463
|
-
}
|
|
464
|
-
|
|
465
|
-
export async function executeHover(this: NovaWindows2Driver, hoverArgs: {
|
|
466
|
-
startElementId?: string,
|
|
467
|
-
startX?: number,
|
|
468
|
-
startY?: number,
|
|
469
|
-
endElementId?: string,
|
|
470
|
-
endX?: number,
|
|
471
|
-
endY?: number,
|
|
472
|
-
modifierKeys?: ('shift' | 'ctrl' | 'alt' | 'win') | ('shift' | 'ctrl' | 'alt' | 'win')[],
|
|
473
|
-
durationMs?: number,
|
|
474
|
-
}) {
|
|
475
|
-
const {
|
|
476
|
-
startElementId,
|
|
477
|
-
startX, startY,
|
|
478
|
-
endElementId,
|
|
479
|
-
endX, endY,
|
|
480
|
-
modifierKeys = [],
|
|
481
|
-
durationMs = 500,
|
|
482
|
-
} = hoverArgs;
|
|
483
|
-
|
|
484
|
-
if ((startX != null) !== (startY != null)) {
|
|
485
|
-
throw new errors.InvalidArgumentError('Both startX and startY must be provided if either is set.');
|
|
486
|
-
}
|
|
487
|
-
|
|
488
|
-
if ((endX != null) !== (endY != null)) {
|
|
489
|
-
throw new errors.InvalidArgumentError('Both endX and endY must be provided if either is set.');
|
|
490
|
-
}
|
|
491
|
-
|
|
492
|
-
const processesModifierKeys = Array.isArray(modifierKeys) ? modifierKeys : [modifierKeys];
|
|
493
|
-
let startPos: [number, number];
|
|
494
|
-
if (startElementId) {
|
|
495
|
-
if (await this.sendPowerShellCommand(/* ps1 */ `$null -eq ${new FoundAutomationElement(startElementId).toString()}`)) {
|
|
496
|
-
const condition = new PropertyCondition(Property.RUNTIME_ID, new PSInt32Array(startElementId.split('.').map(Number)));
|
|
497
|
-
const elId = await this.sendPowerShellCommand(AutomationElement.automationRoot.findFirst(TreeScope.SUBTREE, condition).buildCommand());
|
|
498
|
-
|
|
499
|
-
if (elId.trim() === '') {
|
|
500
|
-
throw new errors.NoSuchElementError();
|
|
501
|
-
}
|
|
502
|
-
}
|
|
503
|
-
|
|
504
|
-
const rectJson = await this.sendPowerShellCommand(new FoundAutomationElement(startElementId).buildGetElementRectCommand());
|
|
505
|
-
const rect = JSON.parse(rectJson.replaceAll(/(?:infinity)/gi, 0x7FFFFFFF.toString())) as Rect;
|
|
506
|
-
startPos = [
|
|
507
|
-
rect.x + (startX ?? rect.width / 2),
|
|
508
|
-
rect.y + (startY ?? rect.height / 2)
|
|
509
|
-
];
|
|
510
|
-
} else {
|
|
511
|
-
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
512
|
-
startPos = [startX!, startY!];
|
|
513
|
-
}
|
|
514
|
-
|
|
515
|
-
let endPos: [number, number];
|
|
516
|
-
if (endElementId) {
|
|
517
|
-
if (await this.sendPowerShellCommand(/* ps1 */ `$null -eq ${new FoundAutomationElement(endElementId).toString()}`)) {
|
|
518
|
-
const condition = new PropertyCondition(Property.RUNTIME_ID, new PSInt32Array(endElementId.split('.').map(Number)));
|
|
519
|
-
const elId = await this.sendPowerShellCommand(AutomationElement.automationRoot.findFirst(TreeScope.SUBTREE, condition).buildCommand());
|
|
520
|
-
|
|
521
|
-
if (elId.trim() === '') {
|
|
522
|
-
throw new errors.NoSuchElementError();
|
|
523
|
-
}
|
|
524
|
-
}
|
|
525
|
-
|
|
526
|
-
const rectJson = await this.sendPowerShellCommand(new FoundAutomationElement(endElementId).buildGetElementRectCommand());
|
|
527
|
-
const rect = JSON.parse(rectJson.replaceAll(/(?:infinity)/gi, 0x7FFFFFFF.toString())) as Rect;
|
|
528
|
-
endPos = [
|
|
529
|
-
rect.x + (endX ?? rect.width / 2),
|
|
530
|
-
rect.y + (endY ?? rect.height / 2)
|
|
531
|
-
];
|
|
532
|
-
} else {
|
|
533
|
-
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
534
|
-
endPos = [endX!, endY!];
|
|
535
|
-
}
|
|
536
|
-
|
|
537
|
-
await mouseMoveAbsolute(startPos[0], startPos[1], 0);
|
|
538
|
-
|
|
539
|
-
if (processesModifierKeys.some((key) => key.toLowerCase() === 'ctrl')) {
|
|
540
|
-
keyDown(Key.CONTROL);
|
|
541
|
-
}
|
|
542
|
-
if (processesModifierKeys.some((key) => key.toLowerCase() === 'alt')) {
|
|
543
|
-
keyDown(Key.ALT);
|
|
544
|
-
}
|
|
545
|
-
if (processesModifierKeys.some((key) => key.toLowerCase() === 'shift')) {
|
|
546
|
-
keyDown(Key.SHIFT);
|
|
547
|
-
}
|
|
548
|
-
if (processesModifierKeys.some((key) => key.toLowerCase() === 'win')) {
|
|
549
|
-
keyDown(Key.META);
|
|
550
|
-
}
|
|
551
|
-
|
|
552
|
-
await mouseMoveAbsolute(endPos[0], endPos[1], durationMs, this.caps.smoothPointerMove);
|
|
553
|
-
|
|
554
|
-
if (processesModifierKeys.some((key) => key.toLowerCase() === 'ctrl')) {
|
|
555
|
-
keyUp(Key.CONTROL);
|
|
556
|
-
}
|
|
557
|
-
if (processesModifierKeys.some((key) => key.toLowerCase() === 'alt')) {
|
|
558
|
-
keyUp(Key.ALT);
|
|
559
|
-
}
|
|
560
|
-
if (processesModifierKeys.some((key) => key.toLowerCase() === 'shift')) {
|
|
561
|
-
keyUp(Key.SHIFT);
|
|
562
|
-
}
|
|
563
|
-
if (processesModifierKeys.some((key) => key.toLowerCase() === 'win')) {
|
|
564
|
-
keyUp(Key.META);
|
|
565
|
-
}
|
|
566
|
-
}
|
|
567
|
-
|
|
568
|
-
export async function executeScroll(this: NovaWindows2Driver, scrollArgs: {
|
|
569
|
-
elementId?: string,
|
|
570
|
-
x?: number,
|
|
571
|
-
y?: number,
|
|
572
|
-
deltaX?: number,
|
|
573
|
-
deltaY?: number,
|
|
574
|
-
modifierKeys?: ('shift' | 'ctrl' | 'alt' | 'win') | ('shift' | 'ctrl' | 'alt' | 'win')[], // TODO: add types
|
|
575
|
-
}) {
|
|
576
|
-
const {
|
|
577
|
-
elementId,
|
|
578
|
-
x, y,
|
|
579
|
-
deltaX, deltaY,
|
|
580
|
-
modifierKeys = [],
|
|
581
|
-
} = scrollArgs;
|
|
582
|
-
|
|
583
|
-
if (!!elementId && ((x !== null && x !== undefined) || (y !== null && y !== undefined))) {
|
|
584
|
-
throw new errors.InvalidArgumentError('Either elementId or x and y must be provided.');
|
|
585
|
-
}
|
|
586
|
-
|
|
587
|
-
if ((x !== null && x !== undefined) !== (y !== null && y !== undefined)) {
|
|
588
|
-
throw new errors.InvalidArgumentError('Both x and y must be provided.');
|
|
589
|
-
}
|
|
590
|
-
|
|
591
|
-
const processesModifierKeys = Array.isArray(modifierKeys) ? modifierKeys : [modifierKeys];
|
|
592
|
-
let pos: [number, number];
|
|
593
|
-
if (elementId) {
|
|
594
|
-
if (await this.sendPowerShellCommand(/* ps1 */ `$null -eq ${new FoundAutomationElement(elementId).toString()}`)) {
|
|
595
|
-
const condition = new PropertyCondition(Property.RUNTIME_ID, new PSInt32Array(elementId.split('.').map(Number)));
|
|
596
|
-
const elId = await this.sendPowerShellCommand(AutomationElement.automationRoot.findFirst(TreeScope.SUBTREE, condition).buildCommand());
|
|
597
|
-
|
|
598
|
-
if (elId.trim() === '') {
|
|
599
|
-
throw new errors.NoSuchElementError();
|
|
600
|
-
}
|
|
601
|
-
}
|
|
602
|
-
|
|
603
|
-
const rectJson = await this.sendPowerShellCommand(new FoundAutomationElement(elementId).buildGetElementRectCommand());
|
|
604
|
-
const rect = JSON.parse(rectJson.replaceAll(/(?:infinity)/gi, 0x7FFFFFFF.toString())) as Rect;
|
|
605
|
-
pos = [rect.x + (rect.width / 2), rect.y + (rect.height / 2)];
|
|
606
|
-
} else {
|
|
607
|
-
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
608
|
-
pos = [x!, y!];
|
|
609
|
-
}
|
|
610
|
-
|
|
611
|
-
await mouseMoveAbsolute(pos[0], pos[1], 0);
|
|
612
|
-
|
|
613
|
-
if (processesModifierKeys.some((key) => key.toLowerCase() === 'ctrl')) {
|
|
614
|
-
keyDown(Key.CONTROL);
|
|
615
|
-
}
|
|
616
|
-
if (processesModifierKeys.some((key) => key.toLowerCase() === 'alt')) {
|
|
617
|
-
keyDown(Key.ALT);
|
|
618
|
-
}
|
|
619
|
-
if (processesModifierKeys.some((key) => key.toLowerCase() === 'shift')) {
|
|
620
|
-
keyDown(Key.SHIFT);
|
|
621
|
-
}
|
|
622
|
-
if (processesModifierKeys.some((key) => key.toLowerCase() === 'win')) {
|
|
623
|
-
keyDown(Key.META);
|
|
624
|
-
}
|
|
625
|
-
|
|
626
|
-
mouseScroll(deltaX ?? 0, deltaY ?? 0);
|
|
627
|
-
|
|
628
|
-
if (processesModifierKeys.some((key) => key.toLowerCase() === 'ctrl')) {
|
|
629
|
-
keyUp(Key.CONTROL);
|
|
630
|
-
}
|
|
631
|
-
if (processesModifierKeys.some((key) => key.toLowerCase() === 'alt')) {
|
|
632
|
-
keyUp(Key.ALT);
|
|
633
|
-
}
|
|
634
|
-
if (processesModifierKeys.some((key) => key.toLowerCase() === 'shift')) {
|
|
635
|
-
keyUp(Key.SHIFT);
|
|
636
|
-
}
|
|
637
|
-
if (processesModifierKeys.some((key) => key.toLowerCase() === 'win')) {
|
|
638
|
-
keyUp(Key.META);
|
|
639
|
-
}
|
|
640
|
-
}
|