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,229 +0,0 @@
1
- import {
2
- ActionSequence,
3
- KeyAction,
4
- KeyActionSequence,
5
- NullActionSequence,
6
- PointerActionSequence,
7
- PointerMoveAction,
8
- Rect,
9
- ScrollAction,
10
- WheelActionSequence,
11
- } from '@appium/types';
12
-
13
- import { W3C_ELEMENT_KEY, errors } from '@appium/base-driver';
14
- import { NovaWindows2Driver } from '../driver';
15
- import { keyDown, keyUp, mouseMoveRelative, mouseMoveAbsolute, mouseDown, mouseUp, mouseScroll } from '../winapi/user32';
16
- import { sleep } from '../util';
17
- import { AutomationElement, FoundAutomationElement } from '../powershell';
18
- import { Key } from '../enums';
19
-
20
- export async function performActions(this: NovaWindows2Driver, actionSequences: ActionSequence[]): Promise<void> {
21
- for (const actionSequence of actionSequences) {
22
- switch (actionSequence.type) {
23
- case 'key':
24
- await this.handleKeyActionSequence(actionSequence);
25
- break;
26
- case 'wheel':
27
- await this.handleWheelActionSequence(actionSequence);
28
- break;
29
- case 'pointer':
30
- await this.handlePointerActionSequence(actionSequence);
31
- break;
32
- case 'none':
33
- await this.handleNullActionSequence(actionSequence);
34
- break;
35
- default:
36
- throw new errors.InvalidArgumentError();
37
- }
38
- }
39
- };
40
-
41
- export async function handleKeyActionSequence(this: NovaWindows2Driver, actionSequence: KeyActionSequence): Promise<void> {
42
- const actions = actionSequence.actions;
43
- for (const action of actions) {
44
- await this.handleKeyAction(action);
45
- }
46
- }
47
-
48
- export async function handlePointerActionSequence(this: NovaWindows2Driver, actionSequence: PointerActionSequence): Promise<void> {
49
- switch (actionSequence.parameters?.pointerType) {
50
- case 'touch':
51
- case 'pen':
52
- throw new errors.NotImplementedError(`Pointer type ${actionSequence.parameters?.pointerType} not implemented yet.`);
53
- case 'mouse':
54
- default:
55
- await this.handleMousePointerActionSequence(actionSequence);
56
- }
57
- }
58
-
59
- export async function handleMousePointerActionSequence(this: NovaWindows2Driver, actionSequence: PointerActionSequence): Promise<void> {
60
- const actions = actionSequence.actions;
61
- for (const action of actions) {
62
- switch (action.type) {
63
- case 'pointerMove':
64
- await this.handleMouseMoveAction(action);
65
- break;
66
- case 'pointerDown':
67
- mouseDown(action.button);
68
- break;
69
- case 'pointerUp':
70
- mouseUp(action.button);
71
- break;
72
- case 'pause':
73
- if (action.duration) {
74
- await sleep(action.duration);
75
- }
76
- break;
77
- default:
78
- throw new errors.InvalidArgumentError();
79
- }
80
- }
81
- }
82
-
83
- export async function handleWheelActionSequence(this: NovaWindows2Driver, actionSequence: WheelActionSequence): Promise<void> {
84
- const actions = actionSequence.actions;
85
- for (const action of actions) {
86
- switch (action.type) {
87
- case 'scroll':
88
- await this.handleMouseMoveAction(action);
89
- mouseScroll(action.deltaX, action.deltaY);
90
- break;
91
- case 'pause':
92
- if (action.duration) {
93
- await sleep(action.duration);
94
- }
95
- break;
96
- default:
97
- throw new errors.InvalidArgumentError();
98
- }
99
- }
100
- }
101
-
102
- export async function handleNullActionSequence(this: NovaWindows2Driver, actionSequence: NullActionSequence): Promise<void> {
103
- const actions = actionSequence.actions;
104
- for (const action of actions) {
105
- if (action.duration) {
106
- await sleep(action.duration);
107
- }
108
- }
109
- }
110
-
111
- export async function handleMouseMoveAction(this: NovaWindows2Driver, action: PointerMoveAction | ScrollAction): Promise<void> {
112
- const easingFunction = this.caps.smoothPointerMove;
113
- switch (action.origin) {
114
- case 'pointer':
115
- await mouseMoveRelative(action.x, action.y, action.duration, easingFunction);
116
- break;
117
- case 'viewport': {
118
- const rootRectJson = await this.sendPowerShellCommand(AutomationElement.automationRoot.buildGetElementRectCommand());
119
- const rootRect = JSON.parse(rootRectJson.replaceAll(/(?:infinity)/gi, 0x7FFFFFFF.toString())) as Rect;
120
- await mouseMoveAbsolute(action.x + rootRect.x, action.y + rootRect.y, action.duration, easingFunction);
121
- break;
122
- }
123
- default:
124
- if (action.origin?.[W3C_ELEMENT_KEY]) {
125
- const element = new FoundAutomationElement(action.origin[W3C_ELEMENT_KEY]);
126
- const rectJson = await this.sendPowerShellCommand(element.buildGetElementRectCommand());
127
- let rect = JSON.parse(rectJson.replaceAll(/(?:infinity)/gi, 0x7FFFFFFF.toString())) as Rect;
128
-
129
- if (Object.values(rect).some((x) => x === 0x7FFFFFFF)) {
130
- await this.sendPowerShellCommand(element.buildScrollIntoViewCommand());
131
- rect = JSON.parse(rectJson.replaceAll(/(?:infinity)/gi, 0x7FFFFFFF.toString())) as Rect;
132
- }
133
-
134
- await mouseMoveAbsolute(action.x === 0 ? rect.x + rect.width / 2 : action.x, action.y === 0 ? rect.y + rect.height / 2 : action.y, action.duration, easingFunction);
135
- break;
136
- }
137
-
138
- throw new errors.InvalidArgumentError();
139
- }
140
- }
141
-
142
- export async function handleKeyAction(this: NovaWindows2Driver, action: KeyAction): Promise<void> {
143
- if (action.type === 'pause') {
144
- if (action.duration) {
145
- await sleep(action.duration);
146
- }
147
- return;
148
- }
149
-
150
- switch (action.value) {
151
- case Key.SHIFT:
152
- case Key.R_SHIFT:
153
- if (action.type === 'keyDown') {
154
- keyDown(action.value);
155
- this.keyboardState.shift = true;
156
- return;
157
- }
158
-
159
- keyUp(Key.SHIFT);
160
- keyUp(Key.R_SHIFT);
161
- this.keyboardState.shift = false;
162
- return;
163
- case Key.CONTROL:
164
- case Key.R_CONTROL:
165
- if (action.type === 'keyDown') {
166
- keyDown(action.value);
167
- this.keyboardState.ctrl = true;
168
- return;
169
- }
170
-
171
- keyUp(Key.CONTROL);
172
- keyUp(Key.R_CONTROL);
173
- this.keyboardState.ctrl = false;
174
- return;
175
- case Key.META:
176
- case Key.R_META:
177
- if (action.type === 'keyDown') {
178
- keyDown(action.value);
179
- this.keyboardState.meta = true;
180
- return;
181
- }
182
-
183
- keyUp(Key.META);
184
- keyUp(Key.R_META);
185
- this.keyboardState.meta = false;
186
- return;
187
- case Key.ALT:
188
- case Key.R_ALT:
189
- if (action.type === 'keyDown') {
190
- keyDown(action.value);
191
- this.keyboardState.alt = true;
192
- return;
193
- }
194
-
195
- keyUp(Key.ALT);
196
- keyUp(Key.R_ALT);
197
- this.keyboardState.alt = false;
198
- return;
199
- case Key.NULL:
200
- if (action.type === 'keyDown') {
201
- if (this.keyboardState.shift) {
202
- await this.handleKeyAction({ type: 'keyUp', value: Key.SHIFT });
203
- }
204
- if (this.keyboardState.ctrl) {
205
- await this.handleKeyAction({ type: 'keyUp', value: Key.CONTROL });
206
- }
207
- if (this.keyboardState.meta) {
208
- await this.handleKeyAction({ type: 'keyUp', value: Key.META });
209
- }
210
- if (this.keyboardState.alt) {
211
- await this.handleKeyAction({ type: 'keyUp', value: Key.ALT });
212
- }
213
- for (const key in Array.of(this.keyboardState.pressed)) {
214
- keyUp(key);
215
- this.keyboardState.pressed.delete(key);
216
- }
217
- }
218
- return;
219
- default:
220
- if (action.type === 'keyDown') {
221
- keyDown(action.value);
222
- this.keyboardState.pressed.add(action.value);
223
- }
224
- else {
225
- keyUp(action.value);
226
- this.keyboardState.pressed.delete(action.value);
227
- }
228
- }
229
- }
@@ -1,227 +0,0 @@
1
- import { normalize } from 'node:path';
2
- import { Element, Rect } from '@appium/types';
3
- import { NovaWindows2Driver } from '../driver';
4
- import {
5
- AutomationElement,
6
- FoundAutomationElement,
7
- PSInt32,
8
- PSString,
9
- Property,
10
- PropertyCondition,
11
- TreeScope,
12
- TrueCondition,
13
- pwsh$,
14
- pwsh,
15
- } from '../powershell';
16
- import { sleep } from '../util';
17
- import { errors, W3C_ELEMENT_KEY } from '@appium/base-driver';
18
- import {
19
- getWindowAllHandlesForProcessIds,
20
- trySetForegroundWindow,
21
- } from '../winapi/user32';
22
-
23
- const GET_PAGE_SOURCE_COMMAND = pwsh$ /* ps1 */ `
24
- $el = ${0}
25
-
26
- if ($el -eq $null) {
27
- $dummy = [xml]'<DummyRoot></DummyRoot>'
28
- return $dummy.OuterXml
29
- }
30
-
31
- Get-PageSource $el |
32
- ForEach-Object { $_.OuterXml }
33
- `;
34
-
35
- const GET_SCREENSHOT_COMMAND = pwsh /* ps1 */ `
36
- if ($rootElement -eq $null) {
37
- $bitmap = New-Object Drawing.Bitmap 1,1
38
- $stream = New-Object IO.MemoryStream
39
- $bitmap.Save($stream, [Drawing.Imaging.ImageFormat]::Png)
40
- $bitmap.Dispose()
41
- return [Convert]::ToBase64String($stream.ToArray())
42
- }
43
-
44
- $rect = $rootElement.Current.BoundingRectangle
45
- $bitmap = New-Object Drawing.Bitmap([int32]$rect.Width, [int32]$rect.Height)
46
-
47
- $graphics = [Drawing.Graphics]::FromImage($bitmap)
48
- $graphics.CopyFromScreen([int32]$rect.Left, [int32]$rect.Top, 0, 0, $bitmap.Size)
49
- $graphics.Dispose()
50
-
51
- $stream = New-Object IO.MemoryStream
52
- $bitmap.Save($stream, [Drawing.Imaging.ImageFormat]::Png)
53
- $bitmap.Dispose()
54
-
55
- [Convert]::ToBase64String($stream.ToArray())
56
- `;
57
-
58
- export async function getPageSource(this: NovaWindows2Driver): Promise<string> {
59
- return await this.sendPowerShellCommand(GET_PAGE_SOURCE_COMMAND.format(AutomationElement.automationRoot));
60
- }
61
-
62
- export async function getScreenshot(this: NovaWindows2Driver): Promise<string> {
63
- const automationRootId = await this.sendPowerShellCommand(AutomationElement.automationRoot.buildCommand());
64
-
65
- if (this.caps.app && this.caps.app.toLowerCase() !== 'root') {
66
- try {
67
- await this.focusElement({
68
- [W3C_ELEMENT_KEY]: automationRootId.trim(),
69
- } satisfies Element);
70
- } catch {
71
- // noop
72
- }
73
- }
74
-
75
- return await this.sendPowerShellCommand(GET_SCREENSHOT_COMMAND);
76
- }
77
-
78
- export async function getWindowRect(this: NovaWindows2Driver): Promise<Rect> {
79
- const result = await this.sendPowerShellCommand(AutomationElement.automationRoot.buildGetElementRectCommand());
80
- return JSON.parse(result.replaceAll(/(?:infinity)/gi, 0x7FFFFFFF.toString()));
81
- }
82
-
83
- export async function getWindowHandle(this: NovaWindows2Driver): Promise<string> {
84
- const nativeWindowHandle = await this.sendPowerShellCommand(AutomationElement.automationRoot.buildGetPropertyCommand(Property.NATIVE_WINDOW_HANDLE));
85
- return `0x${Number(nativeWindowHandle).toString(16).padStart(8, '0')}`;
86
- }
87
-
88
- export async function getWindowHandles(this: NovaWindows2Driver): Promise<string[]> {
89
- const result = await this.sendPowerShellCommand(AutomationElement.rootElement.findAll(TreeScope.CHILDREN, new TrueCondition()).buildCommand());
90
- const elIds = result.split('\n').map((x) => x.trim()).filter(Boolean);
91
- const nativeWindowHandles: string[] = [];
92
-
93
- for (const elId of elIds) {
94
- const nativeWindowHandle = await this.sendPowerShellCommand(new FoundAutomationElement(elId).buildGetPropertyCommand(Property.NATIVE_WINDOW_HANDLE));
95
- nativeWindowHandles.push(`0x${Number(nativeWindowHandle).toString(16).padStart(8, '0')}`);
96
- }
97
-
98
- return nativeWindowHandles;
99
- }
100
-
101
- export async function setWindow(this: NovaWindows2Driver, nameOrHandle: string): Promise<void> {
102
- const handle = Number(nameOrHandle);
103
- for (let i = 1; i <= 20; i++) { // TODO: make a setting for the number of retries or timeout
104
- if (!isNaN(handle)) {
105
- const condition = new PropertyCondition(Property.NATIVE_WINDOW_HANDLE, new PSInt32(handle));
106
- const elementId = await this.sendPowerShellCommand(AutomationElement.rootElement.findFirst(TreeScope.CHILDREN_OR_SELF, condition).buildCommand());
107
-
108
- if (elementId.trim() !== '') {
109
- await this.sendPowerShellCommand(/* ps1 */ `$rootElement = ${new FoundAutomationElement(elementId).buildCommand()}`);
110
- trySetForegroundWindow(handle);
111
- return;
112
- }
113
- }
114
-
115
- const name = nameOrHandle;
116
- const condition = new PropertyCondition(Property.NAME, new PSString(name));
117
- const elementId = await this.sendPowerShellCommand(AutomationElement.rootElement.findFirst(TreeScope.CHILDREN, condition).buildCommand());
118
-
119
- if (elementId.trim() !== '') {
120
- this.log.info(`Found window with name '${name}'. Setting it as the root element.`);
121
- await this.sendPowerShellCommand(/* ps1 */ `$rootElement = ${new FoundAutomationElement(elementId).buildCommand()}`);
122
- trySetForegroundWindow(handle);
123
- return;
124
- }
125
-
126
- this.log.info(`Failed to locate window with name '${name}'. Sleeping for 500 milliseconds and retrying... (${i}/20)`); // TODO: make a setting for the number of retries or timeout
127
- await sleep(500); // TODO: make a setting for the sleep timeout
128
- }
129
-
130
- throw new errors.NoSuchWindowError(`No window was found with name or handle '${nameOrHandle}'.`);
131
- }
132
-
133
- export async function changeRootElement(this: NovaWindows2Driver, path: string): Promise<void>
134
- export async function changeRootElement(this: NovaWindows2Driver, nativeWindowHandle: number): Promise<void>
135
- export async function changeRootElement(this: NovaWindows2Driver, pathOrNativeWindowHandle: string | number): Promise<void> {
136
- if (typeof pathOrNativeWindowHandle === 'number') {
137
- const nativeWindowHandle = pathOrNativeWindowHandle;
138
- const condition = new PropertyCondition(Property.NATIVE_WINDOW_HANDLE, new PSInt32(nativeWindowHandle));
139
- const elementId = await this.sendPowerShellCommand(AutomationElement.rootElement.findFirst(TreeScope.CHILDREN_OR_SELF, condition).buildCommand());
140
-
141
- if (elementId.trim() !== '') {
142
- await this.sendPowerShellCommand(/* ps1 */ `$rootElement = ${new FoundAutomationElement(elementId).buildCommand()}`);
143
- trySetForegroundWindow(nativeWindowHandle);
144
- return;
145
- }
146
-
147
- throw new errors.UnknownError('Failed to locate top level window with that window handle.');
148
- }
149
-
150
-
151
- const path = pathOrNativeWindowHandle;
152
- if (path.includes('!') && path.includes('_') && !(path.includes('/') || path.includes('\\'))) {
153
- this.log.debug('Detected app path to be in the UWP format.');
154
- await this.sendPowerShellCommand(/* ps1 */ `Start-Process 'explorer.exe' 'shell:AppsFolder\\${path}'${this.caps.appArguments ? ` -ArgumentList '${this.caps.appArguments}'` : ''}`);
155
- await sleep(500); // TODO: make a setting for the initial wait time
156
- for (let i = 1; i <= 20; i++) {
157
- const result = await this.sendPowerShellCommand(/* ps1 */ `(Get-Process -Name 'ApplicationFrameHost').Id`);
158
- const processIds = result.split('\n').map((pid) => pid.trim()).filter(Boolean).map(Number);
159
-
160
- this.log.debug('Process IDs of ApplicationFrameHost processes: ' + processIds.join(', '));
161
- try {
162
- await this.attachToApplicationWindow(processIds);
163
- return;
164
- } catch {
165
- // noop
166
- }
167
-
168
- this.log.info(`Failed to locate window of the app. Sleeping for 500 milliseconds and retrying... (${i}/20)`); // TODO: make a setting for the number of retries or timeout
169
- await sleep(500); // TODO: make a setting for the sleep timeout
170
- }
171
- } else {
172
- this.log.debug('Detected app path to be in the classic format.');
173
- const normalizedPath = normalize(path);
174
- await this.sendPowerShellCommand(/* ps1 */ `Start-Process '${normalizedPath}'${this.caps.appArguments ? ` -ArgumentList '${this.caps.appArguments}'` : ''}`);
175
- await sleep(500); // TODO: make a setting for the initial wait time
176
- for (let i = 1; i <= 20; i++) {
177
- try {
178
- const breadcrumbs = normalizedPath.toLowerCase().split('\\').flatMap((x) => x.split('/'));
179
- const executable = breadcrumbs[breadcrumbs.length - 1];
180
- const processName = executable.endsWith('.exe') ? executable.slice(0, executable.length - 4) : executable;
181
- const result = await this.sendPowerShellCommand(/* ps1 */ `(Get-Process -Name '${processName}' | Sort-Object StartTime -Descending).Id`);
182
- const processIds = result.split('\n').map((pid) => pid.trim()).filter(Boolean).map(Number);
183
- this.log.debug(`Process IDs of '${processName}' processes: ` + processIds.join(', '));
184
-
185
- await this.attachToApplicationWindow(processIds);
186
- return;
187
- } catch (err) {
188
- if (err instanceof Error) {
189
- this.log.debug(`Received error:\n${err.message}`);
190
- }
191
- }
192
-
193
- this.log.info(`Failed to locate window of the app. Sleeping for 500 milliseconds and retrying... (${i}/20)`); // TODO: make a setting for the number of retries or timeout
194
- await sleep(500); // TODO: make a setting for the sleep timeout
195
- }
196
- }
197
-
198
- throw new errors.UnknownError('Failed to locate window of the app.');
199
- }
200
-
201
- export async function attachToApplicationWindow(this: NovaWindows2Driver, processIds: number[]): Promise<void> {
202
- const nativeWindowHandles = getWindowAllHandlesForProcessIds(processIds);
203
- this.log.debug(`Detected the following native window handles for the given process IDs: ${nativeWindowHandles.map((handle) => `0x${handle.toString(16).padStart(8, '0')}`).join(', ')}`);
204
-
205
- if (nativeWindowHandles.length !== 0) {
206
- let elementId = '';
207
- for (let i = 1; i <= 20; i++) {
208
- elementId = await this.sendPowerShellCommand(AutomationElement.rootElement.findFirst(TreeScope.CHILDREN, new PropertyCondition(Property.NATIVE_WINDOW_HANDLE, new PSInt32(nativeWindowHandles[0]))).buildCommand());
209
- if (elementId) {
210
- break;
211
- }
212
- this.log.info(`The window with handle 0x${nativeWindowHandles[0].toString(16).padStart(8, '0')} is not yet available in the UI Automation tree. Sleeping for 500 milliseconds and retrying... (${i}/20)`); // TODO: make a setting for the number of retries or timeout
213
- await sleep(500); // TODO: make a setting for the sleep timeout
214
- }
215
-
216
- await this.sendPowerShellCommand(/* ps1 */ `$rootElement = ${new FoundAutomationElement(elementId).buildCommand()}`);
217
- if ((await this.sendPowerShellCommand(/* ps1 */ `$null -ne $rootElement`)).toLowerCase() === 'true') {
218
- const nativeWindowHandle = Number(await this.sendPowerShellCommand(AutomationElement.automationRoot.buildGetPropertyCommand(Property.NATIVE_WINDOW_HANDLE)));
219
- if (!trySetForegroundWindow(nativeWindowHandle)) {
220
- await this.focusElement({
221
- [W3C_ELEMENT_KEY]: elementId,
222
- } satisfies Element);
223
- };
224
- return;
225
- }
226
- }
227
- }
@@ -1,41 +0,0 @@
1
- import { NovaWindows2Driver } from '../driver';
2
- import { PSString, pwsh$ } from '../powershell';
3
-
4
- const GET_SYSTEM_TIME_COMMAND = pwsh$ /* ps1 */ `(Get-Date).ToString(${0})`;
5
- const ISO_8061_FORMAT = 'yyyy-MM-ddTHH:mm:sszzz';
6
-
7
- export async function getDeviceTime(this: NovaWindows2Driver, format?: string): Promise<string> {
8
- format = format ? new PSString(format).toString() : `'${ISO_8061_FORMAT}'`;
9
- return await this.sendPowerShellCommand(GET_SYSTEM_TIME_COMMAND.format(format));
10
- }
11
-
12
- // command: 'hideKeyboard'
13
- // payloadParams: { optional: ['strategy', 'key', 'keyCode', 'keyName'] }
14
-
15
- // command: 'isKeyboardShown'
16
-
17
- // command: 'pushFile'
18
- // payloadParams: { required: ['path', 'data'] }
19
-
20
- // command: 'pullFile'
21
- // payloadParams: { required: ['path'] }
22
-
23
- // command: 'pullFolder'
24
- // payloadParams: { required: ['path'] }
25
-
26
- // # APP MANAGEMENT
27
-
28
- // command: 'activateApp'
29
- // payloadParams: { required: [['appId'], ['bundleId']], optional: ['options'] }
30
-
31
- // command: 'removeApp'
32
- // payloadParams: { required: [['appId'], ['bundleId']], optional: ['options'] }
33
-
34
- //command: 'terminateApp'
35
- // payloadParams: { required: [['appId'], ['bundleId']], optional: ['options'] }
36
-
37
- // command: 'isAppInstalled'
38
- // payloadParams: { required: [['appId'], ['bundleId']] }
39
-
40
- // command: 'installApp'
41
- // payloadParams: { required: ['appPath'], optional: ['options'] }