gdharness 1.3.42 → 1.3.44
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/build/cli.js +383 -243
- package/build/godot/addons/auto_reload/auto_reload.gd +18 -19
- package/build/godot/addons/gdharness_editor/animation_reads.gd +55 -33
- package/build/godot/addons/gdharness_editor/bridge_client.gd +53 -58
- package/build/godot/addons/gdharness_editor/declared_values.gd +68 -32
- package/build/godot/addons/gdharness_editor/file_reads.gd +83 -42
- package/build/godot/addons/gdharness_editor/file_walk.gd +12 -5
- package/build/godot/addons/gdharness_editor/headless_check.gd +68 -44
- package/build/godot/addons/gdharness_editor/plugin.gd +2 -3
- package/build/godot/addons/gdharness_editor/property_paths.gd +22 -12
- package/build/godot/addons/gdharness_editor/property_values.gd +143 -78
- package/build/godot/addons/gdharness_editor/reading.gd +51 -17
- package/build/godot/addons/gdharness_editor/same_values.gd +4 -4
- package/build/godot/addons/gdharness_editor/scene_file.gd +127 -80
- package/build/godot/addons/gdharness_editor/scene_uids.gd +12 -6
- package/build/godot/addons/gdharness_editor/serialisation.gd +75 -51
- package/build/godot/addons/gdharness_editor/setting_reads.gd +7 -6
- package/build/godot/addons/gdharness_editor/tool_executor.gd +3 -6
- package/build/godot/addons/gdharness_editor/tools/animation_states.gd +37 -27
- package/build/godot/addons/gdharness_editor/tools/animation_tools.gd +79 -49
- package/build/godot/addons/gdharness_editor/tools/animation_tracks.gd +70 -40
- package/build/godot/addons/gdharness_editor/tools/class_tools.gd +65 -42
- package/build/godot/addons/gdharness_editor/tools/filesystem_tools.gd +24 -22
- package/build/godot/addons/gdharness_editor/tools/navigation_bake.gd +49 -29
- package/build/godot/addons/gdharness_editor/tools/play_tools.gd +26 -21
- package/build/godot/addons/gdharness_editor/tools/profile_tools.gd +40 -40
- package/build/godot/addons/gdharness_editor/tools/resource_tools.gd +166 -107
- package/build/godot/addons/gdharness_editor/tools/scene_groups.gd +16 -9
- package/build/godot/addons/gdharness_editor/tools/scene_kin.gd +68 -41
- package/build/godot/addons/gdharness_editor/tools/scene_paths.gd +35 -20
- package/build/godot/addons/gdharness_editor/tools/scene_placing.gd +28 -13
- package/build/godot/addons/gdharness_editor/tools/scene_sharing.gd +12 -5
- package/build/godot/addons/gdharness_editor/tools/scene_tools.gd +113 -67
- package/build/godot/addons/gdharness_editor/tools/script_paths.gd +20 -8
- package/build/godot/addons/gdharness_editor/tools/settings_tools.gd +11 -8
- package/build/godot/addons/gdharness_editor/tools/signal_tools.gd +47 -34
- package/build/godot/addons/gdharness_editor/tools/tileset_tools.gd +77 -50
- package/build/godot/addons/gdharness_editor/value_shapes.gd +5 -6
- package/build/godot/addons/gdharness_runtime/call_errors.gd +1 -2
- package/build/godot/addons/gdharness_runtime/declared_values.gd +68 -32
- package/build/godot/addons/gdharness_runtime/error_report.gd +1 -2
- package/build/godot/addons/gdharness_runtime/reading.gd +51 -17
- package/build/godot/addons/gdharness_runtime/runtime_accessibility.gd +84 -63
- package/build/godot/addons/gdharness_runtime/runtime_autoload.gd +149 -147
- package/build/godot/addons/gdharness_runtime/runtime_capture.gd +64 -42
- package/build/godot/addons/gdharness_runtime/runtime_changes.gd +184 -122
- package/build/godot/addons/gdharness_runtime/runtime_frames.gd +2 -2
- package/build/godot/addons/gdharness_runtime/runtime_hover.gd +24 -20
- package/build/godot/addons/gdharness_runtime/runtime_input.gd +134 -92
- package/build/godot/addons/gdharness_runtime/runtime_items.gd +29 -13
- package/build/godot/addons/gdharness_runtime/runtime_menus.gd +0 -1
- package/build/godot/addons/gdharness_runtime/runtime_mouse.gd +34 -17
- package/build/godot/addons/gdharness_runtime/runtime_pad.gd +17 -13
- package/build/godot/addons/gdharness_runtime/runtime_paths.gd +84 -46
- package/build/godot/addons/gdharness_runtime/runtime_queries.gd +117 -79
- package/build/godot/addons/gdharness_runtime/runtime_says.gd +14 -17
- package/build/godot/addons/gdharness_runtime/runtime_screen.gd +23 -16
- package/build/godot/addons/gdharness_runtime/runtime_targets.gd +117 -66
- package/build/godot/addons/gdharness_runtime/runtime_touch.gd +15 -15
- package/build/godot/addons/gdharness_runtime/runtime_typing.gd +44 -27
- package/build/godot/addons/gdharness_runtime/runtime_values.gd +108 -73
- package/build/godot/addons/gdharness_runtime/runtime_waits.gd +111 -84
- package/build/godot/addons/gdharness_runtime/runtime_words.gd +10 -7
- package/build/godot/addons/gdharness_runtime/serialisation.gd +75 -51
- package/build/godot/addons/gdharness_runtime/value_shapes.gd +5 -6
- package/build/godot/addons/gdharness_tests/bench.gd +4 -5
- package/build/godot/addons/gdharness_tests/event.gd +10 -5
- package/build/godot/addons/gdharness_tests/share.gd +38 -18
- package/build/godot/addons/gdharness_tests/suites.gd +3 -3
- package/build/godot/addons/gdharness_tests/wait.gd +3 -2
- package/build/godot/loader/loader.gd +9 -9
- package/build/godot/operations/animation_reads.gd +55 -33
- package/build/godot/operations/audio_buses.gd +48 -19
- package/build/godot/operations/class_cache.gd +16 -11
- package/build/godot/operations/classdb_queries.gd +89 -44
- package/build/godot/operations/declared_values.gd +68 -32
- package/build/godot/operations/dependencies.gd +190 -109
- package/build/godot/operations/editor_tools.gd +10 -10
- package/build/godot/operations/export_presets.gd +100 -54
- package/build/godot/operations/file_reads.gd +83 -42
- package/build/godot/operations/file_walk.gd +12 -5
- package/build/godot/operations/gdscript_analysis.gd +86 -65
- package/build/godot/operations/gdscript_authoring.gd +83 -36
- package/build/godot/operations/godot_operations.gd +17 -11
- package/build/godot/operations/import_pipeline.gd +110 -59
- package/build/godot/operations/input_actions.gd +62 -39
- package/build/godot/operations/patterns.gd +3 -1
- package/build/godot/operations/plugins.gd +36 -16
- package/build/godot/operations/project_config.gd +61 -32
- package/build/godot/operations/project_diagnostics.gd +24 -11
- package/build/godot/operations/project_file.gd +16 -16
- package/build/godot/operations/project_validation.gd +71 -44
- package/build/godot/operations/property_paths.gd +22 -12
- package/build/godot/operations/property_values.gd +143 -78
- package/build/godot/operations/reading.gd +51 -17
- package/build/godot/operations/rename_checks.gd +2 -2
- package/build/godot/operations/resource_files.gd +11 -9
- package/build/godot/operations/same_values.gd +4 -4
- package/build/godot/operations/scene_connections.gd +27 -13
- package/build/godot/operations/script_check.gd +52 -49
- package/build/godot/operations/serialisation.gd +75 -51
- package/build/godot/operations/setting_reads.gd +7 -6
- package/build/godot/operations/value_shapes.gd +5 -6
- package/build/godot/tests/listed.gd +321 -268
- package/build/keeper.js +43 -43
- package/package.json +1 -1
|
@@ -1,19 +1,17 @@
|
|
|
1
1
|
extends RefCounted
|
|
2
|
-
|
|
3
2
|
## What the running game tells a screen reader: its accessibility tree, as UI Automation reads it.
|
|
4
3
|
##
|
|
5
4
|
## The engine builds the tree only when something asks for it, and nothing on gdharness's desktop
|
|
6
5
|
## does, so a game's NOTIFICATION_ACCESSIBILITY_UPDATE never came and what its controls expose could
|
|
7
6
|
## not be checked. The engine offers no way to read the tree back, so the question is put the way a
|
|
8
|
-
## screen reader puts it: a UI Automation client started by the game lands on the game's own
|
|
9
|
-
## its first question makes the engine build the tree, and what it reads is what a screen
|
|
10
|
-
## told, names left empty included.
|
|
7
|
+
## screen reader puts it: a UI Automation client started by the game lands on the game's own
|
|
8
|
+
## desktop, its first question makes the engine build the tree, and what it reads is what a screen
|
|
9
|
+
## reader is told, names left empty included.
|
|
11
10
|
|
|
12
11
|
const GdhRead = preload("reading.gd")
|
|
13
12
|
const GdhSays = preload("runtime_says.gd")
|
|
14
|
-
|
|
15
|
-
##
|
|
16
|
-
## with its windows alone and fills them in over the next frames.
|
|
13
|
+
## How long the client keeps walking the tree for it to settle: the engine answers the first
|
|
14
|
+
## question with its windows alone and fills them in over the next frames.
|
|
17
15
|
const SETTLE_MS: int = 8000
|
|
18
16
|
## How long a window with nothing in it is walked before the client stops: a game building its tree
|
|
19
17
|
## fills the window within a few frames of being asked, and one building none never does.
|
|
@@ -33,12 +31,11 @@ const MOST_LEVELS: int = 40
|
|
|
33
31
|
## Where an element holds its node's instance id between matching and placing, removed before the
|
|
34
32
|
## answer goes.
|
|
35
33
|
const NODE_ID: String = "_node_instance"
|
|
36
|
-
|
|
37
34
|
## The client, as PowerShell, with $Handles, $Out, $Progress, $SettleMs, $EmptyMs and $MostLevels
|
|
38
|
-
## set before it. Each element answers what UI Automation names its role, its name, its value where
|
|
39
|
-
## has one, its bounds in the window's pixels, and the actions a screen reader is offered on it.
|
|
40
|
-
## stage it reaches is marked in $Progress as it is reached, with the time, so a client stopped
|
|
41
|
-
## deadline still says how far it got.
|
|
35
|
+
## set before it. Each element answers what UI Automation names its role, its name, its value where
|
|
36
|
+
## it has one, its bounds in the window's pixels, and the actions a screen reader is offered on it.
|
|
37
|
+
## Each stage it reaches is marked in $Progress as it is reached, with the time, so a client stopped
|
|
38
|
+
## at the deadline still says how far it got.
|
|
42
39
|
const WALK: String = r"""
|
|
43
40
|
$ErrorActionPreference = 'Stop'
|
|
44
41
|
function Answer($value) {
|
|
@@ -200,17 +197,17 @@ func get_accessibility(params: Dictionary) -> Dictionary:
|
|
|
200
197
|
if _setting() != "always":
|
|
201
198
|
also = (
|
|
202
199
|
(
|
|
203
|
-
' and engineArgs ["--accessibility", "always"], since this project\'s'
|
|
204
|
-
+ "
|
|
205
|
-
+ " only when asked"
|
|
200
|
+
' and engineArgs ["--accessibility", "always"], since this project\'s '
|
|
201
|
+
+ "accessibility/general/accessibility_support is %s and the engine builds the "
|
|
202
|
+
+ "tree only when asked"
|
|
206
203
|
)
|
|
207
204
|
% _setting()
|
|
208
205
|
)
|
|
209
206
|
return _refused(
|
|
210
207
|
(
|
|
211
208
|
(
|
|
212
|
-
"A headless run has no window, so a screen reader is told nothing: start the
|
|
213
|
-
+ " headless: false%s."
|
|
209
|
+
"A headless run has no window, so a screen reader is told nothing: start the "
|
|
210
|
+
+ "run with headless: false%s."
|
|
214
211
|
)
|
|
215
212
|
% also
|
|
216
213
|
)
|
|
@@ -219,8 +216,8 @@ func get_accessibility(params: Dictionary) -> Dictionary:
|
|
|
219
216
|
return _refused(
|
|
220
217
|
(
|
|
221
218
|
(
|
|
222
|
-
"The tree is read through UI Automation, the interface a Windows screen reader
|
|
223
|
-
+ " game runs on %s, whose screen readers ask it through another"
|
|
219
|
+
"The tree is read through UI Automation, the interface a Windows screen reader "
|
|
220
|
+
+ "uses, and this game runs on %s, whose screen readers ask it through another"
|
|
224
221
|
)
|
|
225
222
|
% OS.get_name()
|
|
226
223
|
)
|
|
@@ -239,7 +236,10 @@ func get_accessibility(params: Dictionary) -> Dictionary:
|
|
|
239
236
|
var progress: String = out + ".progress"
|
|
240
237
|
var script: String = (
|
|
241
238
|
(
|
|
242
|
-
|
|
239
|
+
(
|
|
240
|
+
"$Handles = @(%s)\n$Out = '%s'\n$Progress = '%s'\n$SettleMs = %d\n$EmptyMs = "
|
|
241
|
+
+ "%d\n$MostLevels = %d\n"
|
|
242
|
+
)
|
|
243
243
|
% [
|
|
244
244
|
", ".join(handles),
|
|
245
245
|
out.replace("'", "''"),
|
|
@@ -271,9 +271,9 @@ func get_accessibility(params: Dictionary) -> Dictionary:
|
|
|
271
271
|
if pid <= 0:
|
|
272
272
|
return _refused("PowerShell could not be started from %s to read the tree" % shell)
|
|
273
273
|
# Waited out a frame at a time rather than blocking: the client's questions are answered on the
|
|
274
|
-
# game's main thread, which a blocking wait would hold, and neither side would move.
|
|
275
|
-
#
|
|
276
|
-
#
|
|
274
|
+
# game's main thread, which a blocking wait would hold, and neither side would move. Two
|
|
275
|
+
# budgets, so a slow start is never charged to the walk: one for PowerShell to begin and load UI
|
|
276
|
+
# Automation, and once it has, one for the walks.
|
|
277
277
|
var began_at: int = Time.get_ticks_msec()
|
|
278
278
|
var deadline: int = _deadline(began_at, -1, handles.size())
|
|
279
279
|
var walking: bool = false
|
|
@@ -299,7 +299,9 @@ func get_accessibility(params: Dictionary) -> Dictionary:
|
|
|
299
299
|
|
|
300
300
|
var text: String = FileAccess.get_file_as_string(out)
|
|
301
301
|
var took: Dictionary = _took(
|
|
302
|
-
FileAccess.get_file_as_string(progress),
|
|
302
|
+
FileAccess.get_file_as_string(progress),
|
|
303
|
+
started_ms,
|
|
304
|
+
int(Time.get_unix_time_from_system() * 1000.0)
|
|
303
305
|
)
|
|
304
306
|
# Not checked: a file that is not there was never written, which the answer below says.
|
|
305
307
|
var _removed: Error = DirAccess.remove_absolute(out)
|
|
@@ -309,7 +311,9 @@ func get_accessibility(params: Dictionary) -> Dictionary:
|
|
|
309
311
|
return _refused("UI Automation answered nothing readable: %s" % text.left(500))
|
|
310
312
|
var answer: Dictionary = read
|
|
311
313
|
if answer.has("error"):
|
|
312
|
-
return _refused(
|
|
314
|
+
return _refused(
|
|
315
|
+
"UI Automation could not read the game's windows: %s" % str(answer["error"])
|
|
316
|
+
)
|
|
313
317
|
|
|
314
318
|
var windows: Array = answer.get("windows", [])
|
|
315
319
|
var made_by: Dictionary = {}
|
|
@@ -333,25 +337,28 @@ func get_accessibility(params: Dictionary) -> Dictionary:
|
|
|
333
337
|
_unmark(window)
|
|
334
338
|
elements += _count(window)
|
|
335
339
|
unnamed += _unnamed_text(window)
|
|
336
|
-
var result: Dictionary = {"windows": windows, "elements": elements}
|
|
340
|
+
var result: Dictionary = { "windows": windows, "elements": elements }
|
|
337
341
|
if not took.is_empty():
|
|
338
342
|
result["tookMsBy"] = took
|
|
339
343
|
if placing.tooltips > 0:
|
|
340
344
|
result["tooltip_note"] = (
|
|
341
|
-
"tooltip is the node's tooltip_text, which the engine puts in the tree, and UI
|
|
342
|
-
+ " AccessKit fills it in, has no property that carries it (measured on
|
|
343
|
-
+ " reader on Windows is not told it. Say what a reader needs in
|
|
345
|
+
"tooltip is the node's tooltip_text, which the engine puts in the tree, and UI "
|
|
346
|
+
+ "Automation, as AccessKit fills it in, has no property that carries it (measured on "
|
|
347
|
+
+ "4.7.2), so a screen reader on Windows is not told it. Say what a reader needs in "
|
|
348
|
+
+ "accessibility_description."
|
|
344
349
|
)
|
|
345
350
|
if placing.asked > 0 and placing.placed == 0:
|
|
346
351
|
# Nothing at all matched: the element ids are not the engine's element RIDs any more, which
|
|
347
|
-
# an AccessKit that numbers its elements another way would do, and every node would read
|
|
352
|
+
# an AccessKit that numbers its elements another way would do, and every node would read
|
|
353
|
+
# null.
|
|
348
354
|
result["node_note"] = (
|
|
349
|
-
"No element could be matched to the node that made it: UI Automation's runtime ids did
|
|
350
|
-
+ " carry the engine's element ids, so node and part_of are the windows' alone."
|
|
355
|
+
"No element could be matched to the node that made it: UI Automation's runtime ids did "
|
|
356
|
+
+ "not carry the engine's element ids, so node and part_of are the windows' alone."
|
|
351
357
|
)
|
|
352
358
|
if answer.has("description_unread"):
|
|
353
359
|
result["description_note"] = (
|
|
354
|
-
"Descriptions could not be read, so none is shown: %s"
|
|
360
|
+
"Descriptions could not be read, so none is shown: %s"
|
|
361
|
+
% str(answer["description_unread"])
|
|
355
362
|
)
|
|
356
363
|
if elements <= windows.size():
|
|
357
364
|
var setting: String = _setting()
|
|
@@ -359,31 +366,35 @@ func get_accessibility(params: Dictionary) -> Dictionary:
|
|
|
359
366
|
# the setting and a screen reader can say the tree is built; otherwise an empty window is
|
|
360
367
|
# most likely a game that builds none.
|
|
361
368
|
# 1 is a screen reader running, 0 none and -1 a platform that cannot say.
|
|
362
|
-
var read_aloud: bool =
|
|
369
|
+
var read_aloud: bool = (
|
|
370
|
+
setting == "auto" and DisplayServer.accessibility_screen_reader_active() == 1
|
|
371
|
+
)
|
|
363
372
|
if setting != "always" and not read_aloud:
|
|
364
373
|
return _refused(
|
|
365
374
|
(
|
|
366
375
|
(
|
|
367
|
-
"UI Automation found nothing in the game's windows: the engine builds the
|
|
368
|
-
+ " reader reads only with
|
|
369
|
-
+ "
|
|
370
|
-
+
|
|
376
|
+
"UI Automation found nothing in the game's windows: the engine builds the "
|
|
377
|
+
+ "tree a screen reader reads only with "
|
|
378
|
+
+ "accessibility/general/accessibility_support at Always Active, or at "
|
|
379
|
+
+ "Auto with a screen reader running when it starts, and this project's "
|
|
380
|
+
+ "is %s. "
|
|
381
|
+
+ 'Start the run with engineArgs ["--accessibility", "always"].'
|
|
371
382
|
)
|
|
372
383
|
% setting
|
|
373
384
|
)
|
|
374
385
|
)
|
|
375
386
|
result["_note"] = (
|
|
376
|
-
"The windows hold nothing a screen reader is told: Controls are in the tree, and
|
|
377
|
-
+ " Node3D are not unless the game creates elements for them."
|
|
387
|
+
"The windows hold nothing a screen reader is told: Controls are in the tree, and "
|
|
388
|
+
+ "Node2D and Node3D are not unless the game creates elements for them."
|
|
378
389
|
)
|
|
379
390
|
elif unnamed > 0:
|
|
380
391
|
# Seen on a game naming its lines with accessibility_update_set_name: the text was there in
|
|
381
392
|
# the game and empty to the screen reader.
|
|
382
393
|
result["_note"] = (
|
|
383
394
|
(
|
|
384
|
-
"%d text element(s) on screen have no name, so a screen reader reads them as
|
|
385
|
-
+ " text is read from its value,
|
|
386
|
-
+ " set on it is not read."
|
|
395
|
+
"%d text element(s) on screen have no name, so a screen reader reads them as "
|
|
396
|
+
+ "nothing. Static text is read from its value, "
|
|
397
|
+
+ "DisplayServer.accessibility_update_set_value, and a name set on it is not read."
|
|
387
398
|
)
|
|
388
399
|
% unnamed
|
|
389
400
|
)
|
|
@@ -498,7 +509,9 @@ static func _cut(element: Dictionary, left: Array[int], omitted: Array[int]) ->
|
|
|
498
509
|
|
|
499
510
|
## The project's accessibility mode, as the command line's --accessibility names them.
|
|
500
511
|
static func _setting() -> String:
|
|
501
|
-
match GdhRead.as_int(
|
|
512
|
+
match GdhRead.as_int(
|
|
513
|
+
ProjectSettings.get_setting("accessibility/general/accessibility_support", 0), 0
|
|
514
|
+
):
|
|
502
515
|
1:
|
|
503
516
|
return "always"
|
|
504
517
|
2:
|
|
@@ -576,7 +589,9 @@ static func _match(element: Dictionary, made_by: Dictionary, placing: GdhPlacing
|
|
|
576
589
|
## column of plain containers came out straight under the window. So the node is found where it
|
|
577
590
|
## must be: below the shown element's node, itself left out of the tree (a node that is shown would
|
|
578
591
|
## have the part under it), drawn around the part, and, for text, holding its words.
|
|
579
|
-
static func _attribute(
|
|
592
|
+
static func _attribute(
|
|
593
|
+
element: Dictionary, holder: Node, placing: GdhPlacing, is_window: bool
|
|
594
|
+
) -> void:
|
|
580
595
|
var children: Array = element.get("children", [])
|
|
581
596
|
for child: Variant in children:
|
|
582
597
|
if not child is Dictionary:
|
|
@@ -636,7 +651,9 @@ static func _owners_of(element: Dictionary, holder: Node, placing: GdhPlacing) -
|
|
|
636
651
|
|
|
637
652
|
## Where a Control is drawn is read off its screen transform, which for a window that is not
|
|
638
653
|
## embedded is in that window's own pixels, as the bounds are.
|
|
639
|
-
static func _drawn_around(
|
|
654
|
+
static func _drawn_around(
|
|
655
|
+
node: Node, drawn: Rect2, placing: GdhPlacing, found: Array[Node]
|
|
656
|
+
) -> void:
|
|
640
657
|
for child: Node in node.get_children(true):
|
|
641
658
|
# A node that is shown has its parts under it, and so do the nodes below it.
|
|
642
659
|
if placing.shown.has(child.get_instance_id()):
|
|
@@ -678,7 +695,7 @@ static func _text_of(node: Node) -> String:
|
|
|
678
695
|
static func _made(parts: Array, made_by: Dictionary) -> Node:
|
|
679
696
|
var halves: Array[int] = []
|
|
680
697
|
for part: Variant in parts:
|
|
681
|
-
halves.append(GdhRead.as_int(part, 0) &
|
|
698
|
+
halves.append(GdhRead.as_int(part, 0) & 0xffffffff)
|
|
682
699
|
for at: int in [0, 2]:
|
|
683
700
|
var id: int = (halves[at] << 32) | halves[at + 1]
|
|
684
701
|
if made_by.has(id):
|
|
@@ -686,21 +703,15 @@ static func _made(parts: Array, made_by: Dictionary) -> Node:
|
|
|
686
703
|
return null
|
|
687
704
|
|
|
688
705
|
|
|
689
|
-
## Counts kept while the elements are placed, and the nodes whose own elements UI Automation shows,
|
|
690
|
-
## by instance id.
|
|
691
|
-
class GdhPlacing:
|
|
692
|
-
extends RefCounted
|
|
693
|
-
var asked: int = 0
|
|
694
|
-
var placed: int = 0
|
|
695
|
-
var tooltips: int = 0
|
|
696
|
-
var shown: Dictionary = {}
|
|
697
|
-
|
|
698
|
-
|
|
699
706
|
## Text elements with bounds and no name. The window's announcement element has no bounds and is
|
|
700
707
|
## left out with them: it is empty until something is announced.
|
|
701
708
|
static func _unnamed_text(element: Dictionary) -> int:
|
|
702
709
|
var total: int = 0
|
|
703
|
-
if
|
|
710
|
+
if (
|
|
711
|
+
element.get("role") == "text"
|
|
712
|
+
and str(element.get("name", "")).is_empty()
|
|
713
|
+
and element.has("bounds")
|
|
714
|
+
):
|
|
704
715
|
total += 1
|
|
705
716
|
var children: Array = element.get("children", [])
|
|
706
717
|
for child: Variant in children:
|
|
@@ -710,8 +721,8 @@ static func _unnamed_text(element: Dictionary) -> int:
|
|
|
710
721
|
return total
|
|
711
722
|
|
|
712
723
|
|
|
713
|
-
## When a client started at [param began_at] is stopped, in ticks: [constant START_MS] after it
|
|
714
|
-
## while UI Automation is loading ([param loaded_at] -1), and once it was seen loaded at
|
|
724
|
+
## When a client started at [param began_at] is stopped, in ticks: [constant START_MS] after it
|
|
725
|
+
## began while UI Automation is loading ([param loaded_at] -1), and once it was seen loaded at
|
|
715
726
|
## [param loaded_at], [constant SETTLE_MS] for each of [param windows] and [constant WALK_SLACK_MS]
|
|
716
727
|
## after that.
|
|
717
728
|
static func _deadline(began_at: int, loaded_at: int, windows: int) -> int:
|
|
@@ -763,8 +774,8 @@ static func _reached(progress: String, started_ms: int) -> String:
|
|
|
763
774
|
)
|
|
764
775
|
return (
|
|
765
776
|
(
|
|
766
|
-
"PowerShell began the client after %d ms and loaded UI Automation in %d ms, and the
|
|
767
|
-
+ " were walked %d time%s, the last finding %s element%s"
|
|
777
|
+
"PowerShell began the client after %d ms and loaded UI Automation in %d ms, and the "
|
|
778
|
+
+ "windows were walked %d time%s, the last finding %s element%s"
|
|
768
779
|
)
|
|
769
780
|
% [began, loaded, walks, "" if walks == 1 else "s", last, "" if last == "1" else "s"]
|
|
770
781
|
)
|
|
@@ -789,4 +800,14 @@ static func _took(progress: String, started_ms: int, done_ms: int) -> Dictionary
|
|
|
789
800
|
|
|
790
801
|
|
|
791
802
|
static func _refused(message: String) -> Dictionary:
|
|
792
|
-
return {"type": "error", "message": message}
|
|
803
|
+
return { "type": "error", "message": message }
|
|
804
|
+
|
|
805
|
+
|
|
806
|
+
## Counts kept while the elements are placed, and the nodes whose own elements UI Automation shows,
|
|
807
|
+
## by instance id.
|
|
808
|
+
class GdhPlacing:
|
|
809
|
+
extends RefCounted
|
|
810
|
+
var asked: int = 0
|
|
811
|
+
var placed: int = 0
|
|
812
|
+
var tooltips: int = 0
|
|
813
|
+
var shown: Dictionary = {}
|