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.
Files changed (103) hide show
  1. package/LICENSE +201 -201
  2. package/README.md +557 -557
  3. package/build/lib/commands/actions.d.ts.map +1 -1
  4. package/build/lib/commands/actions.js +3 -4
  5. package/build/lib/commands/actions.js.map +1 -1
  6. package/build/lib/commands/app.d.ts.map +1 -1
  7. package/build/lib/commands/app.js +53 -45
  8. package/build/lib/commands/app.js.map +1 -1
  9. package/build/lib/commands/device.d.ts.map +1 -1
  10. package/build/lib/commands/device.js +2 -0
  11. package/build/lib/commands/device.js.map +1 -1
  12. package/build/lib/commands/element.d.ts.map +1 -1
  13. package/build/lib/commands/element.js +42 -12
  14. package/build/lib/commands/element.js.map +1 -1
  15. package/build/lib/commands/extension.d.ts.map +1 -1
  16. package/build/lib/commands/extension.js +29 -17
  17. package/build/lib/commands/extension.js.map +1 -1
  18. package/build/lib/commands/file.d.ts +5 -0
  19. package/build/lib/commands/file.d.ts.map +1 -0
  20. package/build/lib/commands/file.js +49 -0
  21. package/build/lib/commands/file.js.map +1 -0
  22. package/build/lib/commands/functions.d.ts.map +1 -1
  23. package/build/lib/commands/functions.js +189 -187
  24. package/build/lib/commands/functions.js.map +1 -1
  25. package/build/lib/commands/index.d.ts +3 -0
  26. package/build/lib/commands/index.d.ts.map +1 -1
  27. package/build/lib/commands/index.js +2 -0
  28. package/build/lib/commands/index.js.map +1 -1
  29. package/build/lib/commands/powershell.d.ts.map +1 -1
  30. package/build/lib/commands/powershell.js +114 -68
  31. package/build/lib/commands/powershell.js.map +1 -1
  32. package/build/lib/constraints.d.ts +18 -0
  33. package/build/lib/constraints.d.ts.map +1 -1
  34. package/build/lib/constraints.js +18 -0
  35. package/build/lib/constraints.js.map +1 -1
  36. package/build/lib/driver.d.ts.map +1 -1
  37. package/build/lib/driver.js +35 -4
  38. package/build/lib/driver.js.map +1 -1
  39. package/build/lib/powershell/converter.d.ts.map +1 -1
  40. package/build/lib/powershell/converter.js +12 -0
  41. package/build/lib/powershell/converter.js.map +1 -1
  42. package/build/lib/powershell/elements.d.ts.map +1 -1
  43. package/build/lib/powershell/elements.js +270 -265
  44. package/build/lib/powershell/elements.js.map +1 -1
  45. package/build/lib/winapi/user32.js.map +1 -1
  46. package/build/lib/xpath/core.d.ts +2 -2
  47. package/build/lib/xpath/core.d.ts.map +1 -1
  48. package/build/lib/xpath/core.js +32 -26
  49. package/build/lib/xpath/core.js.map +1 -1
  50. package/build/lib/xpath/functions.d.ts +1 -1
  51. package/build/lib/xpath/functions.d.ts.map +1 -1
  52. package/build/lib/xpath/functions.js +2 -2
  53. package/build/lib/xpath/functions.js.map +1 -1
  54. package/build/tsconfig.tsbuildinfo +1 -0
  55. package/package.json +67 -62
  56. package/.github/ISSUE_TEMPLATE/bug_report.yml +0 -97
  57. package/.github/ISSUE_TEMPLATE/feature_request.yml +0 -33
  58. package/.github/PULL_REQUEST_TEMPLATE.md +0 -28
  59. package/.github/workflows/lint-build.yml +0 -30
  60. package/.github/workflows/release.yml +0 -39
  61. package/.releaserc +0 -41
  62. package/CHANGELOG.md +0 -33
  63. package/eslint.config.mjs +0 -11
  64. package/examples/api_test.js +0 -69
  65. package/examples/concurrency_test.js +0 -82
  66. package/examples/debug_test.js +0 -36
  67. package/examples/stress_test.js +0 -94
  68. package/examples/verify_driver.js +0 -142
  69. package/lib/commands/actions.ts +0 -229
  70. package/lib/commands/app.ts +0 -227
  71. package/lib/commands/device.ts +0 -41
  72. package/lib/commands/element.ts +0 -242
  73. package/lib/commands/extension.ts +0 -640
  74. package/lib/commands/functions.ts +0 -192
  75. package/lib/commands/index.ts +0 -28
  76. package/lib/commands/powershell.ts +0 -256
  77. package/lib/commands/system.ts +0 -7
  78. package/lib/constants.ts +0 -1
  79. package/lib/constraints.ts +0 -43
  80. package/lib/driver.ts +0 -266
  81. package/lib/enums.ts +0 -96
  82. package/lib/powershell/common.ts +0 -137
  83. package/lib/powershell/conditions.ts +0 -169
  84. package/lib/powershell/converter.ts +0 -373
  85. package/lib/powershell/core.ts +0 -29
  86. package/lib/powershell/elements.ts +0 -584
  87. package/lib/powershell/index.ts +0 -7
  88. package/lib/powershell/regex.ts +0 -77
  89. package/lib/powershell/types.ts +0 -208
  90. package/lib/util.ts +0 -52
  91. package/lib/winapi/types/index.ts +0 -7
  92. package/lib/winapi/types/input.ts +0 -12
  93. package/lib/winapi/types/keyeventf.ts +0 -14
  94. package/lib/winapi/types/mouseeventf.ts +0 -37
  95. package/lib/winapi/types/scancode.ts +0 -96
  96. package/lib/winapi/types/systemmetric.ts +0 -215
  97. package/lib/winapi/types/virtualkey.ts +0 -354
  98. package/lib/winapi/types/xmousebutton.ts +0 -8
  99. package/lib/winapi/user32.ts +0 -842
  100. package/lib/xpath/core.ts +0 -699
  101. package/lib/xpath/functions.ts +0 -366
  102. package/lib/xpath/index.ts +0 -2
  103. 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
- }