I am using ncurses for a terminal application which should also be usable on windows but every time the user resizes the terminal everything is mashed. So I need a way to detect resizing and redraw.
Since Windows does not support signals that does not work. (At least SIGWINCH is not defined). Also KEY_RESIZE is not send when resizing. getmaxx and getmaxy always return the initial terminal size and do not update when the user resizes the window (the same for GetConsoleBufferInfo). Is there another way to get the current actual size of the terminal or check if it has been resized by the user or another way to prevent everything drawn in the terminal to be moshed when resized?
Edit: Like I said I already tried GetConsoleBufferInfo. It works with a normal terminal but stops working when I call initscr from ncurses.
void getConsoleSize(int *w, int *h){
CONSOLE_SCREEN_BUFFER_INFO csbi;
GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi);
*w = csbi.srWindow.Right - csbi.srWindow.Left + 1;
*h = csbi.srWindow.Bottom - csbi.srWindow.Top + 1;
}
This code is what I use to detect console resize events. There are other ways, such as polling the event queue for an actual ms windows resize event. But in my experience, that method was unreliable and ultimately you need to check the new console size anyway...
... and so that necessity gave birth to this code. Your code must query function check_console_window_resize_event()
repeatedly somewhere in your main execution loop. If the function returns TRUE
, your console has a new size, else, no. It works by checking the CONSOLE_SCREEN_BUFFER_INFO
structure srWindow
member which is the actual console rectangle size (not to be confused with console buffer size which can be much bigger, but never smaller), and comparing current dimension values against static
stored dimension values.
This code is compiled and tested by me today and the featured Output
is actually copied from the console window the program ran in just minutes ago as I dragged the console window edges with the mouse:
#include <windows.h>
#include <stdio.h>
HANDLE hConOut = NULL;
/*------------------------------------------------------------
getConsoleOutputHandle()
There are simpler ways to get the console handle, but they
arguably lack precision.
*------------------------------------------------------------*/
HANDLE getConsoleOutputHandle(void)
{
SECURITY_ATTRIBUTES sa;
if(!hConOut)
{
/* First call -- get the window handle one time and save it*/
sa.nLength = sizeof(sa);
sa.lpSecurityDescriptor = NULL;
sa.bInheritHandle = TRUE;
/* Using CreateFile we get the true console handle", avoiding any redirection.*/
hConOut = CreateFile( TEXT("CONOUT$"),
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
&sa, OPEN_EXISTING, (DWORD)0, (HANDLE)0 );
}
if(!hConOut) /* actually, this is a bad error, let your app handle the error as needed*/
{
printf("getConsoleOutputHandle(): failed to get Console Window Handle\n");
return NULL;
}
return hConOut;
}
/*----------------------------------------------------------------------------------------
check_console_window_resize_event()
Params: COORD to return new window size
Returns: TRUE if the console window has changed size. FALSE if not.
USAGE: Best practice is to call the function repeatedly from your main application
loop. Preferably a place where the function can be called several times per second
throughout the program's run time.
DATE: Reason:
2022.10.05 Created -- placed in public domain
*----------------------------------------------------------------------------------------*/
int check_console_window_resize_event(COORD *info)
{
static short old_screen_w=0, old_screen_h=0;
/* variables declared static hold their value between function calls.*/
short current_screen_w, current_screen_h;
int window_resized = FALSE;
CONSOLE_SCREEN_BUFFER_INFO csbi;
hConOut = getConsoleOutputHandle();
if(!hConOut)
return FALSE;
if(!GetConsoleScreenBufferInfo( getConsoleOutputHandle(), &csbi ))
{
//printf("check_console_window_resize_event(): GetConsoleScreenBufferInfo() FAILED!! %s\n", __FILE__);
return FALSE;
}
current_screen_w = csbi.srWindow.Right - csbi.srWindow.Left + 1;
current_screen_h = csbi.srWindow.Bottom - csbi.srWindow.Top + 1;
if(!old_screen_w && !old_screen_h)
{
/* Execution comes here if this is first time this function is called.
** Initialize the static variables and bail...*/
old_screen_w = current_screen_w;
old_screen_h = current_screen_h;
return FALSE;
}
/* At last the real work of this function can be realized...*/
if(current_screen_w != old_screen_w || current_screen_h != old_screen_h)
{
old_screen_w = current_screen_w;
old_screen_h = current_screen_h;
window_resized = TRUE;
info->X = current_screen_w;
info->Y = current_screen_h;
//printf("check_console_window_resize_event(): new screenwidth: %d new screenheight: %d", current_screen_w, current_screen_h);
}
return window_resized;
}
/*---------------------------------------------------------------------------------------------
main()
*--------------------------------------------------------------------------------------------*/
int main()
{
BOOL user_quit = FALSE;
COORD winsize;
while(!user_quit)
{
if(check_console_window_resize_event(&winsize))
{
printf("Hey! You resize me? I'm really %dx%d now?\n", winsize.X, winsize.Y);
}
}
return 0;
}
Output:
Hey! You resize me? I'm really 159x48 now?
Hey! You resize me? I'm really 158x48 now?
Hey! You resize me? I'm really 157x48 now?
Hey! You resize me? I'm really 156x48 now?
Hey! You resize me? I'm really 155x48 now?
Hey! You resize me? I'm really 154x48 now?
Hey! You resize me? I'm really 153x48 now?
Hey! You resize me? I'm really 152x48 now?
Hey! You resize me? I'm really 151x48 now?
Hey! You resize me? I'm really 150x48 now?
Hey! You resize me? I'm really 149x48 now?
Hey! You resize me? I'm really 148x48 now?
Hey! You resize me? I'm really 147x48 now?
Hey! You resize me? I'm really 146x48 now?
Hey! You resize me? I'm really 145x48 now?
Hey! You resize me? I'm really 144x48 now?
Hey! You resize me? I'm really 143x48 now?
Hey! You resize me? I'm really 142x48 now?
Hey! You resize me? I'm really 141x48 now?
Hey! You resize me? I'm really 140x48 now?
Hey! You resize me? I'm really 140x47 now?
Hey! You resize me? I'm really 140x46 now?
Hey! You resize me? I'm really 140x45 now?
Hey! You resize me? I'm really 140x44 now?
Hey! You resize me? I'm really 140x43 now?
Hey! You resize me? I'm really 140x42 now?
Hey! You resize me? I'm really 140x41 now?
Hey! You resize me? I'm really 140x40 now?
Hey! You resize me? I'm really 140x39 now?
Hey! You resize me? I'm really 140x38 now?