You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Termcaps实时获取终端窗口尺寸:窗口Resize时lines与columns值不更新的问题求解

如何通过Termcaps实时获取终端窗口尺寸?

我来帮你解决这个问题——你遇到的核心问题是:tgetnum("li")和tgetnum("co")只会从termcap数据库读取终端的默认初始尺寸,并不会主动追踪窗口大小的实时变化。同样,ncurses的LINES和COLS全局变量也不会自动更新,除非你主动处理窗口变化的信号并触发尺寸刷新。

问题根源

termcap本质上是一个静态的终端特性数据库,tgetnum("li")和"co"对应的是终端的标准默认行数/列数,不是当前运行时终端窗口的实际大小。而ncurses在初始化后,默认不会自动监听窗口调整事件,所以LINES和COLS会一直停留在初始值。

解决方案

要实现实时获取,你需要处理系统发送的SIGWINCH信号(窗口大小改变时系统会触发这个信号),并在信号触发后重新获取当前终端的实际尺寸。这里有两种可行的方案:

方案1:Termcap + ioctl(轻量无ncurses依赖)

ioctl的TIOCGWINSZ命令可以直接从终端设备文件描述符获取当前窗口的实时尺寸,这是最可靠的方式。我们可以结合它和信号处理来实现实时更新:

#include <term.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#include <sys/ioctl.h>

// 全局变量存储当前窗口尺寸(信号处理函数中可以访问)
int current_lines, current_cols;

void handle_window_resize(int sig) {
    struct winsize win_size;
    // 从标准输出获取当前窗口尺寸
    if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &win_size) == 0) {
        current_lines = win_size.ws_row;
        current_cols = win_size.ws_col;
    }
}

int main(void) {
    char * term_type = getenv("TERM");
    int ret;

    if (!term_type) {
        write(2, "TERM env must be set\n", 21);
        return (-1);
    }
    if ((ret = tgetent(NULL, term_type)) == -1) {
        write(2, "Could not access to the termcap database\n", 41);
        return (-1);
    }
    if (!ret) {
        write(2, "This terminal is not supported by termcaps\n", 43);
        return (-1);
    }

    // 初始化尺寸
    handle_window_resize(0);
    // 注册SIGWINCH信号处理函数,窗口调整时自动触发
    signal(SIGWINCH, handle_window_resize);

    while (1) {
        sleep(1);
        printf("%d %d\n", current_lines, current_cols);
    }
    return (0);
}

方案2:使用ncurses正确更新尺寸

如果你已经依赖ncurses,需要在SIGWINCH信号触发时,让ncurses重新获取窗口尺寸。可以用endwin()+refresh()组合,或者更高效的resizeterm():

#include <ncurses.h>
#include <signal.h>
#include <unistd.h>

void handle_window_resize(int sig) {
    // 重置ncurses终端状态,重新获取尺寸
    endwin();
    refresh();
    // 也可以用resizeterm,它会直接更新LINES和COLS
    // resizeterm(LINES, COLS);
}

int main(void) {
    // 初始化ncurses
    initscr();
    cbreak();
    noecho();

    // 注册窗口调整信号处理
    signal(SIGWINCH, handle_window_resize);

    while (1) {
        sleep(1);
        // 把尺寸打印到终端左上角
        mvprintw(0, 0, "%d %d", LINES, COLS);
        refresh();
    }

    endwin();
    return 0;
}

额外注意事项

  • SIGWINCH信号可能会打断sleep()这类系统调用,如果你需要确保睡眠时长准确,可以在循环中检查sleep()的返回值(返回剩余睡眠秒数),然后补全睡眠。
  • 如果你不需要termcap的其他终端特性,直接用ioctl获取尺寸是更轻量的选择,不需要依赖termcap数据库。

内容的提问来源于stack exchange,提问作者Fayeure

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.29 11:17:47