appium-novawindows2-driver 1.1.21 → 1.1.22

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.
@@ -2,388 +2,388 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.PAGE_SOURCE = exports.FIND_CHILDREN_RECURSIVELY = exports.FIND_DESCENDANTS_FUNCTIONS = exports.GET_LEGACY_PROPERTY_SAFE = void 0;
4
4
  const powershell_1 = require("../powershell");
5
- exports.GET_LEGACY_PROPERTY_SAFE = (0, powershell_1.pwsh /* ps1 */) `
6
- function Get-LegacyPropertySafe {
7
- param (
8
- [Parameter(Mandatory=$false)]
9
- [AutomationElement]$element,
10
- [string]$propName,
11
- [string]$accPropName
12
- );
13
-
14
- if ($null -eq $element) { return $null };
15
-
16
- # 1. Try PowerShell: UIA LegacyIAccessiblePattern
17
- try {
18
- $val = $element.GetCurrentPattern([System.Windows.Automation.LegacyIAccessiblePattern]::Pattern).Current.$propName;
19
- if ($null -ne $val) { return $val };
20
- } catch {};
21
-
22
- # 2. Try C#: Win32 MSAA with PID validation
23
- try {
24
- $hwnd = 0; try { $hwnd = [int]$element.Current.NativeWindowHandle; } catch { }
25
- $rect = $element.Current.BoundingRectangle;
26
- $cx = 0; $cy = 0;
27
- try { $cx = [int]($rect.Left + $rect.Width / 2); $cy = [int]($rect.Top + $rect.Height / 2); } catch { }
28
- try { [Win32Helper]::SetExpectedPid([uint32]$element.Current.ProcessId); } catch { }
29
- return [Win32Helper]::GetLegacyPropertyWithFallback([IntPtr]$hwnd, $cx, $cy, $accPropName);
30
- } catch {};
31
-
32
- return $null;
33
- }
5
+ exports.GET_LEGACY_PROPERTY_SAFE = (0, powershell_1.pwsh /* ps1 */) `
6
+ function Get-LegacyPropertySafe {
7
+ param (
8
+ [Parameter(Mandatory=$false)]
9
+ [AutomationElement]$element,
10
+ [string]$propName,
11
+ [string]$accPropName
12
+ );
13
+
14
+ if ($null -eq $element) { return $null };
15
+
16
+ # 1. Try PowerShell: UIA LegacyIAccessiblePattern
17
+ try {
18
+ $val = $element.GetCurrentPattern([System.Windows.Automation.LegacyIAccessiblePattern]::Pattern).Current.$propName;
19
+ if ($null -ne $val) { return $val };
20
+ } catch {};
21
+
22
+ # 2. Try C#: Win32 MSAA with PID validation
23
+ try {
24
+ $hwnd = 0; try { $hwnd = [int]$element.Current.NativeWindowHandle; } catch { }
25
+ $rect = $element.Current.BoundingRectangle;
26
+ $cx = 0; $cy = 0;
27
+ try { $cx = [int]($rect.Left + $rect.Width / 2); $cy = [int]($rect.Top + $rect.Height / 2); } catch { }
28
+ try { [Win32Helper]::SetExpectedPid([uint32]$element.Current.ProcessId); } catch { }
29
+ return [Win32Helper]::GetLegacyPropertyWithFallback([IntPtr]$hwnd, $cx, $cy, $accPropName);
30
+ } catch {};
31
+
32
+ return $null;
33
+ }
34
34
  `;
35
- exports.FIND_DESCENDANTS_FUNCTIONS = (0, powershell_1.pwsh /* ps1 */) `
36
- # Streaming, memory-bounded subtree walk used as the safe fallback for
37
- # Find-AllDescendants when the fast-path FindAll(Subtree) would either
38
- # OutOfMemoryException (observed on desktop-rooted sessions: UIA's
39
- # FindAll on a large tree materialises too much intermediate state) or
40
- # take pathologically long.
41
- #
42
- # Iterative DFS via TreeWalker. At any moment, only a stack-depth's
43
- # worth of AutomationElement references + the matches list is in memory
44
- # - not the entire visited set. Each element is filter-tested
45
- # individually via FindFirst([Element], $condition), which is O(1) in
46
- # the size of the subtree.
47
- #
48
- # The walker respects the active $cacheRequest's TreeFilter (same as
49
- # the upstream walker behaviour FindAll uses), so excluded views (e.g.
50
- # Chrome content) stay excluded.
51
- function Find-AllDescendantsStreaming {
52
- param (
53
- [Parameter(Mandatory=$false)]
54
- [AutomationElement]$element,
55
- [Parameter(Mandatory=$false)]
56
- [Condition]$condition,
57
- [switch]$includeSelf
58
- );
59
-
60
- if ($null -eq $element -or $null -eq $condition) { return @() };
61
-
62
- $walker = [TreeWalker]::new($cacheRequest.TreeFilter);
63
- $matches = New-Object System.Collections.Generic.List[AutomationElement];
64
-
65
- if ($includeSelf) {
66
- try {
67
- $selfMatch = $element.FindFirst([TreeScope]::Element, $condition);
68
- if ($null -ne $selfMatch) { $matches.Add($selfMatch); }
69
- } catch { }
70
- }
71
-
72
- $stack = New-Object System.Collections.Generic.Stack[AutomationElement];
73
- try {
74
- $first = $walker.GetFirstChild($element);
75
- if ($null -ne $first) { $stack.Push($first); }
76
- } catch { }
77
-
78
- while ($stack.Count -gt 0) {
79
- $current = $stack.Pop();
80
- try {
81
- if ($null -ne $current.FindFirst([TreeScope]::Element, $condition)) {
82
- $matches.Add($current);
83
- }
84
- $sibling = $walker.GetNextSibling($current);
85
- if ($null -ne $sibling) { $stack.Push($sibling); }
86
- $firstChild = $walker.GetFirstChild($current);
87
- if ($null -ne $firstChild) { $stack.Push($firstChild); }
88
- } catch {
89
- # Dead element / COM disconnect / property fetch failed.
90
- # Skip it and keep walking - a single bad node shouldn't
91
- # abort the entire search.
92
- continue;
93
- }
94
- }
95
-
96
- return $matches;
97
- }
98
-
99
- function Find-Descendant {
100
- param (
101
- [Parameter(Mandatory=$false)]
102
- [AutomationElement]$element,
103
- [Parameter(Mandatory=$false)]
104
- [Condition]$condition,
105
- [switch]$includeSelf
106
- );
107
-
108
- if ($null -eq $element -or $null -eq $condition) { return $null };
109
-
110
- $scope = if ($includeSelf) { [TreeScope]::Subtree } else { [TreeScope]::Descendants };
111
- return $element.FindFirst($scope, $condition);
112
- }
113
-
114
- function Find-AllDescendants {
115
- param (
116
- [Parameter(Mandatory=$false)]
117
- [AutomationElement]$element,
118
- [Parameter(Mandatory=$false)]
119
- [Condition]$condition,
120
- [switch]$includeSelf
121
- );
122
-
123
- if ($null -eq $element -or $null -eq $condition) { return @() };
124
-
125
- # Fast vs safe path selection.
126
- #
127
- # The built-in UIA FindAll([TreeScope]::Subtree, ...) is dramatically
128
- # faster than walking with TreeWalker for bounded subtrees, but on
129
- # the desktop root it materialises so much intermediate state that
130
- # it throws System.OutOfMemoryException on busy hosts. That kills
131
- # the PowerShell subprocess and (under memory pressure) can cascade
132
- # into Appium's Node.js process being killed by the Windows OOM
133
- # handler.
134
- #
135
- # Route any search starting at [AutomationElement]::RootElement
136
- # through the streaming walker. All other (window-scoped) searches
137
- # keep the fast path.
138
- $isDesktopRoot = $false;
139
- try {
140
- $isDesktopRoot = [object]::ReferenceEquals($element, [AutomationElement]::RootElement) -or $element.Equals([AutomationElement]::RootElement);
141
- } catch { }
142
-
143
- if ($isDesktopRoot) {
144
- return Find-AllDescendantsStreaming -element $element -condition $condition -includeSelf:$includeSelf;
145
- }
146
-
147
- $scope = if ($includeSelf) { [TreeScope]::Subtree } else { [TreeScope]::Descendants };
148
- try {
149
- return $element.FindAll($scope, $condition);
150
- } catch [System.OutOfMemoryException] {
151
- # Defence in depth: if FindAll OOMs on a non-root scope (huge
152
- # Edge window with many tabs, complex dashboards, etc.), fall
153
- # back to streaming. Note CLR OOM isn't always catchable; this
154
- # is best-effort.
155
- return Find-AllDescendantsStreaming -element $element -condition $condition -includeSelf:$includeSelf;
156
- }
157
- }
35
+ exports.FIND_DESCENDANTS_FUNCTIONS = (0, powershell_1.pwsh /* ps1 */) `
36
+ # Streaming, memory-bounded subtree walk used as the safe fallback for
37
+ # Find-AllDescendants when the fast-path FindAll(Subtree) would either
38
+ # OutOfMemoryException (observed on desktop-rooted sessions: UIA's
39
+ # FindAll on a large tree materialises too much intermediate state) or
40
+ # take pathologically long.
41
+ #
42
+ # Iterative DFS via TreeWalker. At any moment, only a stack-depth's
43
+ # worth of AutomationElement references + the matches list is in memory
44
+ # - not the entire visited set. Each element is filter-tested
45
+ # individually via FindFirst([Element], $condition), which is O(1) in
46
+ # the size of the subtree.
47
+ #
48
+ # The walker respects the active $cacheRequest's TreeFilter (same as
49
+ # the upstream walker behaviour FindAll uses), so excluded views (e.g.
50
+ # Chrome content) stay excluded.
51
+ function Find-AllDescendantsStreaming {
52
+ param (
53
+ [Parameter(Mandatory=$false)]
54
+ [AutomationElement]$element,
55
+ [Parameter(Mandatory=$false)]
56
+ [Condition]$condition,
57
+ [switch]$includeSelf
58
+ );
59
+
60
+ if ($null -eq $element -or $null -eq $condition) { return @() };
61
+
62
+ $walker = [TreeWalker]::new($cacheRequest.TreeFilter);
63
+ $matches = New-Object System.Collections.Generic.List[AutomationElement];
64
+
65
+ if ($includeSelf) {
66
+ try {
67
+ $selfMatch = $element.FindFirst([TreeScope]::Element, $condition);
68
+ if ($null -ne $selfMatch) { $matches.Add($selfMatch); }
69
+ } catch { }
70
+ }
71
+
72
+ $stack = New-Object System.Collections.Generic.Stack[AutomationElement];
73
+ try {
74
+ $first = $walker.GetFirstChild($element);
75
+ if ($null -ne $first) { $stack.Push($first); }
76
+ } catch { }
77
+
78
+ while ($stack.Count -gt 0) {
79
+ $current = $stack.Pop();
80
+ try {
81
+ if ($null -ne $current.FindFirst([TreeScope]::Element, $condition)) {
82
+ $matches.Add($current);
83
+ }
84
+ $sibling = $walker.GetNextSibling($current);
85
+ if ($null -ne $sibling) { $stack.Push($sibling); }
86
+ $firstChild = $walker.GetFirstChild($current);
87
+ if ($null -ne $firstChild) { $stack.Push($firstChild); }
88
+ } catch {
89
+ # Dead element / COM disconnect / property fetch failed.
90
+ # Skip it and keep walking - a single bad node shouldn't
91
+ # abort the entire search.
92
+ continue;
93
+ }
94
+ }
95
+
96
+ return $matches;
97
+ }
98
+
99
+ function Find-Descendant {
100
+ param (
101
+ [Parameter(Mandatory=$false)]
102
+ [AutomationElement]$element,
103
+ [Parameter(Mandatory=$false)]
104
+ [Condition]$condition,
105
+ [switch]$includeSelf
106
+ );
107
+
108
+ if ($null -eq $element -or $null -eq $condition) { return $null };
109
+
110
+ $scope = if ($includeSelf) { [TreeScope]::Subtree } else { [TreeScope]::Descendants };
111
+ return $element.FindFirst($scope, $condition);
112
+ }
113
+
114
+ function Find-AllDescendants {
115
+ param (
116
+ [Parameter(Mandatory=$false)]
117
+ [AutomationElement]$element,
118
+ [Parameter(Mandatory=$false)]
119
+ [Condition]$condition,
120
+ [switch]$includeSelf
121
+ );
122
+
123
+ if ($null -eq $element -or $null -eq $condition) { return @() };
124
+
125
+ # Fast vs safe path selection.
126
+ #
127
+ # The built-in UIA FindAll([TreeScope]::Subtree, ...) is dramatically
128
+ # faster than walking with TreeWalker for bounded subtrees, but on
129
+ # the desktop root it materialises so much intermediate state that
130
+ # it throws System.OutOfMemoryException on busy hosts. That kills
131
+ # the PowerShell subprocess and (under memory pressure) can cascade
132
+ # into Appium's Node.js process being killed by the Windows OOM
133
+ # handler.
134
+ #
135
+ # Route any search starting at [AutomationElement]::RootElement
136
+ # through the streaming walker. All other (window-scoped) searches
137
+ # keep the fast path.
138
+ $isDesktopRoot = $false;
139
+ try {
140
+ $isDesktopRoot = [object]::ReferenceEquals($element, [AutomationElement]::RootElement) -or $element.Equals([AutomationElement]::RootElement);
141
+ } catch { }
142
+
143
+ if ($isDesktopRoot) {
144
+ return Find-AllDescendantsStreaming -element $element -condition $condition -includeSelf:$includeSelf;
145
+ }
146
+
147
+ $scope = if ($includeSelf) { [TreeScope]::Subtree } else { [TreeScope]::Descendants };
148
+ try {
149
+ return $element.FindAll($scope, $condition);
150
+ } catch [System.OutOfMemoryException] {
151
+ # Defence in depth: if FindAll OOMs on a non-root scope (huge
152
+ # Edge window with many tabs, complex dashboards, etc.), fall
153
+ # back to streaming. Note CLR OOM isn't always catchable; this
154
+ # is best-effort.
155
+ return Find-AllDescendantsStreaming -element $element -condition $condition -includeSelf:$includeSelf;
156
+ }
157
+ }
158
158
  `;
