Skip to content

fix(mindmap): autonomous FreeMind SVG export — desktop attach + focus + tabs reset - #275

Merged
jsboige merged 1 commit into
masterfrom
fix/freemind-autonomous-foreground-and-tabs
May 16, 2026
Merged

fix(mindmap): autonomous FreeMind SVG export — desktop attach + focus + tabs reset#275
jsboige merged 1 commit into
masterfrom
fix/freemind-autonomous-foreground-and-tabs

Conversation

@jsboige

@jsboige jsboige commented May 16, 2026

Copy link
Copy Markdown
Contributor

Summary

Six fixes so the FreeMind GUI automation in FallacyMindMapDocumentConfig survives unattended runs and stops silently exporting to the wrong file on large mindmaps. Validated tonight on a Windows 11 RDP session: 17/20 SVGs regenerated autonomously.

Changes

# Fix Why
1 TryAttachToInteractiveDesktop (P/Invoke OpenInputDesktop + SetThreadDesktop) Process spawned from non-interactive context sees a NULL foreground → keystrokes drop. Switching the worker thread to WinSta0\Default lets GetForegroundWindow actually see FreeMind. Idempotent.
2 ForceForeground(hWnd) — AttachThreadInput + verify loop (up to 5 attempts) Plain SetForegroundWindow is silently refused by Windows when the caller isn't already foreground. We attach our input queue to the current foreground thread for the call, BringWindowToTop, then verify GetForegroundWindow == hWnd before continuing. Re-asserted right before typing in case focus drifted.
3 SendKeysSafe(keys) — wraps SendKeys.SendWait and swallows the spurious Win32Exception (NativeErrorCode 0, "L'opération a réussi.") Without this guard, the very first keystroke aborts the whole export. Same swallow pattern as the sibling Mindmapper/xslt/Export-FreeMindSvg.ps1.
4 ClearFreeMindAutoOpenedTabs(freemindUserDir) — empties lastOpened= and mindmap_last_state_map_storage= in ~/.freemind/auto.properties before each launch Without this, FreeMind silently restores 5 stale tabs from previous runs; our keystrokes target whichever tab gets focus first, and SVG export lands on the wrong .svg (or none).
5 Broader KillAllFreeMind — kill ALL javaw, no MainWindowTitle.Contains("FreeMind") filter A FreeMind still loading a large .mm has an empty/unstable title; the previous filter let it survive between iterations and steal focus from the next run. Also called on window-not-found timeout.
6 Polling timeout 30 s → 90 s Cards-per-fallacy variants (~1 MB .mm) take 30-60 s to load on FreeMind 1.0.1. 30 s was timing out, leaving orphan javaw.

All wrapped with a try/finally that releases the input desktop handle.

Validation

Test plan

  • dotnet build clean (0 errors, 15 warnings, all pre-existing)
  • Re-run on a clean RDP session and confirm SVG export rate is back to 100% for the supported mindmaps
  • Re-run from a Service-context / non-interactive process to confirm desktop attach actually unblocks foreground (was the original failure mode)

Limitations

🤖 Generated with Claude Code

…-foreground + tabs reset

Six fixes so the FreeMind SVG export loop survives unattended runs without RDP
focus, and large mindmaps stop silently exporting to the wrong file:

- **TryAttachToInteractiveDesktop**: switch the worker thread to WinSta0\Default
  before SendKeys, so a process spawned from a non-interactive context can see
  the FreeMind window. Idempotent (silently no-ops on ERROR_BUSY when names
  match), releases the desktop handle in finally.

- **ForceForeground (AttachThreadInput + verify loop)**: plain SetForegroundWindow
  is silently refused unless the caller is already foreground. We attach our
  input queue to the current foreground thread for the call, BringWindowToTop,
  then verify GetForegroundWindow actually points at the target — up to 5
  attempts. Re-asserted right before sending keystrokes in case focus drifted.

- **SendKeysSafe**: swallows the spurious Win32Exception 'L'opération a réussi.'
  (NativeErrorCode 0) that SendKeys.SendWait raises as a false negative —
  same swallow as Mindmapper/xslt/Export-FreeMindSvg.ps1. Without this, the
  very first keystroke aborts the whole export.

- **ClearFreeMindAutoOpenedTabs**: empties lastOpened= and
  mindmap_last_state_map_storage= in ~/.freemind/auto.properties before each
  launch. Without it, FreeMind silently restores 5 stale tabs from previous
  runs, and our keystrokes target whichever tab gets focus first — the SVG
  export goes to the wrong file or nowhere.

- **Broader KillAllFreeMind**: kill ALL javaw, not just those whose
  MainWindowTitle.Contains('FreeMind'). A FreeMind that's still loading a
  large .mm has an empty/unstable title and would otherwise survive between
  iterations and steal focus from the next run. Also kill on window-not-found
  timeout.

- **90s polling timeout** (was 30s): the cards-per-fallacy variants (~1MB .mm)
  take 30-60s to load on FreeMind 1.0.1; 30s was failing them.

Validated 2026-05-16 on Windows 11 RDP session: 17/20 SVGs regenerated
autonomously in run #9 (#272 / #274 cover the residual broken-viewBox output
on Virtues post-processing, separate from this fix).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@jsboige
jsboige merged commit feb148a into master May 16, 2026
1 check passed
@jsboige
jsboige deleted the fix/freemind-autonomous-foreground-and-tabs branch June 1, 2026 21:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant