在 Windows 下使用 ncurses 检查终端大小调整

问题描述 投票:0回答:1

我正在将 ncurses 用于终端应用程序,该应用程序也应该可以在 Windows 上使用,但每次用户调整终端大小时,所有内容都会被破坏。所以我需要一种方法来检测调整大小和重绘。

由于Windows不支持不起作用的信号。 (至少 SIGWINCH 没有定义)。调整大小时也不会发送 KEY_RESIZE。 getmaxx 和 getmaxy 始终返回初始终端大小,并且当用户调整窗口大小时不会更新(与 GetConsoleBufferInfo 相同)。是否有另一种方法来获取终端的当前实际大小或检查用户是否已调整大小,或另一种方法来防止在调整大小时终端中绘制的所有内容都被修改?

c windows ncurses curses
1个回答
0
投票

此代码是我用来检测控制台调整大小事件的代码。还有其他方法,例如轮询事件队列以查找实际的 ms windows 调整大小事件。但根据我的经验,这种方法并不可靠,最终你还是需要检查新的控制台大小......

...所以这种必要性催生了这段代码。您的代码必须在主执行循环中的某个位置重复查询函数

check_console_window_resize_event()
。如果函数返回
TRUE
,则您的控制台具有新的大小,否则,否。它的工作原理是检查
CONSOLE_SCREEN_BUFFER_INFO
结构
srWindow
成员,它是实际的控制台矩形大小(不要与控制台缓冲区大小混淆,控制台缓冲区大小可以更大,但永远不会更小),并将当前尺寸值与存储的
static
进行比较尺寸值。

这段代码是我今天编译和测试的,特色

Output
实际上是从程序几分钟前运行的控制台窗口复制的:

#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;

    if(!(hConOut = getConsoleOutputHandle()))
        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;
}

输出:


    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?
© www.soinside.com 2019 - 2024. All rights reserved.