159
- exports.FIND_CHILDREN_RECURSIVELY = (0, powershell_1.pwsh /* ps1 */) `
160
- function Find-ChildrenRecursively {
161
- param (
162
- [Parameter(Mandatory=$false)]
163
- [AutomationElement]$element,
164
- [Parameter(Mandatory=$false)]
165
- [Condition]$condition,
166
- [Parameter(Mandatory=$false)]
167
- [bool]$includeSelf = $false
168
- );
169
-
170
- if ($null -eq $element -or $null -eq $condition) { return $null };
171
-
172
- $scope = if ($includeSelf) {
173
- [TreeScope]::Element -bor [TreeScope]::Children;
174
- } else {
175
- [TreeScope]::Children;
176
- };
177
-
178
- $validChild = $element.FindFirst($scope, $condition);
179
-
180
- if ($validChild -ne $null) {
181
- return $validChild;
182
- }
183
-
184
- $children = $element.FindAll([TreeScope]::Children, [Condition]::TrueCondition);
185
- foreach ($child in $children) {
186
- $result = Find-AllChildrenRecursively -element $child -condition $condition -returnFirstResult $true;
187
- if ($result -ne $null) {
188
- return $result[0];
189
- }
190
- }
191
-
192
- return $null;
193
- }
194
-
195
- function Find-AllChildrenRecursively {
196
- param (
197
- [Parameter(Mandatory=$false)]
198
- [AutomationElement]$element,
199
- [Parameter(Mandatory=$false)]
200
- [Condition]$condition,
201
- [bool]$returnFirstResult = $false,
202
- [Parameter(Mandatory=$false)]
203
- [bool]$includeSelf = $false
204
- );
205
-
206
- if ($null -eq $element -or $null -eq $condition) { return @() };
207
-
208
- $children = $element.FindAll([TreeScope]::Children, [Condition]::TrueCondition);
209
- $validChildren = @($children | Where-Object { $_.FindFirst([TreeScope]::Element, $condition) -ne $null });
210
-
211
- if ($includeSelf) {
212
- $self = $element.FindFirst([TreeScope]::Element, $condition);
213
- }
214
-
215
- if ($null -ne $self) {
216
- $validChildren += $self;
217
- }
218
-
219
- foreach ($child in $children) {
220
- $Allresults = Find-AllChildrenRecursively -element $child -condition $condition;
221
- if ($returnFirstResult -and $Allresults.Count -gt 0) {
222
- return $Allresults;
223
- }
224
-
225
- foreach ($result in $Allresults) {
226
- $validChildren += ($result | Where-Object { $_.FindFirst([TreeScope]::Element, $condition) -ne $null });
227
- }
228
- }
229
-
230
- return $validChildren;
231
- }
159
+ exports.FIND_CHILDREN_RECURSIVELY = (0, powershell_1.pwsh /* ps1 */) `
160
+ function Find-ChildrenRecursively {
161
+ param (
162
+ [Parameter(Mandatory=$false)]
163
+ [AutomationElement]$element,
164
+ [Parameter(Mandatory=$false)]
165
+ [Condition]$condition,
166
+ [Parameter(Mandatory=$false)]
167
+ [bool]$includeSelf = $false
168
+ );
169
+
170
+ if ($null -eq $element -or $null -eq $condition) { return $null };
171
+
172
+ $scope = if ($includeSelf) {
173
+ [TreeScope]::Element -bor [TreeScope]::Children;
174
+ } else {
175
+ [TreeScope]::Children;
176
+ };
177
+
178
+ $validChild = $element.FindFirst($scope, $condition);
179
+
180
+ if ($validChild -ne $null) {
181
+ return $validChild;
182
+ }
183
+
184
+ $children = $element.FindAll([TreeScope]::Children, [Condition]::TrueCondition);
185
+ foreach ($child in $children) {
186
+ $result = Find-AllChildrenRecursively -element $child -condition $condition -returnFirstResult $true;
187
+ if ($result -ne $null) {
188
+ return $result[0];
189
+ }
190
+ }
191
+
192
+ return $null;
193
+ }
194
+
195
+ function Find-AllChildrenRecursively {
196
+ param (
197
+ [Parameter(Mandatory=$false)]
198
+ [AutomationElement]$element,
199
+ [Parameter(Mandatory=$false)]
200
+ [Condition]$condition,
201
+ [bool]$returnFirstResult = $false,
202
+ [Parameter(Mandatory=$false)]
203
+ [bool]$includeSelf = $false
204
+ );
205
+
206
+ if ($null -eq $element -or $null -eq $condition) { return @() };
207
+
208
+ $children = $element.FindAll([TreeScope]::Children, [Condition]::TrueCondition);
209
+ $validChildren = @($children | Where-Object { $_.FindFirst([TreeScope]::Element, $condition) -ne $null });
210
+
211
+ if ($includeSelf) {
212
+ $self = $element.FindFirst([TreeScope]::Element, $condition);
213
+ }
214
+
215
+ if ($null -ne $self) {
216
+ $validChildren += $self;
217
+ }
218
+
219
+ foreach ($child in $children) {
220
+ $Allresults = Find-AllChildrenRecursively -element $child -condition $condition;
221
+ if ($returnFirstResult -and $Allresults.Count -gt 0) {
222
+ return $Allresults;
223
+ }
224
+
225
+ foreach ($result in $Allresults) {
226
+ $validChildren += ($result | Where-Object { $_.FindFirst([TreeScope]::Element, $condition) -ne $null });
227
+ }
228
+ }
229
+
230
+ return $validChildren;
231
+ }
232
232
  `;
233
- exports.PAGE_SOURCE = (0, powershell_1.pwsh /* ps1 */) `
234
- # Builds the XML node for a single AutomationElement (no traversal).
235
- # Pulled out of Get-PageSource so the iterative walker below can call it
236
- # per node without each call adding a PS stack frame.
237
- function Build-PageSourceNode {
238
- param (
239
- [Parameter(Mandatory = $true)]
240
- [AutomationElement]$element,
241
- [Parameter(Mandatory = $true)]
242
- [Xml.XmlDocument]$xmlDoc
243
- );
244
-
245
- $localizedControlType = $element.GetCurrentPropertyValue([AutomationElement]::LocalizedControlTypeProperty);
246
- $controlType = $element.GetCurrentPropertyValue([AutomationElement]::ControlTypeProperty);
247
-
248
- $tagName = '';
249
- try {
250
- $tagName = $controlType.ProgrammaticName.Split('.')[-1];
251
- } catch {
252
- # fallback to LocalizedControlType if ControlType is empty
253
- $tagName = -join ($localizedControlType -split ' ' | ForEach-Object {
254
- $_.Substring(0, 1).ToUpper() + $_.Substring(1).ToLower();
255
- });
256
- }
257
- if ($tagName -eq 'DataGrid') { $tagName = 'List' }
258
- elseif ($tagName -eq 'DataItem') { $tagName = 'ListItem' };
259
-
260
- $acceleratorKey = $element.GetCurrentPropertyValue([AutomationElement]::AcceleratorKeyProperty);
261
- $accessKey = $element.GetCurrentPropertyValue([AutomationElement]::AccessKeyProperty);
262
- $automationId = $element.GetCurrentPropertyValue([AutomationElement]::AutomationIdProperty);
263
- $className = $element.GetCurrentPropertyValue([AutomationElement]::ClassNameProperty);
264
- $frameworkId = $element.GetCurrentPropertyValue([AutomationElement]::FrameworkIdProperty);
265
- $hasKeyboardfocus = $element.GetCurrentPropertyValue([AutomationElement]::HasKeyboardfocusProperty);
266
- $helpText = $element.GetCurrentPropertyValue([AutomationElement]::HelpTextProperty);
267
- $isContentelement = $element.GetCurrentPropertyValue([AutomationElement]::IsContentelementProperty);
268
- $isControlelement = $element.GetCurrentPropertyValue([AutomationElement]::IsControlelementProperty);
269
- $isEnabled = $element.GetCurrentPropertyValue([AutomationElement]::IsEnabledProperty);
270
- $isKeyboardfocusable = $element.GetCurrentPropertyValue([AutomationElement]::IsKeyboardfocusableProperty);
271
- $isOffscreen = $element.GetCurrentPropertyValue([AutomationElement]::IsOffscreenProperty);
272
- $isPassword = $element.GetCurrentPropertyValue([AutomationElement]::IsPasswordProperty);
273
- $isRequiredforform = $element.GetCurrentPropertyValue([AutomationElement]::IsRequiredforformProperty);
274
- $itemStatus = $element.GetCurrentPropertyValue([AutomationElement]::ItemStatusProperty);
275
- $itemType = $element.GetCurrentPropertyValue([AutomationElement]::ItemTypeProperty);
276
- $name = $element.GetCurrentPropertyValue([AutomationElement]::NameProperty);
277
- $orientation = $element.GetCurrentPropertyValue([AutomationElement]::OrientationProperty);
278
- $processId = $element.GetCurrentPropertyValue([AutomationElement]::ProcessIdProperty);
279
- $runtimeId = $element.GetCurrentPropertyValue([AutomationElement]::RuntimeIdProperty) -join '.';
280
- $boundingRectangle = $element.Current.BoundingRectangle;
281
- $x = $boundingRectangle.X - $rootElement.Current.BoundingRectangle.X;
282
- $y = $boundingRectangle.Y - $rootElement.Current.BoundingRectangle.Y;
283
- $width = $boundingRectangle.Width;
284
- $height = $boundingRectangle.Height;
285
-
286
- $newXmlElement = $xmlDoc.CreateElement($tagName);
287
- $newXmlElement.SetAttribute("AcceleratorKey", $acceleratorKey);
288
- $newXmlElement.SetAttribute("AccessKey", $accessKey);
289
- $newXmlElement.SetAttribute("AutomationId", $automationId);
290
- $newXmlElement.SetAttribute("ClassName", $className);
291
- $newXmlElement.SetAttribute("FrameworkId", $frameworkId);
292
- $newXmlElement.SetAttribute("HasKeyboardfocus", $hasKeyboardfocus);
293
- $newXmlElement.SetAttribute("HelpText", $helpText);
294
- $newXmlElement.SetAttribute("IsContentelement", $isContentelement);
295
- $newXmlElement.SetAttribute("IsControlelement", $isControlelement);
296
- $newXmlElement.SetAttribute("IsEnabled", $isEnabled);
297
- $newXmlElement.SetAttribute("IsKeyboardfocusable", $isKeyboardfocusable);
298
- $newXmlElement.SetAttribute("IsOffscreen", $isOffscreen);
299
- $newXmlElement.SetAttribute("IsPassword", $isPassword);
300
- $newXmlElement.SetAttribute("IsRequiredforform", $isRequiredforform);
301
- $newXmlElement.SetAttribute("ItemStatus", $itemStatus);
302
- $newXmlElement.SetAttribute("ItemType", $itemType);
303
- $newXmlElement.SetAttribute("LocalizedControlType", $localizedControlType);
304
- $newXmlElement.SetAttribute("Name", $name);
305
- $newXmlElement.SetAttribute("Orientation", $orientation);
306
- $newXmlElement.SetAttribute("ProcessId", $processId);
307
- $newXmlElement.SetAttribute("RuntimeId", $runtimeId);
308
- $newXmlElement.SetAttribute("x", $x);
309
- $newXmlElement.SetAttribute("y", $y);
310
- $newXmlElement.SetAttribute("width", $width);
311
- $newXmlElement.SetAttribute("height", $height);
312
-
313
- $pattern = $null;
314
- if ($element.TryGetCurrentPattern([WindowPattern]::Pattern, [ref]$pattern)) {
315
- $newXmlElement.SetAttribute("CanMaximize", $pattern.Current.CanMaximize);
316
- $newXmlElement.SetAttribute("CanMinimize", $pattern.Current.CanMinimize);
317
- $newXmlElement.SetAttribute("IsModal", $pattern.Current.IsModal);
318
- $newXmlElement.SetAttribute("WindowVisualState", $pattern.Current.WindowVisualState);
319
- $newXmlElement.SetAttribute("WindowInteractionState", $pattern.Current.WindowInteractionState);
320
- $newXmlElement.SetAttribute("IsTopmost", $pattern.Current.IsTopmost);
321
- }
322
- if ($element.TryGetCurrentPattern([TransformPattern]::Pattern, [ref]$pattern)) {
323
- $newXmlElement.SetAttribute("CanRotate", $pattern.Current.CanRotate);
324
- $newXmlElement.SetAttribute("CanResize", $pattern.Current.CanResize);
325
- $newXmlElement.SetAttribute("CanMove", $pattern.Current.CanMove);
326
- }
327
-
328
- # TODO: more to be added depending on the available patterns
329
-
330
- return $newXmlElement;
331
- }
332
-
333
- # Iterative BFS over the UIA subtree, producing the same XML output as
334
- # the previous recursive Get-PageSource. The recursive version blew the
335
- # PS function-call stack on deep desktop-rooted trees, which crashed the
336
- # PS subprocess (~5000-frame ceiling). The iterative version keeps stack
337
- # depth at O(1) regardless of tree depth; memory at any moment is bounded
338
- # by the queue size (siblings still to visit), not by tree depth.
339
- #
340
- # Public signature unchanged so callers don't break:
341
- # Get-PageSource $element - new document, return root XML element
342
- # Get-PageSource $element $xmlDoc $xmlElement - append under $xmlElement (legacy)
343
- function Get-PageSource {
344
- param (
345
- [Parameter(Mandatory = $true)]
346
- [AutomationElement]$element,
347
- [Xml.XmlDocument]$xmlDoc,
348
- [Xml.XmlElement]$xmlElement
349
- );
350
-
351
- if ($null -eq $xmlDoc) { $xmlDoc = [Xml.XmlDocument]::new() };
352
-
353
- # Queue of (element, parentXmlElementOrNull). parentXmlElement = $null
354
- # for the seed entry means "append to xmlDoc directly".
355
- $queue = New-Object System.Collections.Queue;
356
- $queue.Enqueue(@($element, $xmlElement));
357
-
358
- $resultXmlElement = $null;
359
-
360
- while ($queue.Count -gt 0) {
361
- $pair = $queue.Dequeue();
362
- $curElement = $pair[0];
363
- $curParent = $pair[1];
364
-
365
- try {
366
- $newXmlElement = Build-PageSourceNode -element $curElement -xmlDoc $xmlDoc;
367
-
368
- if ($null -eq $curParent) {
369
- $appended = $xmlDoc.AppendChild($newXmlElement);
370
- } else {
371
- $appended = $curParent.AppendChild($newXmlElement);
372
- }
373
-
374
- if ($null -eq $resultXmlElement) { $resultXmlElement = $appended };
375
-
376
- # Enqueue children with the freshly-appended node as their parent.
377
- $curElement.FindAll([TreeScope]::Children, $cacheRequest.TreeFilter) | ForEach-Object {
378
- $queue.Enqueue(@($_, $appended));
379
- };
380
- } catch {
381
- # Skip this node and keep walking the rest of the tree.
382
- continue;
383
- }
384
- }
385
-
386
- return $resultXmlElement;
387
- }
233
+ exports.PAGE_SOURCE = (0, powershell_1.pwsh /* ps1 */) `
234
+ # Builds the XML node for a single AutomationElement (no traversal).
235
+ # Pulled out of Get-PageSource so the iterative walker below can call it
236
+ # per node without each call adding a PS stack frame.
237
+ function Build-PageSourceNode {
238
+ param (
239
+ [Parameter(Mandatory = $true)]
240
+ [AutomationElement]$element,
241
+ [Parameter(Mandatory = $true)]
242
+ [Xml.XmlDocument]$xmlDoc
243
+ );
244
+
245
+ $localizedControlType = $element.GetCurrentPropertyValue([AutomationElement]::LocalizedControlTypeProperty);
246
+ $controlType = $element.GetCurrentPropertyValue([AutomationElement]::ControlTypeProperty);
247
+
248
+ $tagName = '';
249
+ try {
250
+ $tagName = $controlType.ProgrammaticName.Split('.')[-1];
251
+ } catch {
252
+ # fallback to LocalizedControlType if ControlType is empty
253
+ $tagName = -join ($localizedControlType -split ' ' | ForEach-Object {
254
+ $_.Substring(0, 1).ToUpper() + $_.Substring(1).ToLower();
255
+ });
256
+ }
257
+ if ($tagName -eq 'DataGrid') { $tagName = 'List' }
258
+ elseif ($tagName -eq 'DataItem') { $tagName = 'ListItem' };
259
+
260
+ $acceleratorKey = $element.GetCurrentPropertyValue([AutomationElement]::AcceleratorKeyProperty);
261
+ $accessKey = $element.GetCurrentPropertyValue([AutomationElement]::AccessKeyProperty);
262
+ $automationId = $element.GetCurrentPropertyValue([AutomationElement]::AutomationIdProperty);
263
+ $className = $element.GetCurrentPropertyValue([AutomationElement]::ClassNameProperty);
264
+ $frameworkId = $element.GetCurrentPropertyValue([AutomationElement]::FrameworkIdProperty);
265
+ $hasKeyboardfocus = $element.GetCurrentPropertyValue([AutomationElement]::HasKeyboardfocusProperty);
266
+ $helpText = $element.GetCurrentPropertyValue([AutomationElement]::HelpTextProperty);
267
+ $isContentelement = $element.GetCurrentPropertyValue([AutomationElement]::IsContentelementProperty);
268
+ $isControlelement = $element.GetCurrentPropertyValue([AutomationElement]::IsControlelementProperty);
269
+ $isEnabled = $element.GetCurrentPropertyValue([AutomationElement]::IsEnabledProperty);
270
+ $isKeyboardfocusable = $element.GetCurrentPropertyValue([AutomationElement]::IsKeyboardfocusableProperty);
271
+ $isOffscreen = $element.GetCurrentPropertyValue([AutomationElement]::IsOffscreenProperty);
272
+ $isPassword = $element.GetCurrentPropertyValue([AutomationElement]::IsPasswordProperty);
273
+ $isRequiredforform = $element.GetCurrentPropertyValue([AutomationElement]::IsRequiredforformProperty);
274
+ $itemStatus = $element.GetCurrentPropertyValue([AutomationElement]::ItemStatusProperty);
275
+ $itemType = $element.GetCurrentPropertyValue([AutomationElement]::ItemTypeProperty);
276
+ $name = $element.GetCurrentPropertyValue([AutomationElement]::NameProperty);
277
+ $orientation = $element.GetCurrentPropertyValue([AutomationElement]::OrientationProperty);
278
+ $processId = $element.GetCurrentPropertyValue([AutomationElement]::ProcessIdProperty);
279
+ $runtimeId = $element.GetCurrentPropertyValue([AutomationElement]::RuntimeIdProperty) -join '.';
280
+ $boundingRectangle = $element.Current.BoundingRectangle;
281
+ $x = $boundingRectangle.X - $rootElement.Current.BoundingRectangle.X;
282
+ $y = $boundingRectangle.Y - $rootElement.Current.BoundingRectangle.Y;
283
+ $width = $boundingRectangle.Width;
284
+ $height = $boundingRectangle.Height;
285
+
286
+ $newXmlElement = $xmlDoc.CreateElement($tagName);
287
+ $newXmlElement.SetAttribute("AcceleratorKey", $acceleratorKey);
288
+ $newXmlElement.SetAttribute("AccessKey", $accessKey);
289
+ $newXmlElement.SetAttribute("AutomationId", $automationId);
290
+ $newXmlElement.SetAttribute("ClassName", $className);
291
+ $newXmlElement.SetAttribute("FrameworkId", $frameworkId);
292
+ $newXmlElement.SetAttribute("HasKeyboardfocus", $hasKeyboardfocus);
293
+ $newXmlElement.SetAttribute("HelpText", $helpText);
294
+ $newXmlElement.SetAttribute("IsContentelement", $isContentelement);
295
+ $newXmlElement.SetAttribute("IsControlelement", $isControlelement);
296
+ $newXmlElement.SetAttribute("IsEnabled", $isEnabled);
297
+ $newXmlElement.SetAttribute("IsKeyboardfocusable", $isKeyboardfocusable);
298
+ $newXmlElement.SetAttribute("IsOffscreen", $isOffscreen);
299
+ $newXmlElement.SetAttribute("IsPassword", $isPassword);
300
+ $newXmlElement.SetAttribute("IsRequiredforform", $isRequiredforform);
301
+ $newXmlElement.SetAttribute("ItemStatus", $itemStatus);
302
+ $newXmlElement.SetAttribute("ItemType", $itemType);
303
+ $newXmlElement.SetAttribute("LocalizedControlType", $localizedControlType);
304
+ $newXmlElement.SetAttribute("Name", $name);
305
+ $newXmlElement.SetAttribute("Orientation", $orientation);
306
+ $newXmlElement.SetAttribute("ProcessId", $processId);
307
+ $newXmlElement.SetAttribute("RuntimeId", $runtimeId);
308
+ $newXmlElement.SetAttribute("x", $x);
309
+ $newXmlElement.SetAttribute("y", $y);
310
+ $newXmlElement.SetAttribute("width", $width);
311
+ $newXmlElement.SetAttribute("height", $height);
312
+
313
+ $pattern = $null;
314
+ if ($element.TryGetCurrentPattern([WindowPattern]::Pattern, [ref]$pattern)) {
315
+ $newXmlElement.SetAttribute("CanMaximize", $pattern.Current.CanMaximize);
316
+ $newXmlElement.SetAttribute("CanMinimize", $pattern.Current.CanMinimize);
317
+ $newXmlElement.SetAttribute("IsModal", $pattern.Current.IsModal);
318
+ $newXmlElement.SetAttribute("WindowVisualState", $pattern.Current.WindowVisualState);
319
+ $newXmlElement.SetAttribute("WindowInteractionState", $pattern.Current.WindowInteractionState);
320
+ $newXmlElement.SetAttribute("IsTopmost", $pattern.Current.IsTopmost);
321
+ }
322
+ if ($element.TryGetCurrentPattern([TransformPattern]::Pattern, [ref]$pattern)) {
323
+ $newXmlElement.SetAttribute("CanRotate", $pattern.Current.CanRotate);
324
+ $newXmlElement.SetAttribute("CanResize", $pattern.Current.CanResize);
325
+ $newXmlElement.SetAttribute("CanMove", $pattern.Current.CanMove);
326
+ }
327
+
328
+ # TODO: more to be added depending on the available patterns
329
+
330
+ return $newXmlElement;
331
+ }
332
+
333
+ # Iterative BFS over the UIA subtree, producing the same XML output as
334
+ # the previous recursive Get-PageSource. The recursive version blew the
335
+ # PS function-call stack on deep desktop-rooted trees, which crashed the
336
+ # PS subprocess (~5000-frame ceiling). The iterative version keeps stack
337
+ # depth at O(1) regardless of tree depth; memory at any moment is bounded
338
+ # by the queue size (siblings still to visit), not by tree depth.
339
+ #
340
+ # Public signature unchanged so callers don't break:
341
+ # Get-PageSource $element - new document, return root XML element
342
+ # Get-PageSource $element $xmlDoc $xmlElement - append under $xmlElement (legacy)
343
+ function Get-PageSource {
344
+ param (
345
+ [Parameter(Mandatory = $true)]
346
+ [AutomationElement]$element,
347
+ [Xml.XmlDocument]$xmlDoc,
348
+ [Xml.XmlElement]$xmlElement
349
+ );
350
+
351
+ if ($null -eq $xmlDoc) { $xmlDoc = [Xml.XmlDocument]::new() };
352
+
353
+ # Queue of (element, parentXmlElementOrNull). parentXmlElement = $null
354
+ # for the seed entry means "append to xmlDoc directly".
355
+ $queue = New-Object System.Collections.Queue;
356
+ $queue.Enqueue(@($element, $xmlElement));
357
+
358
+ $resultXmlElement = $null;
359
+
360
+ while ($queue.Count -gt 0) {
361
+ $pair = $queue.Dequeue();
362
+ $curElement = $pair[0];
363
+ $curParent = $pair[1];
364
+
365
+ try {
366
+ $newXmlElement = Build-PageSourceNode -element $curElement -xmlDoc $xmlDoc;
367
+
368
+ if ($null -eq $curParent) {
369
+ $appended = $xmlDoc.AppendChild($newXmlElement);
370
+ } else {
371
+ $appended = $curParent.AppendChild($newXmlElement);
372
+ }
373
+
374
+ if ($null -eq $resultXmlElement) { $resultXmlElement = $appended };
375
+
376
+ # Enqueue children with the freshly-appended node as their parent.
377
+ $curElement.FindAll([TreeScope]::Children, $cacheRequest.TreeFilter) | ForEach-Object {
378
+ $queue.Enqueue(@($_, $appended));
379
+ };
380
+ } catch {
381
+ # Skip this node and keep walking the rest of the tree.
382
+ continue;
383
+ }
384
+ }
385
+
386
+ return $resultXmlElement;
387
+ }
388
388
  `;
389
389
  //# sourceMappingURL=functions.js.map