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
After reading through the blog post and relevant MSDN pages, I didn't find a way for a modern Windows console app to detect when its output console gets resized. On Unix we have SIGWINCH, but on Windows we only have ReadConsoleInput and WINDOW_BUFFER_SIZE_EVENT, which seems awkward when used alongside simple stdin reading (will they fight for normal input events?).
There's also GetConsoleScreenBufferInfo which will tell you dimensions, but it's obviously done by polling. You could also poll with an ANSI sequence - there are some half-baked tricks like moving the cursor way off screen - beyond any reasonable window size, then reading the actual position of the cursor afterwards. Example with WSL:
The CR killed the horizontal position reporting interactively, but at least you can see my window is 47 rows high. Again, this would need to be polled but at least it's somewhat cross platform. Other techniques I've seen on other platforms (osx,linux) is either shelling out to stty to get info, or more commonly, with an ioctl call to TIOCGWINSZ.
Unfortunately, the only SIGWINCH equivalent on Windows is, as you've noted, using ReadConsoleInput for reading the input from the console and looking for WINDOW_BUFFER_SIZE_EVENTs. It's really not great, but if your app is dependent upon the size of the viewport, then that's the only way to do it :/
Well, thanks for the clarification. The situation feels kind of disappointing, though. It's hard to qualify a console system as "VT-speaking" when it can't get SIGWINCH right without making clients "un-speak" VT. Polling is not really a solution if one needs to forwardSIGWINCH or port something that relies on it.
If all other console input types are converted anyway, maybe we can just do a simple hack and PostMessageW something somewhere for WINDOW_BUFFER_SIZE_EVENT? Then we'll be able to listen to that in a separate thread and simulate SIGWINCH without disturbing stdin.
Unfortunately, the only SIGWINCH equivalent on Windows is, as you've noted, using ReadConsoleInput for reading the input from the console and looking for WINDOW_BUFFER_SIZE_EVENTs. It's really not great, but if your app is dependent upon the size of the viewport, then that's the only way to do it :/
Mike Griese (@zadjii-msft) Mike, I've been playing with this the last few days and noticed that using WINDOWS_BUFFER_SIZE_EVENT doesn't concern itself with the viewport at all; it only deals with the underlying buffer. Additionally, the buffer only ever gets increased in size, so when you resize the console window larger than the buffer, you get a resize event - which is actually defective in itself since it currently only seems to be reporting the vertical size/number of lines, and returning 1 for columns each time. - and you never get a resize event when you reduce the viewport. (running 18282)
Found this thread while I was looking for inspiration, eventually realised WM_ERASEBKGND was better suited since you just need to have a static global by your hook and compare against that, here's a snippet from my code for how I'm planning to implement it:
pawttyxy _pawsig_ttysize = {0};
pawld _pawsig_catch_PAWSIG_TTYSIZE( pawsig *sig, UINT msg, WPARAM wp, LPARAM lp )
{
pawttyxy xy = {0};
CONSOLE_SCREEN_BUFFER_INFO csbi = {{0}};
if ( msg == WM_ERASEBKGND )
return 0;
GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi);
xy.x = csbi.dwSize.X;
xy.y = csbi.dwSize.Y;
/* Only trigger the event if at least one of limits have changed */
if ( xy.x && _pawsig_ttysize.x && xy.y == _pawsig_ttysize.y )
return 0;
sig->signal = PAWSIG_TTYSIZE;
sig->extinf.size = xy;
return 1;
}
I might need to tweak it a little for non-console apps but that's the jist of it. Events like WM_ERASEBKGND are guaranteed to be triggered upon the row & col count changing since the console would need to re-align any visible text.
FWIW I fully suspect that won't work in the Windows Terminal, since the HWND returned by GetConsoleWindow is not the actual HWND of the visible Terminal window.
Also, it probably won't work if the console/Terminal is minimized, hidden, etc.
Well given the snippet ...this function returns a window handle for message queue purposes only from GetConsoleWindow I expect it in all cases the HWND should work fine for this, I'll test it anyways once I've completed enough of my library to actually do the tests I wanted to do (this is a byproduct of development rather than the intended product).
Activity
oising commentedon Nov 10, 2018
There's also
GetConsoleScreenBufferInfowhich will tell you dimensions, but it's obviously done by polling. You could also poll with an ANSI sequence - there are some half-baked tricks like moving the cursor way off screen - beyond any reasonable window size, then reading the actual position of the cursor afterwards. Example with WSL:The CR killed the horizontal position reporting interactively, but at least you can see my window is 47 rows high. Again, this would need to be polled but at least it's somewhat cross platform. Other techniques I've seen on other platforms (osx,linux) is either shelling out to
sttyto get info, or more commonly, with an ioctl call toTIOCGWINSZ.zadjii-msft commentedon Nov 12, 2018
Unfortunately, the only SIGWINCH equivalent on Windows is, as you've noted, using
ReadConsoleInputfor reading the input from the console and looking forWINDOW_BUFFER_SIZE_EVENTs. It's really not great, but if your app is dependent upon the size of the viewport, then that's the only way to do it :/HouQiming commentedon Nov 13, 2018
Well, thanks for the clarification. The situation feels kind of disappointing, though. It's hard to qualify a console system as "VT-speaking" when it can't get
SIGWINCHright without making clients "un-speak" VT. Polling is not really a solution if one needs to forwardSIGWINCHor port something that relies on it.If all other console input types are converted anyway, maybe we can just do a simple hack and
PostMessageWsomething somewhere forWINDOW_BUFFER_SIZE_EVENT? Then we'll be able to listen to that in a separate thread and simulateSIGWINCHwithout disturbingstdin.oising commentedon Nov 22, 2018
Mike Griese (@zadjii-msft) Mike, I've been playing with this the last few days and noticed that using
WINDOWS_BUFFER_SIZE_EVENTdoesn't concern itself with the viewport at all; it only deals with the underlying buffer. Additionally, the buffer only ever gets increased in size, so when you resize the console window larger than the buffer, you get a resize event - which is actually defective in itself since it currently only seems to be reporting the vertical size/number of lines, and returning1for columns each time. - and you never get a resize event when you reduce the viewport. (running 18282)zadjii-msft commentedon Nov 26, 2018
I'm gonna go ahead and link in #281 here - that thread has WAY more information on basically the same topic.
In fact, we shout probably just commit to that thread being the master thread for all window WINDOW_BUFFER_SIZE_EVENT / SIGWINCH discussion.
awsdert commentedon Jul 17, 2023
Found this thread while I was looking for inspiration, eventually realised WM_ERASEBKGND was better suited since you just need to have a static global by your hook and compare against that, here's a snippet from my code for how I'm planning to implement it:
I might need to tweak it a little for non-console apps but that's the jist of it. Events like
WM_ERASEBKGNDare guaranteed to be triggered upon the row & col count changing since the console would need to re-align any visible text.zadjii-msft commentedon Jul 17, 2023
FWIW I fully suspect that won't work in the Windows Terminal, since the HWND returned by
GetConsoleWindowis not the actual HWND of the visible Terminal window.Also, it probably won't work if the console/Terminal is minimized, hidden, etc.
awsdert commentedon Jul 17, 2023
Well given the snippet
...this function returns a window handle for message queue purposes onlyfrom GetConsoleWindow I expect it in all cases theHWNDshould work fine for this, I'll test it anyways once I've completed enough of my library to actually do the tests I wanted to do (this is a byproduct of development rather than the intended product).