如何获取终端窗口宽度?

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

我正在使用

C
linux
开发嵌入式系统。用户可以通过 SSH 或控制台串行电缆连接到设备。他可以通过 PuTTY 或 Tera Term 来完成此操作。我的问题是,他连接后,我怎么知道他的窗口宽度呢?我尝试了不同的方法,如果我在 Linux 电脑上模拟我的系统,它们就可以工作,但它们都不能在设备上工作:

  1. ioctl()

    struct winsize ws;
    ioctl(..., TIOCGWINSZ, &ws); 
    

    此方法在PC上有效,但在设备上始终返回0。

  2. tgetnum()

    setupterm((char *)0, 1, (int *)0);
    CGR_INT columns = tgetnum("co");
    

    此方法适用于 PC,但在设备上始终返回 80x24。

  3. getmaxyx()

    CGR_INT xdim;
    CGR_INT ydim;
    initscr();
    refresh();
    getmaxyx(stdscr, ydim, xdim);
    

    此方法在pc上有效,但在设备上总是返回0

c linux console terminal
4个回答
4
投票

TIOCGWINSZ 是正确的选择。您的相关设备必须宣布其尺寸,否则这将无法工作。以xterm为例:

device —— ttyS driver —— ttyS0 devnode —— screen/minicom
xterm —— pty devnode —— pty driver —— pts devnode —— bash

xterm 在第一次生成时执行 ioctl(TIOCSWINSZ) 让 tty 驱动程序知道窗口大小。 bash 和由它生成的程序可以查询它。如果您调整 xterm 窗口的大小,它将告诉 tty 驱动程序新的大小,并且 xterm 还会向其子进程(本例中为 bash)发出 SIGWINCH 以通知其大小更改。

如果设备(例如您的设备)一开始就不知道自己连接的是什么,则不会发生这种情况。 tty 驱动程序也不知道连接到它的是什么。 (它通常也不关心。)xterm 可以告诉驱动程序大小,因为它可以发出 ioctl,但 ioctl 不是通过串行传输的。理论上需要的是一个专门的内核驱动程序,它知道如何与您的特定设备通信大小变化(可能是串行协议之上的协议,这样就不需要重写核心组件)。

请注意,连接的设备甚至可能没有固定区域的概念,例如一台打印机实际上可以被认为有无限多的行。

ncurses 如果看到 0x0,就会假设 80x24,因为程序员是这样定义的。这个大小可能不正确,实际上通常不是因为人们可以调整窗口大小(即使他们不能,就像在 tty1 上一样,他们仍然可以使用 screen(1) 之类的东西并将大小缩小到小于 80x24 ).


4
投票

串行线无法协商终端的大小。运行真正的 xterm 等。通过 TTY/PTY 设备对使用

TIOCSWINSZ
/
TIOCGWINSZ
ioctl()
对来传递此信息。

传统上,此信息保存在关于带有荧光粉涂层的真实物理玻璃片终端(例如 DEC VT220)的

termcap
terminfo
中。这是一个预先已知的静态固定数据库,在“终端”实际上是这个固定硬件的时候是正确的,但在终端只是程序的现代时代,它的工作效果不太好绘制到帧缓冲区或类似的缓冲区。

我建议最好的方法是尝试

TIOCGWINSZ
,如果失败,请使用
terminfo
tgetnum("co")
,如果失败,则假设 80x24。


3
投票

我使用此代码打印一堆等号作为分隔符。适用于我尝试过的大多数框/术语。不确定您在谈论什么设备。我想值得一试;-)

#include <termios.h>
#include <sys/ioctl.h>
#include <stdio.h>
int main(int argc, char *argv[])
{
   struct winsize ws;
   ioctl(0, TIOCGWINSZ, &ws);

   int i=0;
   for(;i<10*ws.ws_col;++i) printf("=");
   printf("\n");
   return 0;
}

0
投票

串行设备不会协商窗口大小,因此

TIOCGWINSZ
在这种情况下总是会失败 - 除非加载“正确的值”,例如,使用
resize
程序,或使用
stty
等,去做这个。但对于这种情况,
resize
更可靠。

tgetnum
getmaxxy
的不同结果遗漏了有助于解释这一点的信息:所使用的
TERM
的值,以及(可能)使用的不同终端数据库:

  • termcap (tgetnum) 描述通常指定终端屏幕的大小,但这仅对硬件终端有用。在过去的四十年里,这些已经变得不那么常见了。
  • terminfo 描述通常不会指定大小,因为curses 初始化将填充此信息,例如使用
    TIOCGWINSZ
    。如果不可用,它将使用终端描述中的尺寸。

鉴于OP报告的结果,tgetnum调用使用了与curses调用中使用的不同的终端描述。

进一步阅读:

© www.soinside.com 2019 - 2024. All rights reserved.