Skip to content

Windows: new console windows steal keyboard focus (start with SW_SHOWMINNOACTIVE?) #59

Closed as not planned

Description

@ValenMX

Summary

On Windows, every console that the proxy creates (start_console, or a new console after the previous one died) opens as the active window. If the user is typing in another application at that moment, the keyboard focus jumps to the new console and the next few keystrokes land in the agent's PowerShell session instead of the user's document. With an Enter among them, that text even gets executed.

The cause is that PwshLauncherWindows.LaunchPwsh passes an empty STARTUPINFOW, so the new window is shown with the default (activating) show command. Asking for SW_SHOWMINNOACTIVE fixes it: I tested this with Windows Terminal as the default terminal, and that is the only value of the ones I tried that it honors.

Environment

  • PowerShell.MCP 1.14.1 (the same code is still on main @ 1f904c8, PowerShellProcessManager.cs line 317)
  • Windows 11 25H2, build 26200
  • Windows Terminal 1.24.12741.0, set as the default terminal ("Let Windows decide"), so a CREATE_NEW_CONSOLE pwsh is handed off to Windows Terminal
  • PowerShell 7.6

Where it happens

PowerShell.MCP.Proxy/Services/PowerShellProcessManager.cs, PwshLauncherWindows.LaunchPwsh:

var si = new STARTUPINFOW { cb = (uint)Marshal.SizeOf<STARTUPINFOW>() };
...
bool ok = CreateProcessW(null, commandLine, IntPtr.Zero, IntPtr.Zero, false,
    CREATE_UNICODE_ENVIRONMENT | CREATE_NEW_CONSOLE, env, startLocation ?? userProfile, ref si, out pi);

dwFlags is 0, so wShowWindow is ignored and the console window is shown and activated.

What I measured

Same machine, same Windows Terminal, the only difference being STARTUPINFOW.dwFlags / wShowWindow passed to CreateProcessW for pwsh.exe with CREATE_NEW_CONSOLE. "Took focus" means GetForegroundWindow() returned the new Windows Terminal window right after it appeared, while the user's window had been in the foreground before.

dwFlags / wShowWindow New window took focus?
0 / (ignored), as today yes (2 of 2 runs)
STARTF_USESHOWWINDOW / SW_SHOWNOACTIVATE (4) yes (1 of 1 run): Windows Terminal seems to ignore it through the default-terminal handoff
STARTF_USESHOWWINDOW / SW_SHOWMINNOACTIVE (7) no (2 of 2 runs): the window appears minimized on the taskbar and the user keeps typing where they were

Not tested: the classic conhost case (Windows Terminal not the default terminal); there SW_SHOWNOACTIVATE may work as documented.

Proposed change

+    private const uint STARTF_USESHOWWINDOW = 0x00000001;
+    private const ushort SW_SHOWMINNOACTIVE = 7;
 ...
-            var si = new STARTUPINFOW { cb = (uint)Marshal.SizeOf<STARTUPINFOW>() };
+            // Do not take the keyboard focus from whatever the user is typing in. Windows Terminal
+            // (default terminal handoff) honors SW_SHOWMINNOACTIVE but not SW_SHOWNOACTIVATE.
+            var si = new STARTUPINFOW
+            {
+                cb = (uint)Marshal.SizeOf<STARTUPINFOW>(),
+                dwFlags = STARTF_USESHOWWINDOW,
+                wShowWindow = SW_SHOWMINNOACTIVE,
+            };

Trade-off: the console starts minimized, so a user who wants to watch it has to click it on the taskbar. If you'd rather keep today's behaviour by default, an opt-in switch would be enough for me, e.g. an environment variable read by the proxy (POWERSHELL_MCP_CONSOLE_NOACTIVATE=1) or a CLI option.

Happy to test a build. Thanks for PowerShell.MCP, it's the tool my agents use for everything on Windows.

Activity

  1. ValenMX commented on Oct 23, 2026

    @ValenMX
    Author

    Duplicate of #56 (missed it before opening this). The measurements are posted there: Windows Terminal ignores SW_SHOWNOACTIVATE through the handoff but honors SW_SHOWMINNOACTIVE.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions