Welcome!

By registering with us, you'll be able to discuss, share and private message with other members of our community.

SignUp Now!

Fixed Windows Terminal interaction with aborting batch files - window loses focus

Jan
25
0
I've posted this to the Windows Terminal GitHub page as well, but I've since discovered that this doesn't happen with cmd, so seems to be a TCC specific problem.

TCC version​

TCC 27.00.21 x64 (Also verified with TCMD29)

Windows Terminal version​

1.16.2641.0

Windows build number​

10.0.19044.2251

Steps to reproduce​

  1. Create a batch file that takes some time - and run it
  2. Hit CTRL-C to abort the batch file
  3. Notice the "Cancel batch job C:\batch.bat ? (Y/N/A) :"
  4. Try and press "A"
  5. The window no longer has focus - nothing happens
  6. Click the mouse in the CMD window
  7. Press "A"

Expected Behavior​

  1. Create a batch file that takes some time - and run it
  2. Hit CTRL-C to abort the batch file
  3. Notice the "Cancel batch job C:\batch.bat ? (Y/N/A) :"
  4. Press "A"
  5. The batch file aborts
No mouse usage necessary.
 
TCC 27.01.24 x64
Microsoft Windows 10 Pro for Workstations
10.0.19045.2251 (2009, 22H2)
WindowsTerminalPreview: 1.16.2209.21001

What's happening is that foreground is going to the "PseudoConsoleWindow" class window owned by OpenConsole.exe. When that happens, if you look hard, you might see a vestige of that window in the upper-left corner of your primary monitor. That's the window that TCC gets when it calls the function GetConsoleWindow and something TCC does causes it to become visible and take the foreground; it should not be made visible. I can reproduce this problem, but only if I don't load plugins. I have a "4WT" plugin which goes through some gyrations to make TCC and WT get along better. One of those gyrations is to make TCC's PseudoConsole window "message-only". That prevents it from being shown and taking the foreground.

I don't know if Rex is inclined to do something about this, but in case he is, it's as simple as ... get the console window ... get its class ... if its class is "PseudoConsoleWindow", make it message-only with SetParent(..., HWND_MESSAGE). I could give some other tips if needed. I doubt very much that any such change would be exported back to TCC v27.
 
That's very cool that you actually understand all the windows gyrations! It's not a big deal, just an annoyance.

I'd probably upgrade if it got fixed though.
 
That's very cool that you actually understand all the windows gyrations! It's not a big deal, just an annoyance.
Not even close to all.
I did a quick look for this 4WT plugin you mentioned. Is that something you wrote? Any chance you'd share it?!
Yes, I wrote it. Try ftp://vefatica.net/4plugins/x64/4wt.zip. There's no document, but there's not much in it. Do "plugin 4wt" and then HELP for each of the items listed. The keyhandler is pretty cool. Ctrl-R will give a ruler which you can move up/down; Ctrl-N will give line numbers; cancel either with <Esc>.

Another problem is that TCC relies on the console window to locate things, notably the GUI pop-ups (command history, dir history, options dialog, ...). Those things tend to be misplaced because that window is, by default, 32x32 pixels and at screen coordinates 0,0. In addition to making the PseudoConsole window un-showable, I made it follow the CASCADIA (windows terminal) window in size and location. It works pretty well when TCC uses that window to locate things.
 
Huzzah! Works like a treat!

Thanks very much for your help. I'd still like to see it "fixed" but you've got me where I wanted to go!
 
I don't know if Rex is inclined to do something about this, but in case he is, it's as simple as ... get the console window ... get its class ... if its class is "PseudoConsoleWindow", make it message-only with SetParent(..., HWND_MESSAGE). I could give some other tips if needed. I doubt very much that any such change would be exported back to TCC v27.

That would break a number of other things. For example, TCC wouldn't get broadcast messages (like environment changes).
 
That would break a number of other things. For example, TCC wouldn't get broadcast messages (like environment changes).

The PseudoConsoleClass class window won't get them but the TCC.EXE class window will.

