You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Extend dialog detection to also detect Unity progress bars and the
startup splash window. Progress bars (EditorUtility.DisplayProgressBar,
DisplayCancelableProgressBar) and the UnitySplashWindow are now treated
as dialogs with optional progress/description fields.
On Windows, detects msctls_progress32 child controls (reading position
via PBM_GETPOS/PBM_GETRANGE) and Static text labels for descriptions.
Also matches UnitySplashWindow class in addition to #32770 dialogs.
DialogInfo DTO gains nullable description and progress fields, omitted
from JSON when not present for backwards compatibility.
Copy file name to clipboardExpand all lines: docs/dialog-detection.md
+63-8Lines changed: 63 additions & 8 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,12 +1,12 @@
1
1
# Dialog Detection
2
2
3
-
Unity Editor shows modal dialog popups in various situations — compilation errors triggering Safe Mode, license issues, import failures, etc. These dialogs block Unity's main thread, which means:
3
+
Unity Editor shows modal dialog popups and progress bars in various situations — compilation errors triggering Safe Mode, license issues, import failures, asset imports, builds, editor startup, etc. These block Unity's main thread, which means:
4
4
5
5
- The UnityCtl plugin cannot process any RPC commands
6
6
-`unityctl wait` hangs indefinitely
7
7
- The bridge reports Unity as connected, but all commands time out (504)
8
8
9
-
The `dialog` command detects these popups from the CLI side (no bridge or plugin needed) and can dismiss them programmatically.
9
+
The `dialog` command detects these popups from the CLI side (no bridge or plugin needed) and can dismiss them programmatically. Progress bars (e.g., asset imports, builds, editor startup) are treated as dialogs — they may have no buttons but include progress percentage and description text.
Dialog detection is purely client-side — it runs in the CLI process using OS-level window APIs. This is necessary because dialogs block Unity's main thread, so the plugin can't respond to bridge commands.
53
84
54
85
The flow is:
55
86
1. Find the Unity process for the project (`FindUnityProcessForProject`)
56
-
2. Use platform-specific APIs to enumerate that process's dialog windows
57
-
3. Extract window titles and button labels
87
+
2. Use platform-specific APIs to enumerate that process's dialog and splash windows
88
+
3. Extract window titles, button labels, progress bar values, and description text
58
89
4. Optionally click a button to dismiss
59
90
60
91
## Platform Support
@@ -63,11 +94,22 @@ The flow is:
63
94
64
95
Uses Win32 P/Invoke APIs to detect and interact with dialogs:
65
96
66
-
-**Detection**: `EnumWindows` to find visible windows belonging to the Unity PID, filtering for the `#32770` dialog window class
97
+
-**Detection**: `EnumWindows` to find visible windows belonging to the Unity PID, filtering for the `#32770` dialog window class and `UnitySplashWindow` (Unity's startup/loading window)
67
98
-**Button enumeration**: `EnumChildWindows` to find child controls with the `Button` class, reading text via `GetWindowText`
68
99
-**Button text cleanup**: Win32 button text includes `&` accelerator prefixes (e.g., `&OK`, `&Cancel`) — these are stripped automatically
100
+
-**Progress bars**: Detects `msctls_progress32` child controls, reads position via `SendMessage(PBM_GETPOS)` and range via `SendMessage(PBM_GETRANGE)`, normalizes to 0.0-1.0
-**Clicking**: `SendMessage(WM_COMMAND)` to the parent dialog with the button's control ID (via `GetDlgCtrlID`). `SetForegroundWindow` is called first to ensure the dialog processes messages
|`UnitySplashWindow`| Unity startup/loading splash | "Opening project..." with progress bar during editor launch |
110
+
111
+
Both classes can contain `msctls_progress32` progress bar controls and `Static` text labels. The `UnitySplashWindow` typically has no buttons (or an empty-text button), while `#32770` dialogs from `DisplayCancelableProgressBar` include Cancel and Skip Transcoding buttons.
112
+
71
113
**Why `SendMessage(WM_COMMAND)` instead of `PostMessage(BM_CLICK)`**: During testing, `PostMessage(BM_CLICK)` proved unreliable across processes — the dismiss would report success but the dialog wouldn't actually close. `SendMessage(WM_COMMAND)` mimics exactly what the dialog's own message loop does when a button is clicked, making it reliable cross-process. Falls back to `SendMessage(BM_CLICK)` if control ID lookup fails.
72
114
73
115
**No special permissions required.** Works from any terminal, SSH session, or CI environment.
@@ -184,17 +226,30 @@ Key details:
184
226
185
227
### `DialogDetector.cs`
186
228
187
-
Single static class with platform dispatch (`DetectDialogs`, `ClickButton`). Best-effort on all platforms — if detection fails (missing tools, no permissions), returns empty list silently. Never fails the parent command.
229
+
Single static class with platform dispatch (`DetectDialogs`, `ClickButton`). Best-effort on all platforms — if detection fails (missing tools, no permissions), returns empty list silently. Never fails the parent command. Returns `DetectedDialog` objects with optional `Description` (from static text labels) and `Progress` (0.0-1.0 from progress bar controls).
188
230
189
231
### `DialogCommands.cs`
190
232
191
233
Two subcommands under `unityctl dialog`:
192
-
-`list` — enumerates dialogs, outputs human-readable or JSON
234
+
-`list` — enumerates dialogs, outputs human-readable or JSON. Shows progress percentage and description when present.
193
235
-`dismiss --button <text>` — clicks the named button (case-insensitive), defaults to first button
194
236
195
237
### `StatusCommand.cs`
196
238
197
-
If Unity is running, calls `DialogDetector.DetectDialogs` and includes any detected dialogs in both human-readable and JSON output.
239
+
If Unity is running, calls `DialogDetector.DetectDialogs` and includes any detected dialogs (including progress bars) in both human-readable and JSON output. The "Use 'unityctl dialog dismiss' to dismiss" hint is only shown when at least one dialog has buttons.
240
+
241
+
### `DialogInfo` (Protocol DTO)
242
+
243
+
```json
244
+
{
245
+
"title": "Building Player (busy for 35s)...",
246
+
"buttons": ["Cancel", "Skip Transcoding"],
247
+
"description": "Write asset files",
248
+
"progress": 1.0
249
+
}
250
+
```
251
+
252
+
The `description` and `progress` fields are nullable — omitted from JSON when not present (e.g., for plain button dialogs like Safe Mode prompts).
0 commit comments