如何使用 ioctl 获取终端的宽度和高度?

Posted

技术标签:

【中文标题】如何使用 ioctl 获取终端的宽度和高度?【英文标题】:How do I get width and height of my terminal with ioctl? 【发布时间】:2010-11-26 14:37:20 【问题描述】:

我必须改变什么才能使它工作?

 #!/usr/bin/perl
 use 5.012;
 use warnings;
 require "/usr/lib/perl5/vendor_perl/5.12.1/x86_64-linux-thread-multi/sys/ioctl.ph";
 my ($rows, $cols, $xpix, $ypix);

 my $winsize = "\0" x 8;
 my $TIOCGWINSZ = 0x40087468;  # should be require sys/ioctl.pl
 if (ioctl(STDOUT, $TIOCGWINSZ, $winsize)) 
     ($rows, $cols, $xpix, $ypix) = unpack('S4', $winsize);
  else 
     say "something didn't work" and exit;
 

灵感来自tchrist's answer in From column to row

【问题讨论】:

你真的有一个正确安装了sys/ioctl.ph的系统吗?哪一个? 【参考方案1】:

要获取行数和列数,我这样做:

#!/usr/bin/perl
use strict;
use warnings;

my $cols = 80;
my $rows = 24;
for (`stty -a`) 
    /columns ([0-9]+);/ and do  if ($1 > 0)  $cols = $1; ;
    /rows ([0-9]+);/    and do  if ($1 > 0)  $rows = $1; ;

print "cols=$cols\trows=$rows\n";

【讨论】:

【参考方案2】:

为什么不直接使用Term::Size?这使用了ioctl() 方法,包裹在漂亮整洁的 XS 代码中,所有这些都可以从 Perl 中使用。

【讨论】:

【参考方案3】:

Term::ReadKey 有一个内置的方法来检索终端的大小,它supports a range of different terminals 包括 Windows。考虑到sheer number of modules on CPAN that use this module,您可能已经安装了它。

#!/usr/bin/perl -w
use strict;
use Term::ReadKey   qw/ GetTerminalSize /;

my @winsize = &GetTerminalSize(\*STDOUT);
my ($cols, $rows, $xpix, $ypix) = @winsize;
print "cols:$cols rows:$rows xpix:$xpix ypix:$ypix\n";

【讨论】:

【参考方案4】:

这对我来说很好用:

#!perl

use strict;
use warnings;

require 'sys/ioctl.ph';

my $winsize = ""; # Silence warning
if (ioctl(STDOUT, TIOCGWINSZ() , $winsize)) 
        my ($rows, $cols, $xpix, $ypix) = unpack 'S4', $winsize;
        print join ":", $rows, $cols, $xpix, $ypix;
        print "\n";
 else 
        warn "Something didn't work.\n";

require 不需要(也不应该有)完整路径; TIOCGWINSZ 已经通过加载 ioctl 标头进行了定义,并且没有迹象表明必须将目标标量初始化为正确的大小(尽管如果根本没有初始化,perl 会抛出警告,因为它似乎无法识别特殊的 @ 987654322@-like ioctl 的性质,所以我将它设置为 "" 只是为了让它安静)。

【讨论】:

您会发现很少系统实际安装了sys/ioctl.ph文件。【参考方案5】:

另一种方法是让 C 告诉你TIOCGWINSZ 的值是什么。还不如让它告诉你另一个参数的大小,当你在它的时候。

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <termios.h>

int
main(argc, argv)
    int   argc;
    char *argv[];

    struct winsize mywinsize;
    int ttyfd;

    if ((ttyfd = open("/dev/tty", O_RDWR|O_NOCTTY)) == -1) 
        perror("open /dev/tty");
        exit(-1);
    

    if (ioctl(ttyfd, TIOCGWINSZ, &mywinsize) == -1) 
        perror("ioctl TIOCGWINSZ");
        exit(-1);
    

    printf("TIOCGWINSZ %#08lx\n",           TIOCGWINSZ             );
    printf("sizeof struct winsize %lu\n",   sizeof(struct winsize) ); 
    printf("rows %d\n",                     mywinsize.ws_row       );
    printf("cols %d\n",                     mywinsize.ws_col       );

    if (fclose(stdout) == EOF) 
        perror("close stdout");
        exit(-1);
    

    exit(0);

也许某个善良的灵魂会告诉你如何为你将其包装在Inline::C 中,但与此同时,这应该就足够了。请注意,这是一个可移植的程序,因为它可以在 ̲b̲o̲t̲h̲  类型的系统上运行:

☺ BSD ☺

    OpenBSD% cc getwinsz.c && a.out
    TIOCGWINSZ 0x40087468
    sizeof struct winsize 8
    rows 81
    cols 166

    Darwin% cc getwinsz.c && a.out
    TIOCGWINSZ 0x40087468
    sizeof struct winsize 8
    rows 37
    cols 126

☹ SysV ☹

   Slolaris% cc getwinsz.c && a.out
   TIOCGWINSZ 0x005468
   sizeof struct winsize 8
   rows 37
   cols 126

   Leenooxe% cc getwinsz.c && a.out
   TIOCGWINSZ 0x005413
   sizeof struct winsize 8
   rows 37
   cols 126

【讨论】:

以上是关于如何使用 ioctl 获取终端的宽度和高度?的主要内容,如果未能解决你的问题,请参考以下文章

如何在运行时获取设备高度和宽度?

如何找到终端窗口的宽度和高度?

ID3DXFont : 文本被拉伸,如何获取字体的宽度和高度?

如何通过 CSS 使所有不同高度和宽度的图像相同?

如何在 Mac 插件中使用 ioctl() 设置 RTS?

如何使 svg 适合 html 的宽度和高度?