Equivalent of SIGWINCH? #447

Closed
opened 2026-01-30 21:52:36 +00:00 by claunia · 8 comments
Owner

Originally created by @HouQiming on GitHub (Nov 10, 2018).

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?).

Can someone share some light on this situation?

Thanks.

Originally created by @HouQiming on GitHub (Nov 10, 2018). 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?). Can someone share some light on this situation? Thanks.
claunia added the Issue-QuestionResolution-Duplicate labels 2026-01-30 21:52:36 +00:00
Author
Owner

@oising commented on GitHub (Nov 10, 2018):

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:

oisin@laptop$ echo -e "\e[999;999H"; echo -e "\e[6n"; echo ""
^[[47;1R;oisin@laptop$

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.

@oising commented on GitHub (Nov 10, 2018): 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: ``` oisin@laptop$ echo -e "\e[999;999H"; echo -e "\e[6n"; echo "" ^[[47;1R;oisin@laptop$ ``` 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`.
Author
Owner

@zadjii-msft commented on GitHub (Nov 12, 2018):

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 :/

@zadjii-msft commented on GitHub (Nov 12, 2018): 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_EVENT`s. 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 :/
Author
Owner

@HouQiming commented on GitHub (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 SIGWINCH right without making clients "un-speak" VT. Polling is not really a solution if one needs to forward SIGWINCH 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.

@HouQiming commented on GitHub (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 `SIGWINCH` right without making clients "un-speak" VT. Polling is not really a solution if one needs to *forward* `SIGWINCH` 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`.
Author
Owner

@oising commented on GitHub (Nov 22, 2018):

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 :/

@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)

@oising commented on GitHub (Nov 22, 2018): > 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_EVENT`s. 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 :/ @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)
Author
Owner

@zadjii-msft commented on GitHub (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.

@zadjii-msft commented on GitHub (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.
Author
Owner

@awsdert commented on GitHub (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:

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.

@awsdert commented on GitHub (Jul 17, 2023): Found this thread while I was looking for inspiration, eventually realised [WM_ERASEBKGND](https://learn.microsoft.com/en-us/windows/win32/winmsg/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.
Author
Owner

@zadjii-msft commented on GitHub (Jul 17, 2023):

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.

@zadjii-msft commented on GitHub (Jul 17, 2023): 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.
Author
Owner

@awsdert commented on GitHub (Jul 17, 2023):

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).

@awsdert commented on GitHub (Jul 17, 2023): Well given the snippet `...this function returns a window handle for message queue purposes only` from [GetConsoleWindow](https://learn.microsoft.com/en-us/windows/console/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).
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/terminal#447