With the PseudoConsoleWindow class window message-only, I tried this (65535 = HWND_BROADCAST, 26 = WM_SETTINGCHANGE) while watching with Spy++.

Code:
echo %@winapi[user32.dll,SendMessageTimeout,65535,26,0,0]

The TCC.EXE class window got the message.

1670293891298.png
 
The PseudoConsoleClass class window won't get them but the TCC.EXE class window will.

With the PseudoConsoleWindow class window message-only, I tried this (65535 = HWND_BROADCAST, 26 = WM_SETTINGCHANGE) while watching with Spy++.

Code:
echo %@winapi[user32.dll,SendMessageTimeout,65535,26,0,0]

The TCC.EXE class window got the message.

View attachment 3788

That's not how this works - TCC doesn't ever read or write any messages from the PseudoConsoleWindow class window. And the TCC.EXE class window can't be used to set the foreground or focus.
 
That's not how this works - TCC doesn't ever read or write any messages from the PseudoConsoleWindow class window. And the TCC.EXE class window can't be used to set the foreground or focus.
I don't know what you're getting at. I wasn't suggesting that TCC was interacting in any way with the PseudoConsoleClass class window. Simply, something TCC does causes that window to become visible (ugly as it is) and steal focus from Windows terminal. If that window is made message-only it can't be shown and it can't steal focus. The TCC.EXE class window still gets broadcast messages.
 
I don't know what you're getting at. I wasn't suggesting that TCC was interacting in any way with the PseudoConsoleClass class window. Simply, something TCC does causes that window to become visible (ugly as it is) and steal focus from Windows terminal. If that window is made message-only it can't be shown and it can't steal focus. The TCC.EXE class window still gets broadcast messages.

The class window does not belong to TCC, and TCC does not use that window. Both are excellent reasons NOT to try to modify the class window's behavior. (The third excellent reason is that we have no idea what might break in Windows Terminal by diddling its properties.)

The only thing that TCC tries to do is set the console window as the foreground window when it prompts for the ^C response. The fact that Windows Terminal causes the wrong handle to be returned for the console window is a Windows Terminal bug, not a TCC bug. (Your fix results in an invalid handle being returned, so the foreground window set fails.)

The appropriate place for a fix is in the Windows Terminal code.
 
I still don't know what you're talking about. What's "the class window"? The window of class "TCC.EXE" is created by TCC and it gets broadcast messages. I reckon it's the only way TCC could find out about WM_SETTINGCHANGE.

When TCC runs in Windows Terminal there is no console window. OpenConsole.exe takes the place of Conhost.exe relaying I/O info between TCC and Windows Terminal. Nothing appears in OpenConsole.exe's PseudoConsoleWindow. By default, that window is rather lame, 32x32 and at (0,0). The window of the user interface is a CASCADIA_HOSTING_WINDOW_CLASS window (one per instance of Windows Terminal regardless of how many tabs/panes there are).

GetConsoleWindow() returns a valid handle to OpenConsole's PseudoConsoleWindow; that handle is almost useless. If TCC uses that handle to try to give the UI focus, or to position GUI popups, it ain't going to work.

To try to make life a little better, I do the following things in a "4WT" plugin.

1. I make the PseudoConsoleWindow message-only. That prevents it from being seen. But (I was wrong earlier) it does not prevent it from becoming the foreground window. So ...

2. With a one-event (EVENT_SYSTEM_FOREGROUND), one-process (OpenConsole.exe) WinEvent hook, I give foreground back to the CASCADIA_HOSTING_WINDOW_CLASS window whenever TCC makes the PseudoConsoleWindow steal it.

3. With another-one event (EVENT_SYSTEM_MOVESIZEEND), one-process (WindowsTerminal.exe) WinEvent hook, I make the PseudoConsoleWindow follow the CASCADIA_HOSTING_WINDOW_CLASS window (the actual UI) in size and location. That makes TCC locate GUI popups correctly when it uses info got with GetConsoleWindow().

While the WinEvent hooks are easy to implement, getting a handle to the actual UI (CASCADIA_HOSTING_WINDOW_CLASS window) is a pain in the butt.
 

Similar threads

Back
Top