代码之家  ›  专栏  ›  技术社区  ›  sid_com

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

  •  2
  • sid_com  · 技术社区  · 15 年前

    我要做些什么才能让这件事成功?

     #!/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 .

    5 回复  |  直到 8 年前
        1
  •  1
  •   hobbs    15 年前

    这对我很好:

    #!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会抛出一个警告,因为它似乎无法识别 read -就像ioctl的性质一样,所以我将其设置为“”只是为了消除这种情况)。

        2
  •  3
  •   Toto    15 年前

    要获取行数和列数,我正在执行以下操作:

    #!/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";
    
        3
  •  2
  •   LeoNerd    13 年前

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

        4
  •  0
  •   tchrist    15 年前

    另一种方法是,你会要求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 对你来说,但同时,这应该足够了。请注意,这是一个可移植程序,因为它运行在各种类型的系统上:

    疯牛病

        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
    

    系统

       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
    
        5
  •  0
  •   amphetamachine    10 年前

    Term::ReadKey 具有用于检索终端大小的内置方法,并且 supports a range of different terminals 包括窗户。考虑到 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";